From 7f4af10bce63da68b4aad4980b222df0edc935d5 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 20 Oct 2021 15:55:51 +0200 Subject: [PATCH 001/805] [CI] Add Clang 13.0 to the build matrix. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1ee7ed43e..6b3b0a7901 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -138,7 +138,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '6.0', '7', '8', '9', '10', '11', '12' ] + version: [ '6.0', '7', '8', '9', '10', '11', '12', '13' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} From 3d9f086be205d1c5e1120d9fc17fa163b62321ee Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sat, 6 Nov 2021 12:36:25 +0000 Subject: [PATCH 002/805] [Java] Style. --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 2d1fcb6d27..543e398d9a 100644 --- a/build.gradle +++ b/build.gradle @@ -841,8 +841,7 @@ class ChecksumTask extends DefaultTask { SHA_256.reset() - final File[] files = inputDirectory.listFiles() - for (final File f : files) + for (final File f : inputDirectory.listFiles()) { final byte[] raw = Files.readAllBytes(f.toPath()) final byte[] normalized = normaliseEol(raw) From 9b9786c5500a560d0d395e3686ea6e7ead95e2dd Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sat, 6 Nov 2021 14:26:12 +0000 Subject: [PATCH 003/805] [C++] Only generate the macros and includes required for enum types. --- .../sbe/generation/cpp/CppGenerator.java | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 219beb8377..913b75f426 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -778,7 +778,7 @@ private void generateEnum(final List tokens) throws IOException try (Writer out = outputManager.createOutput(enumName)) { - out.append(generateFileHeader(ir.namespaces(), enumName, null)); + out.append(generateEnumFileHeader(ir.namespaces(), enumName)); out.append(generateEnumDeclaration(enumName)); out.append(generateEnumValues(tokens.subList(1, tokens.size() - 1), enumToken)); @@ -1168,6 +1168,47 @@ private static CharSequence generateFileHeader( return sb; } + private static CharSequence generateEnumFileHeader(final CharSequence[] namespaces, final String className) + { + final StringBuilder sb = new StringBuilder(); + + sb.append("/* Generated SBE (Simple Binary Encoding) message codec */\n"); + + sb.append(String.format( + "#ifndef _%1$s_%2$s_H_\n" + + "#define _%1$s_%2$s_H_\n\n" + + + "#if !defined(__STDC_LIMIT_MACROS)\n" + + "# define __STDC_LIMIT_MACROS 1\n" + + "#endif\n\n" + + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + + "\n" + + + "#define SBE_NULLVALUE_INT8 (std::numeric_limits::min)()\n" + + "#define SBE_NULLVALUE_INT16 (std::numeric_limits::min)()\n" + + "#define SBE_NULLVALUE_INT32 (std::numeric_limits::min)()\n" + + "#define SBE_NULLVALUE_INT64 (std::numeric_limits::min)()\n" + + "#define SBE_NULLVALUE_UINT8 (std::numeric_limits::max)()\n" + + "#define SBE_NULLVALUE_UINT16 (std::numeric_limits::max)()\n" + + "#define SBE_NULLVALUE_UINT32 (std::numeric_limits::max)()\n" + + "#define SBE_NULLVALUE_UINT64 (std::numeric_limits::max)()\n", + String.join("_", namespaces).toUpperCase(), + className.toUpperCase())); + + sb.append("\nnamespace "); + sb.append(String.join(" {\nnamespace ", namespaces)); + sb.append(" {\n\n"); + + return sb; + } + private static CharSequence generateClassDeclaration(final String className) { return From 2697b8eebf3b64317a9c37cf6c2536a04fb6194b Mon Sep 17 00:00:00 2001 From: ratcash Date: Thu, 11 Nov 2021 12:21:59 +0100 Subject: [PATCH 004/805] Mark classes of deprecated messages with @Deprecated. (#876) * Mark classes of deprecated messages with @Deprecated * Revert breaking changes * Create a dedicated xml for java test --- .../sbe/generation/java/JavaGenerator.java | 4 ++++ .../generation/java/JavaGeneratorTest.java | 23 +++++++++++++++++++ .../resources/deprecated-msg-test-schema.xml | 20 ++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 sbe-tool/src/test/resources/deprecated-msg-test-schema.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index f9dd57a178..a96f018116 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1657,6 +1657,10 @@ private static CharSequence generateDeclaration( final StringBuilder sb = new StringBuilder(); generateTypeJavadoc(sb, BASE_INDENT, typeToken); + if (typeToken.deprecated() > 0) + { + sb.append("@Deprecated\n"); + } sb.append("@SuppressWarnings(\"all\")\n") .append("public final class ").append(className).append(implementsString).append('\n') .append("{\n"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 5ffc034cd8..3a9064b810 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -458,6 +458,29 @@ public void shouldGenerateRepeatingGroupCountLimits() throws Exception assertEquals(65534, maxValue.invoke(null)); } + @Test + public void shouldMarkDeprecatedClasses() throws Exception + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(Tests.getLocalResource("deprecated-msg-test-schema.xml"), options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + + generator().generate(); + final String encoderFqcn = ir.applicableNamespace() + ".DeprecatedMessageEncoder"; + final Class encoderClazz = compile(encoderFqcn); + assertNotNull(encoderClazz); + assertTrue(encoderClazz.isAnnotationPresent(Deprecated.class)); + + final String decoderFqcn = ir.applicableNamespace() + ".DeprecatedMessageDecoder"; + final Class decoderClazz = compile(decoderFqcn); + assertNotNull(decoderClazz); + assertTrue(decoderClazz.isAnnotationPresent(Deprecated.class)); + } + private Class getModelClass(final Object encoder) throws ClassNotFoundException { final String className = "Model"; diff --git a/sbe-tool/src/test/resources/deprecated-msg-test-schema.xml b/sbe-tool/src/test/resources/deprecated-msg-test-schema.xml new file mode 100644 index 0000000000..e7ed27e445 --- /dev/null +++ b/sbe-tool/src/test/resources/deprecated-msg-test-schema.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + From 0bfe5d705bde401a012d7b14e60acf4c63f0118e Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 11 Nov 2021 17:47:22 +0000 Subject: [PATCH 005/805] [Java] Upgrade to Checkstyle 9.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 543e398d9a..c0a572bd37 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ def toolchainLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(buildJavaVersion) } -def checkstyleVersion = '9.0.1' +def checkstyleVersion = '9.1' def hamcrestVersion = '2.2' def mockitoVersion = '4.0.0' def junitVersion = '5.8.1' From 680e28ff08151d4c2ca74b9b7c407be28aa91c15 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Tue, 16 Nov 2021 05:55:26 -0600 Subject: [PATCH 006/805] [Rust] fixed rust codegen to support multiple schema file with same package (#877) Co-authored-by: Michael Ward --- rust/benches/car_benchmark.rs | 2 +- rust/benches/md_benchmark.rs | 2 +- rust/tests/baseline_test.rs | 4 +- rust/tests/big_endian_test.rs | 4 +- rust/tests/extension_test.rs | 4 +- rust/tests/issue_435_test.rs | 16 ++-- .../java/uk/co/real_logic/sbe/SbeTool.java | 2 +- .../sbe/generation/rust/LibRsDef.java | 73 ++++------------- .../sbe/generation/rust/MessageCoderDef.java | 2 +- .../sbe/generation/rust/RustGenerator.java | 78 +++++++++---------- .../generation/rust/RustOutputManager.java | 36 ++++++--- .../sbe/generation/rust/RustUtil.java | 5 ++ 12 files changed, 101 insertions(+), 127 deletions(-) diff --git a/rust/benches/car_benchmark.rs b/rust/benches/car_benchmark.rs index c6425ad379..7ca9c2e5c8 100644 --- a/rust/benches/car_benchmark.rs +++ b/rust/benches/car_benchmark.rs @@ -28,7 +28,7 @@ fn encode(state: &mut State) -> SbeResult { let mut acceleration = AccelerationEncoder::default(); let mut extras = OptionalExtras::default(); - car = car.wrap(WriteBuf::new(buffer), message_header::ENCODED_LENGTH); + car = car.wrap(WriteBuf::new(buffer), message_header_codec::ENCODED_LENGTH); car = car.header(0).parent()?; car.code(Model::A); diff --git a/rust/benches/md_benchmark.rs b/rust/benches/md_benchmark.rs index 3b59709a06..b429622f92 100644 --- a/rust/benches/md_benchmark.rs +++ b/rust/benches/md_benchmark.rs @@ -22,7 +22,7 @@ fn encode_md(state: &mut State) -> SbeResult { let mut market_data = MarketDataIncrementalRefreshTradesEncoder::default(); let mut md_inc_grp = MdIncGrpEncoder::default(); - market_data = market_data.wrap(WriteBuf::new(buffer), message_header::ENCODED_LENGTH); + market_data = market_data.wrap(WriteBuf::new(buffer), message_header_codec::ENCODED_LENGTH); market_data = market_data.header(0).parent()?; market_data.transact_time(1234); diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index 8156b71e53..a19b39a96e 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -33,7 +33,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); - assert_eq!(car::SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(car_codec::SBE_TEMPLATE_ID, header.template_id()); car = car.header(header); // Car... @@ -167,7 +167,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car = car.wrap( WriteBuf::new(buffer.as_mut_slice()), - message_header::ENCODED_LENGTH, + message_header_codec::ENCODED_LENGTH, ); car = car.header(0).parent()?; diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index ae677dce21..40b652c1be 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -30,7 +30,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); - assert_eq!(car::SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(car_codec::SBE_TEMPLATE_ID, header.template_id()); car = car.header(header); // Car... @@ -161,7 +161,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car = car.wrap( WriteBuf::new(buffer.as_mut_slice()), - message_header::ENCODED_LENGTH, + message_header_codec::ENCODED_LENGTH, ); car = car.header(0).parent()?; diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index 56496d271c..5e993f7701 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -32,7 +32,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); - assert_eq!(car::SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(car_codec::SBE_TEMPLATE_ID, header.template_id()); car = car.header(header); // Car... @@ -168,7 +168,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car = car.wrap( WriteBuf::new(buffer.as_mut_slice()), - message_header::ENCODED_LENGTH, + message_header_codec::ENCODED_LENGTH, ); car = car.header(0).parent()?; diff --git a/rust/tests/issue_435_test.rs b/rust/tests/issue_435_test.rs index e4e6c1e3c5..3c9b43b0da 100644 --- a/rust/tests/issue_435_test.rs +++ b/rust/tests/issue_435_test.rs @@ -3,7 +3,7 @@ use ::issue_435::*; fn create_encoder(buffer: &mut Vec) -> Issue435Encoder { let issue_435 = Issue435Encoder::default().wrap( WriteBuf::new(buffer.as_mut_slice()), - message_header::ENCODED_LENGTH, + message_header_codec::ENCODED_LENGTH, ); let mut header = issue_435.header(0); header.s(*SetRef::default().set_one(true)); @@ -12,9 +12,9 @@ fn create_encoder(buffer: &mut Vec) -> Issue435Encoder { #[test] fn issue_435_ref_test() -> SbeResult<()> { - assert_eq!(9, message_header::ENCODED_LENGTH); - assert_eq!(1, issue_435::SBE_BLOCK_LENGTH); - assert_eq!(0, issue_435::SBE_SCHEMA_VERSION); + assert_eq!(9, message_header_codec::ENCODED_LENGTH); + assert_eq!(1, issue_435_codec::SBE_BLOCK_LENGTH); + assert_eq!(0, issue_435_codec::SBE_SCHEMA_VERSION); // encode... let mut buffer = vec![0u8; 256]; @@ -24,10 +24,10 @@ fn issue_435_ref_test() -> SbeResult<()> { // decode... let buf = ReadBuf::new(buffer.as_slice()); let header = MessageHeaderDecoder::default().wrap(buf, 0); - assert_eq!(issue_435::SBE_BLOCK_LENGTH, header.block_length()); - assert_eq!(issue_435::SBE_SCHEMA_VERSION, header.version()); - assert_eq!(issue_435::SBE_TEMPLATE_ID, header.template_id()); - assert_eq!(issue_435::SBE_SCHEMA_ID, header.schema_id()); + assert_eq!(issue_435_codec::SBE_BLOCK_LENGTH, header.block_length()); + assert_eq!(issue_435_codec::SBE_SCHEMA_VERSION, header.version()); + assert_eq!(issue_435_codec::SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(issue_435_codec::SBE_SCHEMA_ID, header.schema_id()); assert_eq!(*SetRef::default().set_one(true), header.s()); let decoder = Issue435Decoder::default().header(header); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index 565aea2145..ba8fb99784 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -164,7 +164,7 @@ public class SbeTool * Specifies token that should be appended to keywords to avoid compilation errors. *

* If none is supplied then use of keywords results in an error during schema parsing. The - * underscore character is a good example fo a token to use. + * underscore character is a good example of a token to use. */ public static final String KEYWORD_APPEND_TOKEN = "sbe.keyword.append.token"; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index aab9f6a592..6799c64a27 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -15,17 +15,12 @@ */ package uk.co.real_logic.sbe.generation.rust; -import org.agrona.generation.OutputManager; -import uk.co.real_logic.sbe.generation.rust.RustGenerator.CodecType; - import java.io.IOException; import java.io.Writer; import java.nio.ByteOrder; +import java.nio.file.Files; import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.Map; import static java.nio.ByteOrder.LITTLE_ENDIAN; import static uk.co.real_logic.sbe.generation.rust.RustGenerator.*; @@ -36,11 +31,7 @@ */ class LibRsDef { - private final LinkedHashMap> modules = new LinkedHashMap<>(); - private final ArrayList enumDefs = new ArrayList<>(); - private final ArrayList bitSetDefs = new ArrayList<>(); - - private final OutputManager outputManager; + private final RustOutputManager outputManager; private final ByteOrder byteOrder; /** @@ -50,28 +41,13 @@ class LibRsDef * @param byteOrder for the Encoding. */ LibRsDef( - final OutputManager outputManager, + final RustOutputManager outputManager, final ByteOrder byteOrder) { this.outputManager = outputManager; this.byteOrder = byteOrder; } - void addMod(final String modName, final CodecType codecType) - { - modules.computeIfAbsent(modName, __ -> new HashSet<>()).add(codecType); - } - - void addEnum(final String enumDef) - { - enumDefs.add(enumDef); - } - - void addBitSet(final String bitSetDef) - { - bitSetDefs.add(bitSetDef); - } - void generate() throws IOException { try (Writer libRs = outputManager.createOutput("lib")) @@ -79,31 +55,28 @@ void generate() throws IOException indent(libRs, 0, "#![forbid(unsafe_code)]\n"); indent(libRs, 0, "#![allow(clippy::upper_case_acronyms)]\n"); indent(libRs, 0, "#![allow(non_camel_case_types)]\n"); - indent(libRs, 0, "use core::{convert::TryInto};\n\n"); + indent(libRs, 0, "use ::core::{convert::TryInto};\n\n"); + + final ArrayList modules = new ArrayList<>(); + Files.walk(outputManager.getSrcDirPath()) + .filter(Files::isRegularFile) + .map(path -> path.getFileName().toString()) + .filter(fileName -> fileName.endsWith(".rs")) + .filter(fileName -> !fileName.equals("lib.rs")) + .map(fileName -> fileName.substring(0, fileName.length() - 3)) + .forEach(modules::add); // add modules - for (final String mod : modules.keySet()) + for (final String mod : modules) { indent(libRs, 0, "pub mod %s;\n", toLowerSnakeCase(mod)); } indent(libRs, 0, "\n"); // add re-export of modules - for (final Map.Entry> entry : modules.entrySet()) + for (final String module : modules) { - final String mod = entry.getKey(); - final HashSet codecTypes = entry.getValue(); - - if (codecTypes.size() == 1) - { - indent(libRs, 0, "pub use %s::%s::*;\n", - toLowerSnakeCase(mod), - toLowerSnakeCase(codecTypes.toArray()[0].toString())); - } - else - { - indent(libRs, 0, "pub use %s::{decoder::*, encoder::*};\n", toLowerSnakeCase(mod)); - } + indent(libRs, 0, "pub use %s::*;\n", toLowerSnakeCase(module)); } indent(libRs, 0, "\n"); @@ -115,20 +88,6 @@ void generate() throws IOException generateReadBuf(libRs, byteOrder); generateWriteBuf(libRs, byteOrder); - - // append generated enums - for (final String code : enumDefs) - { - libRs.append(code); - indent(libRs, 0, "\n"); - } - - // append generated bitSets - for (final String code : bitSetDefs) - { - libRs.append(code); - indent(libRs, 0, "\n"); - } } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 1a7f7a2315..e885735663 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -147,7 +147,7 @@ void appendMessageHeaderDecoderFn(final Appendable out) throws IOException indent(out, 3, "let acting_version = header.version();\n\n"); indent(out, 3, "self.wrap(\n"); indent(out, 4, "header.parent().unwrap(),\n"); - indent(out, 4, "message_header::ENCODED_LENGTH,\n"); + indent(out, 4, "message_header_codec::ENCODED_LENGTH,\n"); indent(out, 4, "acting_block_length,\n"); indent(out, 4, "acting_version,\n"); indent(out, 3, ")\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index a1f253b8ce..c58a38dc27 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -126,17 +126,14 @@ public void generate() throws IOException // lib.rs final LibRsDef libRsDef = new LibRsDef(outputManager, ir.byteOrder()); - generateEnums(ir, libRsDef); - generateBitSets(ir, libRsDef); - generateComposites(ir, libRsDef, outputManager); + generateEnums(ir, outputManager); + generateBitSets(ir, outputManager); + generateComposites(ir, outputManager); for (final List tokens : ir.messages()) { final Token msgToken = tokens.get(0); - - libRsDef.addMod(msgToken.name(), Encoder); - libRsDef.addMod(msgToken.name(), Decoder); - + final String codecModName = codecModName(msgToken.name()); final List messageBody = getMessageBody(tokens); int i = 0; @@ -149,9 +146,11 @@ public void generate() throws IOException final List varData = new ArrayList<>(); collectVarData(messageBody, i, varData); - try (Writer out = outputManager.createOutput(msgToken.name())) + try (Writer out = outputManager.createOutput(codecModName)) { indent(out, 0, "use crate::*;\n\n"); + indent(out, 0, "pub use encoder::*;\n"); + indent(out, 0, "pub use decoder::*;\n\n"); final String blockLengthType = blockLengthType(); final String templateIdType = rustTypeName(ir.headerStructure().templateIdType()); final String schemaIdType = rustTypeName(ir.headerStructure().schemaIdType()); @@ -981,32 +980,36 @@ static void generateDecoderVarData( private static void generateBitSets( final Ir ir, - final LibRsDef libRsDef) throws IOException + final RustOutputManager outputManager) throws IOException { for (final List tokens : ir.types()) { if (!tokens.isEmpty() && tokens.get(0).signal() == BEGIN_SET) { - final StringBuilder sb = new StringBuilder(); - generateSingleBitSet(tokens, sb); - libRsDef.addBitSet(sb.toString()); + final Token beginToken = tokens.get(0); + final String bitSetType = formatStructName(beginToken.applicableTypeName()); + + try (Writer out = outputManager.createOutput(bitSetType)) + { + generateSingleBitSet(bitSetType, tokens, out); + } } } } private static void generateSingleBitSet( + final String bitSetType, final List tokens, final Appendable writer) throws IOException { final Token beginToken = tokens.get(0); - final String setType = formatStructName(beginToken.applicableTypeName()); final String rustPrimitiveType = rustTypeName(beginToken.encoding().primitiveType()); indent(writer, 0, "#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\n"); - indent(writer, 0, "pub struct %s(pub %s);\n", setType, rustPrimitiveType); - indent(writer, 0, "impl %s {\n", setType); + indent(writer, 0, "pub struct %s(pub %s);\n", bitSetType, rustPrimitiveType); + indent(writer, 0, "impl %s {\n", bitSetType); indent(writer, 1, "#[inline]\n"); indent(writer, 1, "pub fn new(value: %s) -> Self {\n", rustPrimitiveType); - indent(writer, 2, "%s(value)\n", setType); + indent(writer, 2, "%s(value)\n", bitSetType); indent(writer, 1, "}\n\n"); indent(writer, 1, "#[inline]\n"); @@ -1044,10 +1047,10 @@ private static void generateSingleBitSet( } indent(writer, 0, "}\n"); - indent(writer, 0, "impl core::fmt::Debug for %s {\n", setType); + indent(writer, 0, "impl core::fmt::Debug for %s {\n", bitSetType); indent(writer, 1, "#[inline]\n"); indent(writer, 1, "fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {\n"); - indent(writer, 2, "write!(fmt, \"%s[", setType); + indent(writer, 2, "write!(fmt, \"%s[", bitSetType); final StringBuilder builder = new StringBuilder(); final StringBuilder arguments = new StringBuilder(); @@ -1128,7 +1131,7 @@ static void appendImplDecoderTrait( private static void generateEnums( final Ir ir, - final LibRsDef libRsDef) throws IOException + final RustOutputManager outputManager) throws IOException { final Set enumTypeNames = new HashSet<>(); for (final List tokens : ir.types()) @@ -1145,16 +1148,15 @@ private static void generateEnums( } final String typeName = beginToken.applicableTypeName(); - if (enumTypeNames.contains(typeName)) + if (!enumTypeNames.add(typeName)) { continue; } - final StringBuilder sb = new StringBuilder(); - generateEnum(tokens, sb); - enumTypeNames.add(typeName); - - libRsDef.addEnum(sb.toString()); + try (Writer out = outputManager.createOutput(typeName)) + { + generateEnum(tokens, out); + } } } @@ -1219,39 +1221,41 @@ private static void generateEnum( private static void generateComposites( final Ir ir, - final LibRsDef libRsDef, - final OutputManager outputManager) throws IOException + final RustOutputManager outputManager) throws IOException { for (final List tokens : ir.types()) { if (!tokens.isEmpty() && tokens.get(0).signal() == Signal.BEGIN_COMPOSITE) { - generateComposite(tokens, libRsDef, outputManager); + generateComposite(tokens, outputManager); } } } private static void generateComposite( final List tokens, - final LibRsDef libRsDef, - final OutputManager outputManager) throws IOException + final RustOutputManager outputManager) throws IOException { final Token token = tokens.get(0); final String compositeName = token.applicableTypeName(); + final String compositeModName = codecModName(compositeName); - try (Writer out = outputManager.createOutput(compositeName)) + try (Writer out = outputManager.createOutput(compositeModName)) { indent(out, 0, "use crate::*;\n\n"); + indent(out, 0, "pub use encoder::*;\n"); + indent(out, 0, "pub use decoder::*;\n\n"); + final int encodedLength = tokens.get(0).encodedLength(); if (encodedLength > 0) { indent(out, 0, "pub const ENCODED_LENGTH: usize = %d;\n\n", encodedLength); } - generateCompositeEncoder(tokens, libRsDef, compositeName, encoderName(compositeName), out); + generateCompositeEncoder(tokens, encoderName(compositeName), out); indent(out, 0, "\n"); - generateCompositeDecoder(tokens, libRsDef, compositeName, decoderName(compositeName), out); + generateCompositeDecoder(tokens, decoderName(compositeName), out); } } @@ -1331,13 +1335,9 @@ static void appendImplDecoderForComposite( private static void generateCompositeEncoder( final List tokens, - final LibRsDef libRsDef, - final String compositeName, final String encoderName, final Writer out) throws IOException { - libRsDef.addMod(compositeName, Encoder); - indent(out, 0, "pub mod encoder {\n"); indent(out, 1, "use super::*;\n\n"); @@ -1395,16 +1395,12 @@ private static void generateCompositeEncoder( private static void generateCompositeDecoder( final List tokens, - final LibRsDef libRsDef, - final String compositeName, final String decoderName, final Writer out) throws IOException { indent(out, 0, "pub mod decoder {\n"); indent(out, 1, "use super::*;\n\n"); - libRsDef.addMod(compositeName, Decoder); - indent(out, 1, "#[derive(Debug, Default)]\n"); indent(out, 1, "pub struct %s

{\n", decoderName); indent(out, 2, "parent: Option

,\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java index e1cd8d9941..5fa9c4bf93 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java @@ -21,10 +21,11 @@ import java.io.File; import java.io.IOException; import java.io.Writer; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import static java.io.File.separatorChar; +import static java.nio.charset.StandardCharsets.UTF_8; import static uk.co.real_logic.sbe.generation.rust.RustUtil.toLowerSnakeCase; /** @@ -36,8 +37,19 @@ public class RustOutputManager implements OutputManager private final File rootDir; private final File srcDir; + static File createDir(final String dirName) + { + final File dir = new File(dirName); + if (!dir.exists() && !dir.mkdirs()) + { + throw new IllegalStateException("Unable to create directory: " + dirName); + } + return dir; + } + /** * Create a new {@link OutputManager} for generating rust source files into a given module. + * * @param baseDirName for the generated source code. * @param packageName for the generated source code relative to the baseDirName. */ @@ -52,12 +64,7 @@ public RustOutputManager(final String baseDirName, final String packageName) rootDir = new File(libDirName); final String srcDirName = libDirName + separatorChar + "src"; - - srcDir = new File(srcDirName); - if (!srcDir.exists() && !srcDir.mkdirs()) - { - throw new IllegalStateException("Unable to create directory: " + srcDirName); - } + srcDir = createDir(srcDirName); } /** @@ -70,15 +77,17 @@ public RustOutputManager(final String baseDirName, final String packageName) * @return a {@link java.io.Writer} to which the source code should be written. * @throws IOException if an issue occurs when creating the file. */ - @Override public Writer createOutput(final String name) throws IOException + @Override + public Writer createOutput(final String name) throws IOException { final String fileName = toLowerSnakeCase(name) + ".rs"; final File targetFile = new File(srcDir, fileName); - return Files.newBufferedWriter(targetFile.toPath(), StandardCharsets.UTF_8); + return Files.newBufferedWriter(targetFile.toPath(), UTF_8); } /** - * + * Creates a new Cargo.toml file + *

* @return a {@link java.io.Writer} to which the crate definition should be written. * @throws IOException if an issue occurs when creating the file. */ @@ -86,7 +95,12 @@ public Writer createCargoToml() throws IOException { final String fileName = "Cargo.toml"; final File targetFile = new File(rootDir, fileName); - return Files.newBufferedWriter(targetFile.toPath(), StandardCharsets.UTF_8); + return Files.newBufferedWriter(targetFile.toPath(), UTF_8); + } + + Path getSrcDirPath() + { + return srcDir.toPath(); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 9ee5bd204c..19aff8c97d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -122,6 +122,11 @@ static String formatStructName(final String structName) return Generators.toUpperFirstChar(structName); } + static String codecModName(final String prefix) + { + return toLowerSnakeCase(prefix + "Codec"); + } + static String codecName(final String structName, final CodecType codecType) { return formatStructName(structName + codecType.name()); From 67a5cf17c3f7b00bb1b2a640c5a37bb341f4309c Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 16 Nov 2021 12:05:16 +0000 Subject: [PATCH 007/805] [Java] Tidy up after merge of PR #877. --- .../sbe/generation/rust/LibRsDef.java | 8 +++---- .../sbe/generation/rust/MessageCoderDef.java | 1 - .../sbe/generation/rust/RustGenerator.java | 21 +++++++++---------- .../generation/rust/RustOutputManager.java | 3 +-- .../sbe/generation/rust/RustUtil.java | 5 ++--- .../sbe/generation/rust/SubGroup.java | 1 - 6 files changed, 17 insertions(+), 22 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 6799c64a27..1baf03f047 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -60,10 +60,10 @@ void generate() throws IOException final ArrayList modules = new ArrayList<>(); Files.walk(outputManager.getSrcDirPath()) .filter(Files::isRegularFile) - .map(path -> path.getFileName().toString()) - .filter(fileName -> fileName.endsWith(".rs")) - .filter(fileName -> !fileName.equals("lib.rs")) - .map(fileName -> fileName.substring(0, fileName.length() - 3)) + .map((path) -> path.getFileName().toString()) + .filter((fileName) -> fileName.endsWith(".rs")) + .filter((fileName) -> !fileName.equals("lib.rs")) + .map((fileName) -> fileName.substring(0, fileName.length() - 3)) .forEach(modules::add); // add modules diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index e885735663..8eef8ecd77 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -119,7 +119,6 @@ void appendTo(final Appendable dest) throws IOException dest.append(sb); } - @Override public SubGroup addSubGroup(final String name, final int level, final Token groupToken) { final SubGroup subGroup = new SubGroup(name, level, groupToken); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index c58a38dc27..27ccaea108 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -33,10 +33,11 @@ import java.util.Set; import static java.lang.String.format; -import static uk.co.real_logic.sbe.generation.rust.RustGenerator.CodecType.Decoder; -import static uk.co.real_logic.sbe.generation.rust.RustGenerator.CodecType.Encoder; import static uk.co.real_logic.sbe.generation.rust.RustUtil.*; -import static uk.co.real_logic.sbe.ir.GenerationUtil.*; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; +import static uk.co.real_logic.sbe.ir.GenerationUtil.getMessageBody; import static uk.co.real_logic.sbe.ir.Signal.BEGIN_ENUM; import static uk.co.real_logic.sbe.ir.Signal.BEGIN_SET; @@ -53,7 +54,7 @@ enum CodecType { Decoder { - @Override String bufType() + String bufType() { return READ_BUF_TYPE; } @@ -61,7 +62,7 @@ enum CodecType Encoder { - @Override String bufType() + String bufType() { return WRITE_BUF_TYPE; } @@ -81,8 +82,8 @@ interface ParentDef /** * Create a new Rust language {@link CodeGenerator}. * - * @param ir for the messages and types. - * @param outputManager for generating the codecs to. + * @param ir for the messages and types. + * @param outputManager for generating the codecs to. */ public RustGenerator( final Ir ir, @@ -227,9 +228,9 @@ static void generateEncoderFields( break; } } - catch (final IOException e) + catch (final IOException ex) { - throw new RuntimeException(e); + throw new RuntimeException(ex); } }); } @@ -1465,6 +1466,4 @@ private static void appendConstAccessor( indent(writer, level + 1, rustExpression + "\n"); indent(writer, level, "}\n\n"); } - - } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java index 5fa9c4bf93..864b8b1dd2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java @@ -44,6 +44,7 @@ static File createDir(final String dirName) { throw new IllegalStateException("Unable to create directory: " + dirName); } + return dir; } @@ -77,7 +78,6 @@ public RustOutputManager(final String baseDirName, final String packageName) * @return a {@link java.io.Writer} to which the source code should be written. * @throws IOException if an issue occurs when creating the file. */ - @Override public Writer createOutput(final String name) throws IOException { final String fileName = toLowerSnakeCase(name) + ".rs"; @@ -102,5 +102,4 @@ Path getSrcDirPath() { return srcDir.toPath(); } - } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 19aff8c97d..5e65a327f4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -32,13 +32,12 @@ import static uk.co.real_logic.sbe.generation.rust.RustGenerator.CodecType.Encoder; /** - * + * Utility method for Rust codec generation. */ public class RustUtil { static final String INDENT = " "; - public static final Map TYPE_NAME_BY_PRIMITIVE_TYPE_MAP = - new EnumMap<>(PrimitiveType.class); + static final Map TYPE_NAME_BY_PRIMITIVE_TYPE_MAP = new EnumMap<>(PrimitiveType.class); static { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 2fc4098335..2d2af72993 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -41,7 +41,6 @@ class SubGroup implements RustGenerator.ParentDef this.groupToken = groupToken; } - @Override public SubGroup addSubGroup(final String name, final int level, final Token groupToken) { final SubGroup subGroup = new SubGroup(name, level, groupToken); From 245dd30ecb3c6987d7d0020700cac4636f97dd9f Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 16 Nov 2021 20:03:28 +0100 Subject: [PATCH 008/805] Version bump for release. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index d07d97c65b..63610187e2 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.24.1-SNAPSHOT \ No newline at end of file +1.25.0-SNAPSHOT From 57979f81aca34adf47c1b5c9ee9c8144f9fce1b8 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 16 Nov 2021 20:29:03 +0000 Subject: [PATCH 009/805] [Java] Upgrade to Agrona 1.13.0. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c0a572bd37..99b17ba7b8 100644 --- a/build.gradle +++ b/build.gradle @@ -47,8 +47,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.0.0' def junitVersion = '5.8.1' def jmhVersion = '1.33' -def agronaVersion = '1.12.0' -def agronaVersionRange = '[1.12,1.13[' // allow any patch release of 1.12.x +def agronaVersion = '1.13.0' +def agronaVersionRange = '[1.13,1.14[' // allow any patch release of 1.13.x def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From afb62b59e2310630914fca0f0ad39490777e8133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Ram=C3=A9?= Date: Wed, 17 Nov 2021 09:31:23 +0000 Subject: [PATCH 010/805] DirectBuffer - Support ArraySegment for underlying array (#878) * DirectBuffer - Support ArraySegment for backing storage * fix comments --- csharp/sbe-dll/DirectBuffer.cs | 37 +++++++++++++++++++++++++++ csharp/sbe-tests/DirectBufferTests.cs | 34 ++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/csharp/sbe-dll/DirectBuffer.cs b/csharp/sbe-dll/DirectBuffer.cs index 52b78ea4af..09eb64ec7e 100644 --- a/csharp/sbe-dll/DirectBuffer.cs +++ b/csharp/sbe-dll/DirectBuffer.cs @@ -64,6 +64,25 @@ public DirectBuffer(byte* pBuffer, int bufferLength, BufferOverflowDelegate buff Wrap(pBuffer, bufferLength); } + ///

+ /// Attach a view to a buffer owned by external code + /// + /// byte buffer + public DirectBuffer(ArraySegment buffer) : this(buffer, null) + { + } + + /// + /// Attach a view to a buffer owned by external code + /// + /// byte buffer + /// delegate to allow reallocation of buffer + public DirectBuffer(ArraySegment buffer, BufferOverflowDelegate bufferOverflow) + { + this.bufferOverflow = bufferOverflow; + Wrap(buffer); + } + /// /// Creates a DirectBuffer that can later be wrapped /// @@ -114,6 +133,24 @@ public void Wrap(byte* pBuffer, int bufferLength) _needToFreeGCHandle = false; } + /// + /// Recycles an existing from a byte buffer owned by external code + /// + /// buffer of bytes + public void Wrap(ArraySegment buffer) + { + if (buffer == null) throw new ArgumentNullException(nameof(buffer)); + + FreeGCHandle(); + + // pin the buffer so it does not get moved around by GC, this is required since we use pointers + _pinnedGCHandle = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); + _needToFreeGCHandle = true; + + _pBuffer = ((byte*)_pinnedGCHandle.AddrOfPinnedObject().ToPointer()) + buffer.Offset; + _capacity = buffer.Count; + } + /// /// Capacity of the underlying buffer /// diff --git a/csharp/sbe-tests/DirectBufferTests.cs b/csharp/sbe-tests/DirectBufferTests.cs index 2ac82e4e07..4c37ebe1f0 100644 --- a/csharp/sbe-tests/DirectBufferTests.cs +++ b/csharp/sbe-tests/DirectBufferTests.cs @@ -66,6 +66,40 @@ public void ConstructFromNativeBuffer() } } + [TestMethod] + public void ConstructFromByteArray() + { + var buffer = new byte[16]; + + const int value = 5; + const int index = 0; + + using (var directBuffer = new DirectBuffer(buffer)) + { + directBuffer.Int64PutLittleEndian(index, value); + Assert.AreEqual(value, buffer[index]); + } + } + + [TestMethod] + public void ConstructFromArraySegment() + { + const int value = 5; + const int index = 0; + const int offset = 512; + const int size = 1024; + + var bigBuffer = new byte[size]; + var buffer = new ArraySegment(bigBuffer, offset, size - offset); + + using (var directBuffer = new DirectBuffer(buffer)) + { + directBuffer.Int64PutLittleEndian(index, value); + Assert.AreEqual(value, bigBuffer[offset + index]); + Assert.AreEqual(value, buffer.AsSpan()[index]); + } + } + [TestMethod] public void Recycle() { From 6434c28ccf248f5f94d8f67c654c57c978664546 Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Wed, 17 Nov 2021 08:34:32 -0800 Subject: [PATCH 011/805] 1.25.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 63610187e2..ad2191947f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.0-SNAPSHOT +1.25.0 From f611518bec16d2c9ef3df2f6b3ec2dcfb6e256a5 Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Wed, 17 Nov 2021 08:36:29 -0800 Subject: [PATCH 012/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index ad2191947f..b1d7655df2 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.0 +1.25.1-SNAPSHOT From d20adc38e5ce8007813717dbc7974f54111c938f Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sun, 21 Nov 2021 13:43:31 +0000 Subject: [PATCH 013/805] [Java] Upgrade to Mockito 4.1.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 99b17ba7b8..ce4fd4e7b1 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.1' def hamcrestVersion = '2.2' -def mockitoVersion = '4.0.0' +def mockitoVersion = '4.1.0' def junitVersion = '5.8.1' def jmhVersion = '1.33' def agronaVersion = '1.13.0' From a2f348a3113cc8eea2e1c73378829f068e18acf1 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 21 Nov 2021 15:06:59 +0100 Subject: [PATCH 014/805] [Java] Upgrade to Agrona 1.13.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ce4fd4e7b1..f7389425a5 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.1.0' def junitVersion = '5.8.1' def jmhVersion = '1.33' -def agronaVersion = '1.13.0' +def agronaVersion = '1.13.1' def agronaVersionRange = '[1.13,1.14[' // allow any patch release of 1.13.x def sbeGroup = 'uk.co.real-logic' From 8d1b6a0591f24bef98b8ccc37ed3dab960487d75 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 23 Nov 2021 17:52:00 +0100 Subject: [PATCH 015/805] [Java] Upgrade to Agrona 1.14.0. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index f7389425a5..2b4c4748bb 100644 --- a/build.gradle +++ b/build.gradle @@ -47,8 +47,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.1.0' def junitVersion = '5.8.1' def jmhVersion = '1.33' -def agronaVersion = '1.13.1' -def agronaVersionRange = '[1.13,1.14[' // allow any patch release of 1.13.x +def agronaVersion = '1.14.0' +def agronaVersionRange = '[1.14,1.15[' // allow any patch release of 1.14.x def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 60d1b2fede2f1995cbf53da04f9dcf24e6a57806 Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Wed, 24 Nov 2021 08:25:44 -0800 Subject: [PATCH 016/805] 1.25.1 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index b1d7655df2..d905a6d1d6 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.1-SNAPSHOT +1.25.1 From 0aca497ea66ec954bda2bfeb6ca9f00366e50267 Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Wed, 24 Nov 2021 08:27:17 -0800 Subject: [PATCH 017/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index d905a6d1d6..6fb671d7e9 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.1 +1.25.2-SNAPSHOT From 0ee9e55ada49fec533eb826ae485d51241b76f5e Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Nov 2021 13:36:39 +0100 Subject: [PATCH 018/805] [Java] Upgrade to JUnit 5.8.2. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2b4c4748bb..7c2bad88a9 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.1' def hamcrestVersion = '2.2' def mockitoVersion = '4.1.0' -def junitVersion = '5.8.1' +def junitVersion = '5.8.2' def jmhVersion = '1.33' def agronaVersion = '1.14.0' def agronaVersionRange = '[1.14,1.15[' // allow any patch release of 1.14.x From 44ca92f152cbfaaaf0b72bc9ee08e2f2c345b303 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 30 Nov 2021 15:38:13 +0000 Subject: [PATCH 019/805] [Java] Upgrade to Checkstyle 9.2. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7c2bad88a9..f506c48c66 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ def toolchainLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(buildJavaVersion) } -def checkstyleVersion = '9.1' +def checkstyleVersion = '9.2' def hamcrestVersion = '2.2' def mockitoVersion = '4.1.0' def junitVersion = '5.8.2' From b7b2e0ccba80a3b00ea53b7d53586f0c6a1359e0 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 2 Dec 2021 13:19:39 +0000 Subject: [PATCH 020/805] [Java] Upgrade to Gradle 7.3.1. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index f506c48c66..da5da5feb5 100644 --- a/build.gradle +++ b/build.gradle @@ -820,7 +820,7 @@ tasks.named('dependencyUpdates').configure { tasks.findByName('build').dependsOn verifyJavaIrCodecsInSync wrapper { - gradleVersion = '7.2' + gradleVersion = '7.3.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a0f7639f7d..3cd8500c13 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 15391b4f53219f6074b7d4a3a774638a1691e2b8 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 15 Dec 2021 11:18:16 +0100 Subject: [PATCH 021/805] [Java] Upgrade to Shadow 7.1.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index da5da5feb5..d93b8b5ea4 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ import java.security.MessageDigest plugins { id 'java-library' - id 'com.github.johnrengelman.shadow' version '7.1.0' apply false + id 'com.github.johnrengelman.shadow' version '7.1.1' apply false id "com.github.ben-manes.versions" version "0.39.0" } From 470db5384d7fb60de7dd89adc4968afaf7ccfd48 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 15 Dec 2021 22:57:00 +0000 Subject: [PATCH 022/805] [Java] Upgrade to Gradle 7.3.2. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index d93b8b5ea4..b58aff0ca0 100644 --- a/build.gradle +++ b/build.gradle @@ -820,7 +820,7 @@ tasks.named('dependencyUpdates').configure { tasks.findByName('build').dependsOn verifyJavaIrCodecsInSync wrapper { - gradleVersion = '7.3.1' + gradleVersion = '7.3.2' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3cd8500c13..ac0b842f19 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From c36cef0c6f0ed438e630c379978096d9a6483b9b Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Dec 2021 11:00:48 +0100 Subject: [PATCH 023/805] [Java] Regenerate Gradle wrapper scripts. --- gradlew | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradlew b/gradlew index c53aefaa5f..1b6c787337 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # From c02b4247cd30534e6e328c06a8712694b44745c3 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 16 Dec 2021 13:51:01 +0000 Subject: [PATCH 024/805] [Java] Upgrade to Mockito 4.2.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b58aff0ca0..ae8126b1d9 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.2' def hamcrestVersion = '2.2' -def mockitoVersion = '4.1.0' +def mockitoVersion = '4.2.0' def junitVersion = '5.8.2' def jmhVersion = '1.33' def agronaVersion = '1.14.0' From 0bc4268e609ffcbab108a52295c08f8b977f08fb Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 22 Dec 2021 15:47:04 +0000 Subject: [PATCH 025/805] [Java] Upgrade to Gradle 7.3.3. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index ae8126b1d9..e080a8a410 100644 --- a/build.gradle +++ b/build.gradle @@ -820,7 +820,7 @@ tasks.named('dependencyUpdates').configure { tasks.findByName('build').dependsOn verifyJavaIrCodecsInSync wrapper { - gradleVersion = '7.3.2' + gradleVersion = '7.3.3' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac0b842f19..669386b870 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787337..c53aefaa5f 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # From 0b1e282d66f154f5a9de4adbf45ae7c260241355 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 22 Dec 2021 17:27:54 +0000 Subject: [PATCH 026/805] [Java] Add missing Javadoc. --- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java index a4f2b6235a..2696d1eee1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java @@ -27,6 +27,9 @@ */ public class Field { + /** + * Value to indicate a {@link Field} is invalid or not yet set. + */ public static final int INVALID_ID = Integer.MAX_VALUE; // schemaId must be a short, so this is way out of range. private final String name; // required for field/data & group From 4bcd9429ac452d4c417e1ea34f3a72ff05558c5b Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 22 Dec 2021 17:48:22 +0000 Subject: [PATCH 027/805] [Java] Restrict JVM version range for test. --- .../sbe/generation/csharp/Issue567GroupSizeTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index b59caa3f4a..fb916d5f40 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -19,6 +19,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import uk.co.real_logic.sbe.Tests; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.xml.IrGenerator; @@ -32,6 +34,7 @@ import static org.mockito.Mockito.verify; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; +@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_17) public class Issue567GroupSizeTest { public static final String ERR_MSG = From 24061c25e7e949c7fc41507dc55ea9a66c5012b4 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 23 Dec 2021 16:39:37 +0000 Subject: [PATCH 028/805] [Java] Upgrade to JMH 1.34. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e080a8a410..5c15c8c467 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ def checkstyleVersion = '9.2' def hamcrestVersion = '2.2' def mockitoVersion = '4.2.0' def junitVersion = '5.8.2' -def jmhVersion = '1.33' +def jmhVersion = '1.34' def agronaVersion = '1.14.0' def agronaVersionRange = '[1.14,1.15[' // allow any patch release of 1.14.x From 1e2187013a3ee529668182879b3045a56cbb5b70 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 24 Dec 2021 16:43:44 +0000 Subject: [PATCH 029/805] [Java] Set encoding type for test to see if it works for charset changes in Java 18. --- .../csharp/Issue567GroupSizeTest.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index fb916d5f40..9092e8f3fe 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -19,14 +19,15 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; +import org.xml.sax.InputSource; import uk.co.real_logic.sbe.Tests; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.IOException; +import java.io.InputStream; import java.io.PrintStream; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -34,7 +35,6 @@ import static org.mockito.Mockito.verify; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_17) public class Issue567GroupSizeTest { public static final String ERR_MSG = @@ -58,18 +58,25 @@ public void after() } @Test - public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupSize() + public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupSize() throws IOException { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - assertThrows(IllegalArgumentException.class, - () -> parse(Tests.getLocalResource("issue567-invalid.xml"), options)); + final InputStream in = Tests.getLocalResource("issue567-invalid.xml"); + final InputSource is = new InputSource(in); + is.setEncoding("UTF-8"); + + assertThrows(IllegalArgumentException.class, () -> parse(is, options)); } @Test public void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupSize() throws Exception { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("issue567-valid.xml"), options); + final InputStream in = Tests.getLocalResource("issue567-valid.xml"); + final InputSource is = new InputSource(in); + is.setEncoding("UTF-8"); + + final MessageSchema schema = parse(is, options); final IrGenerator irg = new IrGenerator(); final Ir ir = irg.generate(schema); From d332e5c26e2a2dd22e09fbeab5f7af48370e91c9 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 24 Dec 2021 18:16:02 +0000 Subject: [PATCH 030/805] [Java] Disable test for Java 18. --- .../sbe/generation/csharp/Issue567GroupSizeTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 9092e8f3fe..c1af4c495a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -19,6 +19,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import org.xml.sax.InputSource; import uk.co.real_logic.sbe.Tests; import uk.co.real_logic.sbe.ir.Ir; @@ -35,6 +37,7 @@ import static org.mockito.Mockito.verify; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; +@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_17) public class Issue567GroupSizeTest { public static final String ERR_MSG = From 4ace22a7af1d6ce313f60b652540fe0457403e2e Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 17:40:55 +0000 Subject: [PATCH 031/805] [Java] Remove unnecessary checks. --- .../uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index e20562b4f5..c1f4e26333 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -289,12 +289,6 @@ public static String getAttributeValue(final Node elementNode, final String attr } final NamedNodeMap attributes = elementNode.getAttributes(); - if (null == attributes) - { - throw new IllegalStateException( - "element '" + elementNode.getNodeName() + "' has empty or missing attribute: " + attrName); - } - final Node attrNode = attributes.getNamedItemNS(null, attrName); if (null == attrNode || "".equals(attrNode.getNodeValue())) { @@ -322,11 +316,6 @@ public static String getAttributeValue(final Node elementNode, final String attr } final NamedNodeMap attributes = elementNode.getAttributes(); - if (null == attributes) - { - return defValue; - } - final Node attrNode = attributes.getNamedItemNS(null, attrName); if (null == attrNode) { @@ -345,7 +334,7 @@ public static String getAttributeValue(final Node elementNode, final String attr */ public static String getAttributeValueOrNull(final Node elementNode, final String attrName) { - if (null == elementNode || null == elementNode.getAttributes()) + if (null == elementNode) { return null; } From ca83fd753c19295722f3ec86654fb0cc20d243f6 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 17:50:09 +0000 Subject: [PATCH 032/805] [Java] Don't create xpath factory until needed and set character encoding for test. --- .../java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 3 +-- .../sbe/generation/csharp/Issue567GroupSizeTest.java | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index c1f4e26333..49cdcd0fd1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -129,11 +129,10 @@ public static MessageSchema parse(final InputSource is, final ParserOptions opti } final Document document = factory.newDocumentBuilder().parse(is); - final XPath xPath = XPathFactory.newInstance().newXPath(); - final ErrorHandler errorHandler = new ErrorHandler(options); document.setUserData(ERROR_HANDLER_KEY, errorHandler, null); + final XPath xPath = XPathFactory.newInstance().newXPath(); final Map typeByNameMap = findTypes(document, xPath); errorHandler.checkIfShouldExit(); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index c1af4c495a..6b0eadc6d3 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -30,14 +30,16 @@ import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.PrintStream; +import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_17) +@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_18) public class Issue567GroupSizeTest { public static final String ERR_MSG = @@ -65,8 +67,7 @@ public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupS { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final InputStream in = Tests.getLocalResource("issue567-invalid.xml"); - final InputSource is = new InputSource(in); - is.setEncoding("UTF-8"); + final InputSource is = new InputSource(new InputStreamReader(in, StandardCharsets.UTF_8)); assertThrows(IllegalArgumentException.class, () -> parse(is, options)); } @@ -76,8 +77,7 @@ public void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupS { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final InputStream in = Tests.getLocalResource("issue567-valid.xml"); - final InputSource is = new InputSource(in); - is.setEncoding("UTF-8"); + final InputSource is = new InputSource(new InputStreamReader(in, StandardCharsets.UTF_8)); final MessageSchema schema = parse(is, options); final IrGenerator irg = new IrGenerator(); From b35ab85f22892643e8efe0657a8c1111a274f648 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 17:53:53 +0000 Subject: [PATCH 033/805] [Java] Revert testing on Java 18. --- .../real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 6b0eadc6d3..363b3d4149 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -39,7 +39,7 @@ import static org.mockito.Mockito.verify; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_18) +@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_17) public class Issue567GroupSizeTest { public static final String ERR_MSG = From a8c21ed77ffab65c7a7dce986551cc4d182d7d23 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 17:58:46 +0000 Subject: [PATCH 034/805] [Java] Formatting. --- sbe-tool/src/test/resources/issue435.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/test/resources/issue435.xml b/sbe-tool/src/test/resources/issue435.xml index ddebd2fad1..8cf1a3794b 100644 --- a/sbe-tool/src/test/resources/issue435.xml +++ b/sbe-tool/src/test/resources/issue435.xml @@ -27,6 +27,6 @@ - + From 23c67a31de34366da2be5a7fdac034982c9ab348 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 18:00:06 +0000 Subject: [PATCH 035/805] [Java] Formatting. --- sbe-tool/src/test/resources/issue567-valid.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/test/resources/issue567-valid.xml b/sbe-tool/src/test/resources/issue567-valid.xml index a7a52c19bf..c9cd88b933 100644 --- a/sbe-tool/src/test/resources/issue567-valid.xml +++ b/sbe-tool/src/test/resources/issue567-valid.xml @@ -15,7 +15,7 @@ - + @@ -33,7 +33,7 @@ - + From 369ef4c409348a69f18e4d5f2c46626da74e4ca4 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 18:01:24 +0000 Subject: [PATCH 036/805] [Java] Formatting. --- sbe-tool/src/test/resources/issue567-invalid.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/test/resources/issue567-invalid.xml b/sbe-tool/src/test/resources/issue567-invalid.xml index 445b1c69f2..b5cb41b1c6 100644 --- a/sbe-tool/src/test/resources/issue567-invalid.xml +++ b/sbe-tool/src/test/resources/issue567-invalid.xml @@ -28,12 +28,12 @@ - + - + From 814b2a5fa9353f231fd300a8bdc3b66bf9a69c19 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 18:34:04 +0000 Subject: [PATCH 037/805] [Java] Formatting. --- sbe-tool/src/test/resources/issue827.xml | 2 +- sbe-tool/src/test/resources/issue847.xml | 12 ++++++------ sbe-tool/src/test/resources/issue848.xml | 12 ++++++------ sbe-tool/src/test/resources/issue849.xml | 12 ++++++------ 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/sbe-tool/src/test/resources/issue827.xml b/sbe-tool/src/test/resources/issue827.xml index 08430a6e73..cfc0f7fefd 100644 --- a/sbe-tool/src/test/resources/issue827.xml +++ b/sbe-tool/src/test/resources/issue827.xml @@ -19,6 +19,6 @@ - + diff --git a/sbe-tool/src/test/resources/issue847.xml b/sbe-tool/src/test/resources/issue847.xml index ce015bbb1c..784608ac9e 100644 --- a/sbe-tool/src/test/resources/issue847.xml +++ b/sbe-tool/src/test/resources/issue847.xml @@ -1,11 +1,11 @@ + package="issue847" + id="1" + version="0" + semanticVersion="1.0" + description="test case 847 20210511" + byteOrder="littleEndian"> diff --git a/sbe-tool/src/test/resources/issue848.xml b/sbe-tool/src/test/resources/issue848.xml index cf31b53740..e30b4b9589 100644 --- a/sbe-tool/src/test/resources/issue848.xml +++ b/sbe-tool/src/test/resources/issue848.xml @@ -1,11 +1,11 @@ + package="issue848" + id="1" + version="0" + semanticVersion="1.0" + description="test case 848 20210511" + byteOrder="littleEndian"> diff --git a/sbe-tool/src/test/resources/issue849.xml b/sbe-tool/src/test/resources/issue849.xml index 4eb45ce8ee..6533a270c6 100644 --- a/sbe-tool/src/test/resources/issue849.xml +++ b/sbe-tool/src/test/resources/issue849.xml @@ -1,11 +1,11 @@ + package="issue849" + id="1" + version="0" + semanticVersion="1.0" + description="test case 849 20210512" + byteOrder="littleEndian"> From 60cdde5fc76afb41065da176546199c7e11916c4 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 18:59:48 +0000 Subject: [PATCH 038/805] [Java] Improve test for Issue #567. --- .../generation/csharp/Issue567GroupSizeTest.java | 13 +++++++++++-- sbe-tool/src/test/resources/issue567-invalid.xml | 11 +++-------- sbe-tool/src/test/resources/issue567-valid.xml | 11 +++-------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 363b3d4149..615ce24fc4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -35,6 +35,7 @@ import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -42,9 +43,15 @@ @EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_17) public class Issue567GroupSizeTest { - public static final String ERR_MSG = + private static final String ERR_MSG = "WARNING: at \"numInGroup\" should be UINT8 or UINT16"; + private static final String EXPECTED_COUNT_CHECK = + " if ((uint) count > 2147483647)\n" + + " {\n" + + " ThrowHelper.ThrowCountOutOfRangeException(count);\n" + + " }"; + private final PrintStream mockErr = mock(PrintStream.class); private PrintStream err; @@ -87,7 +94,9 @@ public void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupS outputManager.setPackageName(ir.applicableNamespace()); final CSharpGenerator generator = new CSharpGenerator(ir, outputManager); - // Act + Assert (no exception) generator.generate(); + + final String source = outputManager.getSource("tests.Issue567").toString(); + assertTrue(source.contains(EXPECTED_COUNT_CHECK)); } } diff --git a/sbe-tool/src/test/resources/issue567-invalid.xml b/sbe-tool/src/test/resources/issue567-invalid.xml index b5cb41b1c6..d31d1eff64 100644 --- a/sbe-tool/src/test/resources/issue567-invalid.xml +++ b/sbe-tool/src/test/resources/issue567-invalid.xml @@ -1,7 +1,7 @@ - - - - - - + diff --git a/sbe-tool/src/test/resources/issue567-valid.xml b/sbe-tool/src/test/resources/issue567-valid.xml index c9cd88b933..e5f56d82bf 100644 --- a/sbe-tool/src/test/resources/issue567-valid.xml +++ b/sbe-tool/src/test/resources/issue567-valid.xml @@ -1,7 +1,7 @@ - - - - - - + From 7b0c022d81ec33d13038193fb8d5c9aadbe2a973 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 19:26:59 +0000 Subject: [PATCH 039/805] [Java] Add the ability to ParserOptions for setting which stream errors gets printed to and improve test for Issue #567. --- .../co/real_logic/sbe/xml/ErrorHandler.java | 8 +-- .../co/real_logic/sbe/xml/ParserOptions.java | 49 ++++++++++++++++--- .../csharp/Issue567GroupSizeTest.java | 20 +++----- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java index 4dbc5ff4e4..4afaf0e092 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java @@ -30,7 +30,8 @@ public class ErrorHandler private int warnings = 0; /** - * Construct a new {@link ErrorHandler} that outputs to a provided {@link PrintStream}. + * Construct a new {@link ErrorHandler} that outputs to a provided {@link PrintStream} which overrides the value + * set in {@link ParserOptions#errorPrintStream()}. * * @param stream to which output should be sent. * @param options the parsing options. @@ -44,13 +45,14 @@ public ErrorHandler(final PrintStream stream, final ParserOptions options) } /** - * Default {@link ErrorHandler} that outputs to {@link System#err}. + * Default {@link ErrorHandler} that outputs to {@link System#err} if {@link ParserOptions#errorPrintStream()} is + * not set. * * @param options the parsing options. */ public ErrorHandler(final ParserOptions options) { - this(System.err, options); + this(options.errorPrintStream() != null ? options.errorPrintStream() : System.err, options); } /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java index 9ff509d56d..3743f860ce 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java @@ -15,40 +15,49 @@ */ package uk.co.real_logic.sbe.xml; +import java.io.PrintStream; + /** * Class to hold the values of the parsing options. */ public final class ParserOptions { - public static final ParserOptions DEFAULT = new ParserOptions(false, false, false, true, null); + /** + * Default parser options which can be used for convenience. + */ + public static final ParserOptions DEFAULT = new ParserOptions(false, false, false, true, null, null); private final boolean stopOnError; private final boolean warningsFatal; private final boolean suppressOutput; private final boolean xIncludeAware; private final String xsdFilename; + private final PrintStream errorPrintStream; /** * Sets up the parsing options. * - * @param stopOnError specifies whether the parsing should stop on error. - * @param warningsFatal specifies whether the warnings should be handled as fatal errors. - * @param suppressOutput specifies whether to suppress the output of errors and warnings. - * @param xIncludeAware should parse expect XInclude references. - * @param xsdFilename the name of the schema file. + * @param stopOnError specifies whether the parsing should stop on error. + * @param warningsFatal specifies whether the warnings should be handled as fatal errors. + * @param suppressOutput specifies whether to suppress the output of errors and warnings. + * @param xIncludeAware should parse expect XInclude references. + * @param xsdFilename the name of the schema file. + * @param errorPrintStream the {@link PrintStream} to which parsing errors and warnings are printed. */ private ParserOptions( final boolean stopOnError, final boolean warningsFatal, final boolean suppressOutput, final boolean xIncludeAware, - final String xsdFilename) + final String xsdFilename, + final PrintStream errorPrintStream) { this.stopOnError = stopOnError; this.warningsFatal = warningsFatal; this.suppressOutput = suppressOutput; this.xIncludeAware = xIncludeAware; this.xsdFilename = xsdFilename; + this.errorPrintStream = errorPrintStream; } /** @@ -101,6 +110,16 @@ public String xsdFilename() return xsdFilename; } + /** + * The {@link PrintStream} to which errors and warnings are printed when parsing. + * + * @return the {@link PrintStream} to which errors and warnings are printed when parsing. + */ + public PrintStream errorPrintStream() + { + return errorPrintStream; + } + /** * Creates a builder. * @@ -121,6 +140,7 @@ public static class Builder private boolean suppressOutput; private boolean xIncludeAware; private String xsdFilename; + private PrintStream errorPrintStream; /** * The value of the stopOnError parameter. @@ -232,6 +252,18 @@ public Builder xsdFilename(final String xsdFilename) return this; } + /** + * Set the {@link PrintStream} to which parsing errors and warnings are printed. + * + * @param errorPrintStream to which parsing errors and warnings are printed. + * @return this instance + */ + public Builder errorPrintStream(final PrintStream errorPrintStream) + { + this.errorPrintStream = errorPrintStream; + return this; + } + /** * Creates an instance of {@link ParserOptions} with all the values set. * @@ -239,7 +271,8 @@ public Builder xsdFilename(final String xsdFilename) */ public ParserOptions build() { - return new ParserOptions(stopOnError, warningsFatal, suppressOutput, xIncludeAware, xsdFilename); + return new ParserOptions( + stopOnError, warningsFatal, suppressOutput, xIncludeAware, xsdFilename, errorPrintStream); } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 615ce24fc4..01b75ec135 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -17,7 +17,6 @@ import org.agrona.generation.StringWriterOutputManager; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledForJreRange; import org.junit.jupiter.api.condition.JRE; @@ -53,26 +52,20 @@ public class Issue567GroupSizeTest " }"; private final PrintStream mockErr = mock(PrintStream.class); - private PrintStream err; - - @BeforeEach - public void before() - { - err = System.err; - System.setErr(mockErr); - } @AfterEach public void after() { - System.setErr(err); verify(mockErr).println(ERR_MSG); } @Test public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupSize() throws IOException { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final ParserOptions options = ParserOptions.builder() + .errorPrintStream(mockErr) + .stopOnError(true) + .build(); final InputStream in = Tests.getLocalResource("issue567-invalid.xml"); final InputSource is = new InputSource(new InputStreamReader(in, StandardCharsets.UTF_8)); @@ -82,7 +75,10 @@ public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupS @Test public void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupSize() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final ParserOptions options = ParserOptions.builder() + .errorPrintStream(mockErr) + .stopOnError(true) + .build(); final InputStream in = Tests.getLocalResource("issue567-valid.xml"); final InputSource is = new InputSource(new InputStreamReader(in, StandardCharsets.UTF_8)); From 7c943f6c2eeb4d94697ed2315e042bf6d2e5fea9 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 19:32:43 +0000 Subject: [PATCH 040/805] [Java] Test again with Java 18. --- .../real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 01b75ec135..0f60a83d3f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -39,7 +39,7 @@ import static org.mockito.Mockito.verify; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_17) +@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_18) public class Issue567GroupSizeTest { private static final String ERR_MSG = From fb22bcd8b6712957565f1d1c8ab5f24ac3f4f5ba Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 28 Dec 2021 19:35:53 +0000 Subject: [PATCH 041/805] [Java] Remove range check for Java 18. --- .../sbe/generation/csharp/Issue567GroupSizeTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 0f60a83d3f..96d7f84fb6 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -18,8 +18,6 @@ import org.agrona.generation.StringWriterOutputManager; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import org.xml.sax.InputSource; import uk.co.real_logic.sbe.Tests; import uk.co.real_logic.sbe.ir.Ir; @@ -39,7 +37,6 @@ import static org.mockito.Mockito.verify; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -@EnabledForJreRange(min = JRE.JAVA_8, max = JRE.JAVA_18) public class Issue567GroupSizeTest { private static final String ERR_MSG = From 1c8856e59bdcc442e5c2ab8be3eba47e288ad12d Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 29 Dec 2021 09:43:39 +0000 Subject: [PATCH 042/805] [Java] Simplify and clarify test. --- .../generation/csharp/Issue567GroupSizeTest.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 96d7f84fb6..4f6b99bf71 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -16,7 +16,6 @@ package uk.co.real_logic.sbe.generation.csharp; import org.agrona.generation.StringWriterOutputManager; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.xml.sax.InputSource; import uk.co.real_logic.sbe.Tests; @@ -24,6 +23,7 @@ import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import uk.co.real_logic.sbe.xml.XmlSchemaParser; import java.io.IOException; import java.io.InputStream; @@ -35,7 +35,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; public class Issue567GroupSizeTest { @@ -50,12 +49,6 @@ public class Issue567GroupSizeTest private final PrintStream mockErr = mock(PrintStream.class); - @AfterEach - public void after() - { - verify(mockErr).println(ERR_MSG); - } - @Test public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupSize() throws IOException { @@ -66,7 +59,8 @@ public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupS final InputStream in = Tests.getLocalResource("issue567-invalid.xml"); final InputSource is = new InputSource(new InputStreamReader(in, StandardCharsets.UTF_8)); - assertThrows(IllegalArgumentException.class, () -> parse(is, options)); + assertThrows(IllegalArgumentException.class, () -> XmlSchemaParser.parse(is, options)); + verify(mockErr).println(ERR_MSG); } @Test @@ -79,7 +73,9 @@ public void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupS final InputStream in = Tests.getLocalResource("issue567-valid.xml"); final InputSource is = new InputSource(new InputStreamReader(in, StandardCharsets.UTF_8)); - final MessageSchema schema = parse(is, options); + final MessageSchema schema = XmlSchemaParser.parse(is, options); + verify(mockErr).println(ERR_MSG); + final IrGenerator irg = new IrGenerator(); final Ir ir = irg.generate(schema); From 1ddd6b3e7298373ed95d978f8d2a4108a8de73fc Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 29 Dec 2021 09:52:40 +0000 Subject: [PATCH 043/805] [Java] Improve tests so failures are easier to debug. --- .../real_logic/sbe/generation/cpp/CppGeneratorTest.java | 9 +++++---- .../sbe/generation/csharp/Issue567GroupSizeTest.java | 5 +++-- .../co/real_logic/sbe/generation/rust/RustUtilTest.java | 9 +++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index 5106c1a7bf..f59ffbfb89 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -23,8 +23,9 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; public class CppGeneratorTest @@ -43,7 +44,7 @@ public void shouldUseGeneratedLiteralForConstantOneWhenGeneratingBitsetCode() th generator.generate(); final String source = outputManager.getSource("issue827.FlagsSet").toString(); - assertFalse(source.contains("1u << ")); - assertTrue(source.contains("UINT64_C(0x1) << ")); + assertThat(source, not(containsString("1u << "))); + assertThat(source, containsString("UINT64_C(0x1) << ")); } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 4f6b99bf71..832f94cdce 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -31,8 +31,9 @@ import java.io.PrintStream; import java.nio.charset.StandardCharsets; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -86,6 +87,6 @@ public void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupS generator.generate(); final String source = outputManager.getSource("tests.Issue567").toString(); - assertTrue(source.contains(EXPECTED_COUNT_CHECK)); + assertThat(source, containsString(EXPECTED_COUNT_CHECK)); } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index a1f36f4d98..b409cb103e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -39,22 +39,19 @@ public class RustUtilTest @Test public void nullParamToEightBitCharacterThrowsNPE() { - assertThrows(NullPointerException.class, () -> - RustUtil.eightBitCharacter(null)); + assertThrows(NullPointerException.class, () -> RustUtil.eightBitCharacter(null)); } @Test public void emptyParamToEightBitCharacterThrowsIAE() { - assertThrows(IllegalArgumentException.class, () -> - RustUtil.eightBitCharacter("")); + assertThrows(IllegalArgumentException.class, () -> RustUtil.eightBitCharacter("")); } @Test public void tooManyCharactersParamToEightBitCharacterThrowsIAE() { - assertThrows(IllegalArgumentException.class, () -> - RustUtil.eightBitCharacter("ABC")); + assertThrows(IllegalArgumentException.class, () -> RustUtil.eightBitCharacter("ABC")); } @Test From 778c61cf94c8cf2a5689f4d70ed59ca698b3e985 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 29 Dec 2021 10:05:54 +0000 Subject: [PATCH 044/805] [Java] Enable warnings as errors. --- build.gradle | 1 + .../sbe/generation/rust/RustUtil.java | 20 +++++++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 5c15c8c467..b7979e11b1 100644 --- a/build.gradle +++ b/build.gradle @@ -180,6 +180,7 @@ subprojects { tasks.withType(JavaCompile) { options.encoding = 'UTF-8' options.deprecation = true + options.compilerArgs.addAll(['-Xlint:all', '-Werror']) // Enable all warnings and treat them as errors } javadoc { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 5e65a327f4..d4326bd179 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -104,18 +104,12 @@ static byte eightBitCharacter(final String asciiCharacter) if (bytes.length != 1) { throw new IllegalArgumentException( - format("String value %s did not fit into a single 8-bit character", asciiCharacter)); + "String value `" + asciiCharacter + "` did not fit into a single 8-bit character"); } return bytes[0]; } - /** - * Format a struct name for the generated code. - * - * @param structName to be formatted. - * @return the formatted struct name. - */ static String formatStructName(final String structName) { return Generators.toUpperFirstChar(structName); @@ -300,7 +294,7 @@ static Appendable indent(final Appendable appendable, final int level, final Str return indent(appendable, level).append(format(f, args)); } - private enum ReservedKeyword + enum ReservedKeyword { Abstract, AlignOf, As, Async, Become, Box, Break, Const, Continue, Crate, Do, Else, Enum, Extern, False, Final, Fn, For, If, Impl, In, @@ -313,13 +307,13 @@ private enum ReservedKeyword static { - Arrays.stream(ReservedKeyword.values()) - .map(java.lang.Enum::name) - .map(String::toLowerCase) - .forEach(LOWER_CASE_NAMES::add); + for (final ReservedKeyword value : ReservedKeyword.values()) + { + LOWER_CASE_NAMES.add(value.name()); + } } - private static boolean anyMatch(final String v) + static boolean anyMatch(final String v) { return LOWER_CASE_NAMES.contains(v.toLowerCase()); } From 08ef8e412165e595d0512b630f4ed7949e7ca340 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 29 Dec 2021 10:38:22 +0000 Subject: [PATCH 045/805] [Java] Fix javadoc and scope issues. --- .../uk/co/real_logic/sbe/PrimitiveType.java | 43 ++++ .../uk/co/real_logic/sbe/PrimitiveValue.java | 189 +++++++++++++++--- .../sbe/generation/rust/RustGenerator.java | 6 +- .../co/real_logic/sbe/ir/HeaderStructure.java | 15 ++ .../co/real_logic/sbe/TestTargetLanguage.java | 6 +- 5 files changed, 223 insertions(+), 36 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java index 7fe416e754..7453d4f57e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java @@ -22,16 +22,59 @@ */ public enum PrimitiveType { + /** + * One byte character type which is a flavour of ASCII. + */ CHAR("char", 1, MIN_VALUE_CHAR, MAX_VALUE_CHAR, NULL_VALUE_CHAR), + + /** + * A raw byte or signed 8-bit integer. + */ INT8("int8", 1, MIN_VALUE_INT8, MAX_VALUE_INT8, NULL_VALUE_INT8), + + /** + * A 16-bit signed integer. + */ INT16("int16", 2, MIN_VALUE_INT16, MAX_VALUE_INT16, NULL_VALUE_INT16), + + /** + * A 32-bit signed integer. + */ INT32("int32", 4, MIN_VALUE_INT32, MAX_VALUE_INT32, NULL_VALUE_INT32), + + /** + * A 64-bit signed integer. + */ INT64("int64", 8, MIN_VALUE_INT64, MAX_VALUE_INT64, NULL_VALUE_INT64), + + /** + * A 8-bit unsigned integer. + */ UINT8("uint8", 1, MIN_VALUE_UINT8, MAX_VALUE_UINT8, NULL_VALUE_UINT8), + + /** + * A 16-bit unsigned integer. + */ UINT16("uint16", 2, MIN_VALUE_UINT16, MAX_VALUE_UINT16, NULL_VALUE_UINT16), + + /** + * A 32-bit unsigned integer. + */ UINT32("uint32", 4, MIN_VALUE_UINT32, MAX_VALUE_UINT32, NULL_VALUE_UINT32), + + /** + * A 64-bit unsigned integer. + */ UINT64("uint64", 8, MIN_VALUE_UINT64, MAX_VALUE_UINT64, NULL_VALUE_UINT64), + + /** + * A 32-bit single precision floating point number. + */ FLOAT("float", 4, MIN_VALUE_FLOAT, MAX_VALUE_FLOAT, NULL_VALUE_FLOAT), + + /** + * A 64-bit double precision floating point number. + */ DOUBLE("double", 8, MIN_VALUE_DOUBLE, MAX_VALUE_DOUBLE, NULL_VALUE_DOUBLE); private static final PrimitiveType[] VALUES = PrimitiveType.values(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java index e987de53b9..0336953859 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java @@ -49,50 +49,179 @@ public enum Representation BYTE_ARRAY } + /** + * Minimum value representation for a char type. + */ public static final long MIN_VALUE_CHAR = 0x20; + + /** + * Maximum value representation for a char type. + */ public static final long MAX_VALUE_CHAR = 0x7E; + + /** + * Null value representation for a char type. + */ public static final long NULL_VALUE_CHAR = 0; + /** + * Minimum value representation for a signed 8-bit type. + */ public static final long MIN_VALUE_INT8 = -127; + + /** + * Maximum value representation for a signed 8-bit type. + */ public static final long MAX_VALUE_INT8 = 127; + + /** + * Null value representation for a signed 8-bit type. + */ public static final long NULL_VALUE_INT8 = -128; + /** + * Minimum value representation for an unsigned 8-bit type. + */ public static final long MIN_VALUE_UINT8 = 0; + + /** + * Maximum value representation for an unsigned 8-bit type. + */ public static final long MAX_VALUE_UINT8 = 254; + + /** + * Null value representation for an unsigned 8-bit type. + */ public static final long NULL_VALUE_UINT8 = 255; + /** + * Minimum value representation for a signed 16-bit type. + */ public static final long MIN_VALUE_INT16 = -32767; + + /** + * Maximum value representation for a signed 16-bit type. + */ public static final long MAX_VALUE_INT16 = 32767; + + /** + * Null value representation for a signed 16-bit type. + */ public static final long NULL_VALUE_INT16 = -32768; + /** + * Minimum value representation for an unsigned 16-bit type. + */ public static final long MIN_VALUE_UINT16 = 0; + + /** + * Maximum value representation for an unsigned 16-bit type. + */ public static final long MAX_VALUE_UINT16 = 65534; + + /** + * Null value representation for an unsigned 16-bit type. + */ public static final long NULL_VALUE_UINT16 = 65535; + /** + * Minimum value representation for a signed 32-bit type. + */ public static final long MIN_VALUE_INT32 = -2147483647; + + /** + * Maximum value representation for a signed 32-bit type. + */ public static final long MAX_VALUE_INT32 = 2147483647; + + /** + * Null value representation for a signed 32-bit type. + */ public static final long NULL_VALUE_INT32 = -2147483648; + /** + * Minimum value representation for an unsigned 32-bit type. + */ public static final long MIN_VALUE_UINT32 = 0; + + /** + * Maximum value representation for an unsigned 32-bit type. + */ public static final long MAX_VALUE_UINT32 = 0xFFFF_FFFFL - 1; + + /** + * Null value representation for an unsigned 32-bit type. + */ public static final long NULL_VALUE_UINT32 = 0xFFFF_FFFFL; + /** + * Minimum value representation for a signed 64-bit type. + */ public static final long MIN_VALUE_INT64 = Long.MIN_VALUE + 1; // (-2 ^ 63) + 1 + + /** + * Maximum value representation for a signed 64-bit type. + */ public static final long MAX_VALUE_INT64 = Long.MAX_VALUE; // ( 2 ^ 63) - 1 + + /** + * Null value representation for a signed 64-bit type. + */ public static final long NULL_VALUE_INT64 = Long.MIN_VALUE; // (-2 ^ 63) + /** + * Minimum value representation for an unsigned 64-bit type. + */ public static final long MIN_VALUE_UINT64 = 0; + + /** + * Maximum value representation for an unsigned 64-bit type. + */ public static final BigInteger BI_MAX_VALUE_UINT64 = new BigInteger("18446744073709551614"); + + /** + * Maximum value representation for an unsigned 64-bit type. + */ public static final long MAX_VALUE_UINT64 = BI_MAX_VALUE_UINT64.longValue(); // (2 ^ 64) - 2 + + /** + * Null value representation for an unsigned 64-bit type. + */ public static final BigInteger BI_NULL_VALUE_UINT64 = new BigInteger("18446744073709551615"); + + /** + * Null value representation for an unsigned 64-bit type. + */ public static final long NULL_VALUE_UINT64 = BI_NULL_VALUE_UINT64.longValue(); // (2 ^ 64) - 1 + /** + * Maximum value representation for a single precision 32-bit floating point type. + */ public static final float MIN_VALUE_FLOAT = Float.MIN_VALUE; + + /** + * Maximum value representation for a single precision 32-bit floating point type. + */ public static final float MAX_VALUE_FLOAT = Float.MAX_VALUE; + + /** + * Null value representation for a single precision 32-bit floating point type. + */ public static final float NULL_VALUE_FLOAT = Float.NaN; + /** + * Minimum value representation for a double precision 64-bit floating point type. + */ public static final double MIN_VALUE_DOUBLE = Double.MIN_VALUE; + + /** + * Maximum value representation for a double precision 64-bit floating point type. + */ public static final double MAX_VALUE_DOUBLE = Double.MAX_VALUE; + + /** + * Null value representation for a double precision 64-bit floating point type. + */ public static final double NULL_VALUE_DOUBLE = Double.NaN; private final Representation representation; @@ -106,8 +235,8 @@ public enum Representation /** * Construct and fill in value as a long. * - * @param value in long format - * @param size of the type in bytes + * @param value in long format. + * @param size of the type in bytes. */ public PrimitiveValue(final long value, final int size) { @@ -138,8 +267,8 @@ public PrimitiveValue(final byte value, final String characterEncoding) /** * Construct and fill in value as a double. * - * @param value in double format - * @param size of the type in bytes + * @param value in double format. + * @param size of the type in bytes. */ public PrimitiveValue(final double value, final int size) { @@ -154,9 +283,9 @@ public PrimitiveValue(final double value, final int size) /** * Construct and fill in value as a byte array. * - * @param value as a byte array - * @param characterEncoding of the characters - * @param size of string in characters + * @param value as a byte array. + * @param characterEncoding of the characters. + * @param size of string in characters. */ public PrimitiveValue(final byte[] value, final String characterEncoding, final int size) { @@ -181,8 +310,8 @@ public Representation representation() /** * Parse constant value string and set representation based on type * - * @param value expressed as a String - * @param primitiveType that this is supposed to be + * @param value expressed as a String. + * @param primitiveType that this is supposed to be. * @return a new {@link PrimitiveValue} for the value. * @throws IllegalArgumentException if parsing malformed type */ @@ -240,8 +369,8 @@ public static PrimitiveValue parse(final String value, final PrimitiveType primi /** * Parse constant value string and set representation based on type * - * @param value expressed as a String - * @param primitiveType that this is supposed to be + * @param value expressed as a String. + * @param primitiveType that this is supposed to be. * @param characterEncoding of the constant value. * @return a new {@link PrimitiveValue} for the value. * @throws IllegalArgumentException if parsing malformed type @@ -265,11 +394,11 @@ public static PrimitiveValue parse( /** * Parse constant value string and set representation based on type, length, and characterEncoding * - * @param value expressed as a String - * @param length of the type - * @param characterEncoding of the String + * @param value expressed as a String. + * @param length of the type. + * @param characterEncoding of the String. * @return a new {@link PrimitiveValue} for the value. - * @throws IllegalArgumentException if parsing malformed type + * @throws IllegalArgumentException if parsing malformed type. */ public static PrimitiveValue parse( final String value, final int length, final String characterEncoding) @@ -289,10 +418,10 @@ public static PrimitiveValue parse( } /** - * Return long value for this PrimitiveValue + * Return long value for this PrimitiveValue. * - * @return value expressed as a long - * @throws IllegalStateException if not a long value representation + * @return value expressed as a long. + * @throws IllegalStateException if not a long value representation. */ public long longValue() { @@ -308,8 +437,8 @@ public long longValue() /** * Return double value for this PrimitiveValue. * - * @return value expressed as a double - * @throws IllegalStateException if not a double value representation + * @return value expressed as a double. + * @throws IllegalStateException if not a double value representation. */ public double doubleValue() { @@ -325,8 +454,8 @@ public double doubleValue() /** * Return byte array value for this PrimitiveValue. * - * @return value expressed as a byte array - * @throws IllegalStateException if not a byte array value representation + * @return value expressed as a byte array. + * @throws IllegalStateException if not a byte array value representation. */ public byte[] byteArrayValue() { @@ -342,9 +471,9 @@ public byte[] byteArrayValue() /** * Return byte array value for this PrimitiveValue given a particular type * - * @param type of this value - * @return value expressed as a byte array - * @throws IllegalStateException if not a byte array value representation + * @param type of this value. + * @return value expressed as a byte array. + * @throws IllegalStateException if not a byte array value representation. */ public byte[] byteArrayValue(final PrimitiveType type) { @@ -364,7 +493,7 @@ else if (representation == Representation.LONG && size == 1 && type == Primitive /** * Return encodedLength for this PrimitiveValue for serialization purposes. * - * @return encodedLength for serialization + * @return encodedLength for serialization. */ public int size() { @@ -416,8 +545,8 @@ else if (Representation.BYTE_ARRAY == representation) /** * Determine if two values are equivalent. * - * @param value to compare this value with - * @return equivalence of values + * @param value to compare this value with. + * @return equivalence of values. */ public boolean equals(final Object value) { @@ -445,9 +574,9 @@ public boolean equals(final Object value) } /** - * Return hashCode for value. This is the underlying representations hashCode for the value + * Return hashCode for value. This is the underlying representations hashCode for the value. * - * @return int value of the hashCode + * @return int value of the hashCode. */ public int hashCode() { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 27ccaea108..8cfdbd888d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -46,9 +46,9 @@ */ public class RustGenerator implements CodeGenerator { - public static final String WRITE_BUF_TYPE = "WriteBuf"; - public static final String READ_BUF_TYPE = "ReadBuf"; - public static final String BUF_LIFETIME = "'a"; + static final String WRITE_BUF_TYPE = "WriteBuf"; + static final String READ_BUF_TYPE = "ReadBuf"; + static final String BUF_LIFETIME = "'a"; enum CodecType { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java index 8bc3144538..4906f10915 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java @@ -26,9 +26,24 @@ */ public class HeaderStructure { + /** + * The field containing the length of the root block in bytes. + */ public static final String BLOCK_LENGTH = "blockLength"; + + /** + * The field containing the template id of the following message. + */ public static final String TEMPLATE_ID = "templateId"; + + /** + * The field containing the schema id to which the following message belongs. + */ public static final String SCHEMA_ID = "schemaId"; + + /** + * The field containing the version of the following message. + */ public static final String SCHEMA_VERSION = "version"; private final List tokens; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java index 54f1fc0adb..550499ce41 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java @@ -23,9 +23,9 @@ public class TestTargetLanguage implements TargetCodeGenerator { - public static final CodeGenerator SINGLETON = mock(CodeGenerator.class); - public static Ir ir = null; - public static String outputDir = ""; + static final CodeGenerator SINGLETON = mock(CodeGenerator.class); + static Ir ir = null; + static String outputDir = ""; public CodeGenerator newInstance(final Ir ir, final String outputDir) { From 838771942bbbdf2ba8df28a4e37c2c9eebc88959 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 29 Dec 2021 10:55:39 +0000 Subject: [PATCH 046/805] [Java] Add descriptions to IR. --- .../sbe/ir/generated/ByteOrderCodec.java | 10 ++- .../sbe/ir/generated/FrameCodecDecoder.java | 2 +- .../sbe/ir/generated/FrameCodecEncoder.java | 2 +- .../ir/generated/MessageHeaderDecoder.java | 2 +- .../ir/generated/MessageHeaderEncoder.java | 2 +- .../sbe/ir/generated/PresenceCodec.java | 14 ++- .../sbe/ir/generated/PrimitiveTypeCodec.java | 50 ++++++++++- .../sbe/ir/generated/SignalCodec.java | 70 ++++++++++++++- .../sbe/ir/generated/TokenCodecDecoder.java | 2 +- .../sbe/ir/generated/TokenCodecEncoder.java | 2 +- .../ir/generated/VarDataEncodingDecoder.java | 2 +- .../ir/generated/VarDataEncodingEncoder.java | 2 +- sbe-tool/src/main/resources/sbe-ir.xml | 86 +++++++++---------- 13 files changed, 191 insertions(+), 55 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java index cec61c4eed..fc8fd3463b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java @@ -3,12 +3,20 @@ /** - * Number encoding byte order + * Number encoding byte order. */ public enum ByteOrderCodec { + + /** + * Little Endian byte encoding. + */ SBE_LITTLE_ENDIAN((short)0), + + /** + * Big Endian byte encoding. + */ SBE_BIG_ENDIAN((short)1), /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index 2c0f88f97a..1fc4a81cdd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -6,7 +6,7 @@ /** - * Frame Header for start of encoding IR + * Frame Header for start of encoding IR. */ @SuppressWarnings("all") public final class FrameCodecDecoder diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java index e2534e99b9..3fca868e13 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java @@ -6,7 +6,7 @@ /** - * Frame Header for start of encoding IR + * Frame Header for start of encoding IR. */ @SuppressWarnings("all") public final class FrameCodecEncoder diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java index 04223e1e06..d83fa30430 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java @@ -5,7 +5,7 @@ /** - * Message identifiers and length of message root + * Message identifiers and length of message root. */ @SuppressWarnings("all") public final class MessageHeaderDecoder diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java index 6aa30f16eb..f295379b98 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java @@ -5,7 +5,7 @@ /** - * Message identifiers and length of message root + * Message identifiers and length of message root. */ @SuppressWarnings("all") public final class MessageHeaderEncoder diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java index 638926218e..ceea18d898 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java @@ -3,14 +3,26 @@ /** - * Field presence declaration + * Field presence declaration. */ public enum PresenceCodec { + + /** + * A field is required. + */ SBE_REQUIRED((short)0), + + /** + * A field is optional. + */ SBE_OPTIONAL((short)1), + + /** + * A field is a constant value. + */ SBE_CONSTANT((short)2), /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java index 4dca2be18d..bc2f89cde3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java @@ -3,32 +3,80 @@ /** - * Primitive types in type system + * Primitive types in type system. */ public enum PrimitiveTypeCodec { + + /** + * No type is provided. + */ NONE((short)0), + + /** + * Single byte character encoding in ASCII. + */ CHAR((short)1), + + /** + * 8-bit signed integer. + */ INT8((short)2), + + /** + * 16-bit signed integer. + */ INT16((short)3), + + /** + * 32-bit signed integer. + */ INT32((short)4), + + /** + * 64-bit signed integer. + */ INT64((short)5), + + /** + * 8-bit unsigned integer. + */ UINT8((short)6), + + /** + * 16-bit unsigned integer. + */ UINT16((short)7), + + /** + * 32-bit unsigned integer. + */ UINT32((short)8), + + /** + * 64-bit unsigned integer. + */ UINT64((short)9), + + /** + * 32-bit single precision floating point. + */ FLOAT((short)10), + + /** + * 64-bit double precision floating point. + */ DOUBLE((short)11), /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java index 3a932483bc..59940ef860 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java @@ -3,42 +3,110 @@ /** - * Token signal type in IR + * Token signal type in IR. */ public enum SignalCodec { + + /** + * Signal the beginning of a message. + */ BEGIN_MESSAGE((short)1), + + /** + * Signal the end of a message. + */ END_MESSAGE((short)2), + + /** + * Signal the beginning of a composite. + */ BEGIN_COMPOSITE((short)3), + + /** + * Signal the end of a composite. + */ END_COMPOSITE((short)4), + + /** + * Signal the beginning of a field. + */ BEGIN_FIELD((short)5), + + /** + * Signal end beginning of a field. + */ END_FIELD((short)6), + + /** + * Signal the beginning of a group. + */ BEGIN_GROUP((short)7), + + /** + * Signal the end of a group. + */ END_GROUP((short)8), + + /** + * Signal the beginning of a enum. + */ BEGIN_ENUM((short)9), + + /** + * Signal a value of an enum. + */ VALID_VALUE((short)10), + + /** + * Signal the end of a enum. + */ END_ENUM((short)11), + + /** + * Signal the beginning of a set. + */ BEGIN_SET((short)12), + + /** + * Signal the a choice in a set. + */ CHOICE((short)13), + + /** + * Signal the end of a set. + */ END_SET((short)14), + + /** + * Signal the beginning of variable data. + */ BEGIN_VAR_DATA((short)15), + + /** + * Signal the end of variable data. + */ END_VAR_DATA((short)16), + + /** + * Signal the encoding of a field. + */ ENCODING((short)17), /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index 9e8b467ae5..674a2cd566 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -6,7 +6,7 @@ /** - * Codec for an IR Token + * Codec for an IR Token. */ @SuppressWarnings("all") public final class TokenCodecDecoder diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java index 1af7ed2f53..1790f6f10b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java @@ -6,7 +6,7 @@ /** - * Codec for an IR Token + * Codec for an IR Token. */ @SuppressWarnings("all") public final class TokenCodecEncoder diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java index b227f42d29..9b067585e4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java @@ -5,7 +5,7 @@ /** - * Header for var data fields + * Header for var data fields. */ @SuppressWarnings("all") public final class VarDataEncodingDecoder diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java index 1909b37f7d..d86d2879a2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java @@ -5,7 +5,7 @@ /** - * Header for var data fields + * Header for var data fields. */ @SuppressWarnings("all") public final class VarDataEncodingEncoder diff --git a/sbe-tool/src/main/resources/sbe-ir.xml b/sbe-tool/src/main/resources/sbe-ir.xml index 4aa581e49c..9d70ef93db 100644 --- a/sbe-tool/src/main/resources/sbe-ir.xml +++ b/sbe-tool/src/main/resources/sbe-ir.xml @@ -6,66 +6,66 @@ byteOrder="littleEndian" description="SBE IR Serialization Codecs."> - + - + - + - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 - - 0 - 1 + + 0 + 1 - - 0 - 1 - 2 + + 0 + 1 + 2 - + @@ -74,7 +74,7 @@ - + From a0b19fa6bac54661cee04a4778316cf5de350a22 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 29 Dec 2021 11:08:32 +0000 Subject: [PATCH 047/805] [Java] Simplify use of display builders for Java and C Sharp. --- .../generation/csharp/CSharpGenerator.java | 22 +++++++------- .../sbe/generation/csharp/CSharpUtil.java | 20 +++---------- .../sbe/generation/java/JavaGenerator.java | 30 +++++++++---------- .../sbe/generation/java/JavaUtil.java | 11 ++----- 4 files changed, 32 insertions(+), 51 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 6d9f9d7a38..cef39009bb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1572,9 +1572,9 @@ private void appendGroupInstanceDisplay( append(sb, indent, " return;"); append(sb, indent, " }"); sb.append('\n'); - Separators.BEGIN_COMPOSITE.appendToGeneratedBuilder(sb, indent + INDENT, "builder"); + Separators.BEGIN_COMPOSITE.appendToGeneratedBuilder(sb, indent + INDENT); appendDisplay(sb, fields, groups, varData, indent + INDENT); - Separators.END_COMPOSITE.appendToGeneratedBuilder(sb, indent + INDENT, "builder"); + Separators.END_COMPOSITE.appendToGeneratedBuilder(sb, indent + INDENT); sb.append('\n'); append(sb, indent, "}"); } @@ -1635,7 +1635,7 @@ private void appendDisplay( append(sb, indent, "builder.Append(\"" + Separators.END_GROUP + "\");"); lengthBeforeLastGeneratedSeparator = sb.length(); - Separators.FIELD.appendToGeneratedBuilder(sb, indent, "builder"); + Separators.FIELD.appendToGeneratedBuilder(sb, indent); i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); } @@ -1667,7 +1667,7 @@ private void appendDisplay( } lengthBeforeLastGeneratedSeparator = sb.length(); - Separators.FIELD.appendToGeneratedBuilder(sb, indent, "builder"); + Separators.FIELD.appendToGeneratedBuilder(sb, indent); i += varDataToken.componentTokenCount(); } @@ -1712,7 +1712,7 @@ private int writeTokenDisplay( } else { - Separators.BEGIN_ARRAY.appendToGeneratedBuilder(sb, indent, "builder"); + Separators.BEGIN_ARRAY.appendToGeneratedBuilder(sb, indent); append(sb, indent, "for (int i = 0; i < " + fieldName + "Length; ++i)"); append(sb, indent, "{"); append(sb, indent, " if (i > 0)"); @@ -1721,7 +1721,7 @@ private int writeTokenDisplay( append(sb, indent, " }"); append(sb, indent, " builder.Append(Get" + fieldName + "(i));"); append(sb, indent, "}"); - Separators.END_ARRAY.appendToGeneratedBuilder(sb, indent, "builder"); + Separators.END_ARRAY.appendToGeneratedBuilder(sb, indent); } } else @@ -1754,7 +1754,7 @@ private int writeTokenDisplay( } final int lengthBeforeFieldSeparator = sb.length(); - Separators.FIELD.appendToGeneratedBuilder(sb, indent, "builder"); + Separators.FIELD.appendToGeneratedBuilder(sb, indent); return lengthBeforeFieldSeparator; } @@ -1779,9 +1779,9 @@ private CharSequence generateChoiceDisplay(final String enumName) append(sb, INDENT, "{"); append(sb, TWO_INDENT, "internal static void BuildString(this " + enumName + " val, StringBuilder builder)"); append(sb, TWO_INDENT, "{"); - Separators.BEGIN_SET.appendToGeneratedBuilder(sb, THREE_INDENT, "builder"); + Separators.BEGIN_SET.appendToGeneratedBuilder(sb, THREE_INDENT); append(sb, THREE_INDENT, "builder.Append(val.ToString());"); - Separators.END_SET.appendToGeneratedBuilder(sb, THREE_INDENT, "builder"); + Separators.END_SET.appendToGeneratedBuilder(sb, THREE_INDENT); append(sb, TWO_INDENT, "}"); append(sb, INDENT, "}"); return sb; @@ -1847,7 +1847,7 @@ private CharSequence generateCompositeDisplay(final List tokens) append(sb, TWO_INDENT, " return;"); append(sb, TWO_INDENT, " }"); sb.append('\n'); - Separators.BEGIN_COMPOSITE.appendToGeneratedBuilder(sb, THREE_INDENT, "builder"); + Separators.BEGIN_COMPOSITE.appendToGeneratedBuilder(sb, THREE_INDENT); int lengthBeforeLastGeneratedSeparator = -1; @@ -1864,7 +1864,7 @@ private CharSequence generateCompositeDisplay(final List tokens) sb.setLength(lengthBeforeLastGeneratedSeparator); } - Separators.END_COMPOSITE.appendToGeneratedBuilder(sb, THREE_INDENT, "builder"); + Separators.END_COMPOSITE.appendToGeneratedBuilder(sb, THREE_INDENT); sb.append('\n'); append(sb, TWO_INDENT, "}"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index 82f9114ae3..3a6a10d0f6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -21,17 +21,12 @@ import java.util.EnumMap; import java.util.Map; - /** * Utilities for mapping between IR and the C# language. */ public class CSharpUtil { - - /** - * Useful separator constants for code generation - */ - public enum Separators + enum Separators { BEGIN_GROUP('['), END_GROUP(']'), @@ -52,20 +47,14 @@ public enum Separators this.symbol = symbol; } - /** - * Add separator to a generated append to a {@link StringBuilder}. - * - * @param builder the code generation builder to which information should be added - * @param indent the current generated code indentation - * @param builderName the generated StringBuilder to which separator should be added - */ - public void appendToGeneratedBuilder(final StringBuilder builder, final String indent, final String builderName) + void appendToGeneratedBuilder(final StringBuilder builder, final String indent) { - builder.append(indent).append(builderName).append(".Append('").append(symbol).append("');").append('\n'); + builder.append(indent).append("builder.Append('").append(symbol).append("');").append('\n'); } /** * Returns the string value of this separator. + * * @return the string value of this separator */ public String toString() @@ -182,5 +171,4 @@ public static void append(final StringBuilder builder, final String indent, fina { builder.append(indent).append(line).append('\n'); } - } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index a96f018116..e2d96b4927 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -3331,7 +3331,7 @@ private CharSequence generateCompositeDecoderDisplay(final List tokens) append(sb, INDENT, " return builder;"); append(sb, INDENT, " }"); sb.append('\n'); - Separator.BEGIN_COMPOSITE.appendToGeneratedBuilder(sb, INDENT + INDENT, "builder"); + Separator.BEGIN_COMPOSITE.appendToGeneratedBuilder(sb, INDENT + INDENT); int lengthBeforeLastGeneratedSeparator = -1; @@ -3348,7 +3348,7 @@ private CharSequence generateCompositeDecoderDisplay(final List tokens) sb.setLength(lengthBeforeLastGeneratedSeparator); } - Separator.END_COMPOSITE.appendToGeneratedBuilder(sb, INDENT + INDENT, "builder"); + Separator.END_COMPOSITE.appendToGeneratedBuilder(sb, INDENT + INDENT); sb.append('\n'); append(sb, INDENT, " return builder;"); append(sb, INDENT, "}"); @@ -3364,7 +3364,7 @@ private CharSequence generateChoiceDisplay(final List tokens) sb.append('\n'); append(sb, INDENT, "public StringBuilder appendTo(final StringBuilder builder)"); append(sb, INDENT, "{"); - Separator.BEGIN_SET.appendToGeneratedBuilder(sb, INDENT + INDENT, "builder"); + Separator.BEGIN_SET.appendToGeneratedBuilder(sb, INDENT + INDENT); append(sb, INDENT, " boolean atLeastOne = false;"); for (final Token token : tokens) @@ -3376,7 +3376,7 @@ private CharSequence generateChoiceDisplay(final List tokens) append(sb, INDENT, " {"); append(sb, INDENT, " if (atLeastOne)"); append(sb, INDENT, " {"); - Separator.ENTRY.appendToGeneratedBuilder(sb, INDENT + INDENT + INDENT + INDENT, "builder"); + Separator.ENTRY.appendToGeneratedBuilder(sb, INDENT + INDENT + INDENT + INDENT); append(sb, INDENT, " }"); append(sb, INDENT, " builder.append(\"" + choiceName + "\");"); append(sb, INDENT, " atLeastOne = true;"); @@ -3384,7 +3384,7 @@ private CharSequence generateChoiceDisplay(final List tokens) } } - Separator.END_SET.appendToGeneratedBuilder(sb, INDENT + INDENT, "builder"); + Separator.END_SET.appendToGeneratedBuilder(sb, INDENT + INDENT); sb.append('\n'); append(sb, INDENT, " return builder;"); append(sb, INDENT, "}"); @@ -3454,9 +3454,9 @@ private void appendGroupInstanceDecoderDisplay( append(sb, indent, " return builder;"); append(sb, indent, " }"); sb.append('\n'); - Separator.BEGIN_COMPOSITE.appendToGeneratedBuilder(sb, indent + INDENT, "builder"); + Separator.BEGIN_COMPOSITE.appendToGeneratedBuilder(sb, indent + INDENT); appendDecoderDisplay(sb, fields, groups, varData, indent + INDENT); - Separator.END_COMPOSITE.appendToGeneratedBuilder(sb, indent + INDENT, "builder"); + Separator.END_COMPOSITE.appendToGeneratedBuilder(sb, indent + INDENT); sb.append('\n'); append(sb, indent, " return builder;"); append(sb, indent, "}"); @@ -3507,14 +3507,14 @@ private void appendDecoderDisplay( append(sb, indent, " while (" + groupName + ".hasNext())"); append(sb, indent, " {"); append(sb, indent, " " + groupName + ".next().appendTo(builder);"); - Separator.ENTRY.appendToGeneratedBuilder(sb, indent + INDENT + INDENT, "builder"); + Separator.ENTRY.appendToGeneratedBuilder(sb, indent + INDENT + INDENT); append(sb, indent, " }"); append(sb, indent, " builder.setLength(builder.length() - 1);"); append(sb, indent, "}"); - Separator.END_GROUP.appendToGeneratedBuilder(sb, indent, "builder"); + Separator.END_GROUP.appendToGeneratedBuilder(sb, indent); lengthBeforeLastGeneratedSeparator = sb.length(); - Separator.FIELD.appendToGeneratedBuilder(sb, indent, "builder"); + Separator.FIELD.appendToGeneratedBuilder(sb, indent); i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); } @@ -3550,7 +3550,7 @@ private void appendDecoderDisplay( } lengthBeforeLastGeneratedSeparator = sb.length(); - Separator.FIELD.appendToGeneratedBuilder(sb, indent, "builder"); + Separator.FIELD.appendToGeneratedBuilder(sb, indent); i += varDataToken.componentTokenCount(); } @@ -3586,17 +3586,17 @@ private int writeTokenDisplay( } else { - Separator.BEGIN_ARRAY.appendToGeneratedBuilder(sb, indent, "builder"); + Separator.BEGIN_ARRAY.appendToGeneratedBuilder(sb, indent); append(sb, indent, "if (" + fieldName + "Length() > 0)"); append(sb, indent, "{"); append(sb, indent, " for (int i = 0; i < " + fieldName + "Length(); i++)"); append(sb, indent, " {"); append(sb, indent, " builder.append(" + fieldName + "(i));"); - Separator.ENTRY.appendToGeneratedBuilder(sb, indent + INDENT + INDENT, "builder"); + Separator.ENTRY.appendToGeneratedBuilder(sb, indent + INDENT + INDENT); append(sb, indent, " }"); append(sb, indent, " builder.setLength(builder.length() - 1);"); append(sb, indent, "}"); - Separator.END_ARRAY.appendToGeneratedBuilder(sb, indent, "builder"); + Separator.END_ARRAY.appendToGeneratedBuilder(sb, indent); } } else @@ -3631,7 +3631,7 @@ private int writeTokenDisplay( } final int lengthBeforeFieldSeparator = sb.length(); - Separator.FIELD.appendToGeneratedBuilder(sb, indent, "builder"); + Separator.FIELD.appendToGeneratedBuilder(sb, indent); return lengthBeforeFieldSeparator; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index 4da409b6d8..839923d2e1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -61,16 +61,9 @@ enum Separator this.symbol = symbol; } - /** - * Add separator to a generated append to a {@link StringBuilder}. - * - * @param builder the code generation builder to which information should be added - * @param indent the current generated code indentation - * @param builderName of the generated StringBuilder to which separator should be added - */ - void appendToGeneratedBuilder(final StringBuilder builder, final String indent, final String builderName) + void appendToGeneratedBuilder(final StringBuilder builder, final String indent) { - builder.append(indent).append(builderName).append(".append('").append(symbol).append("');").append('\n'); + builder.append(indent).append("builder.append('").append(symbol).append("');").append('\n'); } /** From e4da8fa2a268695ef92118d65337c5f708c3eacd Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 29 Dec 2021 19:46:17 +0000 Subject: [PATCH 048/805] [Java] Upgrade to Shadow 7.1.2. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b7979e11b1..bf23f7754c 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ import java.security.MessageDigest plugins { id 'java-library' - id 'com.github.johnrengelman.shadow' version '7.1.1' apply false + id 'com.github.johnrengelman.shadow' version '7.1.2' apply false id "com.github.ben-manes.versions" version "0.39.0" } From 2b91e1bd100ada4faed30cb288ec6f1f2986f872 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 29 Dec 2021 19:57:05 +0000 Subject: [PATCH 049/805] [Java] Upgrade to Checkstyle 9.2.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bf23f7754c..c31bcc58e0 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ def toolchainLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(buildJavaVersion) } -def checkstyleVersion = '9.2' +def checkstyleVersion = '9.2.1' def hamcrestVersion = '2.2' def mockitoVersion = '4.2.0' def junitVersion = '5.8.2' From 43b458ce7ab782f866185fb42f4a29b49e6cb46a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sat, 1 Jan 2022 09:08:45 +0000 Subject: [PATCH 050/805] [Java] Upgrade to version 0.40.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c31bcc58e0..dccbca6ad5 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ import java.security.MessageDigest plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '7.1.2' apply false - id "com.github.ben-manes.versions" version "0.39.0" + id "com.github.ben-manes.versions" version "0.40.0" } defaultTasks 'clean', 'build' From 248299d84dc4203766e955945d633f030c6a6b7b Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Jan 2022 10:06:16 +0100 Subject: [PATCH 051/805] [Java] Regenerate Gradle wrapper scripts. --- gradlew | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradlew b/gradlew index c53aefaa5f..1b6c787337 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # From 796a44887c2aaa6c570dc46f7c55e302dcc1161d Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 6 Jan 2022 20:34:36 +0000 Subject: [PATCH 052/805] [Java] Upgrade to Versions 0.41.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index dccbca6ad5..e4d41d6416 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ import java.security.MessageDigest plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '7.1.2' apply false - id "com.github.ben-manes.versions" version "0.40.0" + id "com.github.ben-manes.versions" version "0.41.0" } defaultTasks 'clean', 'build' From ff8d2c9ab2773b0051cd9e701981ef72232c26c5 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 8 Jan 2022 10:57:29 +0100 Subject: [PATCH 053/805] [Java] Charset encoding handling improvements. (#887) * [Java] Use StandardCharsets when generating `CharacterEncoding` methods and make alias names case-insensitive. * [Java] Use `putStringWithoutLengthAscii` for ASCII-encoded property when input is a `CharSequence`. * [Java] Replace use an actual CharSet instance when invoking String constructor and getBytes. * [Java] Use `ArrayUtil.EMPTY_BYTE_ARRAY` instead of creating `byte[0]` when input string is null or empty. * [Java] Add assertions around Charset usage. * [Java] Add an explicit test for case-insensitive alias and remove extra output. * [Java] Resolve canonical charset name when not a standard charset. * [Java] Do not convert character encoding to upper case, i.e. treat character encoding as case-sensitive. --- .../generation/golang/GolangGenerator.java | 49 ++--- .../sbe/generation/java/JavaGenerator.java | 53 ++--- .../sbe/generation/java/JavaUtil.java | 71 ++++++- .../sbe/generation/rust/RustGenerator.java | 51 ++--- .../sbe/ir/generated/FrameCodecDecoder.java | 42 +--- .../sbe/ir/generated/FrameCodecEncoder.java | 36 +--- .../sbe/ir/generated/TokenCodecDecoder.java | 154 ++------------ .../sbe/ir/generated/TokenCodecEncoder.java | 132 ++---------- .../real_logic/sbe/xml/EncodedDataType.java | 4 +- .../java/CharacterEncodingTest.java | 195 ++++++++++++++++++ .../sbe/xml/EncodedDataTypeTest.java | 43 ++++ 11 files changed, 423 insertions(+), 407 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index 4118130c4d..0e5d8438ba 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -20,6 +20,7 @@ import uk.co.real_logic.sbe.generation.CodeGenerator; import org.agrona.generation.OutputManager; import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.generation.java.JavaUtil; import uk.co.real_logic.sbe.ir.*; import org.agrona.Verify; @@ -244,29 +245,31 @@ private void generateCharacterEncodingRangeCheck( if (null != characterEncoding) { - switch (token.encoding().characterEncoding()) + if (JavaUtil.isAsciiEncoding(characterEncoding)) { - case "ASCII": - imports.peek().add("fmt"); - sb.append(String.format( - "\tfor idx, ch := range %1$s {\n" + - "\t\tif ch > 127 {\n" + - "\t\t\treturn fmt.Errorf(\"%1$s[%%d]=%%d" + - " failed ASCII validation\", idx, ch)\n" + - "\t\t}\n" + - "\t}\n", - varName)); - break; - - case "UTF-8": - imports.peek().add("errors"); - imports.peek().add("unicode/utf8"); - sb.append(String.format( - "\tif !utf8.Valid(%1$s[:]) {\n" + - "\t\treturn errors.New(\"%1$s failed UTF-8 validation\")\n" + - "\t}\n", - varName)); - break; + imports.peek().add("fmt"); + sb.append(String.format( + "\tfor idx, ch := range %1$s {\n" + + "\t\tif ch > 127 {\n" + + "\t\t\treturn fmt.Errorf(\"%1$s[%%d]=%%d" + + " failed ASCII validation\", idx, ch)\n" + + "\t\t}\n" + + "\t}\n", + varName)); + } + else if (JavaUtil.isUtf8Encoding(characterEncoding)) + { + imports.peek().add("errors"); + imports.peek().add("unicode/utf8"); + sb.append(String.format( + "\tif !utf8.Valid(%1$s[:]) {\n" + + "\t\treturn errors.New(\"%1$s failed UTF-8 validation\")\n" + + "\t}\n", + varName)); + } + else + { + throw new IllegalArgumentException("Unsupported encoding: " + characterEncoding); } } } @@ -1836,7 +1839,7 @@ private void generateCompositePropertyElements( final String containingTypeName, final List tokens) { - for (int i = 0; i < tokens.size();) + for (int i = 0; i < tokens.size(); ) { final Token token = tokens.get(i); final String propertyName = formatPropertyName(token.name()); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index e2d96b4927..4272a8f436 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -921,25 +921,16 @@ private void generateDataDecodeMethods( indent + " }\n\n" + indent + " final byte[] tmp = new byte[dataLength];\n" + indent + " buffer.getBytes(limit + headerLength, tmp, 0, dataLength);\n\n" + - indent + " final String value;\n" + - indent + " try\n" + - indent + " {\n" + - indent + " value = new String(tmp, \"%6$s\");\n" + - indent + " }\n" + - indent + " catch (final java.io.UnsupportedEncodingException ex)\n" + - indent + " {\n" + - indent + " throw new RuntimeException(ex);\n" + - indent + " }\n\n" + - indent + " return value;\n" + + indent + " return new String(tmp, %6$s);\n" + indent + " }\n", formatPropertyName(propertyName), generateStringNotPresentCondition(token.version(), indent), sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", generateGet(lengthType, "limit", byteOrderStr), - characterEncoding); + charset(characterEncoding)); - if (characterEncoding.contains("ASCII")) + if (isAsciiEncoding(characterEncoding)) { new Formatter(sb).format("\n" + indent + " public int get%1$s(final Appendable appendable)\n" + @@ -1050,7 +1041,7 @@ private void generateCharArrayEncodeMethods( { final PrimitiveType lengthPutType = PrimitiveType.UINT32 == lengthType ? PrimitiveType.INT32 : lengthType; - if (characterEncoding.contains("ASCII")) + if (isAsciiEncoding(characterEncoding)) { new Formatter(sb).format("\n" + indent + " public %1$s %2$s(final String value)\n" + @@ -1099,16 +1090,8 @@ private void generateCharArrayEncodeMethods( new Formatter(sb).format("\n" + indent + " public %1$s %2$s(final String value)\n" + indent + " {\n" + - indent + " final byte[] bytes;\n" + - indent + " try\n" + - indent + " {\n" + - indent + " bytes = null == value || value.isEmpty() ?" + - " org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(\"%3$s\");\n" + - indent + " }\n" + - indent + " catch (final java.io.UnsupportedEncodingException ex)\n" + - indent + " {\n" + - indent + " throw new RuntimeException(ex);\n" + - indent + " }\n\n" + + indent + " final byte[] bytes = (null == value || value.isEmpty()) ?" + + " org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(%3$s);\n\n" + indent + " final int length = bytes.length;\n" + indent + " if (length > %4$d)\n" + indent + " {\n" + @@ -1123,7 +1106,7 @@ private void generateCharArrayEncodeMethods( indent + " }\n", className, formatPropertyName(propertyName), - characterEncoding, + charset(characterEncoding), maxLengthValue, sizeOfLengthField, generatePut(lengthPutType, "limit", "length", byteOrderStr)); @@ -2042,7 +2025,7 @@ private CharSequence generatePrimitiveArrayPropertyDecode( fieldLength, charset(encoding.characterEncoding())); - if (encoding.characterEncoding().contains("ASCII")) + if (isAsciiEncoding(encoding.characterEncoding())) { new Formatter(sb).format("\n" + indent + " public int get%1$s(final Appendable value)\n" + @@ -2240,7 +2223,7 @@ private void generateCharArrayEncodeMethods( fieldLength, offset); - if (encoding.characterEncoding().contains("ASCII")) + if (isAsciiEncoding(encoding.characterEncoding())) { new Formatter(sb).format("\n" + indent + " public %1$s %2$s(final String src)\n" + @@ -2274,15 +2257,10 @@ private void generateCharArrayEncodeMethods( indent + " throw new IndexOutOfBoundsException(" + "\"CharSequence too large for copy: byte length=\" + srcLength);\n" + indent + " }\n\n" + - indent + " for (int i = 0; i < srcLength; ++i)\n" + - indent + " {\n" + - indent + " final char charValue = src.charAt(i);\n" + - indent + " final byte byteValue = charValue > 127 ? (byte)'?' : (byte)charValue;\n" + - indent + " buffer.putByte(offset + %4$d + i, byteValue);\n" + - indent + " }\n\n" + - indent + " for (int i = srcLength; i < length; ++i)\n" + + indent + " buffer.putStringWithoutLengthAscii(offset + %4$d, src);\n\n" + + indent + " for (int start = srcLength; start < length; ++start)\n" + indent + " {\n" + - indent + " buffer.putByte(offset + %4$d + i, (byte)0);\n" + + indent + " buffer.putByte(offset + %4$d + start, (byte)0);\n" + indent + " }\n\n" + indent + " return this;\n" + indent + " }\n", @@ -2297,7 +2275,8 @@ private void generateCharArrayEncodeMethods( indent + " public %s %s(final String src)\n" + indent + " {\n" + indent + " final int length = %d;\n" + - indent + " final byte[] bytes = null == src ? new byte[0] : src.getBytes(%s);\n" + + indent + " final byte[] bytes = (null == src || src.isEmpty()) ?" + + " org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : src.getBytes(%s);\n" + indent + " if (bytes.length > length)\n" + indent + " {\n" + indent + " throw new IndexOutOfBoundsException(" + @@ -2387,7 +2366,7 @@ private static void generateCharacterEncodingMethod( sb.append("\n") .append(indent).append(" public static String ").append(propName).append("CharacterEncoding()\n") .append(indent).append(" {\n") - .append(indent).append(" return \"").append(characterEncoding).append("\";\n") + .append(indent).append(" return ").append(charsetName(characterEncoding)).append(";\n") .append(indent).append(" }\n"); } } @@ -3537,7 +3516,7 @@ private void appendDecoderDisplay( } else { - if (characterEncoding.contains("ASCII") || characterEncoding.contains("ascii")) + if (isAsciiEncoding(characterEncoding)) { append(sb, indent, "builder.append('\\'');"); append(sb, indent, formatGetterName(varDataToken.name()) + "(builder);"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index 839923d2e1..f6969c111e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -18,20 +18,19 @@ import org.agrona.Strings; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.SbeTool; +import uk.co.real_logic.sbe.ValidationUtil; import uk.co.real_logic.sbe.generation.Generators; import uk.co.real_logic.sbe.ir.Token; -import uk.co.real_logic.sbe.ValidationUtil; import java.io.IOException; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; -import static java.lang.reflect.Modifier.STATIC; - /** * Utilities for mapping between {@link uk.co.real_logic.sbe.ir.Ir} and the Java language. */ @@ -96,7 +95,7 @@ public String toString() /** * Indexes known charset aliases to the name of the instance in {@link StandardCharsets}. */ - private static final Map STD_CHARSETS = new HashMap<>(); + static final HashMap STD_CHARSETS = new HashMap<>(); static { @@ -104,11 +103,25 @@ public String toString() { for (final Field field : StandardCharsets.class.getDeclaredFields()) { - if (Charset.class.isAssignableFrom(field.getType()) && ((field.getModifiers() & STATIC) == STATIC)) + if (Charset.class.isAssignableFrom(field.getType()) && Modifier.isStatic(field.getModifiers()) && + Modifier.isPublic(field.getModifiers())) { final Charset charset = (Charset)field.get(null); - STD_CHARSETS.put(charset.name(), field.getName()); - charset.aliases().forEach((alias) -> STD_CHARSETS.put(alias, field.getName())); + final String name = field.getName(); + String oldName = STD_CHARSETS.put(charset.name(), name); + if (null != oldName) + { + throw new IllegalStateException("Duplicate charset alias: old=" + oldName + ", new=" + name); + } + for (final String alias : charset.aliases()) + { + oldName = STD_CHARSETS.put(alias, name); + if (null != oldName) + { + throw new IllegalStateException("Duplicate charset alias: old=" + oldName + ", new=" + + alias); + } + } } } } @@ -207,10 +220,52 @@ public static String charset(final String encoding) } else { - return "java.nio.charset.Charset.forName(\"" + encoding + "\")"; + final String canonicalName = Charset.isSupported(encoding) ? Charset.forName(encoding).name() : encoding; + return "java.nio.charset.Charset.forName(\"" + canonicalName + "\")"; } } + /** + * Code to fetch the name of the {@link Charset} given the encoding. + * + * @param encoding as a string name (eg. UTF-8). + * @return the code to fetch the associated Charset name. + */ + public static String charsetName(final String encoding) + { + final String charsetName = STD_CHARSETS.get(encoding); + if (charsetName != null) + { + return "java.nio.charset.StandardCharsets." + charsetName + ".name()"; + } + else + { + return "\"" + (Charset.isSupported(encoding) ? Charset.forName(encoding).name() : encoding) + "\""; + } + } + + /** + * Checks if the given encoding represents an ASCII charset. + * + * @param encoding as a string name (e.g. ASCII). + * @return {@code true} if the encoding denotes an ASCII charset. + */ + public static boolean isAsciiEncoding(final String encoding) + { + return "US_ASCII".equals(STD_CHARSETS.get(encoding)); + } + + /** + * Checks if the given encoding represents a UTF-8 charset. + * + * @param encoding as a string name (e.g. unicode-1-1-utf-8). + * @return {@code true} if the encoding denotes a UTF-8 charset. + */ + public static boolean isUtf8Encoding(final String encoding) + { + return "UTF_8".equals(STD_CHARSETS.get(encoding)); + } + /** * Generate a literal value to be used in code generation. * diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 8cfdbd888d..b3abad386c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -20,6 +20,7 @@ import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.generation.CodeGenerator; import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.generation.java.JavaUtil; import uk.co.real_logic.sbe.ir.Encoding; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.ir.Signal; @@ -304,20 +305,15 @@ static void generateEncoderVarData( final String varDataType; final String toBytesFn; - switch (characterEncoding) + if (JavaUtil.isUtf8Encoding(characterEncoding)) { - case "UTF-8": - { - varDataType = "&str"; - toBytesFn = ".as_bytes()"; - break; - } - default: - { - varDataType = "&[u8]"; - toBytesFn = ""; - break; - } + varDataType = "&str"; + toBytesFn = ".as_bytes()"; + } + else + { + varDataType = "&[u8]"; + toBytesFn = ""; } // function to write slice ... todo - handle character encoding ? @@ -681,23 +677,20 @@ private static void generatePrimitiveConstantDecoder( indent(sb, level, "/// characterEncoding: '%s'\n", characterEncoding); indent(sb, level, "#[inline]\n"); - switch (characterEncoding) + if (JavaUtil.isAsciiEncoding(characterEncoding)) { - case "US-ASCII": - { - indent(sb, level, "pub fn %s(&self) -> &'static [u8] {\n", - formatFunctionName(name)); - indent(sb, level + 1, "b\"%s\"\n", rawConstValue); - break; - } - case "UTF-8": - { - indent(sb, level, "pub fn %s(&self) -> &'static str {\n", formatFunctionName(name)); - indent(sb, level + 1, "\"%s\"\n", rawConstValue); - break; - } - default: - throw new RuntimeException("Unable to handle " + characterEncoding); + indent(sb, level, "pub fn %s(&self) -> &'static [u8] {\n", + formatFunctionName(name)); + indent(sb, level + 1, "b\"%s\"\n", rawConstValue); + } + else if (JavaUtil.isUtf8Encoding(characterEncoding)) + { + indent(sb, level, "pub fn %s(&self) -> &'static str {\n", formatFunctionName(name)); + indent(sb, level + 1, "\"%s\"\n", rawConstValue); + } + else + { + throw new IllegalArgumentException("Unsupported encoding: " + characterEncoding); } indent(sb, level, "}\n\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index 1fc4a81cdd..d958498953 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -299,7 +299,7 @@ public static int packageNameSinceVersion() public static String packageNameCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String packageNameMetaAttribute(final MetaAttribute metaAttribute) @@ -382,17 +382,7 @@ public String packageName() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int namespaceNameId() @@ -407,7 +397,7 @@ public static int namespaceNameSinceVersion() public static String namespaceNameCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String namespaceNameMetaAttribute(final MetaAttribute metaAttribute) @@ -490,17 +480,7 @@ public String namespaceName() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int semanticVersionId() @@ -515,7 +495,7 @@ public static int semanticVersionSinceVersion() public static String semanticVersionCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String semanticVersionMetaAttribute(final MetaAttribute metaAttribute) @@ -598,17 +578,7 @@ public String semanticVersion() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public String toString() diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java index 3fca868e13..4bcc266652 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java @@ -267,7 +267,7 @@ public static int packageNameId() public static String packageNameCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String packageNameMetaAttribute(final MetaAttribute metaAttribute) @@ -319,15 +319,7 @@ public FrameCodecEncoder putPackageName(final byte[] src, final int srcOffset, f public FrameCodecEncoder packageName(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -351,7 +343,7 @@ public static int namespaceNameId() public static String namespaceNameCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String namespaceNameMetaAttribute(final MetaAttribute metaAttribute) @@ -403,15 +395,7 @@ public FrameCodecEncoder putNamespaceName(final byte[] src, final int srcOffset, public FrameCodecEncoder namespaceName(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -435,7 +419,7 @@ public static int semanticVersionId() public static String semanticVersionCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String semanticVersionMetaAttribute(final MetaAttribute metaAttribute) @@ -487,15 +471,7 @@ public FrameCodecEncoder putSemanticVersion(final byte[] src, final int srcOffse public FrameCodecEncoder semanticVersion(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index 674a2cd566..cfac525b67 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -616,7 +616,7 @@ public static int nameSinceVersion() public static String nameCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String nameMetaAttribute(final MetaAttribute metaAttribute) @@ -699,17 +699,7 @@ public String name() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int constValueId() @@ -724,7 +714,7 @@ public static int constValueSinceVersion() public static String constValueCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String constValueMetaAttribute(final MetaAttribute metaAttribute) @@ -807,17 +797,7 @@ public String constValue() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int minValueId() @@ -832,7 +812,7 @@ public static int minValueSinceVersion() public static String minValueCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String minValueMetaAttribute(final MetaAttribute metaAttribute) @@ -915,17 +895,7 @@ public String minValue() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int maxValueId() @@ -940,7 +910,7 @@ public static int maxValueSinceVersion() public static String maxValueCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String maxValueMetaAttribute(final MetaAttribute metaAttribute) @@ -1023,17 +993,7 @@ public String maxValue() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int nullValueId() @@ -1048,7 +1008,7 @@ public static int nullValueSinceVersion() public static String nullValueCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String nullValueMetaAttribute(final MetaAttribute metaAttribute) @@ -1131,17 +1091,7 @@ public String nullValue() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int characterEncodingId() @@ -1156,7 +1106,7 @@ public static int characterEncodingSinceVersion() public static String characterEncodingCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String characterEncodingMetaAttribute(final MetaAttribute metaAttribute) @@ -1239,17 +1189,7 @@ public String characterEncoding() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int epochId() @@ -1264,7 +1204,7 @@ public static int epochSinceVersion() public static String epochCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String epochMetaAttribute(final MetaAttribute metaAttribute) @@ -1347,17 +1287,7 @@ public String epoch() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int timeUnitId() @@ -1372,7 +1302,7 @@ public static int timeUnitSinceVersion() public static String timeUnitCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String timeUnitMetaAttribute(final MetaAttribute metaAttribute) @@ -1455,17 +1385,7 @@ public String timeUnit() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int semanticTypeId() @@ -1480,7 +1400,7 @@ public static int semanticTypeSinceVersion() public static String semanticTypeCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String semanticTypeMetaAttribute(final MetaAttribute metaAttribute) @@ -1563,17 +1483,7 @@ public String semanticType() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int descriptionId() @@ -1588,7 +1498,7 @@ public static int descriptionSinceVersion() public static String descriptionCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String descriptionMetaAttribute(final MetaAttribute metaAttribute) @@ -1671,17 +1581,7 @@ public String description() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public static int referencedNameId() @@ -1696,7 +1596,7 @@ public static int referencedNameSinceVersion() public static String referencedNameCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String referencedNameMetaAttribute(final MetaAttribute metaAttribute) @@ -1779,17 +1679,7 @@ public String referencedName() final byte[] tmp = new byte[dataLength]; buffer.getBytes(limit + headerLength, tmp, 0, dataLength); - final String value; - try - { - value = new String(tmp, "UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } - - return value; + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } public String toString() diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java index 1790f6f10b..1f429e09b5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java @@ -567,7 +567,7 @@ public static int nameId() public static String nameCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String nameMetaAttribute(final MetaAttribute metaAttribute) @@ -619,15 +619,7 @@ public TokenCodecEncoder putName(final byte[] src, final int srcOffset, final in public TokenCodecEncoder name(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -651,7 +643,7 @@ public static int constValueId() public static String constValueCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String constValueMetaAttribute(final MetaAttribute metaAttribute) @@ -703,15 +695,7 @@ public TokenCodecEncoder putConstValue(final byte[] src, final int srcOffset, fi public TokenCodecEncoder constValue(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -735,7 +719,7 @@ public static int minValueId() public static String minValueCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String minValueMetaAttribute(final MetaAttribute metaAttribute) @@ -787,15 +771,7 @@ public TokenCodecEncoder putMinValue(final byte[] src, final int srcOffset, fina public TokenCodecEncoder minValue(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -819,7 +795,7 @@ public static int maxValueId() public static String maxValueCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String maxValueMetaAttribute(final MetaAttribute metaAttribute) @@ -871,15 +847,7 @@ public TokenCodecEncoder putMaxValue(final byte[] src, final int srcOffset, fina public TokenCodecEncoder maxValue(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -903,7 +871,7 @@ public static int nullValueId() public static String nullValueCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String nullValueMetaAttribute(final MetaAttribute metaAttribute) @@ -955,15 +923,7 @@ public TokenCodecEncoder putNullValue(final byte[] src, final int srcOffset, fin public TokenCodecEncoder nullValue(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -987,7 +947,7 @@ public static int characterEncodingId() public static String characterEncodingCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String characterEncodingMetaAttribute(final MetaAttribute metaAttribute) @@ -1039,15 +999,7 @@ public TokenCodecEncoder putCharacterEncoding(final byte[] src, final int srcOff public TokenCodecEncoder characterEncoding(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -1071,7 +1023,7 @@ public static int epochId() public static String epochCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String epochMetaAttribute(final MetaAttribute metaAttribute) @@ -1123,15 +1075,7 @@ public TokenCodecEncoder putEpoch(final byte[] src, final int srcOffset, final i public TokenCodecEncoder epoch(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -1155,7 +1099,7 @@ public static int timeUnitId() public static String timeUnitCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String timeUnitMetaAttribute(final MetaAttribute metaAttribute) @@ -1207,15 +1151,7 @@ public TokenCodecEncoder putTimeUnit(final byte[] src, final int srcOffset, fina public TokenCodecEncoder timeUnit(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -1239,7 +1175,7 @@ public static int semanticTypeId() public static String semanticTypeCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String semanticTypeMetaAttribute(final MetaAttribute metaAttribute) @@ -1291,15 +1227,7 @@ public TokenCodecEncoder putSemanticType(final byte[] src, final int srcOffset, public TokenCodecEncoder semanticType(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -1323,7 +1251,7 @@ public static int descriptionId() public static String descriptionCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String descriptionMetaAttribute(final MetaAttribute metaAttribute) @@ -1375,15 +1303,7 @@ public TokenCodecEncoder putDescription(final byte[] src, final int srcOffset, f public TokenCodecEncoder description(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) @@ -1407,7 +1327,7 @@ public static int referencedNameId() public static String referencedNameCharacterEncoding() { - return "UTF-8"; + return java.nio.charset.StandardCharsets.UTF_8.name(); } public static String referencedNameMetaAttribute(final MetaAttribute metaAttribute) @@ -1459,15 +1379,7 @@ public TokenCodecEncoder putReferencedName(final byte[] src, final int srcOffset public TokenCodecEncoder referencedName(final String value) { - final byte[] bytes; - try - { - bytes = null == value || value.isEmpty() ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes("UTF-8"); - } - catch (final java.io.UnsupportedEncodingException ex) - { - throw new RuntimeException(ex); - } + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); final int length = bytes.length; if (length > 65534) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index 4c76c27184..f8b6728851 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -94,12 +94,12 @@ public EncodedDataType(final Node node, final String givenName, final String ref if (PrimitiveType.CHAR == primitiveType) { - characterEncoding = getAttributeValue(node, "characterEncoding", "US-ASCII").trim().toUpperCase(); + characterEncoding = getAttributeValue(node, "characterEncoding", "US-ASCII").trim(); } else { final String characterEncoding = getAttributeValueOrNull(node, "characterEncoding"); - this.characterEncoding = characterEncoding == null ? null : characterEncoding.trim().toUpperCase(); + this.characterEncoding = characterEncoding == null ? null : characterEncoding.trim(); } if (presence() == CONSTANT) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java new file mode 100644 index 0000000000..80125fdcf8 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java @@ -0,0 +1,195 @@ +/* + * Copyright 2013-2021 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import org.agrona.DirectBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.ByteArrayInputStream; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; +import static uk.co.real_logic.sbe.generation.java.JavaUtil.*; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +public class CharacterEncodingTest +{ + private static final String XML_SCHEMA; + + static + { + final StringBuilder buffer = + new StringBuilder("\n") + .append("\n") + .append(" \n") + .append(" \n") + .append(" \n") + .append(" \n") + .append(" \n") + .append(" \n") + .append(" \n"); + + int i = 0; + for (final String alias : STD_CHARSETS.keySet()) + { + buffer.append(" \n"); + buffer.append(" \n") + .append(" \n") + .append(" \n") + .append(" \n"); + i++; + } + buffer.append(" \n"); + buffer.append(" \n") + .append(" \n") + .append(" \n \n"); + buffer.append(" \n"); + buffer.append(" \n"); + + buffer.append(" \n") + .append(" \n"); + i = 0; + for (int j = 0, size = STD_CHARSETS.size(); j < size; j++) + { + buffer.append(" \n"); + i++; + } + buffer.append(""); + buffer.append(""); + buffer.append(""); + + for (int j = 0, size = STD_CHARSETS.size(); j < size; j++) + { + buffer.append(" \n"); + i++; + } + buffer.append(""); + + buffer.append(" \n") + .append(""); + XML_SCHEMA = buffer.toString(); + } + + @Test + public void shouldUseStandardCharsetsForWellKnowEncodings() throws Exception + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = + parse(new ByteArrayInputStream(XML_SCHEMA.getBytes(UTF_8)), options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + final JavaGenerator generator = new JavaGenerator( + ir, MutableDirectBuffer.class.getName(), DirectBuffer.class.getName(), false, false, false, outputManager); + + generator.generate(); + final Map sources = outputManager.getSources(); + final String encoderSources = sources.get("code.generation.test.EncodingTestEncoder").toString(); + final String decoderSources = sources.get("code.generation.test.EncodingTestDecoder").toString(); + + verifyCharacterEncodingMethods(encoderSources); + verifyCharacterEncodingMethods(decoderSources); + + assertThat(encoderSources, not(containsString("java.io.UnsupportedEncodingException"))); + assertThat(encoderSources, not(containsString("new byte[0]"))); + for (final String charset : STD_CHARSETS.values()) + { + if (!"US_ASCII".equals(charset)) + { + assertThat( + encoderSources, containsString("getBytes(java.nio.charset.StandardCharsets." + charset + ")")); + } + } + assertThat(encoderSources, containsString("getBytes(java.nio.charset.Charset.forName(\"custom-encoding\"))")); + assertThat(encoderSources, containsString("getBytes(java.nio.charset.Charset.forName(\"ISO-8859-2\"))")); + assertThat(encoderSources, allOf(not(containsString("\"cp912\"")), not(containsString("\"CP912\"")))); + final int encodeFromStringStartIndex = encoderSources.indexOf("f_std_alias(final String src)"); + final int encodeFromStringEndIndex = encoderSources.indexOf("return this", encodeFromStringStartIndex); + assertThat( + encoderSources.substring(encodeFromStringStartIndex, encodeFromStringEndIndex), + containsString("final byte[] bytes = (null == src || src.isEmpty()) ?" + + " org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY :" + + " src.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1);")); + assertThat(decoderSources, not(containsString("java.io.UnsupportedEncodingException"))); + assertThat(decoderSources, not(containsString("new byte[0]"))); + for (final String charset : STD_CHARSETS.values()) + { + assertThat(decoderSources, containsString("end, java.nio.charset.StandardCharsets." + charset + ")")); + } + assertThat(decoderSources, containsString("end, java.nio.charset.Charset.forName(\"custom-encoding\"))")); + assertThat(decoderSources, containsString("end, java.nio.charset.Charset.forName(\"ISO-8859-2\"))")); + assertThat(decoderSources, allOf(not(containsString("\"cp912\"")), not(containsString("\"CP912\"")))); + } + + private void verifyCharacterEncodingMethods(final String code) + { + int i = 0; + for (final String charset : STD_CHARSETS.values()) + { + assertContainsCharacterEncodingMethod( + "f_" + (i++), "java.nio.charset.StandardCharsets." + charset + ".name()", code); + } + assertContainsCharacterEncodingMethod("f_custom", "\"custom-encoding\"", code); + assertContainsCharacterEncodingMethod( + "f_std_alias", "java.nio.charset.StandardCharsets.ISO_8859_1.name()", code); + assertContainsCharacterEncodingMethod("f_non_std_alias", "\"ISO-8859-2\"", code); + } + + private static void assertContainsCharacterEncodingMethod( + final String fieldName, final String expectedEncoding, final String sources) + { + final String expectedOne = + " public static String " + fieldName + "CharacterEncoding()\n" + + " {\n return " + expectedEncoding + ";\n }"; + assertThat(sources, containsString(expectedOne)); + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java index 4e31d104be..a73173bb16 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java @@ -414,6 +414,49 @@ public void shouldReturnCorrectNullValueWhenSpecified() throws Exception is(parse(nullVal, PrimitiveType.INT8))); } + @Test + public void shouldReturnCharacterEncodingWhenSpecified() throws Exception + { + final String testXmlString = + "" + + " " + + ""; + + final Map map = parseTestXmlWithMap("/types/type", testXmlString); + + assertThat((((EncodedDataType)map.get("testTypeCharacterEncoding")).characterEncoding()), is("cp912")); + } + + @Test + public void shouldReturnCharacterEncodingWhenSpecifiedNonCharType() throws Exception + { + final String testXmlString = + "" + + " " + + ""; + + final Map map = parseTestXmlWithMap("/types/type", testXmlString); + + assertThat( + (((EncodedDataType)map.get("testTypeCharacterEncodingNonChar")).characterEncoding()), is("windows-1251")); + } + + @Test + public void shouldReturnUsAsciiWhenCharacterEncodingNotSpecifiedForTypeChar() throws Exception + { + final String testXmlString = + "" + + " " + + ""; + + final Map map = parseTestXmlWithMap("/types/type", testXmlString); + + assertThat( + (((EncodedDataType)map.get("testCharDefaultCharacterEncoding")).characterEncoding()), is("US-ASCII")); + } + private static Map parseTestXmlWithMap(final String xPathExpr, final String xml) throws ParserConfigurationException, XPathExpressionException, IOException, SAXException { From c08dd7ceb2632b8627fa407241531734848d8b05 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sat, 8 Jan 2022 10:37:45 +0000 Subject: [PATCH 054/805] [Java] Formatting and import tidyup. --- .../sbe/generation/java/JavaGenerator.java | 7 ++++--- .../sbe/generation/java/JavaUtil.java | 19 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 4272a8f436..9254c3c5c6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -15,7 +15,10 @@ */ package uk.co.real_logic.sbe.generation.java; -import org.agrona.*; +import org.agrona.DirectBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.Strings; +import org.agrona.Verify; import org.agrona.generation.OutputManager; import org.agrona.sbe.*; import uk.co.real_logic.sbe.PrimitiveType; @@ -31,8 +34,6 @@ import java.util.function.Function; import static uk.co.real_logic.sbe.SbeTool.JAVA_INTERFACE_PACKAGE; -import static uk.co.real_logic.sbe.generation.cpp.CppUtil.formatClassName; -import static uk.co.real_logic.sbe.generation.cpp.CppUtil.formatPropertyName; import static uk.co.real_logic.sbe.generation.java.JavaGenerator.CodecType.DECODER; import static uk.co.real_logic.sbe.generation.java.JavaGenerator.CodecType.ENCODER; import static uk.co.real_logic.sbe.generation.java.JavaUtil.*; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index f6969c111e..483318936e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -109,17 +109,19 @@ public String toString() final Charset charset = (Charset)field.get(null); final String name = field.getName(); String oldName = STD_CHARSETS.put(charset.name(), name); + if (null != oldName) { throw new IllegalStateException("Duplicate charset alias: old=" + oldName + ", new=" + name); } + for (final String alias : charset.aliases()) { oldName = STD_CHARSETS.put(alias, name); if (null != oldName) { - throw new IllegalStateException("Duplicate charset alias: old=" + oldName + ", new=" + - alias); + throw new IllegalStateException( + "Duplicate charset alias: old=" + oldName + ", new=" + alias); } } } @@ -214,7 +216,7 @@ public static void append(final StringBuilder builder, final String indent, fina public static String charset(final String encoding) { final String charsetName = STD_CHARSETS.get(encoding); - if (charsetName != null) + if (null != charsetName) { return "java.nio.charset.StandardCharsets." + charsetName; } @@ -234,7 +236,7 @@ public static String charset(final String encoding) public static String charsetName(final String encoding) { final String charsetName = STD_CHARSETS.get(encoding); - if (charsetName != null) + if (null != charsetName) { return "java.nio.charset.StandardCharsets." + charsetName + ".name()"; } @@ -323,8 +325,7 @@ public static String generateLiteral(final PrimitiveType type, final String valu * @param indent level for the comment. * @param typeToken for the type. */ - public static void generateTypeJavadoc( - final StringBuilder sb, final String indent, final Token typeToken) + public static void generateTypeJavadoc(final StringBuilder sb, final String indent, final Token typeToken) { final String description = typeToken.description(); if (Strings.isEmpty(description)) @@ -350,8 +351,7 @@ public static void generateTypeJavadoc( * @param optionToken for the type. * @throws IOException on failing to write to output. */ - public static void generateOptionDecodeJavadoc( - final Appendable out, final String indent, final Token optionToken) + public static void generateOptionDecodeJavadoc(final Appendable out, final String indent, final Token optionToken) throws IOException { final String description = optionToken.description(); @@ -379,8 +379,7 @@ public static void generateOptionDecodeJavadoc( * @param optionToken for the type. * @throws IOException on failing to write to output. */ - public static void generateOptionEncodeJavadoc( - final Appendable out, final String indent, final Token optionToken) + public static void generateOptionEncodeJavadoc(final Appendable out, final String indent, final Token optionToken) throws IOException { final String description = optionToken.description(); From 71639dca07b22c98d4529b1014cd9c2e1ba272db Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sat, 8 Jan 2022 10:41:21 +0000 Subject: [PATCH 055/805] Update copyright. --- CMakeLists.txt | 2 +- CONTRIBUTING.md | 2 +- README.md | 2 +- build.gradle | 4 ++-- config/checkstyle/checkstyle.xml | 2 +- sbe-benchmarks/src/main/cpp/CMakeLists.txt | 2 +- sbe-benchmarks/src/main/cpp/CarBench.cpp | 2 +- sbe-benchmarks/src/main/cpp/CodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/MarketDataBench.cpp | 2 +- sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/benchlet-main.cpp | 2 +- sbe-benchmarks/src/main/cpp/benchlet.h | 2 +- .../src/main/java/uk/co/real_logic/sbe/CarBenchmark.java | 2 +- .../main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/package-info.java | 2 +- sbe-samples/src/main/cpp/CMakeLists.txt | 2 +- sbe-samples/src/main/cpp/GeneratedStubExample.cpp | 2 +- sbe-samples/src/main/cpp/OtfExample.cpp | 2 +- .../uk/co/real_logic/sbe/examples/ExampleTokenListener.java | 2 +- .../co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java | 2 +- .../sbe/examples/ExampleUsingGeneratedStubExtension.java | 2 +- .../main/java/uk/co/real_logic/sbe/examples/OtfExample.java | 2 +- .../main/java/uk/co/real_logic/sbe/examples/package-info.java | 2 +- sbe-tool/src/main/cpp/CMakeLists.txt | 2 +- sbe-tool/src/main/cpp/otf/Encoding.h | 2 +- sbe-tool/src/main/cpp/otf/IrDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/Token.h | 2 +- .../src/main/java/uk/co/real_logic/sbe/PrimitiveType.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ValidationUtil.java | 2 +- .../main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java | 2 +- .../java/uk/co/real_logic/sbe/codec/java/MethodSelector.java | 2 +- .../java/uk/co/real_logic/sbe/codec/java/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/CodeGenerator.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/Generators.java | 2 +- .../uk/co/real_logic/sbe/generation/TargetCodeGenerator.java | 2 +- .../real_logic/sbe/generation/TargetCodeGeneratorLoader.java | 2 +- .../java/uk/co/real_logic/sbe/generation/c/CGenerator.java | 2 +- .../uk/co/real_logic/sbe/generation/c/COutputManager.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/c/CUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/c/package-info.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java | 2 +- .../real_logic/sbe/generation/cpp/NamespaceOutputManager.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/csharp/CSharp.java | 2 +- .../co/real_logic/sbe/generation/csharp/CSharpGenerator.java | 2 +- .../sbe/generation/csharp/CSharpNamespaceOutputManager.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/package-info.java | 2 +- .../co/real_logic/sbe/generation/golang/GolangGenerator.java | 2 +- .../real_logic/sbe/generation/golang/GolangOutputManager.java | 2 +- .../uk/co/real_logic/sbe/generation/golang/GolangUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/golang/package-info.java | 2 +- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/JavaUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/java/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 +- .../co/real_logic/sbe/generation/rust/RustOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/RustUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/SubGroup.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/package-info.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java | 2 +- .../main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/package-info.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java | 2 +- .../java/uk/co/real_logic/sbe/json/JsonTokenListener.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/json/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java | 2 +- .../main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java | 2 +- .../main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/otf/package-info.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java | 2 +- .../main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java | 2 +- .../main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/package-info.java | 2 +- sbe-tool/src/test/c/BoundsCheckTest.cpp | 2 +- sbe-tool/src/test/c/CComplianceTest.c | 2 +- sbe-tool/src/test/c/CMakeLists.txt | 2 +- sbe-tool/src/test/c/CodeGenTest.cpp | 2 +- sbe-tool/src/test/c/GroupWithDataTest.cpp | 2 +- sbe-tool/src/test/cpp/BoundsCheckTest.cpp | 2 +- sbe-tool/src/test/cpp/CMakeLists.txt | 2 +- sbe-tool/src/test/cpp/CodeGenTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeElementsTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp | 2 +- sbe-tool/src/test/cpp/GroupWithDataTest.cpp | 2 +- sbe-tool/src/test/cpp/Issue835Test.cpp | 2 +- sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp | 2 +- sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp | 2 +- .../test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java | 2 +- .../java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/TestTargetLanguage.java | 2 +- sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java | 2 +- .../test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java | 2 +- .../sbe/generation/csharp/Issue567GroupSizeTest.java | 2 +- .../co/real_logic/sbe/generation/java/CarDecodeTestUtil.java | 2 +- .../real_logic/sbe/generation/java/CharacterEncodingTest.java | 2 +- .../sbe/generation/java/CompositeElementsGenerationTest.java | 2 +- .../real_logic/sbe/generation/java/ConstantCharArrayTest.java | 2 +- .../sbe/generation/java/FixedSizeDataGeneratorTest.java | 2 +- .../real_logic/sbe/generation/java/GenerateFixBinaryTest.java | 2 +- .../sbe/generation/java/GenerateIlinkBinaryTest.java | 2 +- .../co/real_logic/sbe/generation/java/JavaGeneratorTest.java | 2 +- .../sbe/generation/java/PackageOutputManagerTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/ReflectionUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/RewindTest.java | 2 +- .../real_logic/sbe/generation/java/SchemaExtensionTest.java | 2 +- .../sbe/generation/java/SkipAndDecodedLengthTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/ToStringTest.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/RustUtilTest.java | 2 +- .../uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java | 2 +- .../co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java | 2 +- 160 files changed, 161 insertions(+), 161 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e52939e27a..d98335b346 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2021 Real Logic Limited. +# Copyright 2013-2022 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 882484f46e..656cc2e855 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ If you are adding a new file it should have the following header: ``` /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index e9a0ab9b8c..98f247b51d 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Or run test directly with `Cargo` License (See LICENSE file for full license) ------------------------------------------- -Copyright 2013-2021 Real Logic Limited. +Copyright 2013-2022 Real Logic Limited. Copyright 2017 MarketFactory Inc. Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/build.gradle b/build.gradle index e4d41d6416..b28d4d95d0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -186,7 +186,7 @@ subprojects { javadoc { failOnError false title = '

Simple Binary Encoding (SBE)

' - options.bottom = 'Copyright © 2013-2021 Real Logic Limited. All Rights Reserved.' + options.bottom = 'Copyright © 2013-2022 Real Logic Limited. All Rights Reserved.' options.encoding = 'UTF-8' options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 5197f7bb3e..28aab05fd6 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -23,7 +23,7 @@ - + diff --git a/sbe-benchmarks/src/main/cpp/CMakeLists.txt b/sbe-benchmarks/src/main/cpp/CMakeLists.txt index 51aa80dca9..3e0da195d9 100644 --- a/sbe-benchmarks/src/main/cpp/CMakeLists.txt +++ b/sbe-benchmarks/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2021 Real Logic Limited. +# Copyright 2013-2022 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/CarBench.cpp b/sbe-benchmarks/src/main/cpp/CarBench.cpp index 5e8c42c8e4..7f938c3fc9 100644 --- a/sbe-benchmarks/src/main/cpp/CarBench.cpp +++ b/sbe-benchmarks/src/main/cpp/CarBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/CodecBench.h b/sbe-benchmarks/src/main/cpp/CodecBench.h index f704b3352c..8028ef0bed 100644 --- a/sbe-benchmarks/src/main/cpp/CodecBench.h +++ b/sbe-benchmarks/src/main/cpp/CodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp b/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp index 75cd518b9c..4a01b81049 100644 --- a/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp +++ b/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h index 615c6ba108..217f4eb39a 100644 --- a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h index 18723e9714..e67807adb1 100644 --- a/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/benchlet-main.cpp b/sbe-benchmarks/src/main/cpp/benchlet-main.cpp index 0fcddad03c..dd6136b932 100644 --- a/sbe-benchmarks/src/main/cpp/benchlet-main.cpp +++ b/sbe-benchmarks/src/main/cpp/benchlet-main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/benchlet.h b/sbe-benchmarks/src/main/cpp/benchlet.h index 948b025e96..68e00b2427 100644 --- a/sbe-benchmarks/src/main/cpp/benchlet.h +++ b/sbe-benchmarks/src/main/cpp/benchlet.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java index 46a579427d..c15ebafeea 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java index 125af11b69..f459ae1dc9 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java index c23c5cbf62..568d9b0fad 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/CMakeLists.txt b/sbe-samples/src/main/cpp/CMakeLists.txt index 5c5eba141a..5c8664ca92 100644 --- a/sbe-samples/src/main/cpp/CMakeLists.txt +++ b/sbe-samples/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2021 Real Logic Limited. +# Copyright 2013-2022 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/GeneratedStubExample.cpp b/sbe-samples/src/main/cpp/GeneratedStubExample.cpp index 7e59b8cfab..e2187c87ee 100644 --- a/sbe-samples/src/main/cpp/GeneratedStubExample.cpp +++ b/sbe-samples/src/main/cpp/GeneratedStubExample.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/OtfExample.cpp b/sbe-samples/src/main/cpp/OtfExample.cpp index ef2df6d891..c108bbf9ba 100644 --- a/sbe-samples/src/main/cpp/OtfExample.cpp +++ b/sbe-samples/src/main/cpp/OtfExample.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java index 27ff7e745d..820131c543 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java index d77a8aab29..640458f767 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java index fcacc3e4fb..06bf499719 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java index 2b838b3806..847df95550 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java index 4365a35946..1cafaea915 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/CMakeLists.txt b/sbe-tool/src/main/cpp/CMakeLists.txt index 5306731b2d..3100de1e6b 100644 --- a/sbe-tool/src/main/cpp/CMakeLists.txt +++ b/sbe-tool/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2021 Real Logic Limited. +# Copyright 2013-2022 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/Encoding.h b/sbe-tool/src/main/cpp/otf/Encoding.h index 4607508c0e..33aa3cf1cd 100644 --- a/sbe-tool/src/main/cpp/otf/Encoding.h +++ b/sbe-tool/src/main/cpp/otf/Encoding.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index 6f116f4eef..381a7e9638 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h b/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h index b68d6b9d67..3fdd955a45 100644 --- a/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h index 9d646637a2..f0a225b5f5 100644 --- a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/Token.h b/sbe-tool/src/main/cpp/otf/Token.h index 6cf5bb5b17..9e2a3f0f18 100644 --- a/sbe-tool/src/main/cpp/otf/Token.h +++ b/sbe-tool/src/main/cpp/otf/Token.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java index 7453d4f57e..ba6887f411 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java index 0336953859..804b38bb21 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index ba8fb99784..f954685139 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index ad8b8ffcc4..1c87c1cb40 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java index 8ab31806a3..5407cf1237 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java index 437d984943..fef09f50f0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java index 7f1c6eaa83..ed53dc625a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java index a74a8ee417..9216ed5548 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java index e5a5912efe..775d972e09 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java index 738af3bfda..4f4c31c125 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 344249bac4..07065da1ac 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 34779499e2..39e521a360 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java index 29c7530b15..2158196b40 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java index 40e8b9ce80..2b0346fb0e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java index 055906cf21..86782b9872 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 913b75f426..46e88b39cd 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java index ccb4898421..ec19a53102 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java index e6692adc28..59b0bccfc1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java index 211ee9b813..e9158a3558 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java index 46b13bc35a..9c8643c277 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index cef39009bb..ec0b458d12 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java index 9dca1481b2..b48c50611f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index 3a6a10d0f6..0da828d02f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java index fd0fb30ac8..148b19f141 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index 0e5d8438ba..cdefc9f7c0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java index 29fba30b4a..874b7769ec 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java index 44362a06cb..0858cede34 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java index e52fa637bd..7cffab4c59 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 9254c3c5c6..1c0fc182ff 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index 483318936e..49bdbfdaa9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java index 5207eb5f1c..dfd94ec902 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java index a5562a22b6..d23c989d0b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 1baf03f047..796ef98d16 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 8eef8ecd77..75aa4c49fc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index b3abad386c..2df4ce440f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java index 864b8b1dd2..45458df2de 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index d4326bd179..fe49709908 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 2d2af72993..e56049205c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java index 052fc27bae..265a1f3e82 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java index 733111dd31..78a8b60935 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java index f7e2eee19a..aa2929c08e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java index 4906f10915..98d0592e22 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java index 32a0a8ebee..534827134e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index 420b955864..f5af22d62b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java index da10d93de8..1107511407 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java index febe9c4df0..f791c1b02b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java index cf361733d4..bcdc380a4b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java index 05c16f8468..d9a09966f2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java index fdb8989cf5..8562868ba9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java index d89dab0b9a..99ef90556a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java index a0cc32cebc..3337db04d2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java index 3887d90370..1c58dc66a6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java index 30ae2f87c3..9ea3194669 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java index 21e967497a..6f09a7f85b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java index 56c4d6ef7f..3e4a7266a7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java index 7b37cc80f3..ef991ae99c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java index 2d20b6ab56..2fb3ca07a2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java index 796ac53ce8..cc994a9775 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java index 9689cfd029..7445a48574 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java index 3b6330ed19..98863144b9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index f8b6728851..fc26d9cbdc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java index 1135c39b0b..967a84063f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java index 4afaf0e092..361d2b1e77 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java index 2696d1eee1..2bead68c2a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index 5f9850e983..9a61439426 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java index cb35a143f5..cdb1715179 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index 285c2fd092..3f0bab5ff4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java index 3743f860ce..8ae645180a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java index 8c3697f311..7609e46a0e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java index 6f9931c8b4..92019acec8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java index 886141634f..b9db2c5138 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index 49cdcd0fd1..022777ae8f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java index e1d75032cf..6f79c9b6fa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/BoundsCheckTest.cpp b/sbe-tool/src/test/c/BoundsCheckTest.cpp index ed809cfd11..8cb984e0c7 100644 --- a/sbe-tool/src/test/c/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/c/BoundsCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CComplianceTest.c b/sbe-tool/src/test/c/CComplianceTest.c index 8cead8201b..61763dbb29 100644 --- a/sbe-tool/src/test/c/CComplianceTest.c +++ b/sbe-tool/src/test/c/CComplianceTest.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index 97043728fa..32147f3c73 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2021 Real Logic Limited. +# Copyright 2013-2022 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CodeGenTest.cpp b/sbe-tool/src/test/c/CodeGenTest.cpp index 8b86a10eb5..d1c0c0fcae 100644 --- a/sbe-tool/src/test/c/CodeGenTest.cpp +++ b/sbe-tool/src/test/c/CodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/GroupWithDataTest.cpp b/sbe-tool/src/test/c/GroupWithDataTest.cpp index 404158839c..7d2b0efa2f 100644 --- a/sbe-tool/src/test/c/GroupWithDataTest.cpp +++ b/sbe-tool/src/test/c/GroupWithDataTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp index 6924088137..ee33ebd0cd 100644 --- a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 9d4bcd4b3a..bef2c99280 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2021 Real Logic Limited. +# Copyright 2013-2022 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index dfea4cc0be..1bd387f46e 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeElementsTest.cpp b/sbe-tool/src/test/cpp/CompositeElementsTest.cpp index c3b383de15..d7b6fd6038 100644 --- a/sbe-tool/src/test/cpp/CompositeElementsTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeElementsTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp index 12361521bd..632827a0fc 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp index 3e4ad3abc4..8ddb1101b9 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/GroupWithDataTest.cpp b/sbe-tool/src/test/cpp/GroupWithDataTest.cpp index f1f80496f2..c9bc42621d 100644 --- a/sbe-tool/src/test/cpp/GroupWithDataTest.cpp +++ b/sbe-tool/src/test/cpp/GroupWithDataTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Issue835Test.cpp b/sbe-tool/src/test/cpp/Issue835Test.cpp index 820fd42f32..dfac7a7115 100644 --- a/sbe-tool/src/test/cpp/Issue835Test.cpp +++ b/sbe-tool/src/test/cpp/Issue835Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp b/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp index d7cd2e536e..9767023f54 100644 --- a/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp +++ b/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp b/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp index f6ae957bec..f3ad271857 100644 --- a/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp +++ b/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java index 14679eb22c..f9ee2695ef 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java index b49797e788..7b63c47573 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java index 550499ce41..1911940443 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java index ea148677fc..7a5c92481e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java index bcfe7b5fc0..c9c6bb2aac 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index f59ffbfb89..8187e18813 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 832f94cdce..ef04946d0b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java index 87dd7279cc..b4772e7271 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java index 80125fdcf8..45175be330 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java index 462546a9d3..6f1d4f6fbc 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java index db15186444..91af57d373 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java index be2c9556f7..2ea2738687 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java index d0351dfc76..fb7c599db8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java index 93925c5206..530b9b530d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 3a9064b810..42dc85f09f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java index 465e9c6738..4c72144043 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java index 03fdf60176..56f7ccbc8d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java index 9385da574c..37130e8d40 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java index e3afb850f0..1620bbf740 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java index 8f69440b8c..f1c0cd9824 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java index 1576ec9ea9..36d762fd83 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index b409cb103e..366d8663cd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java index a543f737ca..bdd33c0535 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java index ea79e33f30..ecdae485ef 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java index 298468d454..91f5736a20 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java index f76f153f34..6edf89a346 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index f63b7aef35..5bb0750cfd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java index 2e1a7861b5..2ec78f51db 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java index 33dcac5396..9ff34d4d5d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java index 7792413a94..6fa1006086 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java index 350515db92..4278f91f60 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java index d60d49c838..6c00ca511f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java index 6ea423f870..ee59e45644 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java index c3657df172..7e10355e49 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java index 2262665723..8b3b1dc9ed 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java index a73173bb16..008a3d8199 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java index 0fdd149c40..0a13521102 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java index 8e187211b0..2707138cb6 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * Copyright 2017 MarketFactory Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java index f9c1f8da5e..dd25ca3caf 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java index 9e37f61749..8ddc6f620d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java index 68b7915d3a..1fa997c138 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java index ed49028ff5..0911c8f9d1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Real Logic Limited. + * Copyright 2013-2022 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 9dd7cbb3f658ad8f9c1a074fcb14fc12d4f119e7 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 25 Jan 2022 18:26:09 +0000 Subject: [PATCH 056/805] Upgrade to Mockito 4.3.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b28d4d95d0..ce044cf449 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.2.1' def hamcrestVersion = '2.2' -def mockitoVersion = '4.2.0' +def mockitoVersion = '4.3.1' def junitVersion = '5.8.2' def jmhVersion = '1.34' def agronaVersion = '1.14.0' From e43fb200ec94ef9d9b731fc46c37aefd7db66b9d Mon Sep 17 00:00:00 2001 From: Adam Greenstein <63319780+greenstein@users.noreply.github.com> Date: Mon, 31 Jan 2022 11:15:05 -0600 Subject: [PATCH 057/805] C++ code generation: check composite and bitset version (#888) --- .../sbe/generation/cpp/CppGenerator.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 46e88b39cd..17bbcebd4d 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -2793,7 +2793,24 @@ private void writeTokenDisplay( case BEGIN_SET: case BEGIN_COMPOSITE: - sb.append(indent).append("builder << ").append(fieldName).append("();\n"); + if (0 == typeToken.version()) + { + sb.append(indent).append("builder << ").append(fieldName).append("();\n"); + } + else + { + new Formatter(sb).format( + indent + "if (%1$sInActingVersion())\n" + + indent + "{\n" + + indent + " builder << %1$s();\n" + + indent + "}\n" + + indent + "else\n" + + indent + "{\n" + + indent + " builder << %2$s;\n" + + indent + "}\n", + fieldName, + typeToken.signal() == Signal.BEGIN_SET ? "\"[]\"" : "\"{}\""); + } break; } From 9bf5acb66b5438d44a3419bb67ff4c39b8ded3e7 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 7 Feb 2022 11:56:14 +0000 Subject: [PATCH 058/805] Upgrade to Versions 0.42.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ce044cf449..fab902027d 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ import java.security.MessageDigest plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '7.1.2' apply false - id "com.github.ben-manes.versions" version "0.41.0" + id "com.github.ben-manes.versions" version "0.42.0" } defaultTasks 'clean', 'build' From 26e58934c98ce3fcca95c7bc23f1150ac7ec73d9 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 7 Feb 2022 12:06:02 +0000 Subject: [PATCH 059/805] [Java] Upgrade to Checkstyle 9.3. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fab902027d..84f4da1a82 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ def toolchainLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(buildJavaVersion) } -def checkstyleVersion = '9.2.1' +def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.3.1' def junitVersion = '5.8.2' From 975ce962c5c7e42820340b5139bebede5f0777e1 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 11 Feb 2022 10:39:54 +0000 Subject: [PATCH 060/805] [Java] Reduce scope. --- .../generation/java/CarDecodeTestUtil.java | 2 +- .../java/CharacterEncodingTest.java | 4 +- .../java/CompositeElementsGenerationTest.java | 11 ++-- .../java/ConstantCharArrayTest.java | 4 +- .../java/FixedSizeDataGeneratorTest.java | 10 ++-- .../java/GenerateFixBinaryTest.java | 6 +-- .../java/GenerateIlinkBinaryTest.java | 6 +-- .../generation/java/JavaGeneratorTest.java | 52 +++++++++---------- .../java/PackageOutputManagerTest.java | 4 +- .../sbe/generation/java/RewindTest.java | 3 +- .../generation/java/SchemaExtensionTest.java | 8 +-- .../java/SkipAndDecodedLengthTest.java | 2 +- 12 files changed, 55 insertions(+), 57 deletions(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java index b4772e7271..62657132b1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java @@ -21,7 +21,7 @@ import java.util.ArrayList; -public class CarDecodeTestUtil +class CarDecodeTestUtil { static ArrayList getValues(final CarDecoder carDecoder) { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java index 45175be330..bc380a4665 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java @@ -35,7 +35,7 @@ import static uk.co.real_logic.sbe.generation.java.JavaUtil.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class CharacterEncodingTest +class CharacterEncodingTest { private static final String XML_SCHEMA; @@ -118,7 +118,7 @@ public class CharacterEncodingTest } @Test - public void shouldUseStandardCharsetsForWellKnowEncodings() throws Exception + void shouldUseStandardCharsetsForWellKnowEncodings() throws Exception { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final MessageSchema schema = diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java index 6f1d4f6fbc..10eaedee62 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java @@ -49,7 +49,7 @@ import static org.hamcrest.Matchers.containsString; import static org.mockito.Mockito.*; -public class CompositeElementsGenerationTest +class CompositeElementsGenerationTest { private static final MessageHeaderEncoder MESSAGE_HEADER = new MessageHeaderEncoder(); private static final MsgEncoder MSG_ENCODER = new MsgEncoder(); @@ -57,7 +57,7 @@ public class CompositeElementsGenerationTest private static final int SCHEMA_BUFFER_CAPACITY = 16 * 1024; @Test - public void shouldEncode() + void shouldEncode() { final ByteBuffer encodedMsgBuffer = ByteBuffer.allocate(MSG_BUFFER_CAPACITY); encodeTestMessage(encodedMsgBuffer); @@ -93,7 +93,7 @@ public void shouldEncode() } @Test - public void shouldDecode() + void shouldDecode() { final ByteBuffer encodedMsgBuffer = ByteBuffer.allocate(MSG_BUFFER_CAPACITY); encodeTestMessage(encodedMsgBuffer); @@ -124,7 +124,7 @@ public void shouldDecode() } @Test - public void shouldDisplay() + void shouldDisplay() { final ByteBuffer encodedMsgBuffer = ByteBuffer.allocate(MSG_BUFFER_CAPACITY); encodeTestMessage(encodedMsgBuffer); @@ -137,7 +137,7 @@ public void shouldDisplay() } @Test - public void shouldOtfDecode() throws Exception + void shouldOtfDecode() throws Exception { final ByteBuffer encodedSchemaBuffer = ByteBuffer.allocate(SCHEMA_BUFFER_CAPACITY); encodeSchema(encodedSchemaBuffer); @@ -145,7 +145,6 @@ public void shouldOtfDecode() throws Exception final ByteBuffer encodedMsgBuffer = ByteBuffer.allocate(MSG_BUFFER_CAPACITY); encodeTestMessage(encodedMsgBuffer); - encodedSchemaBuffer.flip(); final Ir ir = decodeIr(encodedSchemaBuffer); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java index 91af57d373..1141e5c983 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java @@ -29,7 +29,7 @@ import static org.hamcrest.core.StringContains.containsString; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class ConstantCharArrayTest +class ConstantCharArrayTest { private static final Class BUFFER_CLASS = MutableDirectBuffer.class; private static final String BUFFER_NAME = BUFFER_CLASS.getName(); @@ -37,7 +37,7 @@ public class ConstantCharArrayTest private static final String READ_ONLY_BUFFER_NAME = READ_ONLY_BUFFER_CLASS.getName(); @Test - public void shouldGenerateConstCharArrayMethods() throws Exception + void shouldGenerateConstCharArrayMethods() throws Exception { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final MessageSchema schema = parse(Tests.getLocalResource("issue505.xml"), options); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java index 2ea2738687..8edb42474c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java @@ -36,7 +36,7 @@ import static uk.co.real_logic.sbe.generation.java.ReflectionUtil.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class FixedSizeDataGeneratorTest +class FixedSizeDataGeneratorTest { private static final Class BUFFER_CLASS = MutableDirectBuffer.class; private static final String BUFFER_NAME = BUFFER_CLASS.getName(); @@ -48,7 +48,7 @@ public class FixedSizeDataGeneratorTest private Ir ir; @BeforeEach - public void setUp() throws Exception + void setUp() throws Exception { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final MessageSchema schema = parse(Tests.getLocalResource("extension-schema.xml"), options); @@ -62,7 +62,7 @@ public void setUp() throws Exception } @Test - public void shouldGeneratePutAndGetByteArrayForFixedLengthBlob() throws Exception + void shouldGeneratePutAndGetByteArrayForFixedLengthBlob() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); @@ -96,7 +96,7 @@ public void shouldGeneratePutAndGetByteArrayForFixedLengthBlob() throws Exceptio } @Test - public void shouldGeneratePutAndGetDirectBufferForFixedLengthBlob() throws Exception + void shouldGeneratePutAndGetDirectBufferForFixedLengthBlob() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); @@ -130,7 +130,7 @@ public void shouldGeneratePutAndGetDirectBufferForFixedLengthBlob() throws Excep } @Test - public void shouldGenerateWrapForFixedLengthBlob() throws Exception + void shouldGenerateWrapForFixedLengthBlob() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java index fb7c599db8..09274ec5f7 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java @@ -32,7 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class GenerateFixBinaryTest +class GenerateFixBinaryTest { private static final Class BUFFER_CLASS = MutableDirectBuffer.class; private static final String BUFFER_NAME = BUFFER_CLASS.getName(); @@ -42,7 +42,7 @@ public class GenerateFixBinaryTest private final StringWriterOutputManager outputManager = new StringWriterOutputManager(); @Test - public void shouldGenerateValidJava() throws Exception + void shouldGenerateValidJava() throws Exception { System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); @@ -76,7 +76,7 @@ public void shouldGenerateValidJava() throws Exception } @Test - public void shouldGenerateAndEncodeIr() throws Exception + void shouldGenerateAndEncodeIr() throws Exception { System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java index 530b9b530d..a8c9e2676a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java @@ -32,7 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class GenerateIlinkBinaryTest +class GenerateIlinkBinaryTest { private static final Class BUFFER_CLASS = MutableDirectBuffer.class; private static final String BUFFER_NAME = BUFFER_CLASS.getName(); @@ -42,7 +42,7 @@ public class GenerateIlinkBinaryTest private final StringWriterOutputManager outputManager = new StringWriterOutputManager(); @Test - public void shouldGenerateValidJava() throws Exception + void shouldGenerateValidJava() throws Exception { System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); @@ -76,7 +76,7 @@ public void shouldGenerateValidJava() throws Exception } @Test - public void shouldGenerateAndEncodeIr() throws Exception + void shouldGenerateAndEncodeIr() throws Exception { System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 42dc85f09f..6ad49097bd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -42,7 +42,7 @@ import static uk.co.real_logic.sbe.generation.java.ReflectionUtil.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class JavaGeneratorTest +class JavaGeneratorTest { private static final Class BUFFER_CLASS = MutableDirectBuffer.class; private static final String BUFFER_NAME = BUFFER_CLASS.getName(); @@ -56,7 +56,7 @@ public class JavaGeneratorTest private Ir ir; @BeforeEach - public void setUp() throws Exception + void setUp() throws Exception { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final MessageSchema schema = parse(Tests.getLocalResource("code-generation-schema.xml"), options); @@ -68,7 +68,7 @@ public void setUp() throws Exception } @Test - public void shouldGenerateMessageHeaderStub() throws Exception + void shouldGenerateMessageHeaderStub() throws Exception { final int bufferOffset = 64; final int templateIdOffset = 2; @@ -95,7 +95,7 @@ public void shouldGenerateMessageHeaderStub() throws Exception } @Test - public void shouldGenerateMessageHeaderDecoderStub() throws Exception + void shouldGenerateMessageHeaderDecoderStub() throws Exception { final int bufferOffset = 64; final int templateIdOffset = 2; @@ -120,7 +120,7 @@ public void shouldGenerateMessageHeaderDecoderStub() throws Exception } @Test - public void shouldGenerateUint8EnumStub() throws Exception + void shouldGenerateUint8EnumStub() throws Exception { final String className = "BooleanType"; final String fqClassName = ir.applicableNamespace() + "." + className; @@ -136,7 +136,7 @@ public void shouldGenerateUint8EnumStub() throws Exception } @Test - public void shouldGenerateCharEnumStub() throws Exception + void shouldGenerateCharEnumStub() throws Exception { generateTypeStubs(); @@ -148,7 +148,7 @@ public void shouldGenerateCharEnumStub() throws Exception } @Test - public void shouldGenerateChoiceSetStub() throws Exception + void shouldGenerateChoiceSetStub() throws Exception { final int bufferOffset = 8; final byte bitset = (byte)0b0000_0100; @@ -172,7 +172,7 @@ public void shouldGenerateChoiceSetStub() throws Exception } @Test - public void shouldGenerateCompositeEncoder() throws Exception + void shouldGenerateCompositeEncoder() throws Exception { final int bufferOffset = 64; final int capacityFieldOffset = bufferOffset; @@ -205,7 +205,7 @@ public void shouldGenerateCompositeEncoder() throws Exception } @Test - public void shouldGenerateCompositeDecoder() throws Exception + void shouldGenerateCompositeDecoder() throws Exception { final int bufferOffset = 64; final int capacityFieldOffset = bufferOffset; @@ -233,7 +233,7 @@ public void shouldGenerateCompositeDecoder() throws Exception } @Test - public void shouldGenerateBasicMessage() throws Exception + void shouldGenerateBasicMessage() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); generator().generate(); @@ -248,7 +248,7 @@ public void shouldGenerateBasicMessage() throws Exception } @Test - public void shouldGenerateRepeatingGroupDecoder() throws Exception + void shouldGenerateRepeatingGroupDecoder() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); generator().generate(); @@ -269,7 +269,7 @@ public void shouldGenerateRepeatingGroupDecoder() throws Exception } @Test - public void shouldGenerateReadOnlyMessage() throws Exception + void shouldGenerateReadOnlyMessage() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); generator().generate(); @@ -284,7 +284,7 @@ public void shouldGenerateReadOnlyMessage() throws Exception } @Test - public void shouldGenerateVarDataCodecs() throws Exception + void shouldGenerateVarDataCodecs() throws Exception { final String expectedManufacturer = "Ford"; final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); @@ -302,7 +302,7 @@ public void shouldGenerateVarDataCodecs() throws Exception } @Test - public void shouldGenerateCompositeDecoding() throws Exception + void shouldGenerateCompositeDecoding() throws Exception { final int expectedEngineCapacity = 2000; final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); @@ -320,7 +320,7 @@ public void shouldGenerateCompositeDecoding() throws Exception } @Test - public void shouldGenerateBitSetCodecs() throws Exception + void shouldGenerateBitSetCodecs() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); @@ -338,7 +338,7 @@ public void shouldGenerateBitSetCodecs() throws Exception } @Test - public void shouldGenerateEnumCodecs() throws Exception + void shouldGenerateEnumCodecs() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); generator().generate(); @@ -355,7 +355,7 @@ public void shouldGenerateEnumCodecs() throws Exception } @Test - public void shouldGenerateGetString() throws Exception + void shouldGenerateGetString() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); generator().generate(); @@ -374,7 +374,7 @@ public void shouldGenerateGetString() throws Exception } @Test - public void shouldGenerateGetFixedLengthStringUsingAppendable() throws Exception + void shouldGenerateGetFixedLengthStringUsingAppendable() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); final StringBuilder result = new StringBuilder(); @@ -399,7 +399,7 @@ public void shouldGenerateGetFixedLengthStringUsingAppendable() throws Exception } @Test - public void shouldGenerateGetVariableStringUsingAppendable() throws Exception + void shouldGenerateGetVariableStringUsingAppendable() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); final StringBuilder result = new StringBuilder(); @@ -423,7 +423,7 @@ public void shouldGenerateGetVariableStringUsingAppendable() throws Exception } @Test - public void shouldGeneratePutCharSequence() throws Exception + void shouldGeneratePutCharSequence() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); generator().generate(); @@ -442,7 +442,7 @@ public void shouldGeneratePutCharSequence() throws Exception } @Test - public void shouldGenerateRepeatingGroupCountLimits() throws Exception + void shouldGenerateRepeatingGroupCountLimits() throws Exception { generator().generate(); @@ -459,7 +459,7 @@ public void shouldGenerateRepeatingGroupCountLimits() throws Exception } @Test - public void shouldMarkDeprecatedClasses() throws Exception + void shouldMarkDeprecatedClasses() throws Exception { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final MessageSchema schema = parse(Tests.getLocalResource("deprecated-msg-test-schema.xml"), options); @@ -518,7 +518,7 @@ private static Object wrap( } @Test - public void shouldValidateMissingMutableBufferClass() + void shouldValidateMissingMutableBufferClass() { assertThrows( IllegalArgumentException.class, @@ -526,7 +526,7 @@ public void shouldValidateMissingMutableBufferClass() } @Test - public void shouldValidateNotImplementedMutableBufferClass() + void shouldValidateNotImplementedMutableBufferClass() { assertThrows( IllegalArgumentException.class, @@ -534,7 +534,7 @@ public void shouldValidateNotImplementedMutableBufferClass() } @Test - public void shouldValidateMissingReadOnlyBufferClass() + void shouldValidateMissingReadOnlyBufferClass() { assertThrows( IllegalArgumentException.class, @@ -542,7 +542,7 @@ public void shouldValidateMissingReadOnlyBufferClass() } @Test - public void shouldValidateNotImplementedReadOnlyBufferClass() + void shouldValidateNotImplementedReadOnlyBufferClass() { assertThrows( IllegalArgumentException.class, diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java index 4c72144043..5152196ed0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java @@ -26,12 +26,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue; -public class PackageOutputManagerTest +class PackageOutputManagerTest { private final String tempDirName = System.getProperty("java.io.tmpdir"); @Test - public void shouldCreateFileWithinPackage() throws Exception + void shouldCreateFileWithinPackage() throws Exception { final String packageName = "uk.co.real_logic.test"; final String exampleClassName = "ExampleClassName"; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java index 37130e8d40..9a4974ebf1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java @@ -27,7 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; -public class RewindTest extends EncodedCarTestBase +class RewindTest extends EncodedCarTestBase { private static final int MSG_BUFFER_CAPACITY = 4 * 1024; @@ -57,5 +57,4 @@ void shouldRewindAfterReadingFullMessage() final ArrayList passThree = CarDecodeTestUtil.getValues(carDecoder); assertEquals(passOne, passThree); } - } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java index 1620bbf740..78c6e2d5de 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java @@ -39,7 +39,7 @@ import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @SuppressWarnings("MethodLength") -public class SchemaExtensionTest +class SchemaExtensionTest { private static final Class BUFFER_CLASS = MutableDirectBuffer.class; private static final String BUFFER_NAME = BUFFER_CLASS.getName(); @@ -51,7 +51,7 @@ public class SchemaExtensionTest private Ir ir; @BeforeEach - public void setup() throws Exception + void setup() throws Exception { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final MessageSchema schema = parse(Tests.getLocalResource("extension-schema.xml"), options); @@ -65,7 +65,7 @@ public void setup() throws Exception } @Test - public void testMessage1() throws Exception + void testMessage1() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); @@ -186,7 +186,7 @@ public void testMessage1() throws Exception } @Test - public void testMessage2() throws Exception + void testMessage2() throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java index f1c0cd9824..23d6246566 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java @@ -25,7 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class SkipAndDecodedLengthTest extends EncodedCarTestBase +class SkipAndDecodedLengthTest extends EncodedCarTestBase { private static final int MSG_BUFFER_CAPACITY = 4 * 1024; From 585cb9d90697269882d52f511178b0f0924e0fcd Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 11 Feb 2022 11:15:50 +0000 Subject: [PATCH 061/805] [Java] Avoid use of String.format. --- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java index 967a84063f..39c8f4e02f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java @@ -82,8 +82,8 @@ public class EnumType extends Type default: // might not have run into this type yet, so look for it - final Node encodingTypeNode = (Node)xPath.compile( - String.format("%s[@name='%s']", XmlSchemaParser.TYPE_XPATH_EXPR, encodingTypeStr)) + final String expression = TYPE_XPATH_EXPR + "[@name='" + encodingTypeStr + "']"; + final Node encodingTypeNode = (Node)xPath.compile(expression) .evaluate(node.getOwnerDocument(), XPathConstants.NODE); if (null == encodingTypeNode) From 2f1b555c2d8e2185ac7c677cc3979fdfa9e857d1 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 11 Feb 2022 14:30:11 +0000 Subject: [PATCH 062/805] [Java] Generate null value for enums based on specialised type when provided rather than default primitive type. PR #889. --- .../sbe/generation/java/JavaGenerator.java | 18 ++--- .../sbe/ir/generated/SignalCodec.java | 2 +- .../uk/co/real_logic/sbe/xml/EnumType.java | 36 ++++------ .../uk/co/real_logic/sbe/xml/IrGenerator.java | 6 +- sbe-tool/src/main/resources/sbe-ir.xml | 2 +- .../generation/java/NullEnumTypedTest.java | 66 +++++++++++++++++++ .../real_logic/sbe/xml/ErrorHandlerTest.java | 2 +- .../resources/error-handler-types-schema.xml | 1 + sbe-tool/src/test/resources/issue889.xml | 26 ++++++++ 9 files changed, 116 insertions(+), 43 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java create mode 100644 sbe-tool/src/test/resources/issue889.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 1c0fc182ff..e928bc90ba 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1236,16 +1236,18 @@ private void generateEnum(final List tokens) throws IOException { final Token enumToken = tokens.get(0); final String enumName = formatClassName(enumToken.applicableTypeName()); + final Encoding encoding = enumToken.encoding(); + final String nullVal = encoding.applicableNullValue().toString(); try (Writer out = outputManager.createOutput(enumName)) { out.append(generateEnumFileHeader(ir.applicableNamespace())); out.append(generateEnumDeclaration(enumName, enumToken)); - out.append(generateEnumValues(getMessageBody(tokens))); + out.append(generateEnumValues(getMessageBody(tokens), generateLiteral(encoding.primitiveType(), nullVal))); out.append(generateEnumBody(enumToken, enumName)); - out.append(generateEnumLookupMethod(getMessageBody(tokens), enumName)); + out.append(generateEnumLookupMethod(getMessageBody(tokens), enumName, nullVal)); out.append("}\n"); } @@ -1451,7 +1453,7 @@ private String bitsetArgType(final PrimitiveType primitiveType) } } - private CharSequence generateEnumValues(final List tokens) + private CharSequence generateEnumValues(final List tokens, final String nullVal) { final StringBuilder sb = new StringBuilder(); @@ -1463,11 +1465,6 @@ private CharSequence generateEnumValues(final List tokens) sb.append(INDENT).append(token.name()).append('(').append(constVal).append("),\n\n"); } - final Token token = tokens.get(0); - final Encoding encoding = token.encoding(); - final CharSequence nullVal = generateLiteral( - encoding.primitiveType(), encoding.applicableNullValue().toString()); - if (shouldDecodeUnknownEnumValues) { sb.append(INDENT).append("/**\n"); @@ -1505,7 +1502,7 @@ private CharSequence generateEnumBody(final Token token, final String enumName) " }\n"; } - private CharSequence generateEnumLookupMethod(final List tokens, final String enumName) + private CharSequence generateEnumLookupMethod(final List tokens, final String enumName, final String nullVal) { final StringBuilder sb = new StringBuilder(); final PrimitiveType primitiveType = tokens.get(0).encoding().primitiveType(); @@ -1528,8 +1525,7 @@ private CharSequence generateEnumLookupMethod(final List tokens, final St sb.append(" case ").append(constStr).append(": return ").append(name).append(";\n"); } - final String nullValue = tokens.get(0).encoding().applicableNullValue().toString(); - sb.append(" case ").append(nullValue).append(": return NULL_VAL").append(";\n"); + sb.append(" case ").append(nullVal).append(": return NULL_VAL").append(";\n"); final String handleUnknownLogic = shouldDecodeUnknownEnumValues ? INDENT + INDENT + "return SBE_UNKNOWN;\n" : diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java index 59940ef860..dd812e782e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java @@ -81,7 +81,7 @@ public enum SignalCodec /** - * Signal the a choice in a set. + * Signal the choice in a set. */ CHOICE((short)13), diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java index 39c8f4e02f..3197c08c47 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java @@ -105,28 +105,20 @@ public class EnumType extends Type final String nullValueStr = getAttributeValueOrNull(node, "nullValue"); if (null != nullValueStr) { - if (presence() != OPTIONAL) - { - handleError(node, "nullValue set, but presence is not optional"); - } - nullValue = PrimitiveValue.parse(nullValueStr, encodingType); } - else if (presence() == OPTIONAL) + else if (null != encodedDataType && null != encodedDataType.nullValue()) { - if (null != encodedDataType && null != encodedDataType.nullValue()) - { - nullValue = encodedDataType.nullValue(); - } - else - { - handleError(node, "presence optional but no null value found"); - nullValue = null; - } + nullValue = encodedDataType.nullValue(); } else { - nullValue = null; + nullValue = encodingType.nullValue(); + } + + if (presence() == OPTIONAL && null == nullValue) + { + handleError(node, "presence optional but no null value found"); } final NodeList list = (NodeList)xPath.compile("validValue").evaluate(node, XPathConstants.NODESET); @@ -152,15 +144,11 @@ else if (presence() == OPTIONAL) encodedDataType.minValue().longValue() : encodingType.minValue().longValue(); final long maxValue = null != encodedDataType && null != encodedDataType.maxValue() ? encodedDataType.maxValue().longValue() : encodingType.maxValue().longValue(); - final long nullLongValue = null != nullValue ? nullValue.longValue() : - encodingType.nullValue().longValue(); + final long nullLongValue = nullValue.longValue(); if (nullLongValue == value) { - handleError( - node, - "validValue " + v.name() + " uses nullValue: " + - (null != nullValue ? nullValue : encodingType.nullValue())); + handleError(node, "validValue " + v.name() + " uses nullValue: " + nullLongValue); } else if (value < minValue || value > maxValue) { @@ -223,9 +211,9 @@ public ValidValue getValidValue(final String name) } /** - * The nullValue of the type + * The nullValue of the type. * - * @return value of the nullValue + * @return value of the nullValue. */ public PrimitiveValue nullValue() { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index 9a61439426..87e3e4717d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -263,13 +263,9 @@ private void add(final EnumType type, final int offset, final Field field) final Encoding.Builder encodingBuilder = new Encoding.Builder() .primitiveType(encodingType) .semanticType(semanticTypeOf(type, field)) + .nullValue(type.nullValue()) .byteOrder(schema.byteOrder()); - if (type.presence() == Presence.OPTIONAL) - { - encodingBuilder.nullValue(encodingType.nullValue()); - } - final Token.Builder builder = new Token.Builder() .signal(Signal.BEGIN_ENUM) .name(type.name()) diff --git a/sbe-tool/src/main/resources/sbe-ir.xml b/sbe-tool/src/main/resources/sbe-ir.xml index 9d70ef93db..4b55318f53 100644 --- a/sbe-tool/src/main/resources/sbe-ir.xml +++ b/sbe-tool/src/main/resources/sbe-ir.xml @@ -47,7 +47,7 @@ 10 11 12 - 13 + 13 14 15 16 diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java new file mode 100644 index 0000000000..9c930485cb --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import org.agrona.DirectBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +class NullEnumTypedTest +{ + private static final Class BUFFER_CLASS = MutableDirectBuffer.class; + private static final String BUFFER_NAME = BUFFER_CLASS.getName(); + private static final Class READ_ONLY_BUFFER_CLASS = DirectBuffer.class; + private static final String READ_ONLY_BUFFER_NAME = READ_ONLY_BUFFER_CLASS.getName(); + + @Test + void shouldGenerateEnumWithNonDefaultNullType() throws Exception + { + final ParserOptions options = ParserOptions.builder() + .stopOnError(true) + .build(); + final MessageSchema schema = parse(Tests.getLocalResource("issue889.xml"), options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, true, outputManager); + + outputManager.setPackageName(ir.applicableNamespace()); + generator.generateMessageHeaderStub(); + generator.generateTypeStubs(); + generator.generate(); + + final Map sources = outputManager.getSources(); + final String source = sources.get("issue889.LotType").toString(); + + assertThat(source, containsString("NULL_VAL((short)0);")); + assertThat(source, containsString("case 0: return NULL_VAL;")); + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java index 2707138cb6..405a63e902 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java @@ -88,7 +88,7 @@ public void shouldNotExitOnTypeErrorsAndWarnings() throws Exception parseTestXmlAddToMap(map, "/types/enum", testXmlString, handler); parseTestXmlAddToMap(map, "/types/set", testXmlString, handler); - assertThat(handler.errorCount(), is(3)); + assertThat(handler.errorCount(), is(2)); assertThat(handler.warningCount(), is(33)); } diff --git a/sbe-tool/src/test/resources/error-handler-types-schema.xml b/sbe-tool/src/test/resources/error-handler-types-schema.xml index 02e6f6fe19..a21430c81a 100644 --- a/sbe-tool/src/test/resources/error-handler-types-schema.xml +++ b/sbe-tool/src/test/resources/error-handler-types-schema.xml @@ -8,6 +8,7 @@ 0 1 + 255 diff --git a/sbe-tool/src/test/resources/issue889.xml b/sbe-tool/src/test/resources/issue889.xml new file mode 100644 index 0000000000..286d472b57 --- /dev/null +++ b/sbe-tool/src/test/resources/issue889.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + 1 + 2 + 3 + + + + + + \ No newline at end of file From 71bb045085518d06c7a493c93f0873c0fd71203a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 11 Feb 2022 16:30:35 +0000 Subject: [PATCH 063/805] [C++] Check for specialised null value when generated enum. PR #889. --- sbe-tool/src/test/cpp/CMakeLists.txt | 13 ++++++++++-- sbe-tool/src/test/cpp/Issue889Test.cpp | 29 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 sbe-tool/src/test/cpp/Issue889Test.cpp diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index bef2c99280..438844b066 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -34,11 +34,12 @@ endfunction() find_package(Java REQUIRED) set(CODE_GENERATION_SCHEMA ${CODEC_SCHEMA_DIR}/code-generation-schema.xml) +set(COMPOSITE_ELEMENTS_SCHEMA ${CODEC_SCHEMA_DIR}/composite-elements-schema.xml) set(COMPOSITE_OFFSETS_SCHEMA ${CODEC_SCHEMA_DIR}/composite-offsets-schema.xml) set(MESSAGE_BLOCK_LENGTH_TEST ${CODEC_SCHEMA_DIR}/message-block-length-test.xml) set(GROUP_WITH_DATA_SCHEMA ${CODEC_SCHEMA_DIR}/group-with-data-schema.xml) -set(COMPOSITE_ELEMENTS_SCHEMA ${CODEC_SCHEMA_DIR}/composite-elements-schema.xml) set(ISSUE835_SCHEMA ${CODEC_SCHEMA_DIR}/issue835.xml) +set(ISSUE889_SCHEMA ${CODEC_SCHEMA_DIR}/issue889.xml) set(GENERATED_CODECS ${CXX_CODEC_TARGET_DIR} @@ -46,7 +47,13 @@ set(GENERATED_CODECS add_custom_command( OUTPUT ${GENERATED_CODECS} - DEPENDS ${CODE_GENERATION_SCHEMA} ${CODE_GENERATION_SCHEMA_CPP} ${COMPOSITE_OFFSETS_SCHEMA} ${MESSAGE_BLOCK_LENGTH_TEST} + DEPENDS ${CODE_GENERATION_SCHEMA} + ${COMPOSITE_ELEMENTS_SCHEMA} + ${COMPOSITE_OFFSETS_SCHEMA} + ${MESSAGE_BLOCK_LENGTH_TEST} + ${GROUP_WITH_DATA_SCHEMA} + ${ISSUE835_SCHEMA} + ${ISSUE889_SCHEMA} sbe-jar ${SBE_JAR} COMMAND ${Java_JAVA_EXECUTABLE} @@ -60,6 +67,7 @@ add_custom_command( ${GROUP_WITH_DATA_SCHEMA} ${COMPOSITE_ELEMENTS_SCHEMA} ${ISSUE835_SCHEMA} + ${ISSUE889_SCHEMA} ) add_custom_target(codecs DEPENDS ${GENERATED_CODECS}) @@ -74,3 +82,4 @@ sbe_test(GroupWithDataTest codecs) sbe_test(Rc3OtfFullIrTest codecs) sbe_test(CompositeElementsTest codecs) sbe_test(Issue835Test codecs) +sbe_test(Issue889Test codecs) diff --git a/sbe-tool/src/test/cpp/Issue889Test.cpp b/sbe-tool/src/test/cpp/Issue889Test.cpp new file mode 100644 index 0000000000..1804152646 --- /dev/null +++ b/sbe-tool/src/test/cpp/Issue889Test.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtest/gtest.h" +#include "issue889/LotType.h" + +using namespace issue889; + +class Issue889Test : public testing::Test +{ +}; + +TEST_F(Issue889Test, shouldGenerateSpecalisedNullValue) +{ + EXPECT_EQ(LotType::get(0), LotType::NULL_VALUE); +} From 595d73c4bed41108f101b0dc378b41971661f5a1 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 11 Feb 2022 16:55:52 +0000 Subject: [PATCH 064/805] [C] Check for specialised null value when generated enum. PR #889. --- sbe-tool/src/test/c/CMakeLists.txt | 5 ++++- sbe-tool/src/test/c/Issue889Test.cpp | 31 ++++++++++++++++++++++++++ sbe-tool/src/test/cpp/Issue889Test.cpp | 3 ++- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 sbe-tool/src/test/c/Issue889Test.cpp diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index 32147f3c73..9d3c2b03dd 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -35,6 +35,7 @@ find_package(Java REQUIRED) set(CODE_GENERATION_SCHEMA ${CODEC_SCHEMA_DIR}/code-generation-schema.xml) set(GROUP_WITH_DATA_SCHEMA ${CODEC_SCHEMA_DIR}/group-with-data-schema.xml) +set(ISSUE889_SCHEMA ${CODEC_SCHEMA_DIR}/issue889.xml) set(GENERATED_CODECS ${C_CODEC_TARGET_DIR} @@ -42,7 +43,7 @@ set(GENERATED_CODECS add_custom_command( OUTPUT ${GENERATED_CODECS} - DEPENDS sbe-jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${GROUP_WITH_DATA_SCHEMA} + DEPENDS sbe-jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${GROUP_WITH_DATA_SCHEMA} ${ISSUE889_SCHEMA} COMMAND ${Java_JAVA_EXECUTABLE} -Dsbe.output.dir=${C_CODEC_TARGET_DIR} @@ -50,6 +51,7 @@ add_custom_command( -jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${GROUP_WITH_DATA_SCHEMA} + ${ISSUE889_SCHEMA} ) add_custom_target(c_codecs DEPENDS ${GENERATED_CODECS}) @@ -58,6 +60,7 @@ add_custom_target(c_codecs DEPENDS ${GENERATED_CODECS}) sbe_test(BoundsCheckTest c_codecs) sbe_test(CodeGenTest c_codecs) sbe_test(GroupWithDataTest c_codecs) +sbe_test(Issue889Test c_codecs) # Compile a dummy C source to test C compliance of generated headers. add_executable(CComplianceTest CComplianceTest.c) diff --git a/sbe-tool/src/test/c/Issue889Test.cpp b/sbe-tool/src/test/c/Issue889Test.cpp new file mode 100644 index 0000000000..c0f5ec36a1 --- /dev/null +++ b/sbe-tool/src/test/c/Issue889Test.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "issue889/lotType.h" + +class Issue889Test : public testing::Test +{ +}; + +TEST_F(Issue889Test, shouldGenerateSpecalisedNullValue) +{ + issue889_lotType lot_type; + + EXPECT_TRUE(issue889_lotType_get(0, &lot_type)); + EXPECT_EQ(lot_type, issue889_lotType::issue889_lotType_NULL_VALUE); +} diff --git a/sbe-tool/src/test/cpp/Issue889Test.cpp b/sbe-tool/src/test/cpp/Issue889Test.cpp index 1804152646..1b0c67433d 100644 --- a/sbe-tool/src/test/cpp/Issue889Test.cpp +++ b/sbe-tool/src/test/cpp/Issue889Test.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include "gtest/gtest.h" +#include + #include "issue889/LotType.h" using namespace issue889; From 9b8c5db52e7b2c49bd2086e9beb080a83adcdbf6 Mon Sep 17 00:00:00 2001 From: spoerri Date: Mon, 7 Mar 2022 04:30:37 -0500 Subject: [PATCH 065/805] toString() shouldn't disturb repeating groups #890 (#892) * toString() shouldn't disturb repeating groups #890 * Remove trailing whitespace * Ugh, removed more whitespace --- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index e928bc90ba..ab8e351395 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -3475,6 +3475,9 @@ private void appendDecoderDisplay( final String groupName = formatPropertyName(groupToken.name()); final String groupDecoderName = decoderName(groupToken.name()); + append(sb, indent, "int " + groupName + "OriginalOffset = " + groupName + ".offset;"); + append(sb, indent, "int " + groupName + "OriginalIndex = " + groupName + ".index;"); + append( sb, indent, "builder.append(\"" + groupName + Separator.KEY_VALUE + Separator.BEGIN_GROUP + "\");"); append(sb, indent, groupDecoderName + " " + groupName + " = " + groupName + "();"); @@ -3489,6 +3492,9 @@ private void appendDecoderDisplay( append(sb, indent, "}"); Separator.END_GROUP.appendToGeneratedBuilder(sb, indent); + append(sb, indent, groupName + ".offset = " + groupName + "OriginalOffset;"); + append(sb, indent, groupName + ".index = " + groupName + "OriginalIndex;"); + lengthBeforeLastGeneratedSeparator = sb.length(); Separator.FIELD.appendToGeneratedBuilder(sb, indent); From c24b79336a6cd2fc45b5021de18dbfd2188320c5 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 7 Mar 2022 09:50:11 +0000 Subject: [PATCH 066/805] [Java] Tidy up generated code style. PR #892. --- .../real_logic/sbe/generation/java/JavaGenerator.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index ab8e351395..8778c06299 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -3475,12 +3475,12 @@ private void appendDecoderDisplay( final String groupName = formatPropertyName(groupToken.name()); final String groupDecoderName = decoderName(groupToken.name()); - append(sb, indent, "int " + groupName + "OriginalOffset = " + groupName + ".offset;"); - append(sb, indent, "int " + groupName + "OriginalIndex = " + groupName + ".index;"); - append( sb, indent, "builder.append(\"" + groupName + Separator.KEY_VALUE + Separator.BEGIN_GROUP + "\");"); - append(sb, indent, groupDecoderName + " " + groupName + " = " + groupName + "();"); + append(sb, indent, "final int " + groupName + "OriginalOffset = " + groupName + ".offset;"); + append(sb, indent, "final int " + groupName + "OriginalIndex = " + groupName + ".index;"); + append(sb, indent, "final " + groupDecoderName + " " + groupName + " = " + groupName + "();"); + append(sb, indent, "if (" + groupName + ".count() > 0)"); append(sb, indent, "{"); append(sb, indent, " while (" + groupName + ".hasNext())"); @@ -3490,10 +3490,11 @@ private void appendDecoderDisplay( append(sb, indent, " }"); append(sb, indent, " builder.setLength(builder.length() - 1);"); append(sb, indent, "}"); - Separator.END_GROUP.appendToGeneratedBuilder(sb, indent); append(sb, indent, groupName + ".offset = " + groupName + "OriginalOffset;"); append(sb, indent, groupName + ".index = " + groupName + "OriginalIndex;"); + Separator.END_GROUP.appendToGeneratedBuilder(sb, indent); + lengthBeforeLastGeneratedSeparator = sb.length(); Separator.FIELD.appendToGeneratedBuilder(sb, indent); From 36ca5b4bcc044c802dcd64bb12601172c150ac5a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 8 Mar 2022 17:16:56 +0000 Subject: [PATCH 067/805] [Java] Upgrade to Mockito 4.4.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 84f4da1a82..d784a2681d 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.3.1' +def mockitoVersion = '4.4.0' def junitVersion = '5.8.2' def jmhVersion = '1.34' def agronaVersion = '1.14.0' From 05d9c4557d8a68ca2178741886fbca4028d1ed7f Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 10 Mar 2022 18:25:50 +0100 Subject: [PATCH 068/805] [Java] Upgrade to Gradle 7.4.1. --- build.gradle | 6 +++--- gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index d784a2681d..0f1c101f79 100644 --- a/build.gradle +++ b/build.gradle @@ -774,9 +774,9 @@ task runJavaBenchmarks(type: Exec, dependsOn: 'sbe-benchmarks:jar') { } task testReport(type: TestReport) { - destinationDir = file("$buildDir/reports/allTests") + destinationDirectory = file("$buildDir/reports/allTests") // Include the results from the `test` task in all sub-projects - reportOn subprojects*.test + testResults.setFrom(subprojects*.test) } final codecsDir = project.file('sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated') @@ -821,7 +821,7 @@ tasks.named('dependencyUpdates').configure { tasks.findByName('build').dependsOn verifyJavaIrCodecsInSync wrapper { - gradleVersion = '7.3.3' + gradleVersion = '7.4.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644 GIT binary patch delta 8958 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 669386b870..d7e66b5c61 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 488167b321cef2af6958a446ab8f61c87c00a37f Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 15 Mar 2022 18:24:40 +0000 Subject: [PATCH 069/805] [Java] Upgrade to Agrona 1.15.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0f1c101f79..b7614cafdb 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.4.0' def junitVersion = '5.8.2' def jmhVersion = '1.34' -def agronaVersion = '1.14.0' +def agronaVersion = '1.15.0' def agronaVersionRange = '[1.14,1.15[' // allow any patch release of 1.14.x def sbeGroup = 'uk.co.real-logic' From 2fc765979ab02a398e8aedc6dbf51ff3434533fd Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 18 Mar 2022 18:01:24 +0000 Subject: [PATCH 070/805] [Java] Increase minor version. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6fb671d7e9..b4f8049e9c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.2-SNAPSHOT +1.26.0-SNAPSHOT From ce68063f21a803b451ccff1c616f0ef7ca24bb54 Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Fri, 18 Mar 2022 11:11:17 -0700 Subject: [PATCH 071/805] 1.25.2 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6fb671d7e9..61b813d5e6 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.2-SNAPSHOT +1.25.2 From 75f10ed0e23ee131548ac7e156bc6d425e3d30e8 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 21 Mar 2022 22:12:12 +0100 Subject: [PATCH 072/805] [CI] Allow only one concurrent build of the same workflow at a time. Every new attempt to build should cancel already running build. --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b3b0a7901..d4bf19f1d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,10 @@ on: branches: - master +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail" CMAKE_VERSION: "3.6.1" From 408976ae5a5b2106402f8264c22baeb3a03518de Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 21 Mar 2022 22:17:17 +0100 Subject: [PATCH 073/805] [Java] Fix Agrona version range to match the 1.15.x release. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b7614cafdb..28808b39da 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ def mockitoVersion = '4.4.0' def junitVersion = '5.8.2' def jmhVersion = '1.34' def agronaVersion = '1.15.0' -def agronaVersionRange = '[1.14,1.15[' // allow any patch release of 1.14.x +def agronaVersionRange = '[1.15,1.16[' // allow any patch release of 1.15.x def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From ebae848f74494dfe79b5afd9d427e0b7d8bf2844 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 22 Mar 2022 19:17:39 +0100 Subject: [PATCH 074/805] [Java] Update JavaDoc URL for JDK 18 GA. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 28808b39da..9648d5b0b6 100644 --- a/build.gradle +++ b/build.gradle @@ -191,7 +191,7 @@ subprojects { options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' options.links("https://www.javadoc.io/doc/org.agrona/agrona/${agronaVersion}/") - if (buildJavaVersion >= 18) { // early access JavaDoc location is different + if (buildJavaVersion >= 19) { // early access JavaDoc location is different options.links("https://download.java.net/java/early_access/jdk${buildJavaVersion}/docs/api/") } else if (buildJavaVersion >= 11) { From cd62d5a4512053728f02c96d48f7b2411e8b4061 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 28 Mar 2022 14:56:39 +0100 Subject: [PATCH 075/805] [Java] Upgrade to JMH 1.35. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9648d5b0b6..07f3c639de 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.4.0' def junitVersion = '5.8.2' -def jmhVersion = '1.34' +def jmhVersion = '1.35' def agronaVersion = '1.15.0' def agronaVersionRange = '[1.15,1.16[' // allow any patch release of 1.15.x From 62b30616ad98147d801e4104082d0db1b7daf882 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 4 Apr 2022 13:02:34 +0200 Subject: [PATCH 076/805] [Java] Upgrade to Gradle 7.4.2. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 07f3c639de..d488148251 100644 --- a/build.gradle +++ b/build.gradle @@ -821,7 +821,7 @@ tasks.named('dependencyUpdates').configure { tasks.findByName('build').dependsOn verifyJavaIrCodecsInSync wrapper { - gradleVersion = '7.4.1' + gradleVersion = '7.4.2' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d7e66b5c61..92f06b50fd 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 227a6f9367b0423132d3bb72fab7dbd3415424c1 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 13 Apr 2022 09:45:54 +0200 Subject: [PATCH 077/805] [CI] Use JDK 18 GA release. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4bf19f1d4..421f93d3f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '8', '11', '17', '18-ea' ] + java: [ '8', '11', '17', '18' ] os: [ 'ubuntu-20.04', 'windows-latest' ] steps: - name: Checkout code From 14467844eada59775d0b87d873e82b6b452c2ac6 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 14 Apr 2022 18:05:29 +0100 Subject: [PATCH 078/805] [Java] Upgrade to Agrona 1.15.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d488148251..1bf300ad28 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.4.0' def junitVersion = '5.8.2' def jmhVersion = '1.35' -def agronaVersion = '1.15.0' +def agronaVersion = '1.15.1' def agronaVersionRange = '[1.15,1.16[' // allow any patch release of 1.15.x def sbeGroup = 'uk.co.real-logic' From 388010963e96fa1a4c21cfb8fe241ec9b7f898a1 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 14 Apr 2022 18:08:46 +0100 Subject: [PATCH 079/805] Set version to 1.25.2. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index b4f8049e9c..6fb671d7e9 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.26.0-SNAPSHOT +1.25.2-SNAPSHOT From 58e9a4bb387b49028d0bb8ab64e3bba0d37055a7 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 14 Apr 2022 18:17:29 +0100 Subject: [PATCH 080/805] Correct version. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6fb671d7e9..47bcf2880a 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.2-SNAPSHOT +1.25.3-SNAPSHOT From 143cfd5df715f3a130e207e627f8b7ddaee758ee Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Thu, 14 Apr 2022 10:30:15 -0700 Subject: [PATCH 081/805] 1.25.3 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 47bcf2880a..5bb76b575e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.3-SNAPSHOT +1.25.3 From 6524c5b10a04132a99309f8f776681d30d0b71ac Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Thu, 14 Apr 2022 10:31:26 -0700 Subject: [PATCH 082/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 5bb76b575e..bda7b6dbcb 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.3 +1.25.4-SNAPSHOT From 48c722ec84d1c8066865907e607c5e965be2b4bb Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 20 Apr 2022 09:58:29 +0100 Subject: [PATCH 083/805] Upgrade to Mockito 4.5.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1bf300ad28..a18ad6c370 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.4.0' +def mockitoVersion = '4.5.0' def junitVersion = '5.8.2' def jmhVersion = '1.35' def agronaVersion = '1.15.1' From 9af63a1ceb5c0f78e2929d7750db97f3fbde0265 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 28 Apr 2022 14:29:46 +0200 Subject: [PATCH 084/805] [Java] Upgrade to Mockito 4.5.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a18ad6c370..c76b35f4d7 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.5.0' +def mockitoVersion = '4.5.1' def junitVersion = '5.8.2' def jmhVersion = '1.35' def agronaVersion = '1.15.1' From 0382cba6e6970b8616c59a5231d0b81ff3844a5e Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 4 May 2022 15:23:34 +0100 Subject: [PATCH 085/805] [Java] Generate SuppressWarnings annotation for enum types. Issue #894. --- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 3 ++- .../java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java | 1 + .../java/uk/co/real_logic/sbe/ir/generated/MetaAttribute.java | 1 + .../java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java | 1 + .../uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java | 1 + .../java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java | 1 + 6 files changed, 7 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 8778c06299..d9ed796c4c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1673,6 +1673,7 @@ private void generateMetaAttributeEnum() throws IOException "/**\n" + " * Meta attribute enum for selecting a particular meta attribute value.\n" + " */\n" + + " @SuppressWarnings(\"all\")\n" + "public enum MetaAttribute\n" + "{\n" + " /**\n" + @@ -1700,7 +1701,7 @@ private static CharSequence generateEnumDeclaration(final String name, final Tok final StringBuilder sb = new StringBuilder(); generateTypeJavadoc(sb, BASE_INDENT, typeToken); - sb.append("public enum ").append(name).append("\n{\n"); + sb.append("@SuppressWarnings(\"all\")\n").append("public enum ").append(name).append("\n{\n"); return sb; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java index fc8fd3463b..76fc614e8b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/ByteOrderCodec.java @@ -5,6 +5,7 @@ /** * Number encoding byte order. */ +@SuppressWarnings("all") public enum ByteOrderCodec { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MetaAttribute.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MetaAttribute.java index 7bac3df062..7e10779484 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MetaAttribute.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MetaAttribute.java @@ -4,6 +4,7 @@ /** * Meta attribute enum for selecting a particular meta attribute value. */ + @SuppressWarnings("all") public enum MetaAttribute { /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java index ceea18d898..8d135992f0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PresenceCodec.java @@ -5,6 +5,7 @@ /** * Field presence declaration. */ +@SuppressWarnings("all") public enum PresenceCodec { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java index bc2f89cde3..464d0af814 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/PrimitiveTypeCodec.java @@ -5,6 +5,7 @@ /** * Primitive types in type system. */ +@SuppressWarnings("all") public enum PrimitiveTypeCodec { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java index dd812e782e..e1ba77713e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/SignalCodec.java @@ -5,6 +5,7 @@ /** * Token signal type in IR. */ +@SuppressWarnings("all") public enum SignalCodec { From a61401114a6bc5cbd933f4196ddd99a53358b62c Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 11 May 2022 15:42:23 +0200 Subject: [PATCH 086/805] [CI] Add Clang 14 to the build matrix. --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 421f93d3f2..2068ac66da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,8 +13,8 @@ concurrency: cancel-in-progress: true env: - GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail" - CMAKE_VERSION: "3.6.1" + GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' + CMAKE_VERSION: '3.14.7' jobs: java-build: @@ -142,7 +142,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '6.0', '7', '8', '9', '10', '11', '12', '13' ] + version: [ '6.0', '7', '8', '9', '10', '11', '12', '13', '14' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} @@ -244,4 +244,4 @@ jobs: profile: minimal toolchain: ${{ matrix.rust }} override: true - - run: ./gradlew runRustTests \ No newline at end of file + - run: ./gradlew runRustTests From 061be357ff7c1a2f387b57b79af27a8051403a36 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 16 May 2022 20:34:29 +0200 Subject: [PATCH 087/805] [Java] Allow any Agrona version >= 1.15.0 and < 2.0.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c76b35f4d7..0e40567df0 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ def mockitoVersion = '4.5.1' def junitVersion = '5.8.2' def jmhVersion = '1.35' def agronaVersion = '1.15.1' -def agronaVersionRange = '[1.15,1.16[' // allow any patch release of 1.15.x +def agronaVersionRange = '[1.15,2.0[' // allow any release >= 1.15.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 63069034c76c26b6e30fa09c17fc62f036bb457d Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 16 May 2022 20:35:34 +0200 Subject: [PATCH 088/805] [Java] Upgrade to Agrona 1.15.2. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0e40567df0..37aba2fb44 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.5.1' def junitVersion = '5.8.2' def jmhVersion = '1.35' -def agronaVersion = '1.15.1' +def agronaVersion = '1.15.2' def agronaVersionRange = '[1.15,2.0[' // allow any release >= 1.15.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' From 95824f3938a6630f9895e4886d181b9a7f05bb81 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 22 May 2022 18:08:08 +0200 Subject: [PATCH 089/805] [Java] Set min Agrona version to 1.15.2. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 37aba2fb44..ce1570debb 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ def mockitoVersion = '4.5.1' def junitVersion = '5.8.2' def jmhVersion = '1.35' def agronaVersion = '1.15.2' -def agronaVersionRange = '[1.15,2.0[' // allow any release >= 1.15.0 and < 2.0.0 +def agronaVersionRange = '[1.15.2,2.0[' // allow any release >= 1.15.2 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From e1c1278b23a0c6322dc95cae6b8aa3f2eb5aeb61 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 24 May 2022 11:07:00 +0100 Subject: [PATCH 090/805] [Rust] Tidy up and fix resource leak. --- .../sbe/generation/rust/LibRsDef.java | 19 ++-- .../sbe/generation/rust/RustGenerator.java | 105 +++++++++--------- .../generation/rust/RustOutputManager.java | 2 +- .../sbe/generation/rust/RustUtil.java | 1 + .../sbe/generation/rust/SubGroup.java | 1 + 5 files changed, 70 insertions(+), 58 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 796ef98d16..4913e30b9d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -19,8 +19,10 @@ import java.io.Writer; import java.nio.ByteOrder; import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.LinkedHashSet; +import java.util.stream.Stream; import static java.nio.ByteOrder.LITTLE_ENDIAN; import static uk.co.real_logic.sbe.generation.rust.RustGenerator.*; @@ -58,13 +60,16 @@ void generate() throws IOException indent(libRs, 0, "use ::core::{convert::TryInto};\n\n"); final ArrayList modules = new ArrayList<>(); - Files.walk(outputManager.getSrcDirPath()) - .filter(Files::isRegularFile) - .map((path) -> path.getFileName().toString()) - .filter((fileName) -> fileName.endsWith(".rs")) - .filter((fileName) -> !fileName.equals("lib.rs")) - .map((fileName) -> fileName.substring(0, fileName.length() - 3)) - .forEach(modules::add); + try (Stream walk = Files.walk(outputManager.getSrcDirPath())) + { + walk + .filter(Files::isRegularFile) + .map((path) -> path.getFileName().toString()) + .filter((fileName) -> fileName.endsWith(".rs")) + .filter((fileName) -> !fileName.equals("lib.rs")) + .map((fileName) -> fileName.substring(0, fileName.length() - 3)) + .forEach(modules::add); + } // add modules for (final String mod : modules) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 2df4ce440f..adb9e7b7ad 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -27,6 +27,7 @@ import uk.co.real_logic.sbe.ir.Token; import java.io.IOException; +import java.io.UncheckedIOException; import java.io.Writer; import java.util.ArrayList; import java.util.HashSet; @@ -208,32 +209,34 @@ static void generateEncoderFields( final List tokens, final int level) { - Generators.forEachField(tokens, (fieldToken, typeToken) -> - { - try + Generators.forEachField( + tokens, + (fieldToken, typeToken) -> { - final String name = fieldToken.name(); - switch (typeToken.signal()) + try { - case ENCODING: - generatePrimitiveEncoder(sb, level, typeToken, name); - break; - case BEGIN_ENUM: - generateEnumEncoder(sb, level, fieldToken, typeToken, name); - break; - case BEGIN_SET: - generateBitSetEncoder(sb, level, typeToken, name); - break; - case BEGIN_COMPOSITE: - generateCompositeEncoder(sb, level, typeToken, name); - break; + final String name = fieldToken.name(); + switch (typeToken.signal()) + { + case ENCODING: + generatePrimitiveEncoder(sb, level, typeToken, name); + break; + case BEGIN_ENUM: + generateEnumEncoder(sb, level, fieldToken, typeToken, name); + break; + case BEGIN_SET: + generateBitSetEncoder(sb, level, typeToken, name); + break; + case BEGIN_COMPOSITE: + generateCompositeEncoder(sb, level, typeToken, name); + break; + } } - } - catch (final IOException ex) - { - throw new RuntimeException(ex); - } - }); + catch (final IOException ex) + { + throw new UncheckedIOException(ex); + } + }); } static void generateEncoderGroups( @@ -489,36 +492,38 @@ static void generateDecoderFields( final List tokens, final int level) { - Generators.forEachField(tokens, (fieldToken, typeToken) -> - { - try + Generators.forEachField( + tokens, + (fieldToken, typeToken) -> { - final String name = fieldToken.name(); - final Encoding encoding = typeToken.encoding(); - - switch (typeToken.signal()) + try { - case ENCODING: - generatePrimitiveDecoder(sb, level, fieldToken, typeToken, name, encoding); - break; - case BEGIN_ENUM: - generateEnumDecoder(sb, level, fieldToken, typeToken, name); - break; - case BEGIN_SET: - generateBitSetDecoder(sb, level, typeToken, name); - break; - case BEGIN_COMPOSITE: - generateCompositeDecoder(sb, level, fieldToken, typeToken, name); - break; - default: - throw new UnsupportedOperationException("Unable to handle: " + typeToken); + final String name = fieldToken.name(); + final Encoding encoding = typeToken.encoding(); + + switch (typeToken.signal()) + { + case ENCODING: + generatePrimitiveDecoder(sb, level, fieldToken, typeToken, name, encoding); + break; + case BEGIN_ENUM: + generateEnumDecoder(sb, level, fieldToken, typeToken, name); + break; + case BEGIN_SET: + generateBitSetDecoder(sb, level, typeToken, name); + break; + case BEGIN_COMPOSITE: + generateCompositeDecoder(sb, level, fieldToken, typeToken, name); + break; + default: + throw new UnsupportedOperationException("Unable to handle: " + typeToken); + } } - } - catch (final IOException e) - { - throw new RuntimeException(e); - } - }); + catch (final IOException ex) + { + throw new UncheckedIOException(ex); + } + }); } private static void generateCompositeDecoder( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java index 45458df2de..4426638193 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java @@ -86,7 +86,7 @@ public Writer createOutput(final String name) throws IOException } /** - * Creates a new Cargo.toml file + * Creates a new Cargo.toml file. *

* @return a {@link java.io.Writer} to which the crate definition should be written. * @throws IOException if an issue occurs when creating the file. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index fe49709908..731f57199d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -157,6 +157,7 @@ static String cleanUpperAcronyms(final String value) final int index = i - 1; return value.substring(0, index).toLowerCase() + value.substring(index); } + return value; } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index e56049205c..79fb608f79 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -45,6 +45,7 @@ public SubGroup addSubGroup(final String name, final int level, final Token grou { final SubGroup subGroup = new SubGroup(name, level, groupToken); subGroups.add(subGroup); + return subGroup; } From d9600d4656a291e375e8dd53c05079ca3075ca36 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Tue, 24 May 2022 09:25:16 -0500 Subject: [PATCH 091/805] [Rust] fix generated comparison when value is NAN (#895) (#896) Co-authored-by: Michael Ward --- .../sbe/generation/rust/RustGenerator.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index adb9e7b7ad..00417ec76d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -746,8 +746,18 @@ private static void generatePrimitiveOptionalDecoder( indent(sb, level + 1, "let value = self.get_buf().get_%s_at(self.%s);\n", rustPrimitiveType, getBufOffset(fieldToken)); - indent(sb, level + 1, "if value == %s {\n", - generateRustLiteral(primitiveType, encoding.applicableNullValue().toString())); + + + final String literal = generateRustLiteral(primitiveType, encoding.applicableNullValue().toString()); + if (literal.endsWith("::NAN")) + { + indent(sb, level + 1, "if value.is_nan() {\n"); + } + else + { + indent(sb, level + 1, "if value == %s {\n", literal); + } + indent(sb, level + 2, "None\n"); indent(sb, level + 1, "} else {\n"); indent(sb, level + 2, "Some(value)\n"); From 30bbb0065221ad946e0a2c4eae0a62d2b3f0768d Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Thu, 26 May 2022 02:54:07 -0500 Subject: [PATCH 092/805] [Rust] added tests for issue #895 (#897) * [Rust] fix generated comparison when value is NAN (#895) * [Rust] added test for issue #895 Co-authored-by: Michael Ward --- build.gradle | 1 + rust/Cargo.toml | 1 + rust/tests/baseline_test.rs | 4 +- rust/tests/big_endian_test.rs | 2 +- rust/tests/extension_test.rs | 4 +- rust/tests/issue_435_test.rs | 12 ++-- rust/tests/issue_895_test.rs | 75 ++++++++++++++++++++++++ sbe-tool/src/test/resources/issue895.xml | 21 +++++++ 8 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 rust/tests/issue_895_test.rs create mode 100644 sbe-tool/src/test/resources/issue895.xml diff --git a/build.gradle b/build.gradle index ce1570debb..60e9d756ca 100644 --- a/build.gradle +++ b/build.gradle @@ -566,6 +566,7 @@ task generateRustTestCodecs(type: JavaExec) { 'sbe.target.language': 'Rust', 'sbe.validation.xsd': validationXsdPath) args = ['sbe-tool/src/test/resources/issue435.xml', + 'sbe-tool/src/test/resources/issue895.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', ] } diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 8aef7aa48c..eb57d8b01c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -12,6 +12,7 @@ examples_uk_co_real_logic_sbe_benchmarks = { path = "../generated/rust/uk_co_rea examples_uk_co_real_logic_sbe_benchmarks_fix = { path = "../generated/rust/uk_co_real_logic_sbe_benchmarks_fix" } issue_435 = { path = "../generated/rust/issue435" } +issue_895 = { path = "../generated/rust/issue895" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } [dev-dependencies] diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index a19b39a96e..ca45f14b43 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -3,7 +3,7 @@ use std::io::prelude::*; use examples_baseline::*; -fn read_sbe_file_generated_from_java_example() -> ::std::io::Result> { +fn read_sbe_file_generated_from_java_example() -> std::io::Result> { // Generated by the generateCarExampleDataFile gradle task. let mut f = File::open("car_example_baseline_data.sbe")?; let mut buffer = Vec::new(); @@ -33,7 +33,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); - assert_eq!(car_codec::SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); car = car.header(header); // Car... diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index 40b652c1be..d3a6952dec 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -30,7 +30,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); - assert_eq!(car_codec::SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); car = car.header(header); // Car... diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index 5e993f7701..c189763c6f 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -3,7 +3,7 @@ use std::io::prelude::*; use examples_extension::*; -fn read_sbe_file_generated_from_java_example() -> ::std::io::Result> { +fn read_sbe_file_generated_from_java_example() -> std::io::Result> { // Generated by the generateCarExampleDataFile gradle task. let mut f = File::open("car_example_extension_data.sbe")?; let mut buffer = Vec::new(); @@ -32,7 +32,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); - assert_eq!(car_codec::SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); car = car.header(header); // Car... diff --git a/rust/tests/issue_435_test.rs b/rust/tests/issue_435_test.rs index 3c9b43b0da..87bd9a075e 100644 --- a/rust/tests/issue_435_test.rs +++ b/rust/tests/issue_435_test.rs @@ -13,8 +13,8 @@ fn create_encoder(buffer: &mut Vec) -> Issue435Encoder { #[test] fn issue_435_ref_test() -> SbeResult<()> { assert_eq!(9, message_header_codec::ENCODED_LENGTH); - assert_eq!(1, issue_435_codec::SBE_BLOCK_LENGTH); - assert_eq!(0, issue_435_codec::SBE_SCHEMA_VERSION); + assert_eq!(1, SBE_BLOCK_LENGTH); + assert_eq!(0, SBE_SCHEMA_VERSION); // encode... let mut buffer = vec![0u8; 256]; @@ -24,10 +24,10 @@ fn issue_435_ref_test() -> SbeResult<()> { // decode... let buf = ReadBuf::new(buffer.as_slice()); let header = MessageHeaderDecoder::default().wrap(buf, 0); - assert_eq!(issue_435_codec::SBE_BLOCK_LENGTH, header.block_length()); - assert_eq!(issue_435_codec::SBE_SCHEMA_VERSION, header.version()); - assert_eq!(issue_435_codec::SBE_TEMPLATE_ID, header.template_id()); - assert_eq!(issue_435_codec::SBE_SCHEMA_ID, header.schema_id()); + assert_eq!(SBE_BLOCK_LENGTH, header.block_length()); + assert_eq!(SBE_SCHEMA_VERSION, header.version()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_SCHEMA_ID, header.schema_id()); assert_eq!(*SetRef::default().set_one(true), header.s()); let decoder = Issue435Decoder::default().header(header); diff --git a/rust/tests/issue_895_test.rs b/rust/tests/issue_895_test.rs new file mode 100644 index 0000000000..6c7090d2da --- /dev/null +++ b/rust/tests/issue_895_test.rs @@ -0,0 +1,75 @@ +use ::issue_895::*; + +fn create_encoder(buffer: &mut Vec) -> Issue895Encoder { + let issue_895 = Issue895Encoder::default().wrap( + WriteBuf::new(buffer.as_mut_slice()), + ENCODED_LENGTH, + ); + let mut header = issue_895.header(0); + header.parent().unwrap() +} + +#[test] +fn issue_895_both_some() -> SbeResult<()> { + assert_eq!(8, ENCODED_LENGTH); + assert_eq!(12, SBE_BLOCK_LENGTH); + assert_eq!(0, SBE_SCHEMA_VERSION); + + // encode... + let mut buf = vec![0u8; 256]; + let mut encoder = create_encoder(&mut buf); + encoder.optional_float(2.07); + encoder.optional_double(4.12); + + // decode... + let buf = ReadBuf::new(buf.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + assert_eq!(SBE_BLOCK_LENGTH, header.block_length()); + assert_eq!(SBE_SCHEMA_VERSION, header.version()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_SCHEMA_ID, header.schema_id()); + + let decoder = Issue895Decoder::default().header(header); + assert_eq!(Some(2.07), decoder.optional_float()); + assert_eq!(Some(4.12), decoder.optional_double()); + + Ok(()) +} + +#[test] +fn issue_895_float_none() -> SbeResult<()> { + // encode... + let mut buf = vec![0u8; 256]; + let mut encoder = create_encoder(&mut buf); + encoder.optional_float(f32::NAN); + encoder.optional_double(4.12); + + // decode... + let buf = ReadBuf::new(buf.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + + let decoder = Issue895Decoder::default().header(header); + assert_eq!(None, decoder.optional_float()); + assert_eq!(Some(4.12), decoder.optional_double()); + + Ok(()) +} + +#[test] +fn issue_895_double_none() -> SbeResult<()> { + // encode... + let mut buffer = vec![0u8; 256]; + let mut encoder = create_encoder(&mut buffer); + encoder.optional_float(2.07); + encoder.optional_double(f64::NAN); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + + let decoder = Issue895Decoder::default().header(header); + assert_eq!(Some(2.07), decoder.optional_float()); + assert_eq!(None, decoder.optional_double()); + + Ok(()) +} \ No newline at end of file diff --git a/sbe-tool/src/test/resources/issue895.xml b/sbe-tool/src/test/resources/issue895.xml new file mode 100644 index 0000000000..5f14dd35a7 --- /dev/null +++ b/sbe-tool/src/test/resources/issue895.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + From cac83597a68f537ccc599fd918baf5a6ba0a8415 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 30 May 2022 09:43:32 +0100 Subject: [PATCH 093/805] [Rust] Upgrade to Mockito 4.6.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 60e9d756ca..290ec362b1 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.5.1' +def mockitoVersion = '4.6.0' def junitVersion = '5.8.2' def jmhVersion = '1.35' def agronaVersion = '1.15.2' From e1f166b5427d0e18c169d230e8bb576e38f3366f Mon Sep 17 00:00:00 2001 From: Naveen <172697+naveensrinivasan@users.noreply.github.com> Date: Tue, 31 May 2022 03:19:57 -0500 Subject: [PATCH 094/805] chore: Set permissions for GitHub actions (#898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict the GitHub token permissions only to the required ones; this way, even if the attackers will succeed in compromising your workflow, they won’t be able to do much. - Included permissions for the action. https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2068ac66da..8f018aa915 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,9 @@ env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' CMAKE_VERSION: '3.14.7' +permissions: + contents: read + jobs: java-build: name: Java ${{ matrix.java }} (${{ matrix.os }}) From b9c60ae28d57cd1bbeb58687d5b812b571909b85 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 6 Jun 2022 17:30:24 +0100 Subject: [PATCH 095/805] [Java] Upgrade to Mockito 4.6.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 290ec362b1..2358dcaae3 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.6.0' +def mockitoVersion = '4.6.1' def junitVersion = '5.8.2' def jmhVersion = '1.35' def agronaVersion = '1.15.2' From 727281a26157a244947ec8c8afa92176c3f98a9b Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 21 Jun 2022 11:28:53 +0100 Subject: [PATCH 096/805] [Java] Check sinceVersion on elements are valid in the context of message schema version. Issue #902. --- .../co/real_logic/sbe/xml/CompositeType.java | 49 ++++-- .../co/real_logic/sbe/xml/ErrorHandler.java | 4 +- .../co/real_logic/sbe/xml/MessageSchema.java | 161 +++++++++++++++++- .../java/uk/co/real_logic/sbe/xml/Type.java | 12 +- .../real_logic/sbe/xml/XmlSchemaParser.java | 2 + .../sbe/TargetCodeGeneratorTest.java | 6 +- .../real_logic/sbe/codec/java/TypesTest.java | 14 +- .../sbe/generation/cpp/CppGeneratorTest.java | 4 +- .../csharp/Issue567GroupSizeTest.java | 6 +- .../sbe/generation/java/ToStringTest.java | 6 +- .../sbe/generation/rust/RustUtilTest.java | 22 +-- .../sbe/ir/BasicXmlIrGenerationTest.java | 15 +- .../sbe/ir/CompositeElementsIrTest.java | 8 +- .../sbe/ir/CompositeOffsetsTest.java | 4 +- .../real_logic/sbe/ir/CompositeRefsTest.java | 4 +- .../co/real_logic/sbe/ir/EncodedIrTest.java | 14 +- .../sbe/ir/GroupWithDataIrTest.java | 10 +- .../sbe/ir/SinceVersionValidationTest.java | 44 +++++ .../co/real_logic/sbe/ir/ValueRefsTest.java | 4 +- .../real_logic/sbe/json/JsonPrinterTest.java | 4 +- .../sbe/xml/BasicSchemaFileTest.java | 21 +-- .../sbe/xml/CompositeElementsTest.java | 4 +- .../real_logic/sbe/xml/CompositeTypeTest.java | 14 +- .../sbe/xml/CyclicReferencesTest.java | 4 +- .../xml/EmbeddedLengthAndCountFileTest.java | 6 +- .../sbe/xml/EncodedDataTypeTest.java | 54 +++--- .../co/real_logic/sbe/xml/EnumTypeTest.java | 28 +-- .../real_logic/sbe/xml/ErrorHandlerTest.java | 26 +-- .../real_logic/sbe/xml/GroupWithDataTest.java | 4 +- .../co/real_logic/sbe/xml/OffsetFileTest.java | 18 +- .../sbe/xml/RelativeXIncludeTest.java | 4 +- .../uk/co/real_logic/sbe/xml/SetTypeTest.java | 16 +- .../resources/error-handler-since-version.xml | 38 +++++ 33 files changed, 447 insertions(+), 183 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java create mode 100644 sbe-tool/src/test/resources/error-handler-since-version.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java index 98863144b9..667da499dc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java @@ -58,7 +58,7 @@ public class CompositeType extends Type /** * Construct a new compositeType from XML Schema. * - * @param node from the XML Schema Parsing + * @param node from the XML Schema parsing. * @param givenName for this node. * @param referencedName of the type when created from a ref in a composite. * @param compositesPath with the path of composites that represents the levels of composition. @@ -88,10 +88,10 @@ public class CompositeType extends Type } /** - * Return the EncodedDataType within this composite with the given name + * Return the EncodedDataType within this composite with the given name. * - * @param name of the EncodedDataType to return - * @return type requested + * @param name of the type to return. + * @return type requested. */ public Type getType(final String name) { @@ -99,9 +99,9 @@ public Type getType(final String name) } /** - * The encodedLength (in octets) of the list of EncodedDataTypes + * The encodedLength (in octets) of the list of encoded types. * - * @return encodedLength of the compositeType + * @return encodedLength of the compositeType. */ public int encodedLength() { @@ -129,9 +129,9 @@ public int encodedLength() } /** - * Return list of the {@link Type}s that compose this composite + * Return list of the {@link Type}s that compose this composite. * - * @return {@link List} that holds the {@link Type}s in this composite + * @return {@link List} that holds the {@link Type}s in this composite. */ public List getTypeList() { @@ -140,7 +140,7 @@ public List getTypeList() /** * Make this composite type, if it has a varData member, variable length - * by making the EncodedDataType with the name "varData" be variable length. + * by making the type with the name "varData" be variable length. */ public void makeDataFieldCompositeType() { @@ -155,7 +155,7 @@ public void makeDataFieldCompositeType() * Check the composite for being a well-formed group encodedLength encoding. This means * that there are the fields "blockLength" and "numInGroup" present. * - * @param node of the XML for this composite + * @param node of the XML for this composite. */ public void checkForWellFormedGroupSizeEncoding(final Node node) { @@ -433,10 +433,7 @@ private Type processType( case "ref": { final XPath xPath = XPathFactory.newInstance().newXPath(); - - final String refName = XmlSchemaParser.getAttributeValue(subTypeNode, "name"); final String refTypeName = XmlSchemaParser.getAttributeValue(subTypeNode, "type"); - final int refOffset = Integer.parseInt(XmlSchemaParser.getAttributeValue(subTypeNode, "offset", "-1")); final Node refTypeNode = (Node)xPath.compile( "/*[local-name() = 'messageSchema']/types/*[@name='" + refTypeName + "']") .evaluate(subTypeNode.getOwnerDocument(), XPathConstants.NODE); @@ -453,11 +450,33 @@ private Type processType( throw new IllegalStateException("ref types cannot create circular dependencies"); } + final String refName = XmlSchemaParser.getAttributeValue(subTypeNode, "name"); type = processType(refTypeNode, refName, refName, refTypeName); - if (-1 != refOffset) + final String refOffset = XmlSchemaParser.getAttributeValueOrNull(subTypeNode, "offset"); + if (null != refOffset) + { + try + { + type.offsetAttribute(Integer.parseInt(refOffset)); + } + catch (final NumberFormatException ex) + { + XmlSchemaParser.handleError(subTypeNode, "invalid number type: " + refOffset); + } + } + + final String refVersion = XmlSchemaParser.getAttributeValueOrNull(subTypeNode, "sinceVersion"); + if (null != refVersion) { - type.offsetAttribute(refOffset); + try + { + type.sinceVersion(Integer.parseInt(refVersion)); + } + catch (final NumberFormatException ex) + { + XmlSchemaParser.handleError(subTypeNode, "invalid number type: " + refVersion); + } } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java index 361d2b1e77..12fe0663a3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java @@ -104,11 +104,11 @@ public void checkIfShouldExit() { if (errors > 0) { - throw new IllegalStateException("had " + errors + " errors"); + throw new IllegalStateException("had " + errors + (errors > 1 ? " errors" : " error")); } else if (warnings > 0 && warningsFatal) { - throw new IllegalStateException("had " + warnings + " warnings"); + throw new IllegalStateException("had " + warnings + (warnings > 1 ? " warnings" : " warning")); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index 3f0bab5ff4..b62495f537 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -19,8 +19,7 @@ import org.agrona.Verify; import java.nio.ByteOrder; -import java.util.Collection; -import java.util.Map; +import java.util.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.*; @@ -164,4 +163,162 @@ public ByteOrder byteOrder() { return byteOrder; } + + /** + * Validate the message schema and delegate warnings and errors to the supplied {@link ErrorHandler}. + * + * @param errorHandler for delegating warnings and errors. + */ + public void validate(final ErrorHandler errorHandler) + { + final Deque path = new ArrayDeque<>(); + + for (final Type type : typeByNameMap.values()) + { + validateType(errorHandler, path, type); + } + + for (final Message message : messageByIdMap.values()) + { + if (message.sinceVersion() > version) + { + errorHandler.error(message.name() + ".sinceVersion=" + message.sinceVersion() + + " > messageSchema.version=" + version); + } + + path.addLast(message.name()); + + for (final Field field : message.fields()) + { + validateField(errorHandler, path, field); + } + + path.removeLast(); + } + } + + private void validateType(final ErrorHandler errorHandler, final Deque path, final Type type) + { + if (type instanceof EncodedDataType) + { + validateEncodedType(errorHandler, path, (EncodedDataType)type); + } + else if (type instanceof EnumType) + { + validateEnumType(errorHandler, path, (EnumType)type); + } + else if (type instanceof SetType) + { + validateSetType(errorHandler, path, (SetType)type); + } + else if (type instanceof CompositeType) + { + validateCompositeType(errorHandler, path, (CompositeType)type); + } + } + + private void validateEncodedType( + final ErrorHandler errorHandler, final Deque path, final EncodedDataType type) + { + if (type.sinceVersion() > version) + { + reportError(errorHandler, path, type.name(), type.sinceVersion()); + } + } + + private void validateEnumType(final ErrorHandler errorHandler, final Deque path, final EnumType type) + { + if (type.sinceVersion() > version) + { + reportError(errorHandler, path, type.name(), type.sinceVersion()); + } + + path.addLast(type.name()); + + for (final EnumType.ValidValue validValue : type.validValues()) + { + if (validValue.sinceVersion() > version) + { + reportError(errorHandler, path, validValue.name(), validValue.sinceVersion()); + } + } + + path.removeLast(); + } + + private void validateSetType(final ErrorHandler errorHandler, final Deque path, final SetType type) + { + if (type.sinceVersion() > version) + { + reportError(errorHandler, path, type.name(), type.sinceVersion()); + } + + path.addLast(type.name()); + + for (final SetType.Choice choice : type.choices()) + { + if (choice.sinceVersion() > version) + { + reportError(errorHandler, path, choice.name(), choice.sinceVersion()); + } + } + + path.removeLast(); + } + + private void validateCompositeType( + final ErrorHandler errorHandler, final Deque path, final CompositeType type) + { + if (type.sinceVersion() > version) + { + reportError(errorHandler, path, type.name(), type.sinceVersion()); + } + + path.addLast(type.name()); + + for (final Type subType : type.getTypeList()) + { + validateType(errorHandler, path, subType); + } + + path.removeLast(); + } + + private void validateField(final ErrorHandler errorHandler, final Deque path, final Field field) + { + if (field.sinceVersion() > version) + { + reportError(errorHandler, path, field.name(), field.sinceVersion()); + } + + final List groupFields = field.groupFields(); + if (null != groupFields) + { + path.addLast(field.name()); + + for (final Field groupField : groupFields) + { + validateField(errorHandler, path, groupField); + } + + path.removeLast(); + } + } + + private void reportError( + final ErrorHandler errorHandler, final Deque path, final String name, final int sinceVersion) + { + final StringBuilder sb = new StringBuilder(); + + for (final String step : path) + { + sb.append(step).append('.'); + } + + sb.append(name) + .append(".sinceVersion=").append(sinceVersion) + .append(" > messageSchema.version=").append(version); + + errorHandler.error(sb.toString()); + } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java index b9db2c5138..8a1e491ff4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java @@ -28,12 +28,12 @@ public abstract class Type private final String name; private final Presence presence; private final String description; - private final int sinceVersion; private final int deprecated; private final String semanticType; private final String referencedName; private int offsetAttribute; + private int sinceVersion; /** * Construct a new Type from XML Schema. Called by subclasses to mostly set common fields @@ -150,6 +150,16 @@ public int sinceVersion() return sinceVersion; } + /** + * Set the sinceVersion for the type. + * + * @param version to be set. + */ + public void sinceVersion(final int version) + { + sinceVersion = version; + } + /** * Version in which type was deprecated. Only valid if greater than zero. * diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index 022777ae8f..fbc66f9888 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -146,6 +146,8 @@ public static MessageSchema parse(final InputSource is, final ParserOptions opti } final MessageSchema messageSchema = new MessageSchema(schemaNode, typeByNameMap, messageByIdMap); + + messageSchema.validate(errorHandler); errorHandler.checkIfShouldExit(); return messageSchema; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java index 7b63c47573..83b71ac815 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java @@ -23,17 +23,17 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class TargetCodeGeneratorTest +class TargetCodeGeneratorTest { @Test - public void shouldThrowOnNoTargetLanguage() + void shouldThrowOnNoTargetLanguage() { assertThrows(IllegalArgumentException.class, () -> SbeTool.generate(mock(Ir.class), ".", "none")); } @Test - public void shouldLoadAndInstantiateNonStandardTargetLanguage() throws Exception + void shouldLoadAndInstantiateNonStandardTargetLanguage() throws Exception { final Ir ir = mock(Ir.class); final String outputDir = "."; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java index c9c6bb2aac..5ca540c2b6 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java @@ -23,7 +23,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class TypesTest +class TypesTest { private static final ByteOrder BYTE_ORDER = ByteOrder.nativeOrder(); private static final int BUFFER_CAPACITY = 64; @@ -31,7 +31,7 @@ public class TypesTest private final MutableDirectBuffer buffer = new UnsafeBuffer(new byte[BUFFER_CAPACITY]); @Test - public void shouldTestBitInByte() + void shouldTestBitInByte() { final byte bits = (byte)0b1000_0000; final int bufferIndex = 8; @@ -53,7 +53,7 @@ public void shouldTestBitInByte() } @Test - public void shouldSetBitInByte() + void shouldSetBitInByte() { final int bufferIndex = 8; @@ -69,7 +69,7 @@ public void shouldSetBitInByte() } @Test - public void shouldTestBitInShort() + void shouldTestBitInShort() { final short bits = (short)0b0000_0000_0000_0100; final int bufferIndex = 8; @@ -91,7 +91,7 @@ public void shouldTestBitInShort() } @Test - public void shouldSetBitInShort() + void shouldSetBitInShort() { final int bufferIndex = 8; @@ -107,7 +107,7 @@ public void shouldSetBitInShort() } @Test - public void shouldTestBitInInt() + void shouldTestBitInInt() { final int bits = 0b0000_0000_0000_0000_0000_0000_0000_0100; final int bufferIndex = 8; @@ -129,7 +129,7 @@ public void shouldTestBitInInt() } @Test - public void shouldSetBitInInt() + void shouldSetBitInInt() { final int bufferIndex = 8; long total = 0; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index 8187e18813..b198de3073 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -28,10 +28,10 @@ import static org.hamcrest.Matchers.not; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class CppGeneratorTest +class CppGeneratorTest { @Test - public void shouldUseGeneratedLiteralForConstantOneWhenGeneratingBitsetCode() throws Exception + void shouldUseGeneratedLiteralForConstantOneWhenGeneratingBitsetCode() throws Exception { final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); final MessageSchema schema = parse(Tests.getLocalResource("issue827.xml"), options); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index ef04946d0b..3a7eeca34c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -37,7 +37,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -public class Issue567GroupSizeTest +class Issue567GroupSizeTest { private static final String ERR_MSG = "WARNING: at \"numInGroup\" should be UINT8 or UINT16"; @@ -51,7 +51,7 @@ public class Issue567GroupSizeTest private final PrintStream mockErr = mock(PrintStream.class); @Test - public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupSize() throws IOException + void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupSize() throws IOException { final ParserOptions options = ParserOptions.builder() .errorPrintStream(mockErr) @@ -65,7 +65,7 @@ public void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupS } @Test - public void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupSize() throws Exception + void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupSize() throws Exception { final ParserOptions options = ParserOptions.builder() .errorPrintStream(mockErr) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java index 36d762fd83..3dde226e72 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java @@ -23,12 +23,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class ToStringTest extends EncodedCarTestBase +class ToStringTest extends EncodedCarTestBase { private static final int MSG_BUFFER_CAPACITY = 4 * 1024; @Test - public void shouldToStringMessage() + void shouldToStringMessage() { final ByteBuffer encodedMsgBuffer = ByteBuffer.allocate(MSG_BUFFER_CAPACITY); encodeTestMessage(encodedMsgBuffer); @@ -56,7 +56,7 @@ public void shouldToStringMessage() } @Test - public void shouldToStringBlankMessage() + void shouldToStringBlankMessage() { final ByteBuffer encodedMsgBuffer = ByteBuffer.allocate(MSG_BUFFER_CAPACITY); CAR.wrap(new UnsafeBuffer(encodedMsgBuffer), 0); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index 366d8663cd..cab7fc9f10 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -34,28 +34,28 @@ import static uk.co.real_logic.sbe.generation.rust.RustUtil.formatFunctionName; import static uk.co.real_logic.sbe.generation.rust.RustUtil.generateRustLiteral; -public class RustUtilTest +class RustUtilTest { @Test - public void nullParamToEightBitCharacterThrowsNPE() + void nullParamToEightBitCharacterThrowsNPE() { assertThrows(NullPointerException.class, () -> RustUtil.eightBitCharacter(null)); } @Test - public void emptyParamToEightBitCharacterThrowsIAE() + void emptyParamToEightBitCharacterThrowsIAE() { assertThrows(IllegalArgumentException.class, () -> RustUtil.eightBitCharacter("")); } @Test - public void tooManyCharactersParamToEightBitCharacterThrowsIAE() + void tooManyCharactersParamToEightBitCharacterThrowsIAE() { assertThrows(IllegalArgumentException.class, () -> RustUtil.eightBitCharacter("ABC")); } @Test - public void happyPathEightBitCharacter() + void happyPathEightBitCharacter() { final byte aByte = RustUtil.eightBitCharacter("a"); assertEquals('a', (char)aByte); @@ -63,7 +63,7 @@ public void happyPathEightBitCharacter() } @Test - public void generateRustLiteralsHappyPaths() + void generateRustLiteralsHappyPaths() { assertEquals("65_u8", generateRustLiteral(CHAR, "65")); assertEquals("64.1_f64", generateRustLiteral(DOUBLE, "64.1")); @@ -83,7 +83,7 @@ public void generateRustLiteralsHappyPaths() } @Test - public void generateRustLiteralsForUnsignedPrimitiveNulls() + void generateRustLiteralsForUnsignedPrimitiveNulls() { assertEquals("0xff_u8", generateRustLiteral(UINT8, UINT8.nullValue().toString())); assertEquals("0xffff_u16", generateRustLiteral(UINT16, UINT16.nullValue().toString())); @@ -92,19 +92,19 @@ public void generateRustLiteralsForUnsignedPrimitiveNulls() } @Test - public void generateRustLiteralNullPrimitiveTypeParam() + void generateRustLiteralNullPrimitiveTypeParam() { assertThrows(NullPointerException.class, () -> generateRustLiteral(null, "65")); } @Test - public void generateRustLiteralNullValueParam() + void generateRustLiteralNullValueParam() { assertThrows(NullPointerException.class, () -> generateRustLiteral(INT8, null)); } @Test - public void testCleanUpperAcronyms() + void testCleanUpperAcronyms() { assertEquals("ABee", cleanUpperAcronyms("ABee")); assertEquals("mdEntryTypeBook", cleanUpperAcronyms("MDEntryTypeBook")); @@ -113,7 +113,7 @@ public void testCleanUpperAcronyms() } @Test - public void functionNameCasing() + void functionNameCasing() { assertEquals("", formatFunctionName("")); assertEquals("a", formatFunctionName("a")); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java index bdd33c0535..b7577f4100 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java @@ -29,10 +29,10 @@ import static uk.co.real_logic.sbe.Tests.getLocalResource; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class BasicXmlIrGenerationTest +class BasicXmlIrGenerationTest { @Test - public void shouldGenerateIrForMessageHeader() throws Exception + void shouldGenerateIrForMessageHeader() throws Exception { final MessageSchema schema = parse(getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -94,7 +94,7 @@ public void shouldGenerateIrForMessageHeader() throws Exception } @Test - public void shouldGenerateIrForBasicMessage() throws Exception + void shouldGenerateIrForBasicMessage() throws Exception { final MessageSchema schema = parse(getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -143,7 +143,7 @@ public void shouldGenerateIrForBasicMessage() throws Exception } @Test - public void shouldGenerateIrForMessageWithVariableLengthField() throws Exception + void shouldGenerateIrForMessageWithVariableLengthField() throws Exception { final MessageSchema schema = parse(getLocalResource( "basic-variable-length-schema.xml"), ParserOptions.DEFAULT); @@ -206,7 +206,7 @@ public void shouldGenerateIrForMessageWithVariableLengthField() throws Exception } @Test - public void shouldGenerateIrForMessageWithRepeatingGroupWithEmbeddedDimensions() throws Exception + void shouldGenerateIrForMessageWithRepeatingGroupWithEmbeddedDimensions() throws Exception { final MessageSchema schema = parse(getLocalResource( "basic-group-schema.xml"), ParserOptions.DEFAULT); @@ -240,8 +240,7 @@ public void shouldGenerateIrForMessageWithRepeatingGroupWithEmbeddedDimensions() } @Test - public void shouldGenerateIrForMessageWithRepeatingGroupWithEmbeddedDimensionsDefaultDimensionType() - throws Exception + void shouldGenerateIrForMessageWithRepeatingGroupWithEmbeddedDimensionsDefaultDimensionType() throws Exception { final MessageSchema schema = parse(getLocalResource( "embedded-length-and-count-schema.xml"), ParserOptions.DEFAULT); @@ -267,7 +266,7 @@ public void shouldGenerateIrForMessageWithRepeatingGroupWithEmbeddedDimensionsDe } @Test - public void shouldGenerateIrForMessageWithVariableLengthFieldWithEmbeddedLength() throws Exception + void shouldGenerateIrForMessageWithVariableLengthFieldWithEmbeddedLength() throws Exception { final MessageSchema schema = parse(getLocalResource( "embedded-length-and-count-schema.xml"), ParserOptions.DEFAULT); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java index ecdae485ef..60a2538922 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java @@ -28,10 +28,10 @@ import static uk.co.real_logic.sbe.Tests.getLocalResource; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class CompositeElementsIrTest +class CompositeElementsIrTest { @Test - public void shouldGenerateIrForCompositeElementsSchema() throws Exception + void shouldGenerateIrForCompositeElementsSchema() throws Exception { final MessageSchema schema = parse(getLocalResource( "composite-elements-schema.xml"), ParserOptions.DEFAULT); @@ -94,7 +94,7 @@ public void shouldGenerateIrForCompositeElementsSchema() throws Exception } @Test - public void shouldGenerateIrForCompositeElementsWithOffsetsSchemaRc4() throws Exception + void shouldGenerateIrForCompositeElementsWithOffsetsSchemaRc4() throws Exception { final MessageSchema schema = parse(getLocalResource( "composite-elements-schema-rc4.xml"), ParserOptions.DEFAULT); @@ -149,7 +149,7 @@ public void shouldGenerateIrForCompositeElementsWithOffsetsSchemaRc4() throws Ex } @Test - public void shouldGenerateIrForCompositeWithRefSchema() throws Exception + void shouldGenerateIrForCompositeWithRefSchema() throws Exception { final MessageSchema schema = parse(getLocalResource( "composite-elements-schema-rc4.xml"), ParserOptions.DEFAULT); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java index 91f5736a20..fa773de170 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java @@ -27,10 +27,10 @@ import static uk.co.real_logic.sbe.Tests.getLocalResource; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class CompositeOffsetsTest +class CompositeOffsetsTest { @Test - public void shouldGenerateOffsetsForFieldsWithEmbeddedComposite() throws Exception + void shouldGenerateOffsetsForFieldsWithEmbeddedComposite() throws Exception { final MessageSchema schema = parse(getLocalResource("composite-offsets-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java index 6edf89a346..aab8b540ab 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java @@ -24,10 +24,10 @@ import static uk.co.real_logic.sbe.Tests.getLocalResource; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class CompositeRefsTest +class CompositeRefsTest { @Test - public void shouldGenerateIrForCompositeRefs() throws Exception + void shouldGenerateIrForCompositeRefs() throws Exception { final MessageSchema schema = parse(getLocalResource("issue496.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index 5bb0750cfd..900ab99e38 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -28,12 +28,12 @@ import static org.hamcrest.core.Is.is; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class EncodedIrTest +class EncodedIrTest { private static final int CAPACITY = 1024 * 16; @Test - public void shouldEncodeIr() throws Exception + void shouldEncodeIr() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -45,7 +45,7 @@ public void shouldEncodeIr() throws Exception } @Test - public void shouldEncodeThenDecodeIr() throws Exception + void shouldEncodeThenDecodeIr() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -61,7 +61,7 @@ public void shouldEncodeThenDecodeIr() throws Exception } @Test - public void shouldHandleRightSizedBuffer() throws Exception + void shouldHandleRightSizedBuffer() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -81,7 +81,7 @@ public void shouldHandleRightSizedBuffer() throws Exception } @Test - public void shouldDecodeFrame() throws Exception + void shouldDecodeFrame() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "code-generation-schema.xml"), ParserOptions.DEFAULT); @@ -104,7 +104,7 @@ public void shouldDecodeFrame() throws Exception } @Test - public void shouldDecodeHeader() throws Exception + void shouldDecodeHeader() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "code-generation-schema.xml"), ParserOptions.DEFAULT); @@ -128,7 +128,7 @@ public void shouldDecodeHeader() throws Exception } @Test - public void shouldDecodeMessagesAndTypes() throws Exception + void shouldDecodeMessagesAndTypes() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "code-generation-schema.xml"), ParserOptions.DEFAULT); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java index 2ec78f51db..83a274dbd3 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java @@ -28,10 +28,10 @@ import static uk.co.real_logic.sbe.Tests.getLocalResource; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class GroupWithDataIrTest +class GroupWithDataIrTest { @Test - public void shouldGenerateIrForSingleVarDataInRepeatingGroup() throws Exception + void shouldGenerateIrForSingleVarDataInRepeatingGroup() throws Exception { final MessageSchema schema = parse(getLocalResource("group-with-data-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -72,7 +72,7 @@ public void shouldGenerateIrForSingleVarDataInRepeatingGroup() throws Exception } @Test - public void shouldGenerateIrForMultipleVarDataInRepeatingGroup() throws Exception + void shouldGenerateIrForMultipleVarDataInRepeatingGroup() throws Exception { final MessageSchema schema = parse(getLocalResource("group-with-data-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -100,7 +100,7 @@ public void shouldGenerateIrForMultipleVarDataInRepeatingGroup() throws Exceptio } @Test - public void shouldGenerateIrForVarDataInNestedRepeatingGroup() throws Exception + void shouldGenerateIrForVarDataInNestedRepeatingGroup() throws Exception { final MessageSchema schema = parse(getLocalResource("group-with-data-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -132,7 +132,7 @@ public void shouldGenerateIrForVarDataInNestedRepeatingGroup() throws Exception } @Test - public void shouldGenerateIrForOnlyMultipleVarDataInRepeatingGroup() throws Exception + void shouldGenerateIrForOnlyMultipleVarDataInRepeatingGroup() throws Exception { final MessageSchema schema = parse(getLocalResource("group-with-data-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java new file mode 100644 index 0000000000..073ffca2f2 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.ir; + +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static uk.co.real_logic.sbe.Tests.getLocalResource; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +class SinceVersionValidationTest +{ + @Test + void shouldErrorOnTypeWithGreaterSinceVersion() throws Exception + { + try + { + final ParserOptions options = ParserOptions.builder().suppressOutput(true).build(); + parse(getLocalResource("error-handler-since-version.xml"), options); + } + catch (final IllegalStateException ex) + { + assertEquals("had 5 errors", ex.getMessage()); + return; + } + + fail("expected IllegalStateException"); + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java index 9ff34d4d5d..eee71d141c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java @@ -25,10 +25,10 @@ import static uk.co.real_logic.sbe.Tests.getLocalResource; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class ValueRefsTest +class ValueRefsTest { @Test - public void shouldGenerateValueRefToEnum() throws Exception + void shouldGenerateValueRefToEnum() throws Exception { final MessageSchema schema = parse(getLocalResource("value-ref-schema.xml"), ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java index 6fa1006086..4d2c9e597f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java @@ -34,13 +34,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class JsonPrinterTest extends EncodedCarTestBase +class JsonPrinterTest extends EncodedCarTestBase { private static final int SCHEMA_BUFFER_CAPACITY = 16 * 1024; private static final int MSG_BUFFER_CAPACITY = 4 * 1024; @Test - public void exampleMessagePrintedAsJson() throws Exception + void exampleMessagePrintedAsJson() throws Exception { final ByteBuffer encodedSchemaBuffer = ByteBuffer.allocate(SCHEMA_BUFFER_CAPACITY); encodeSchema(encodedSchemaBuffer); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java index 4278f91f60..a0b7ef5ae4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java @@ -15,48 +15,43 @@ */ package uk.co.real_logic.sbe.xml; -import java.util.List; - import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import java.util.List; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class BasicSchemaFileTest +class BasicSchemaFileTest { @Test - public void shouldHandleBasicFile() - throws Exception + void shouldHandleBasicFile() throws Exception { parse(Tests.getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); } @Test - public void shouldHandleConstantHeaderField() - throws Exception + void shouldHandleConstantHeaderField() throws Exception { parse(Tests.getLocalResource("basic-schema-constant-header-field.xml"), ParserOptions.DEFAULT); } @Test - public void shouldHandleBasicFileWithGroup() - throws Exception + void shouldHandleBasicFileWithGroup() throws Exception { parse(Tests.getLocalResource("basic-group-schema.xml"), ParserOptions.DEFAULT); } @Test - public void shouldHandleBasicFileWithVariableLengthData() - throws Exception + void shouldHandleBasicFileWithVariableLengthData() throws Exception { parse(Tests.getLocalResource("basic-variable-length-schema.xml"), ParserOptions.DEFAULT); } @Test - public void shouldHandleBasicAllTypes() - throws Exception + void shouldHandleBasicAllTypes() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource("basic-types-schema.xml"), ParserOptions.DEFAULT); final List fields = schema.getMessage(1).fields(); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java index 6c00ca511f..0b29b1bcf2 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java @@ -24,10 +24,10 @@ import static org.hamcrest.core.Is.is; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class CompositeElementsTest +class CompositeElementsTest { @Test - public void shouldParseSchemaSuccessfully() throws Exception + void shouldParseSchemaSuccessfully() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "composite-elements-schema.xml"), ParserOptions.DEFAULT); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java index ee59e45644..f8c3a3aa8a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java @@ -37,10 +37,10 @@ import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.*; -public class CompositeTypeTest +class CompositeTypeTest { @Test - public void shouldHandleDecimalCompositeType() throws Exception + void shouldHandleDecimalCompositeType() throws Exception { final String testXmlString = "" + @@ -64,7 +64,7 @@ public void shouldHandleDecimalCompositeType() throws Exception } @Test - public void shouldHandleDecimal32CompositeType() throws Exception + void shouldHandleDecimal32CompositeType() throws Exception { final String testXmlString = "" + @@ -90,7 +90,7 @@ public void shouldHandleDecimal32CompositeType() throws Exception } @Test - public void shouldHandleDecimal64CompositeType() throws Exception + void shouldHandleDecimal64CompositeType() throws Exception { final String testXmlString = "" + @@ -115,7 +115,7 @@ public void shouldHandleDecimal64CompositeType() throws Exception } @Test - public void shouldHandleCompositeTypeList() throws Exception + void shouldHandleCompositeTypeList() throws Exception { final String testXmlString = "" + @@ -134,7 +134,7 @@ public void shouldHandleCompositeTypeList() throws Exception } @Test - public void shouldHandleCompositeHasNullableType() throws Exception + void shouldHandleCompositeHasNullableType() throws Exception { final String nullValStr = "9223372036854775807"; final String testXmlString = @@ -155,7 +155,7 @@ public void shouldHandleCompositeHasNullableType() throws Exception } @Test - public void shouldThrowExceptionWhenCompositeTypeHasTypeNameDuplicates() + void shouldThrowExceptionWhenCompositeTypeHasTypeNameDuplicates() { final String testXmlString = "" + diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java index 7e10355e49..ca3a0d3dca 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java @@ -22,10 +22,10 @@ import static org.junit.jupiter.api.Assertions.fail; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class CyclicReferencesTest +class CyclicReferencesTest { @Test - public void shouldTestForCyclicRefs() throws Exception + void shouldTestForCyclicRefs() throws Exception { try { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java index 8b3b1dc9ed..a129c7ecc1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java @@ -25,10 +25,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class EmbeddedLengthAndCountFileTest +class EmbeddedLengthAndCountFileTest { @Test - public void shouldHandleEmbeddedCountForGroup() throws Exception + void shouldHandleEmbeddedCountForGroup() throws Exception { final MessageSchema schema = parse( Tests.getLocalResource("embedded-length-and-count-schema.xml"), ParserOptions.DEFAULT); @@ -43,7 +43,7 @@ public void shouldHandleEmbeddedCountForGroup() throws Exception } @Test - public void shouldHandleEmbeddedLengthForData() throws Exception + void shouldHandleEmbeddedLengthForData() throws Exception { parse(Tests.getLocalResource("embedded-length-and-count-schema.xml"), ParserOptions.DEFAULT); } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java index 008a3d8199..6763e2c50f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java @@ -39,10 +39,10 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static uk.co.real_logic.sbe.PrimitiveValue.parse; -public class EncodedDataTypeTest +class EncodedDataTypeTest { @Test - public void shouldHandleSettingAllAttributes() throws Exception + void shouldHandleSettingAllAttributes() throws Exception { final String testXmlString = "" + @@ -65,7 +65,7 @@ public void shouldHandleSettingAllAttributes() throws Exception } @Test - public void shouldHandleMultipleTypes() throws Exception + void shouldHandleMultipleTypes() throws Exception { final String testXmlString = "" + @@ -84,7 +84,7 @@ public void shouldHandleMultipleTypes() throws Exception } @Test - public void shouldSetAppropriateDefaultsWhenNoneSpecified() throws Exception + void shouldSetAppropriateDefaultsWhenNoneSpecified() throws Exception { final String testXmlString = "" + @@ -104,7 +104,7 @@ public void shouldSetAppropriateDefaultsWhenNoneSpecified() throws Exception } @Test - public void shouldUseAppropriatePresence() throws Exception + void shouldUseAppropriatePresence() throws Exception { final String testXmlString = "" + @@ -123,7 +123,7 @@ public void shouldUseAppropriatePresence() throws Exception } @Test - public void shouldThrowExceptionWhenUnknownPresenceSpecified() + void shouldThrowExceptionWhenUnknownPresenceSpecified() { final String testXmlString = "" + @@ -134,7 +134,7 @@ public void shouldThrowExceptionWhenUnknownPresenceSpecified() } @Test - public void shouldThrowExceptionWhenNoPrimitiveTypeSpecified() + void shouldThrowExceptionWhenNoPrimitiveTypeSpecified() { final String testXmlString = "" + @@ -145,7 +145,7 @@ public void shouldThrowExceptionWhenNoPrimitiveTypeSpecified() } @Test - public void shouldThrowExceptionWhenNoNameSpecified() + void shouldThrowExceptionWhenNoNameSpecified() { final String testXmlString = "" + @@ -156,7 +156,7 @@ public void shouldThrowExceptionWhenNoNameSpecified() } @Test - public void shouldUseAppropriatePrimitiveType() throws Exception + void shouldUseAppropriatePrimitiveType() throws Exception { final String testXmlString = "" + @@ -189,7 +189,7 @@ public void shouldUseAppropriatePrimitiveType() throws Exception } @Test - public void shouldThrowExceptionWhenUnknownPrimitiveTypeSpecified() + void shouldThrowExceptionWhenUnknownPrimitiveTypeSpecified() { final String testXmlString = "" + @@ -201,7 +201,7 @@ public void shouldThrowExceptionWhenUnknownPrimitiveTypeSpecified() } @Test - public void shouldReturnCorrectSizeForPrimitiveTypes() throws Exception + void shouldReturnCorrectSizeForPrimitiveTypes() throws Exception { final String testXmlString = "" + @@ -233,7 +233,7 @@ public void shouldReturnCorrectSizeForPrimitiveTypes() throws Exception } @Test - public void shouldReturnCorrectDescriptionForType() throws Exception + void shouldReturnCorrectDescriptionForType() throws Exception { final String desc = "basic description attribute of a type element"; final String testXmlString = @@ -247,7 +247,7 @@ public void shouldReturnCorrectDescriptionForType() throws Exception } @Test - public void shouldReturnNullOnNoDescriptionSet() throws Exception + void shouldReturnNullOnNoDescriptionSet() throws Exception { final String testXmlString = "" + @@ -261,7 +261,7 @@ public void shouldReturnNullOnNoDescriptionSet() throws Exception } @Test - public void shouldReturnCorrectSemanticTypeForType() throws Exception + void shouldReturnCorrectSemanticTypeForType() throws Exception { final String semanticType = "char"; final String testXmlString = @@ -275,7 +275,7 @@ public void shouldReturnCorrectSemanticTypeForType() throws Exception } @Test - public void shouldReturnNullWhenSemanticTypeNotSpecified() throws Exception + void shouldReturnNullWhenSemanticTypeNotSpecified() throws Exception { final String testXmlString = "" + @@ -288,7 +288,7 @@ public void shouldReturnNullWhenSemanticTypeNotSpecified() throws Exception } @Test - public void shouldThrowExceptionWhenConstantPresenceButNoDataSpecified() + void shouldThrowExceptionWhenConstantPresenceButNoDataSpecified() { final String testXmlString = "" + @@ -299,7 +299,7 @@ public void shouldThrowExceptionWhenConstantPresenceButNoDataSpecified() } @Test - public void shouldReturnCorrectPresenceConstantWhenSpecified() throws Exception + void shouldReturnCorrectPresenceConstantWhenSpecified() throws Exception { final String testXmlString = "" + @@ -314,7 +314,7 @@ public void shouldReturnCorrectPresenceConstantWhenSpecified() throws Exception } @Test - public void shouldReturnCorrectConstantStringWhenSpecified() throws Exception + void shouldReturnCorrectConstantStringWhenSpecified() throws Exception { final String strConst = "string constant"; final String testXmlString = @@ -331,7 +331,7 @@ public void shouldReturnCorrectConstantStringWhenSpecified() throws Exception } @Test - public void shouldReturnDefaultMinValueWhenSpecified() throws Exception + void shouldReturnDefaultMinValueWhenSpecified() throws Exception { final String testXmlString = "" + @@ -344,7 +344,7 @@ public void shouldReturnDefaultMinValueWhenSpecified() throws Exception } @Test - public void shouldReturnDefaultMaxValueWhenSpecified() throws Exception + void shouldReturnDefaultMaxValueWhenSpecified() throws Exception { final String testXmlString = "" + @@ -357,7 +357,7 @@ public void shouldReturnDefaultMaxValueWhenSpecified() throws Exception } @Test - public void shouldReturnDefaultNullValueWhenSpecified() throws Exception + void shouldReturnDefaultNullValueWhenSpecified() throws Exception { final String testXmlString = "" + @@ -370,7 +370,7 @@ public void shouldReturnDefaultNullValueWhenSpecified() throws Exception } @Test - public void shouldReturnCorrectMinValueWhenSpecified() throws Exception + void shouldReturnCorrectMinValueWhenSpecified() throws Exception { final String minVal = "10"; final String testXmlString = @@ -384,7 +384,7 @@ public void shouldReturnCorrectMinValueWhenSpecified() throws Exception } @Test - public void shouldReturnCorrectMaxValueWhenSpecified() throws Exception + void shouldReturnCorrectMaxValueWhenSpecified() throws Exception { final String maxVal = "10"; final String testXmlString = @@ -399,7 +399,7 @@ public void shouldReturnCorrectMaxValueWhenSpecified() throws Exception } @Test - public void shouldReturnCorrectNullValueWhenSpecified() throws Exception + void shouldReturnCorrectNullValueWhenSpecified() throws Exception { final String nullVal = "10"; final String testXmlString = @@ -415,7 +415,7 @@ public void shouldReturnCorrectNullValueWhenSpecified() throws Exception } @Test - public void shouldReturnCharacterEncodingWhenSpecified() throws Exception + void shouldReturnCharacterEncodingWhenSpecified() throws Exception { final String testXmlString = "" + @@ -429,7 +429,7 @@ public void shouldReturnCharacterEncodingWhenSpecified() throws Exception } @Test - public void shouldReturnCharacterEncodingWhenSpecifiedNonCharType() throws Exception + void shouldReturnCharacterEncodingWhenSpecifiedNonCharType() throws Exception { final String testXmlString = "" + @@ -444,7 +444,7 @@ public void shouldReturnCharacterEncodingWhenSpecifiedNonCharType() throws Excep } @Test - public void shouldReturnUsAsciiWhenCharacterEncodingNotSpecifiedForTypeChar() throws Exception + void shouldReturnUsAsciiWhenCharacterEncodingNotSpecifiedForTypeChar() throws Exception { final String testXmlString = "" + diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java index 0a13521102..ec6162f05d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java @@ -43,10 +43,10 @@ import static org.junit.jupiter.api.Assertions.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class EnumTypeTest +class EnumTypeTest { @Test - public void shouldHandleBinaryEnumType() throws Exception + void shouldHandleBinaryEnumType() throws Exception { final String testXmlString = "" + @@ -67,7 +67,7 @@ public void shouldHandleBinaryEnumType() throws Exception } @Test - public void shouldHandleBooleanEnumType() throws Exception + void shouldHandleBooleanEnumType() throws Exception { final String testXmlString = "" + @@ -88,7 +88,7 @@ public void shouldHandleBooleanEnumType() throws Exception } @Test - public void shouldHandleOptionalBooleanEnumType() throws Exception + void shouldHandleOptionalBooleanEnumType() throws Exception { final String nullValueStr = "255"; final String testXmlString = @@ -112,7 +112,7 @@ public void shouldHandleOptionalBooleanEnumType() throws Exception } @Test - public void shouldHandleEnumTypeList() throws Exception + void shouldHandleEnumTypeList() throws Exception { final String testXmlString = "" + @@ -156,7 +156,7 @@ public void shouldHandleEnumTypeList() throws Exception } @Test - public void shouldHandleCharEnumEncodingType() throws Exception + void shouldHandleCharEnumEncodingType() throws Exception { final String testXmlString = "" + @@ -179,7 +179,7 @@ public void shouldHandleCharEnumEncodingType() throws Exception } @Test - public void shouldThrowExceptionWhenIllegalEncodingTypeSpecified() + void shouldThrowExceptionWhenIllegalEncodingTypeSpecified() { final String testXmlString = "" + @@ -194,7 +194,7 @@ public void shouldThrowExceptionWhenIllegalEncodingTypeSpecified() } @Test - public void shouldThrowExceptionWhenDuplicateValueSpecified() + void shouldThrowExceptionWhenDuplicateValueSpecified() { final String testXmlString = "" + @@ -210,7 +210,7 @@ public void shouldThrowExceptionWhenDuplicateValueSpecified() } @Test - public void shouldThrowExceptionWhenDuplicateNameSpecified() + void shouldThrowExceptionWhenDuplicateNameSpecified() { final String testXmlString = "" + @@ -226,7 +226,7 @@ public void shouldThrowExceptionWhenDuplicateNameSpecified() } @Test - public void shouldThrowExceptionWhenImplicitNullValueIsUsed() + void shouldThrowExceptionWhenImplicitNullValueIsUsed() { final String testXmlString = "" + @@ -241,7 +241,7 @@ public void shouldThrowExceptionWhenImplicitNullValueIsUsed() } @Test - public void shouldThrowExceptionWhenExplicitNullValueIsUsed() + void shouldThrowExceptionWhenExplicitNullValueIsUsed() { final String testXmlString = "" + @@ -257,7 +257,7 @@ public void shouldThrowExceptionWhenExplicitNullValueIsUsed() @ParameterizedTest @ValueSource(longs = { (long)Integer.MIN_VALUE - 1, (long)Integer.MAX_VALUE + 1 }) - public void shouldThrowExceptionWhenIntValueIsOutOfRange(final long value) + void shouldThrowExceptionWhenIntValueIsOutOfRange(final long value) { final String testXmlString = "" + @@ -272,7 +272,7 @@ public void shouldThrowExceptionWhenIntValueIsOutOfRange(final long value) } @Test - public void shouldThrowExceptionIfEnumValueIsOutOfCustomValueRange() throws IOException + void shouldThrowExceptionIfEnumValueIsOutOfCustomValueRange() throws IOException { final InputStream file = Tests.getLocalResource("error-handler-enum-violates-min-max-value-range.xml"); final IllegalStateException exception = assertThrows(IllegalStateException.class, @@ -281,7 +281,7 @@ public void shouldThrowExceptionIfEnumValueIsOutOfCustomValueRange() throws IOEx } @Test - public void shouldHandleEncodingTypesWithNamedTypes() throws Exception + void shouldHandleEncodingTypesWithNamedTypes() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "encoding-types-schema.xml"), ParserOptions.DEFAULT); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java index 405a63e902..0f75157955 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java @@ -41,10 +41,10 @@ import static org.junit.jupiter.api.Assertions.fail; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class ErrorHandlerTest +class ErrorHandlerTest { @Test - public void shouldNotExitOnTypeErrorsAndWarnings() throws Exception + void shouldNotExitOnTypeErrorsAndWarnings() throws Exception { final String testXmlString = "" + @@ -93,7 +93,7 @@ public void shouldNotExitOnTypeErrorsAndWarnings() throws Exception } @Test - public void shouldExitAfterTypes() throws Exception + void shouldExitAfterTypes() throws Exception { try { @@ -110,7 +110,7 @@ public void shouldExitAfterTypes() throws Exception } @Test - public void shouldExitAfterTypesWhenDupTypesDefined() throws Exception + void shouldExitAfterTypesWhenDupTypesDefined() throws Exception { try { @@ -119,7 +119,7 @@ public void shouldExitAfterTypesWhenDupTypesDefined() throws Exception } catch (final IllegalStateException ex) { - assertEquals("had 1 warnings", ex.getMessage()); + assertEquals("had 1 warning", ex.getMessage()); return; } @@ -127,7 +127,7 @@ public void shouldExitAfterTypesWhenDupTypesDefined() throws Exception } @Test - public void shouldExitAfterMessageWhenDupMessageIdsDefined() throws Exception + void shouldExitAfterMessageWhenDupMessageIdsDefined() throws Exception { try { @@ -136,7 +136,7 @@ public void shouldExitAfterMessageWhenDupMessageIdsDefined() throws Exception } catch (final IllegalStateException ex) { - assertEquals("had 1 errors", ex.getMessage()); + assertEquals("had 1 error", ex.getMessage()); return; } @@ -144,7 +144,7 @@ public void shouldExitAfterMessageWhenDupMessageIdsDefined() throws Exception } @Test - public void shouldExitAfterMessage() throws Exception + void shouldExitAfterMessage() throws Exception { try { @@ -161,7 +161,7 @@ public void shouldExitAfterMessage() throws Exception } @Test - public void shouldExitAfterMessageWhenGroupDimensionsNotComposite() throws Exception + void shouldExitAfterMessageWhenGroupDimensionsNotComposite() throws Exception { try { @@ -170,7 +170,7 @@ public void shouldExitAfterMessageWhenGroupDimensionsNotComposite() throws Excep } catch (final IllegalStateException ex) { - assertEquals("had 1 errors", ex.getMessage()); + assertEquals("had 1 error", ex.getMessage()); return; } @@ -178,7 +178,7 @@ public void shouldExitAfterMessageWhenGroupDimensionsNotComposite() throws Excep } @Test - public void shouldExitAfterTypesWhenCompositeOffsetsIncorrect() throws Exception + void shouldExitAfterTypesWhenCompositeOffsetsIncorrect() throws Exception { try { @@ -195,7 +195,7 @@ public void shouldExitAfterTypesWhenCompositeOffsetsIncorrect() throws Exception } @Test - public void shouldExitAfterTypesWhenCompositeHasInvalidTypes() throws Exception + void shouldExitAfterTypesWhenCompositeHasInvalidTypes() throws Exception { try { @@ -212,7 +212,7 @@ public void shouldExitAfterTypesWhenCompositeHasInvalidTypes() throws Exception } @Test - public void shouldExitInvalidFieldNames() throws Exception + void shouldExitInvalidFieldNames() throws Exception { try { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java index dd25ca3caf..ac203c3693 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java @@ -25,10 +25,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class GroupWithDataTest +class GroupWithDataTest { @Test - public void shouldParseSchemaSuccessfully() throws Exception + void shouldParseSchemaSuccessfully() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "group-with-data-schema.xml"), ParserOptions.DEFAULT); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java index 8ddc6f620d..18176fb7b4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java @@ -28,10 +28,10 @@ /* * Tests associated with offset and blockLength calculation and validation */ -public class OffsetFileTest +class OffsetFileTest { @Test - public void shouldHandleAllTypeOffsets() throws Exception + void shouldHandleAllTypeOffsets() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "basic-types-schema.xml"), ParserOptions.DEFAULT); @@ -50,7 +50,7 @@ public void shouldHandleAllTypeOffsets() throws Exception } @Test - public void shouldHandleAllTypeOffsetsSetByXml() throws Exception + void shouldHandleAllTypeOffsetsSetByXml() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "basic-types-schema.xml"), ParserOptions.DEFAULT); @@ -69,7 +69,7 @@ public void shouldHandleAllTypeOffsetsSetByXml() throws Exception } @Test - public void shouldCalculateGroupOffsetWithNoPaddingFromBlockLength() throws Exception + void shouldCalculateGroupOffsetWithNoPaddingFromBlockLength() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "block-length-schema.xml"), ParserOptions.DEFAULT); @@ -92,7 +92,7 @@ public void shouldCalculateGroupOffsetWithNoPaddingFromBlockLength() throws Exce } @Test - public void shouldCalculateGroupOffsetWithPaddingFromBlockLength() throws Exception + void shouldCalculateGroupOffsetWithPaddingFromBlockLength() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "block-length-schema.xml"), ParserOptions.DEFAULT); @@ -114,7 +114,7 @@ public void shouldCalculateGroupOffsetWithPaddingFromBlockLength() throws Except } @Test - public void shouldCalculateGroupOffsetWithPaddingFromBlockLengthAndGroupBlockLength() throws Exception + void shouldCalculateGroupOffsetWithPaddingFromBlockLengthAndGroupBlockLength() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "block-length-schema.xml"), ParserOptions.DEFAULT); @@ -136,7 +136,7 @@ public void shouldCalculateGroupOffsetWithPaddingFromBlockLengthAndGroupBlockLen } @Test - public void shouldCalculateDataOffsetWithPaddingFromBlockLength() throws Exception + void shouldCalculateDataOffsetWithPaddingFromBlockLength() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "block-length-schema.xml"), ParserOptions.DEFAULT); @@ -149,7 +149,7 @@ public void shouldCalculateDataOffsetWithPaddingFromBlockLength() throws Excepti } @Test - public void shouldCalculateCompositeSizeWithOffsetsSpecified() throws Exception + void shouldCalculateCompositeSizeWithOffsetsSpecified() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "composite-offsets-schema.xml"), ParserOptions.DEFAULT); @@ -159,7 +159,7 @@ public void shouldCalculateCompositeSizeWithOffsetsSpecified() throws Exception } @Test - public void shouldCalculateDimensionSizeWithOffsetsSpecified() throws Exception + void shouldCalculateDimensionSizeWithOffsetsSpecified() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "composite-offsets-schema.xml"), ParserOptions.DEFAULT); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java index 1fa997c138..bde5d84164 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java @@ -24,10 +24,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class RelativeXIncludeTest +class RelativeXIncludeTest { @Test - public void shouldParseFileInSubDir() throws Exception + void shouldParseFileInSubDir() throws Exception { final URL testResource = getClass().getClassLoader().getResource("sub/basic-schema.xml"); assertNotNull(testResource); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java index 0911c8f9d1..c57bddddde 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java @@ -41,10 +41,10 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class SetTypeTest +class SetTypeTest { @Test - public void shouldHandleBinarySetType() throws Exception + void shouldHandleBinarySetType() throws Exception { final String testXmlString = "" + @@ -65,7 +65,7 @@ public void shouldHandleBinarySetType() throws Exception } @Test - public void shouldHandleSetTypeList() throws Exception + void shouldHandleSetTypeList() throws Exception { final String testXmlString = "" + @@ -115,7 +115,7 @@ public void shouldHandleSetTypeList() throws Exception } @Test - public void shouldThrowExceptionWhenIllegalEncodingTypeSpecified() + void shouldThrowExceptionWhenIllegalEncodingTypeSpecified() { final String testXmlString = "" + @@ -130,7 +130,7 @@ public void shouldThrowExceptionWhenIllegalEncodingTypeSpecified() } @Test - public void shouldThrowExceptionWhenDuplicateValueSpecified() + void shouldThrowExceptionWhenDuplicateValueSpecified() { final String testXmlString = "" + @@ -145,7 +145,7 @@ public void shouldThrowExceptionWhenDuplicateValueSpecified() } @Test - public void shouldThrowExceptionWhenDuplicateNameSpecified() + void shouldThrowExceptionWhenDuplicateNameSpecified() { final String testXmlString = "" + @@ -160,7 +160,7 @@ public void shouldThrowExceptionWhenDuplicateNameSpecified() } @Test - public void shouldThrowExceptionWhenValueOutOfBoundsSpecified() + void shouldThrowExceptionWhenValueOutOfBoundsSpecified() { final String testXmlString = "" + @@ -175,7 +175,7 @@ public void shouldThrowExceptionWhenValueOutOfBoundsSpecified() } @Test - public void shouldHandleEncodingTypesWithNamedTypes() throws Exception + void shouldHandleEncodingTypesWithNamedTypes() throws Exception { final MessageSchema schema = parse(Tests.getLocalResource( "encoding-types-schema.xml"), ParserOptions.DEFAULT); diff --git a/sbe-tool/src/test/resources/error-handler-since-version.xml b/sbe-tool/src/test/resources/error-handler-since-version.xml new file mode 100644 index 0000000000..3eac105f08 --- /dev/null +++ b/sbe-tool/src/test/resources/error-handler-since-version.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c93cdea495abe280e5328b5a4156c6d4ba5791f7 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 21 Jun 2022 15:52:56 +0100 Subject: [PATCH 097/805] [Java] Formatting. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2358dcaae3..52b2c4861a 100644 --- a/build.gradle +++ b/build.gradle @@ -869,7 +869,7 @@ class ChecksumTask extends DefaultTask { if (CR == raw[j] && (j == size - 1 || LF == raw[j + 1])) { - continue; + continue } result[i++] = raw[j] From 6afe100b0d1cee2fe0972716231ee3683939c57f Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sun, 26 Jun 2022 16:03:17 +0100 Subject: [PATCH 098/805] [C++] Type. --- sbe-tool/src/test/cpp/Issue889Test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/test/cpp/Issue889Test.cpp b/sbe-tool/src/test/cpp/Issue889Test.cpp index 1b0c67433d..42c87b1720 100644 --- a/sbe-tool/src/test/cpp/Issue889Test.cpp +++ b/sbe-tool/src/test/cpp/Issue889Test.cpp @@ -24,7 +24,7 @@ class Issue889Test : public testing::Test { }; -TEST_F(Issue889Test, shouldGenerateSpecalisedNullValue) +TEST_F(Issue889Test, shouldGenerateSpecialisedNullValue) { EXPECT_EQ(LotType::get(0), LotType::NULL_VALUE); } From 57dd44d12b751d5d4c02d868faf85f719062df9c Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sun, 26 Jun 2022 16:25:36 +0100 Subject: [PATCH 099/805] [C++] Use universal ref in forEach and set min to C++11. Issue #903. --- .../sbe/generation/cpp/CppGenerator.java | 27 +++++-------------- sbe-tool/src/test/cpp/Issue835Test.cpp | 11 ++++++++ 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 17bbcebd4d..4f2d56a5cc 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -378,17 +378,6 @@ private static void generateGroupClassHeader( .append(indent).append(" }\n"); sb.append("\n") - .append(indent).append("#if __cplusplus < 201103L\n") - .append(indent).append(" template inline void forEach(Func &func)\n") - .append(indent).append(" {\n") - .append(indent).append(" while (hasNext())\n") - .append(indent).append(" {\n") - .append(indent).append(" next();\n") - .append(indent).append(" func(*this);\n") - .append(indent).append(" }\n") - .append(indent).append(" }\n\n") - - .append(indent).append("#else\n") .append(indent).append(" template inline void forEach(Func &&func)\n") .append(indent).append(" {\n") .append(indent).append(" while (hasNext())\n") @@ -396,9 +385,7 @@ private static void generateGroupClassHeader( .append(indent).append(" next();\n") .append(indent).append(" func(*this);\n") .append(indent).append(" }\n") - .append(indent).append(" }\n\n") - - .append(indent).append("#endif\n"); + .append(indent).append(" }\n\n"); } private static void generateGroupProperty( @@ -2655,20 +2642,19 @@ private CharSequence appendDisplay( new Formatter(sb).format( indent + "{\n" + indent + " bool atLeastOne = false;\n" + - indent + " builder << R\"(\"%3$s\": [)\";\n" + - indent + " writer.%2$s().forEach(\n" + - indent + " [&](%1$s &%2$s)\n" + + indent + " builder << R\"(\"%2$s\": [)\";\n" + + indent + " writer.%1$s().forEach(\n" + + indent + " [&](auto &&%1$s)\n" + indent + " {\n" + indent + " if (atLeastOne)\n" + indent + " {\n" + indent + " builder << \", \";\n" + indent + " }\n" + indent + " atLeastOne = true;\n" + - indent + " builder << %2$s;\n" + + indent + " builder << %1$s;\n" + indent + " });\n" + indent + " builder << ']';\n" + indent + "}\n\n", - formatClassName(groupToken.name()), formatPropertyName(groupToken.name()), groupToken.name()); @@ -3122,8 +3108,7 @@ private CharSequence generateMessageLength(final List groups, final List< } new Formatter(sbSkip).format( - indent + " %2$s().forEach([](%1$s &e){ e.skip(); });\n", - formatClassName(groupToken.name()), + indent + " %1$s().forEach([](auto &&e){ e.skip(); });\n", formatPropertyName(groupToken.name())); i = endSignal; diff --git a/sbe-tool/src/test/cpp/Issue835Test.cpp b/sbe-tool/src/test/cpp/Issue835Test.cpp index dfac7a7115..b22fdf9277 100644 --- a/sbe-tool/src/test/cpp/Issue835Test.cpp +++ b/sbe-tool/src/test/cpp/Issue835Test.cpp @@ -69,4 +69,15 @@ TEST_F(Issue835Test, shouldCompileWithSkipper) BUFFER_LEN); EXPECT_EQ(decoder.decodeLength(), encoder.encodedLength()); + + MDIncrementalRefreshOrderBook47 decoder2; + decoder2.wrapForDecode( + buffer, + offset, + MDIncrementalRefreshOrderBook47::sbeBlockLength(), + MDIncrementalRefreshOrderBook47::sbeSchemaVersion(), + BUFFER_LEN); + + decoder2.skip(); + EXPECT_EQ(decoder2.encodedLength(), encoder.encodedLength()); } From d5966bf97f5f88660de5440bf4ca823a401d732e Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sun, 26 Jun 2022 16:36:12 +0100 Subject: [PATCH 100/805] [C++] Revert use of auto in lambdas. Issue #903. --- .../real_logic/sbe/generation/cpp/CppGenerator.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 4f2d56a5cc..24c6b07038 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -2642,19 +2642,20 @@ private CharSequence appendDisplay( new Formatter(sb).format( indent + "{\n" + indent + " bool atLeastOne = false;\n" + - indent + " builder << R\"(\"%2$s\": [)\";\n" + - indent + " writer.%1$s().forEach(\n" + - indent + " [&](auto &&%1$s)\n" + + indent + " builder << R\"(\"%3$s\": [)\";\n" + + indent + " writer.%2$s().forEach(\n" + + indent + " [&](%1$s &%2$s)\n" + indent + " {\n" + indent + " if (atLeastOne)\n" + indent + " {\n" + indent + " builder << \", \";\n" + indent + " }\n" + indent + " atLeastOne = true;\n" + - indent + " builder << %1$s;\n" + + indent + " builder << %2$s;\n" + indent + " });\n" + indent + " builder << ']';\n" + indent + "}\n\n", + formatClassName(groupToken.name()), formatPropertyName(groupToken.name()), groupToken.name()); @@ -3108,7 +3109,8 @@ private CharSequence generateMessageLength(final List groups, final List< } new Formatter(sbSkip).format( - indent + " %1$s().forEach([](auto &&e){ e.skip(); });\n", + indent + " %2$s().forEach([](%1$s &e){ e.skip(); });\n", + formatClassName(groupToken.name()), formatPropertyName(groupToken.name())); i = endSignal; From cc441b034a02b8efa4c75f6a2ef9ef33e6565115 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sun, 26 Jun 2022 17:35:22 +0100 Subject: [PATCH 101/805] [C++] Generate skip function without use of lambdas or templates. Issue #903. --- .../uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 24c6b07038..23ffeb642b 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -3109,8 +3109,11 @@ private CharSequence generateMessageLength(final List groups, final List< } new Formatter(sbSkip).format( - indent + " %2$s().forEach([](%1$s &e){ e.skip(); });\n", - formatClassName(groupToken.name()), + indent + (" auto &%1$sGroup { %1$s() };\n") + + indent + (" while (%1$sGroup.hasNext())\n") + + indent + (" {\n") + + indent + (" %1$sGroup.next().skip();\n") + + indent + (" }\n"), formatPropertyName(groupToken.name())); i = endSignal; From b0f91d55a3152a1b91dec107f47b56a4174e3263 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 27 Jun 2022 17:05:26 +0100 Subject: [PATCH 102/805] [Java] Upgrade to Agrona 1.16.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 52b2c4861a..a485cfb9c6 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.6.1' def junitVersion = '5.8.2' def jmhVersion = '1.35' -def agronaVersion = '1.15.2' +def agronaVersion = '1.16.0' def agronaVersionRange = '[1.15.2,2.0[' // allow any release >= 1.15.2 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' From 8aa6caea7c0cea0ccb5273f30b9ef6a87893e9ae Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sun, 10 Jul 2022 16:11:33 +0100 Subject: [PATCH 103/805] [Java] Provide raw access to field containing a bitset via a getRaw() method on the generated bitset decoder. Issue #893. --- .../sbe/generation/cpp/CppGenerator.java | 14 +++++----- .../sbe/generation/java/JavaGenerator.java | 26 ++++++++++++++----- .../sbe/generation/rust/RustGenerator.java | 5 ++-- version.txt | 2 +- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 23ffeb642b..95151c7106 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -706,14 +706,16 @@ private void generateVarDataDescriptors( private void generateChoiceSet(final List tokens) throws IOException { - final String bitSetName = formatClassName(tokens.get(0).applicableTypeName()); + final Token token = tokens.get(0); + final String bitSetName = formatClassName(token.applicableTypeName()); try (Writer out = outputManager.createOutput(bitSetName)) { out.append(generateFileHeader(ir.namespaces(), bitSetName, null)); out.append(generateClassDeclaration(bitSetName)); - out.append(generateFixedFlyweightCode(bitSetName, tokens.get(0).encodedLength())); + out.append(generateFixedFlyweightCode(bitSetName, token.encodedLength())); + final Encoding encoding = token.encoding(); new Formatter(out).format("\n" + " %1$s &clear()\n" + " {\n" + @@ -722,7 +724,7 @@ private void generateChoiceSet(final List tokens) throws IOException " return *this;\n" + " }\n", bitSetName, - cppTypeName(tokens.get(0).encoding().primitiveType())); + cppTypeName(encoding.primitiveType())); new Formatter(out).format("\n" + " SBE_NODISCARD bool isEmpty() const\n" + @@ -731,7 +733,7 @@ private void generateChoiceSet(final List tokens) throws IOException " std::memcpy(&val, m_buffer + m_offset, sizeof(%1$s));\n" + " return 0 == val;\n" + " }\n", - cppTypeName(tokens.get(0).encoding().primitiveType())); + cppTypeName(encoding.primitiveType())); new Formatter(out).format("\n" + " SBE_NODISCARD %1$s rawValue() const\n" + @@ -740,7 +742,7 @@ private void generateChoiceSet(final List tokens) throws IOException " std::memcpy(&val, m_buffer + m_offset, sizeof(%1$s));\n" + " return val;\n" + " }\n", - cppTypeName(tokens.get(0).encoding().primitiveType())); + cppTypeName(encoding.primitiveType())); new Formatter(out).format("\n" + " %1$s &rawValue(%2$s value)\n" + @@ -749,7 +751,7 @@ private void generateChoiceSet(final List tokens) throws IOException " return *this;\n" + " }\n", bitSetName, - cppTypeName(tokens.get(0).encoding().primitiveType())); + cppTypeName(encoding.primitiveType())); out.append(generateChoices(bitSetName, tokens.subList(1, tokens.size() - 1))); out.append(generateChoicesDisplay(bitSetName, tokens.subList(1, tokens.size() - 1))); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index d9ed796c4c..ef0ffe667c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1185,15 +1185,26 @@ private void generateBitSet(final List tokens) throws IOException final String bitSetName = token.applicableTypeName(); final String decoderName = decoderName(bitSetName); final String encoderName = encoderName(bitSetName); - final List messageBody = getMessageBody(tokens); + final List choiceList = tokens.subList(1, tokens.size() - 1); final String implementsString = implementsInterface(Flyweight.class.getSimpleName()); try (Writer out = outputManager.createOutput(decoderName)) { + final Encoding encoding = token.encoding(); generateFixedFlyweightHeader(out, token, decoderName, implementsString, readOnlyBuffer, fqReadOnlyBuffer); - out.append(generateChoiceIsEmpty(token.encoding().primitiveType())); - generateChoiceDecoders(out, messageBody); - out.append(generateChoiceDisplay(messageBody)); + out.append(generateChoiceIsEmpty(encoding.primitiveType())); + + new Formatter(out).format( + "\n" + + " public %s getRaw()\n" + + " {\n" + + " return %s;\n" + + " }\n", + primitiveTypeName(token), + generateGet(encoding.primitiveType(), "offset", byteOrderString(encoding))); + + generateChoiceDecoders(out, choiceList); + out.append(generateChoiceDisplay(choiceList)); out.append("}\n"); } @@ -1201,7 +1212,7 @@ private void generateBitSet(final List tokens) throws IOException { generateFixedFlyweightHeader(out, token, encoderName, implementsString, mutableBuffer, fqMutableBuffer); generateChoiceClear(out, encoderName, token); - generateChoiceEncoders(out, encoderName, messageBody); + generateChoiceEncoders(out, encoderName, choiceList); out.append("}\n"); } } @@ -1244,10 +1255,11 @@ private void generateEnum(final List tokens) throws IOException out.append(generateEnumFileHeader(ir.applicableNamespace())); out.append(generateEnumDeclaration(enumName, enumToken)); - out.append(generateEnumValues(getMessageBody(tokens), generateLiteral(encoding.primitiveType(), nullVal))); + final List valuesList = tokens.subList(1, tokens.size() - 1); + out.append(generateEnumValues(valuesList, generateLiteral(encoding.primitiveType(), nullVal))); out.append(generateEnumBody(enumToken, enumName)); - out.append(generateEnumLookupMethod(getMessageBody(tokens), enumName, nullVal)); + out.append(generateEnumLookupMethod(valuesList, enumName, nullVal)); out.append("}\n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 00417ec76d..e7e26bcc31 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -39,7 +39,6 @@ import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; -import static uk.co.real_logic.sbe.ir.GenerationUtil.getMessageBody; import static uk.co.real_logic.sbe.ir.Signal.BEGIN_ENUM; import static uk.co.real_logic.sbe.ir.Signal.BEGIN_SET; @@ -137,7 +136,7 @@ public void generate() throws IOException { final Token msgToken = tokens.get(0); final String codecModName = codecModName(msgToken.name()); - final List messageBody = getMessageBody(tokens); + final List messageBody = tokens.subList(1, tokens.size() - 1); int i = 0; final List fields = new ArrayList<>(); @@ -1175,7 +1174,7 @@ private static void generateEnum( { final String originalEnumName = enumTokens.get(0).applicableTypeName(); final String enumRustName = formatStructName(originalEnumName); - final List messageBody = getMessageBody(enumTokens); + final List messageBody = enumTokens.subList(1, enumTokens.size() - 1); if (messageBody.isEmpty()) { throw new IllegalArgumentException("No valid values provided for enum " + originalEnumName); diff --git a/version.txt b/version.txt index bda7b6dbcb..b4f8049e9c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.25.4-SNAPSHOT +1.26.0-SNAPSHOT From 9100ce6fc755d3bcbc5e856cf86f384efea50ed3 Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Mon, 11 Jul 2022 16:23:59 +0300 Subject: [PATCH 104/805] 1.26.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index b4f8049e9c..5ff8c4f5d2 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.26.0-SNAPSHOT +1.26.0 From 34d75191ee54decffcd6df38a90935f9416dd2bf Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Mon, 11 Jul 2022 16:25:15 +0300 Subject: [PATCH 105/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 5ff8c4f5d2..28509b3918 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.26.0 +1.26.1-SNAPSHOT From 4ac18d08821869df38c3de04e32547c071d98b45 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 26 Jul 2022 17:41:28 +0100 Subject: [PATCH 106/805] [Java] Set size for constant type to zero. --- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index 87e3e4717d..9ae856ca3b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -404,6 +404,7 @@ private void add(final EncodedDataType type, final int offset) break; case CONSTANT: + tokenBuilder.size(0); encodingBuilder .presence(Encoding.Presence.CONSTANT) .constValue(type.constVal()); From bca88499a57f8301818c563ae0b4ad32bbb4321c Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 26 Jul 2022 18:21:29 +0100 Subject: [PATCH 107/805] [Java] Carry down field sinceVersion into composite types to allow for more convenient OTF parsing. Issue #908. --- .../uk/co/real_logic/sbe/xml/IrGenerator.java | 50 ++++++++----------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index 9ae856ca3b..6ddf288605 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -208,22 +208,19 @@ private void add(final CompositeType type, final int currOffset, final Field fie .semanticType(semanticTypeOf(type, field)) .build(); + final int version = null != field ? Math.max(field.sinceVersion(), type.sinceVersion()) : type.sinceVersion(); + final Token.Builder builder = new Token.Builder() .signal(Signal.BEGIN_COMPOSITE) .name(type.name()) .referencedName(type.referencedName()) .offset(currOffset) .size(type.encodedLength()) - .version(type.sinceVersion()) + .version(version) .deprecated(type.deprecated()) .description(type.description()) .encoding(encoding); - if (null != field) - { - builder.version(Math.max(field.sinceVersion(), type.sinceVersion())); - } - tokenList.add(builder.build()); int offset = 0; @@ -236,19 +233,21 @@ private void add(final CompositeType type, final int currOffset, final Field fie if (elementType instanceof EncodedDataType) { - add((EncodedDataType)elementType, offset); + add((EncodedDataType)elementType, + offset, + null != field ? Math.max(field.sinceVersion(), type.sinceVersion()) : elementType.sinceVersion()); } else if (elementType instanceof EnumType) { - add((EnumType)elementType, offset, null); + add((EnumType)elementType, offset, field); } else if (elementType instanceof SetType) { - add((SetType)elementType, offset, null); + add((SetType)elementType, offset, field); } else if (elementType instanceof CompositeType) { - add((CompositeType)elementType, offset, null); + add((CompositeType)elementType, offset, field); } offset += elementType.encodedLength(); @@ -266,22 +265,19 @@ private void add(final EnumType type, final int offset, final Field field) .nullValue(type.nullValue()) .byteOrder(schema.byteOrder()); + final int version = null != field ? Math.max(field.sinceVersion(), type.sinceVersion()) : type.sinceVersion(); + final Token.Builder builder = new Token.Builder() .signal(Signal.BEGIN_ENUM) .name(type.name()) .referencedName(type.referencedName()) .size(encodingType.size()) .offset(offset) - .version(type.sinceVersion()) + .version(version) .deprecated(type.deprecated()) .description(type.description()) .encoding(encodingBuilder.build()); - if (null != field) - { - builder.version(Math.max(field.sinceVersion(), type.sinceVersion())); - } - tokenList.add(builder.build()); for (final EnumType.ValidValue validValue : type.validValues()) @@ -322,22 +318,19 @@ private void add(final SetType type, final int offset, final Field field) .primitiveType(encodingType) .build(); + final int version = null != field ? Math.max(field.sinceVersion(), type.sinceVersion()) : type.sinceVersion(); + final Token.Builder builder = new Token.Builder() .signal(Signal.BEGIN_SET) .name(type.name()) .referencedName(type.referencedName()) .size(encodingType.size()) .offset(offset) - .version(type.sinceVersion()) + .version(version) .deprecated(type.deprecated()) .description(type.description()) .encoding(encoding); - if (null != field) - { - builder.version(Math.max(field.sinceVersion(), type.sinceVersion())); - } - tokenList.add(builder.build()); for (final SetType.Choice choice : type.choices()) @@ -369,7 +362,7 @@ private void add(final SetType.Choice value, final PrimitiveType encodingType) tokenList.add(builder.build()); } - private void add(final EncodedDataType type, final int offset) + private void add(final EncodedDataType type, final int offset, final int sinceVersion) { final Encoding.Builder encodingBuilder = new Encoding.Builder() .primitiveType(type.primitiveType()) @@ -382,7 +375,7 @@ private void add(final EncodedDataType type, final int offset) .referencedName(type.referencedName()) .size(type.encodedLength()) .description(type.description()) - .version(type.sinceVersion()) + .version(sinceVersion) .deprecated(type.deprecated()) .offset(offset); @@ -426,21 +419,18 @@ private void add(final EncodedDataType type, final int offset, final Field field .timeUnit(field.timeUnit()) .epoch(field.epoch()); + final int version = Math.max(field.sinceVersion(), type.sinceVersion()); + final Token.Builder tokenBuilder = new Token.Builder() .signal(Signal.ENCODING) .name(type.name()) .referencedName(type.referencedName()) .size(type.encodedLength()) .description(type.description()) - .version(type.sinceVersion()) + .version(version) .deprecated(type.deprecated()) .offset(offset); - if (field.type() instanceof CompositeType) - { - tokenBuilder.version(Math.max(field.sinceVersion(), type.sinceVersion())); - } - switch (field.presence()) { case REQUIRED: From 7e6bcc75423324ec7575ed15cb2e3c5de7e25d37 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 28 Jul 2022 11:07:06 +0100 Subject: [PATCH 108/805] [Java] Upgrade to JUnit 5.9.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a485cfb9c6..3b1729a2df 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.6.1' -def junitVersion = '5.8.2' +def junitVersion = '5.9.0' def jmhVersion = '1.35' def agronaVersion = '1.16.0' def agronaVersionRange = '[1.15.2,2.0[' // allow any release >= 1.15.2 and < 2.0.0 From c17d2bf7cbd6b3d15f56de5d0db190c9671a3bef Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 28 Jul 2022 14:24:09 +0100 Subject: [PATCH 109/805] [Java] Fix warnings. --- .../main/java/uk/co/real_logic/sbe/SbeTool.java | 5 ++++- .../java/uk/co/real_logic/sbe/ValidationUtil.java | 15 ++++++++------- .../java/uk/co/real_logic/sbe/xml/SetType.java | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index f954685139..340de63f8f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -205,7 +205,10 @@ public static void main(final String[] args) throws Exception } else if (fileName.endsWith(".sbeir")) { - ir = new IrDecoder(fileName).decode(); + try (IrDecoder irDecoder = new IrDecoder(fileName)) + { + ir = irDecoder.decode(); + } } else { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index 1c87c1cb40..ff01421e7f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -43,7 +43,7 @@ public class ValidationUtil * must have all elements be a letter or digit or '_'. The first character must not be a digit. * And must not be a C keyword. *

- * http://en.cppreference.com/w/c/keyword + * C keywords * * @param value to check * @return true for validity as a C name. false if not. @@ -141,7 +141,7 @@ private static boolean isSbeCIdentifierPart(final char c) * must have all elements be a letter or digit or '_'. The first character must not be a digit. * And must not be a C++ keyword. *

- * http://en.cppreference.com/w/cpp/keyword + * C++ keywords * * @param value to check * @return true for validity as a C++ name. false if not. @@ -228,7 +228,7 @@ private static boolean isSbeCppIdentifierPart(final char c) /** * Check string for validity of usage as a Java identifier. Avoiding keywords. *

- * http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.9 + * Java JLS * * @param value to check * @return true for validity as a Java name. false if not. @@ -314,13 +314,13 @@ private static boolean isJavaIdentifier(final String token) /** * "Check" value for validity of usage as a golang identifier. From: - * https://golang.org/ref/spec#Identifiers + * Golang identifiers *

* identifier = letter { letter | unicode_digit } * letter = unicode_letter | "_" . *

* unicode_letter and unicode_digit are defined in section 4.5 of the unicode - * standard at http://www.unicode.org/versions/Unicode8.0.0/ and + * standard at Unicode 8.0.0 and * the Java Character and Digit functions are unicode friendly * * @param value to check @@ -393,7 +393,8 @@ private static boolean isSbeGolangIdentifierPart(final char c) } /** - * https://docs.microsoft.com/en-gb/dotnet/articles/csharp/language-reference/keywords/index + * + * C# keywords * Note this does not include the contextual keywords * Note "virtual" is no longer but was in early versions of C# */ @@ -417,7 +418,7 @@ private static boolean isSbeGolangIdentifierPart(final char c) /** * "Check" value for validity of usage as a csharp identifier. - * https://msdn.microsoft.com/en-us/library/aa664670(v=vs.71).aspx + * C# identifiers * Which basically boils down to *

* first subsequent* diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java index 92019acec8..3288ff0e03 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java @@ -177,7 +177,7 @@ public Collection choices() /** * Always false. - * + *

* {@inheritDoc} */ public boolean isVariableLength() From 61689959701a01e455affb4b9b676e9b4360ece2 Mon Sep 17 00:00:00 2001 From: Tom Johnson Date: Thu, 28 Jul 2022 15:50:59 +0100 Subject: [PATCH 110/805] Replicate compiler errors in decoders on JDK17 for "yield()" #910 (#911) * Test to replicate compiler errors in decoders on JDK17 when a field is called "yield" #910 * #910 Start fixing unqualified yield errors This now generates code that compiles in Java 17 for groups, composites and fields named "yield", and demonstrates the need for each of these. There are many paths through the JavaGenerator I have not yet tested (or implemented). * #910 Finish(?) fixing unqualified yield errors This now generates code that compiles in Java 17 for all the paths through writeTokenDisplay I can find, and I think that's all that's needed here? * #910 Add a test to ensure we handle both groups called yield and groups with a field called yield, ie that recursive rendering works the way I'd hope and expect. * #910 Use a unit test to highlight compilation errors rather than an entry in the build file. Note: this only fails when running with a Java 17 toolchain, not on Java 8 or 11. * #910 Restrict test to run only on JRE17, and generate updated IR codecs * #910 Fix checkstyle * #910 Remove unnecessary property from unit test * #910 Remove unused import Co-authored-by: tom.johnson --- .../sbe/generation/java/JavaGenerator.java | 18 ++--- .../sbe/ir/generated/FrameCodecDecoder.java | 6 +- .../ir/generated/MessageHeaderDecoder.java | 8 +-- .../sbe/ir/generated/TokenCodecDecoder.java | 20 +++--- .../ir/generated/VarDataEncodingDecoder.java | 2 +- .../generation/java/QualifiedYieldTest.java | 72 +++++++++++++++++++ sbe-tool/src/test/resources/issue910.xml | 65 +++++++++++++++++ 7 files changed, 164 insertions(+), 27 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java create mode 100644 sbe-tool/src/test/resources/issue910.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index ef0ffe667c..21ca6f5a15 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -3492,7 +3492,7 @@ private void appendDecoderDisplay( sb, indent, "builder.append(\"" + groupName + Separator.KEY_VALUE + Separator.BEGIN_GROUP + "\");"); append(sb, indent, "final int " + groupName + "OriginalOffset = " + groupName + ".offset;"); append(sb, indent, "final int " + groupName + "OriginalIndex = " + groupName + ".index;"); - append(sb, indent, "final " + groupDecoderName + " " + groupName + " = " + groupName + "();"); + append(sb, indent, "final " + groupDecoderName + " " + groupName + " = this." + groupName + "();"); append(sb, indent, "if (" + groupName + ".count() > 0)"); append(sb, indent, "{"); @@ -3575,9 +3575,9 @@ private int writeTokenDisplay( if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { append(sb, indent, - "for (int i = 0; i < " + fieldName + "Length() && " + fieldName + "(i) > 0; i++)"); + "for (int i = 0; i < " + fieldName + "Length() && this." + fieldName + "(i) > 0; i++)"); append(sb, indent, "{"); - append(sb, indent, " builder.append((char)" + fieldName + "(i));"); + append(sb, indent, " builder.append((char)this." + fieldName + "(i));"); append(sb, indent, "}"); } else @@ -3587,7 +3587,7 @@ private int writeTokenDisplay( append(sb, indent, "{"); append(sb, indent, " for (int i = 0; i < " + fieldName + "Length(); i++)"); append(sb, indent, " {"); - append(sb, indent, " builder.append(" + fieldName + "(i));"); + append(sb, indent, " builder.append(this." + fieldName + "(i));"); Separator.ENTRY.appendToGeneratedBuilder(sb, indent + INDENT + INDENT); append(sb, indent, " }"); append(sb, indent, " builder.setLength(builder.length() - 1);"); @@ -3598,22 +3598,22 @@ private int writeTokenDisplay( else { // have to duplicate because of checkstyle :/ - append(sb, indent, "builder.append(" + fieldName + "());"); + append(sb, indent, "builder.append(this." + fieldName + "());"); } break; case BEGIN_ENUM: - append(sb, indent, "builder.append(" + fieldName + "());"); + append(sb, indent, "builder.append(this." + fieldName + "());"); break; case BEGIN_SET: - append(sb, indent, fieldName + "().appendTo(builder);"); + append(sb, indent, "this." + fieldName + "().appendTo(builder);"); break; case BEGIN_COMPOSITE: { final String typeName = formatClassName(decoderName(typeToken.applicableTypeName())); - append(sb, indent, "final " + typeName + " " + fieldName + " = " + fieldName + "();"); + append(sb, indent, "final " + typeName + " " + fieldName + " = this." + fieldName + "();"); append(sb, indent, "if (" + fieldName + " != null)"); append(sb, indent, "{"); append(sb, indent, " " + fieldName + ".appendTo(builder);"); @@ -3694,7 +3694,7 @@ private void generateMessageLength( final String groupName = formatPropertyName(groupToken.name()); final String groupDecoderName = decoderName(groupToken.name()); - append(sb, bodyIndent, groupDecoderName + " " + groupName + " = " + groupName + "();"); + append(sb, bodyIndent, groupDecoderName + " " + groupName + " = this." + groupName + "();"); append(sb, bodyIndent, "if (" + groupName + ".count() > 0)"); append(sb, bodyIndent, "{"); append(sb, bodyIndent, " while (" + groupName + ".hasNext())"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index d958498953..12fc62b74b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -623,13 +623,13 @@ public StringBuilder appendTo(final StringBuilder builder) builder.append(BLOCK_LENGTH); builder.append("):"); builder.append("irId="); - builder.append(irId()); + builder.append(this.irId()); builder.append('|'); builder.append("irVersion="); - builder.append(irVersion()); + builder.append(this.irVersion()); builder.append('|'); builder.append("schemaVersion="); - builder.append(schemaVersion()); + builder.append(this.schemaVersion()); builder.append('|'); builder.append("packageName="); builder.append('\'').append(packageName()).append('\''); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java index d83fa30430..b0f47e2bd5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java @@ -217,16 +217,16 @@ public StringBuilder appendTo(final StringBuilder builder) builder.append('('); builder.append("blockLength="); - builder.append(blockLength()); + builder.append(this.blockLength()); builder.append('|'); builder.append("templateId="); - builder.append(templateId()); + builder.append(this.templateId()); builder.append('|'); builder.append("schemaId="); - builder.append(schemaId()); + builder.append(this.schemaId()); builder.append('|'); builder.append("version="); - builder.append(version()); + builder.append(this.version()); builder.append(')'); return builder; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index cfac525b67..5f23d9ef9e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -1724,34 +1724,34 @@ public StringBuilder appendTo(final StringBuilder builder) builder.append(BLOCK_LENGTH); builder.append("):"); builder.append("tokenOffset="); - builder.append(tokenOffset()); + builder.append(this.tokenOffset()); builder.append('|'); builder.append("tokenSize="); - builder.append(tokenSize()); + builder.append(this.tokenSize()); builder.append('|'); builder.append("fieldId="); - builder.append(fieldId()); + builder.append(this.fieldId()); builder.append('|'); builder.append("tokenVersion="); - builder.append(tokenVersion()); + builder.append(this.tokenVersion()); builder.append('|'); builder.append("componentTokenCount="); - builder.append(componentTokenCount()); + builder.append(this.componentTokenCount()); builder.append('|'); builder.append("signal="); - builder.append(signal()); + builder.append(this.signal()); builder.append('|'); builder.append("primitiveType="); - builder.append(primitiveType()); + builder.append(this.primitiveType()); builder.append('|'); builder.append("byteOrder="); - builder.append(byteOrder()); + builder.append(this.byteOrder()); builder.append('|'); builder.append("presence="); - builder.append(presence()); + builder.append(this.presence()); builder.append('|'); builder.append("deprecated="); - builder.append(deprecated()); + builder.append(this.deprecated()); builder.append('|'); builder.append("name="); builder.append('\'').append(name()).append('\''); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java index 9b067585e4..aad78db9fe 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java @@ -139,7 +139,7 @@ public StringBuilder appendTo(final StringBuilder builder) builder.append('('); builder.append("length="); - builder.append(length()); + builder.append(this.length()); builder.append('|'); builder.append(')'); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java new file mode 100644 index 0000000000..8f895f6a5d --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import java.util.Map; + +import org.agrona.DirectBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.generation.CompilerUtil; +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +public class QualifiedYieldTest +{ + private static final Class BUFFER_CLASS = MutableDirectBuffer.class; + private static final String BUFFER_NAME = BUFFER_CLASS.getName(); + private static final Class READ_ONLY_BUFFER_CLASS = DirectBuffer.class; + private static final String READ_ONLY_BUFFER_NAME = READ_ONLY_BUFFER_CLASS.getName(); + + private final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + + @Test + @EnabledForJreRange(min = JRE.JAVA_17) + void shouldGenerateValidJava() throws Exception + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(Tests.getLocalResource("issue910.xml"), options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); + + outputManager.setPackageName(ir.applicableNamespace()); + generator.generateMessageHeaderStub(); + generator.generateTypeStubs(); + generator.generate(); + + final Map sources = outputManager.getSources(); + + { + final String fqClassName = ir.applicableNamespace() + "." + "Issue910FieldDecoder"; + final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); + assertNotNull(aClass); + } + } +} diff --git a/sbe-tool/src/test/resources/issue910.xml b/sbe-tool/src/test/resources/issue910.xml new file mode 100644 index 0000000000..f15f7c83fb --- /dev/null +++ b/sbe-tool/src/test/resources/issue910.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + A + B + C + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d06ff4cd77e543d943935797486f05dfb8d80174 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 8 Aug 2022 10:26:01 +0100 Subject: [PATCH 111/805] [Java] Upgrade to Gradle 7.5.1. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 60756 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 6 ++++++ gradlew.bat | 14 ++++++++------ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 3b1729a2df..290a273060 100644 --- a/build.gradle +++ b/build.gradle @@ -822,7 +822,7 @@ tasks.named('dependencyUpdates').configure { tasks.findByName('build').dependsOn verifyJavaIrCodecsInSync wrapper { - gradleVersion = '7.4.2' + gradleVersion = '7.5.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4d4fb3f96a785543079b8df6723c946b..249e5832f090a2944b7473328c07c9755baa3196 100644 GIT binary patch delta 10197 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 92f06b50fd..8fad3f5a98 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787337..a69d9cb6c2 100755 --- a/gradlew +++ b/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd32c4..f127cfd49d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal From 8a5f760b992b4999a1e3a81cdac062d0b62ae03c Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 9 Aug 2022 12:05:24 +0100 Subject: [PATCH 112/805] [Java] Upgrade github actions. --- .github/workflows/ci.yml | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f018aa915..a532c476f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,21 +30,21 @@ jobs: os: [ 'ubuntu-20.04', 'windows-latest' ] steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Cache Gradle dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Setup java - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -54,7 +54,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Setup java 8 to run the Gradle script - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'zulu' java-version: 8 @@ -73,28 +73,28 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Cache Gradle dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Cache NuGet dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('csharp/**/*.sln') }} restore-keys: | ${{ runner.os }}-nuget- - name: Setup dotnet - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v2 with: dotnet-version: ${{ matrix.dotnet }} - name: Build @@ -116,16 +116,16 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Cache Gradle dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} @@ -151,16 +151,16 @@ jobs: CXX: clang++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Cache Gradle dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} @@ -188,7 +188,7 @@ jobs: CXX: clang++ steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install CMake run: | curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz @@ -209,7 +209,7 @@ jobs: CXX: cl steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install CMake run: | $client = new-object System.Net.WebClient @@ -228,16 +228,16 @@ jobs: rust: [ stable, beta, nightly ] steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Cache Gradle dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} From 02c5b6a61eed1548d4afbb21d71434d09d2a8663 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 15 Aug 2022 11:26:56 +0200 Subject: [PATCH 113/805] [Java] Upgrade to Mockito 4.7.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 290a273060..478167dfeb 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.6.1' +def mockitoVersion = '4.7.0' def junitVersion = '5.9.0' def jmhVersion = '1.35' def agronaVersion = '1.16.0' From 75f85d0b382d875c1ccf766bbab902e2d97f0423 Mon Sep 17 00:00:00 2001 From: vdaniloff Date: Fri, 19 Aug 2022 15:54:17 +0300 Subject: [PATCH 114/805] [Java] Support binary vardata in json printer (#914) --- .../sbe/json/JsonTokenListener.java | 6 +++- .../real_logic/sbe/json/JsonPrinterTest.java | 30 +++++++++++++++++++ .../resources/json-printer-test-schema.xml | 11 +++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java index 3337db04d2..a618463229 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java @@ -16,6 +16,7 @@ package uk.co.real_logic.sbe.json; import org.agrona.DirectBuffer; +import org.agrona.PrintBufferUtil; import uk.co.real_logic.sbe.PrimitiveValue; import uk.co.real_logic.sbe.ir.Encoding; import uk.co.real_logic.sbe.ir.Token; @@ -230,7 +231,10 @@ public void onVarData( final byte[] tempBuffer = new byte[length]; buffer.getBytes(bufferIndex, tempBuffer, 0, length); - final String str = new String(tempBuffer, 0, length, typeToken.encoding().characterEncoding()); + + final String charsetName = typeToken.encoding().characterEncoding(); + final String str = charsetName != null ? new String(tempBuffer, 0, length, charsetName) : + PrintBufferUtil.hexDump(tempBuffer); escape(str); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java index 4d2c9e597f..1134876d22 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java @@ -15,6 +15,9 @@ */ package uk.co.real_logic.sbe.json; +import baseline.CredentialsEncoder; +import baseline.MessageHeaderEncoder; +import org.agrona.concurrent.UnsafeBuffer; import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.EncodedCarTestBase; import uk.co.real_logic.sbe.ir.Ir; @@ -125,6 +128,33 @@ void exampleMessagePrintedAsJson() throws Exception result); } + @Test + public void exampleVarData() throws Exception + { + final ByteBuffer encodedSchemaBuffer = ByteBuffer.allocate(SCHEMA_BUFFER_CAPACITY); + encodeSchema(encodedSchemaBuffer); + + final ByteBuffer encodedMsgBuffer = ByteBuffer.allocate(MSG_BUFFER_CAPACITY); + final UnsafeBuffer buffer = new UnsafeBuffer(encodedMsgBuffer); + final CredentialsEncoder encoder = new CredentialsEncoder(); + encoder.wrapAndApplyHeader(buffer, 0, new MessageHeaderEncoder()); + encoder.login("example"); + encoder.putEncryptedPassword(new byte[] {11, 0, 64, 97}, 0, 4); + encodedMsgBuffer.position(encoder.encodedLength()); + + encodedSchemaBuffer.flip(); + final Ir ir = decodeIr(encodedSchemaBuffer); + + final JsonPrinter printer = new JsonPrinter(ir); + final String result = printer.print(encodedMsgBuffer); + assertEquals( + "{\n" + + " \"login\": \"example\",\n" + + " \"encryptedPassword\": \"0b004061\"\n" + + "}", + result); + } + private static void encodeSchema(final ByteBuffer buffer) throws Exception { final Path path = Paths.get("src/test/resources/json-printer-test-schema.xml"); diff --git a/sbe-tool/src/test/resources/json-printer-test-schema.xml b/sbe-tool/src/test/resources/json-printer-test-schema.xml index 94044b19f7..da01a58fd1 100644 --- a/sbe-tool/src/test/resources/json-printer-test-schema.xml +++ b/sbe-tool/src/test/resources/json-printer-test-schema.xml @@ -23,6 +23,10 @@ + + + + @@ -77,4 +81,11 @@ + + + + + + + From 43f4a7d6ec13748b04a0fd54742b70c906f43f69 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 22 Aug 2022 15:00:17 +0100 Subject: [PATCH 115/805] [CI] Remove deprecated Ubuntu 18.04 builds. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a532c476f2..d37d09af37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,11 +141,11 @@ jobs: cpp-clang-build: name: C++ Clang ${{ matrix.version }} - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: - version: [ '6.0', '7', '8', '9', '10', '11', '12', '13', '14' ] + version: [ '8', '9', '10', '11', '12', '13', '14' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} From 3757794b64ce8d5446bc839a2e1c7fca8d5d06af Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 22 Aug 2022 15:04:17 +0100 Subject: [PATCH 116/805] [CI] Remove deprecated Ubuntu 18.04 builds. --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d37d09af37..79e547e0b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,11 +166,12 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | - curl -L https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-${{ matrix.version }} main" + curl --retry ${INSTALL_COMPILER_RETRIES} -L https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + echo 'Acquire::Retries "${INSTALL_COMPILER_RETRIES}";' | sudo tee -a /etc/apt/apt.conf.d/99retries + sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.version }} main" sudo apt-get update - sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 - curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz + sudo apt-get install -y clang-${{ matrix.version }} libstdc++-7-dev libbsd-dev uuid-dev libidn11 + curl --retry ${INSTALL_COMPILER_RETRIES} -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - name: Build From f1b45ef9d25b1b58ca70040256c88283cb385d6c Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 22 Aug 2022 15:08:40 +0100 Subject: [PATCH 117/805] [CI] Remove deprecated Ubuntu 18.04 builds. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79e547e0b3..8c7f10e57e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -170,7 +170,7 @@ jobs: echo 'Acquire::Retries "${INSTALL_COMPILER_RETRIES}";' | sudo tee -a /etc/apt/apt.conf.d/99retries sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.version }} main" sudo apt-get update - sudo apt-get install -y clang-${{ matrix.version }} libstdc++-7-dev libbsd-dev uuid-dev libidn11 + sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 curl --retry ${INSTALL_COMPILER_RETRIES} -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH From 863b874ab381572c66b2b0be4e4e612b75c49929 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 22 Aug 2022 15:13:36 +0100 Subject: [PATCH 118/805] [CI] Remove deprecated Ubuntu 18.04 builds. --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c7f10e57e..46d5ca6c2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,12 +166,11 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | - curl --retry ${INSTALL_COMPILER_RETRIES} -L https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - echo 'Acquire::Retries "${INSTALL_COMPILER_RETRIES}";' | sudo tee -a /etc/apt/apt.conf.d/99retries + curl -L https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.version }} main" sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 - curl --retry ${INSTALL_COMPILER_RETRIES} -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz + curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - name: Build From dfbe41f4f2fdcf2549462c799504c3de9331966a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 22 Aug 2022 15:16:33 +0100 Subject: [PATCH 119/805] [CI] Remove clang 8. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46d5ca6c2b..6867faae94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,7 +145,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '8', '9', '10', '11', '12', '13', '14' ] + version: [ '9', '10', '11', '12', '13', '14' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} From 303881f4bc2fc02f9361be8954ee01948d3f6a52 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Aug 2022 12:23:27 +0200 Subject: [PATCH 120/805] [CI] Add Ubuntu 22.04 to the build matrix. --- .github/workflows/ci.yml | 88 +++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6867faae94..6bc49bdcf0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: fail-fast: false matrix: java: [ '8', '11', '17', '18' ] - os: [ 'ubuntu-20.04', 'windows-latest' ] + os: [ 'ubuntu-22.04', 'windows-latest' ] steps: - name: Checkout code uses: actions/checkout@v3 @@ -63,7 +63,7 @@ jobs: csharp-build: name: C# ${{ matrix.dotnet }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: @@ -104,8 +104,8 @@ jobs: - name: Pack run: ./csharp/pack.sh - cpp-gcc-build: - name: C++ GCC ${{ matrix.version }} + cpp-gcc-2004-build: + name: C++ GCC ${{ matrix.version }} (Ubuntu 20.04) runs-on: ubuntu-20.04 strategy: fail-fast: false @@ -131,16 +131,50 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | - sudo add-apt-repository "deb http://dk.archive.ubuntu.com/ubuntu/ bionic main universe" + sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ bionic main universe" sudo apt-get install -y g++-${{ matrix.version }} libsparsehash-dev libidn11 curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - name: Build - run: cmake --version && ./cppbuild/cppbuild + run: ./cppbuild/cppbuild + + cpp-gcc-2204-build: + name: C++ GCC ${{ matrix.version }} (Ubuntu 22.04) + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + version: [ '9', '10', '11', '12' ] + env: + CC: gcc-${{ matrix.version }} + CXX: g++-${{ matrix.version }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Cache Gradle dependencies + uses: actions/cache@v3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache Gradle wrappers + uses: actions/cache@v3 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Install compiler + run: | + sudo apt-get install -y g++-${{ matrix.version }} libsparsehash-dev libidn11 + curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz + tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz + echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH + - name: Build + run: ./cppbuild/cppbuild - cpp-clang-build: - name: C++ Clang ${{ matrix.version }} + cpp-clang-2004-build: + name: C++ Clang ${{ matrix.version }} (Ubuntu 20.04) runs-on: ubuntu-20.04 strategy: fail-fast: false @@ -174,7 +208,41 @@ jobs: tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - name: Build - run: cmake --version && ./cppbuild/cppbuild + run: ./cppbuild/cppbuild + + cpp-clang-2204-build: + name: C++ Clang ${{ matrix.version }} (Ubuntu 22.04) + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + version: [ '9', '10', '11', '12', '13', '14' ] + env: + CC: clang-${{ matrix.version }} + CXX: clang++-${{ matrix.version }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Cache Gradle dependencies + uses: actions/cache@v3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache Gradle wrappers + uses: actions/cache@v3 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Install compiler + run: | + sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 + curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz + tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz + echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH + - name: Build + run: ./cppbuild/cppbuild cpp-clang-macos-build: name: C++ Xcode ${{ matrix.version }} (macOS) @@ -221,7 +289,7 @@ jobs: rust-build: name: Rust ${{ matrix.rust }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: From a1a2e05554858b02043a5b458df81010c5957373 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Aug 2022 12:25:58 +0200 Subject: [PATCH 121/805] [CI] Remove some dependencies from Ubuntu 22.04 builds. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6bc49bdcf0..5c4b58f8a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,7 +166,7 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | - sudo apt-get install -y g++-${{ matrix.version }} libsparsehash-dev libidn11 + sudo apt-get install -y g++-${{ matrix.version }} curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH @@ -237,7 +237,7 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | - sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 + sudo apt-get install -y clang-${{ matrix.version }} curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH From d8599bc5d21214dc0833b3a9ca735e0a403b199d Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Aug 2022 12:27:58 +0200 Subject: [PATCH 122/805] [CI] Remove Clang 9 and 10 from Ubuntu 22.04. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c4b58f8a4..a88bfb8a8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -216,7 +216,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '9', '10', '11', '12', '13', '14' ] + version: [ '11', '12', '13', '14' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} From f58e0073fb7630a35c050aa4e1ddc1d8da9dfd96 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 30 Aug 2022 15:07:49 +0100 Subject: [PATCH 123/805] [C/C++] Upgrade to Google Test 1.12.1. --- CMakeLists.txt | 4 ++-- cppbuild/googletest-release-1.11.0.zip | Bin 1121369 -> 0 bytes cppbuild/googletest-release-1.12.1.zip | Bin 0 -> 1081236 bytes 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 cppbuild/googletest-release-1.11.0.zip create mode 100644 cppbuild/googletest-release-1.12.1.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index d98335b346..a8e7b0010c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,8 +67,8 @@ if (SBE_TESTS) ExternalProject_Add( gtest - URL ${CMAKE_CURRENT_SOURCE_DIR}/cppbuild/googletest-release-1.11.0.zip - URL_MD5 52943a59cefce0ae0491d4d2412c120b + URL ${CMAKE_CURRENT_SOURCE_DIR}/cppbuild/googletest-release-1.12.1.zip + URL_MD5 2648d4138129812611cf6b6b4b497a3b PREFIX "${SBE_THIRDPARTY_BINARY_DIR}/gtest" CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER};-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} BUILD_BYPRODUCTS "${SBE_THIRDPARTY_BINARY_DIR}/gtest/src/gtest-build/lib/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX};${SBE_THIRDPARTY_BINARY_DIR}/gtest/src/gtest-build/lib/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}" diff --git a/cppbuild/googletest-release-1.11.0.zip b/cppbuild/googletest-release-1.11.0.zip deleted file mode 100644 index faaf8ea404c3553631e58a44dc9d59a58e3c3ffd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1121369 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�BgYwx47b_}Zyfy*e;xT}Z?g#ZJ0@EWa$X^& z0U9W9d|>g!{^Ln00>U`S;t8cew)sexO-yTC{R4~@MH0zY02&6I@JCALk~i5PdM@7D z192=%K5+(0iM6cd8q{7d9d%PmF>@@Pqh)w=z>rXFZFB+^YX_Mk`KjlQVze8nr>9h` zq0NvkFx36SX`RVh<;q}=uqBLdo3YNp#i@$edRhy-Y%?vrcg}%b%e5l0ho6=3Tx`sv zsRh{~rD4{lX`#M?%y);=G#)#N^D->5zIJzKOQ);5yQi(Y8Ny8hKuCs9)5mvx7!sGDrUC&x-Q1BN}oL|Go(RT?p^AE*F? zTJNMzH)~=lD>o+k1Z%8mj_4>yp4v{DRHUua*te@B**%9vCEsOB`Rt#sy| z6Hf=2|HyoOrrdI&(I4B^c}CqFPcw!%E3v+cIb6|}La3MyTGXN`*L|4MzcD8)L_I5` zX@-ra2QG&22Y0tb`5qKudqL+LO;{7=eE3#O^y|bd-HdTxVBY9qX)>Xh{fpK&OdXlj zsLyipd{SHp0Rl%vKi=(NPX~0rbvWKIT4o>0`V%iLPB3C4f_40?REZKnEJdGzWR)ea zwlbh89Qc%HVLr~JXLvnQ=D+|M=fxT04M&mDAfE4iXehEGT-5))<`mMhHE{j}kgF&m2VD)bT zi8vNP?FPdXwe;+HVy@ZfC`Ux~31G|{#QMdux@PwKb#4|POUC|j_xh##wAiNHoxIWM z32-EDJbaI`;NQ_%cb(*~kp=@aVX^&&LYCS9ovhX6?quwcS#3mf)c3-p4HAV&?C;E- z_9ILzyQ=wY4%l-hY_}+`e*Y?^Vs?`Bb+Cs3Af3f>~`xGRR~s3_*Bl*!#VsuX6b2JpR$PpvN1bj?8%8VLsvI(<`VFd`raehtbB zYrz&@O6A!HC+pQaA$dmnlp`AJb-%;Tq_E&;Wyhsac4s1aboV-DNEKjhJnFUMq<((P z;b$}gTCgVidwKWTm20;VZ?<-YodJQ2FejLaXR?_+G zSl-hnAg6<+6YrD?tjpb8R$U13%38|loF3oGk+H;7CN_D^<&!#u>qZsK!p$tuHl&xvTt6J-XE)Sa z^tmaj#XzklgV?d?_42s{Q&I_0@SiRqY%+;fsS2x1^-|m->F)twZ=8z}K3`TavS_=! zf*~6`WG_AkSrg$@ND_o$j^zbMan1fb2WTXLo_o_^%{6*N-{V=w;u&El#s}}>?KSzC zI}M0Y1#l>jX+=13oH*q8e5}>5mJzAun2CEWEk_EVZZO5(24CVw_E4$1KIQN2$_YES zp|n4g@;{P{54{QvAeUN1l;|C0qq}+{N3CI!eQHryf6az|fQ2Iy&v_;88GnBa6wJQp<$9BHw#NB zTe?JNW(E#ZlyuQCBH;;+9>TG&p!_>d@@xh%(b1xe*RL>h@bS*E2~Tyi-a5dS{^m%8 z^o!xdm-_E0H&6VuN6xF+RwSS-jdV@C08YA<^dCZ*c364`&2CBy*Si)lIXfRTG6As} zpo~Kev7ewplAMX1|9V;q34G*ufj)vgKC9|}^L{*e+N1sqwBMFsf+i0QAQb?m85}@` z`0Q7y(lbH)>pZa`)fju{DEaJWXc}o1!$5pZTzN|e2ccEfJtF#1Hg!qBPKB2=9+Fn2- zugkSU1Do)OS4d0tK?PrN>;OJCM@YsePaH^iLV=)IOQrscRkT(PY&fL}Vbo~~&w%)x z+=A`|vKP}1;tc&UJ`WcN56j#vO!sI&*X4l%lQ#Y<5{QKom~5x9?z$R=#mesK!dFB= z`4emnkqWDU)Nx9Z)Oj$M=;=#sw)C?!L_}};4#M3MVndxE~ioB1~AJ&2jX3z!EJOa zlKhsB{49q_FMg0c_$pY#)2QNRmYm2@ySS_~NzFv@Msn~i4wwJGu%ZZSg`O!_Heo>?dapuLTu~Al{;T&+R)Ny6K?ugkda%Bw2Xp`j4+2c`tQkMj?fo#J_Si@#`rWV34Ue{8$N}e%`%C4SN0|NzZL=ZlK`} zDRwz3I7*nA-1vyV@Onf@CeK>`1+5o5fQK!ffBWuBMh+J*49!^kH|@ec{ChVEaS2Xx zIz|>wUJA(Rv@+~QEyC|)AK-9}vH7n%I~4IW$Moi2)b&A2@`GvZBeb&Z4*^C~u6l(L zT~G&rgqM*(jwvAHMCi>PnvlZ_C@NPDNVL=a7*51CYU^>5A%N5m-C8z@lp5^BLPC;* zGf0pCNE&hp^FO=4@4b3*_eklueg(csS1ZB)gRygL&V`GbbZpx;?%1|%+qRPv+qP|- z*tTus#C9@I)znnY`)TIO{tK(u+TB-scn9EkalF*HgbLB*d0bh)?ckQ2JcSO$$hWIM zqZ;<8LvQWRR%-#9Ej=yCB`R?2Sbl;OKP3!kdGE}x`iu%8#S6B|gh>=FQr88-RRhbQ zh4khm9*n!3!{fiHNzyS18Un9XWc|Wl{FPL>bc}NZqT;&y;6rIPYOn5ej&e1g7hGZG zT66?B73ilBeXTN{6%2?=2G`Siy!c_K9PfiS$HU=|An#@XDq+5Lvdj;mNk$YpGG+uy>2Xsd1>pi7{t7OB zhd(swqbRFHf~+mNZ+6`6H%-n&Br)z$Z6f;l-e`?fq8Njl!f$$2Ys4ivq%dGh%x71X z3Q!?5Bq7^R)+K)lp;`OUh>kCO112+Z_04zLTQ%FkG{P2%H3N0~R87<7q#XmPfK}%a z4y#q+c213Ro{BPnHpzSI2FFS=HbW6W4AZ0&E0xN@pBOb7;G~76)EjKM8W$2RB;i=S zgr<>a+Q2K7U8IYY*FN_e%x{7{)!D&ZbIevvcy#dv;EvBt+{ov+Ev`e~PoibKkH*6K zKFPeA6?eee9TB@=x?$OKQRVUE&j<8bN5iknEv}8Q?w6m6xiK?{2^{eSmmE=M4Pc`{ z-{&WSa^lcu*7gV$7_a*e1?`9gOiRm$}~`5+`@>>=~b)ap;p zTj4E+c-Eg(`HIw-uk2MM3q=I{x^A1)YI4J%`5D@FK(P7FUp4H|peG3gWSHdWCa~&b zG?&_WnUL7wn22FXPiR}+{(RHav`v2*$^peE3Qv6jL(4Zlp8|O%|W8Jk9(6L3BSQu2%y3r|U}Xdt&BEa2V(=YD?DS z=ElDZ_J+U0CdVR8Rao4Wh67Hbb~tSM$*gr&*`NAg4oY{vEO63dnjrGj+F&x8U?o}D z90TNQQJNxlmkYwAuQ-99rKBKowf61K4oCx6?A1}epTozU0dMX4p3^#eI zCm$~?Q=~u~;wZ>}YfR-lL_H<%6&T-walLx+03-k1^oRVh${rkiNI)8?wMw@P9TCPs zXn^I%g($lbnk0~5Af;p$+9}MTUBQ`HN?K~%H-YCm6r@h0c?oDZZUrLtC^J~peT*6X zN}s+;h-;A02zYIcNll|YLkG+>mDP?1bOLVlJY=4Oh0Vo9IFM$$Wwq+T9Lu|du+@iD zAIoXn!{yU^+FJf)%4~qBMu8RHTqg3ehdQ-e{QO%wY#pC>`-Q+w)K_$-3ZNDMR(a9! z*s2=k8>`s0rFe9iMlJybNpd%IPPJC!*CLTjs%2$hImC_4)-m z4QqHIqK`6_fYv9a{CFeo+qCA@;fDsR3$)``<&^A+=xeP$s6rZ+VE1i$B z`l4ySlwW=rO0E})FGXSyP4R6&yEhkCT1Q8to;ld@$9a*qKdC=A6AJH(%|#+*vzxZw zDH*=OJW(Z!`@f;4Be1YRsT zAX|HZg{4m;ydaxd7a<17r%0K9Y;azu-I0!_$1JpY>10k(SVo&>9^Kz=+CbmwTWIVM z6&AA-j;BN@w+9)ToQ>I;ga^{o*cI1N0%wg8M6V{{{Om0){sRUjK$|~0NW*!m|W4z@#H1J=@pyuZIA?ubeC)n@^x~9xP z)H4tTL!=7}NDs>kOTSj0PBoI!PpbB+VR=^&@PmRw&AxEx7as zF3oQ%v^OJ6)Sic_SAQ$eAXl#Y&sw?A>vevLzTDnZOi6nO>%ZCW9eY+g5NXy~CFpTo zI2>X8reVb5DV1bsUtAzYK{m3>d;BZ94E^zrVqUi7WuME>Mg=;=!tn?)z*H-ZGNr7N zzyDVeL(QrKkww-0zB2M`^WnvMj+9UJ@^pAI#l!pX6J9OF`?Jy?@fYzgE4mLHAn(DC9f*gJLXP)OKd`BRq%F;xiL;(gQpKvd z)5YMmOcxYP8v?cBFaFV`%GlVe!ON&cquaZ; z`i2jx3qyk5Fyurz&_ThRE9}DauS*vnmYT-*+->3;J>z@bN)6MaT`o^T`*5a962Lrh z?e^z*6EiE5b^@ebwI?CuX#rTNdPTUd;s@ zw*T6%G3-t2uv{my*t9n4>^2$5lE#L9>{{$)dUL)q5l(1V{^TT9`L0Ak+Bn0>;K<(Q z32x9yl#x>e4d;UCxOjW-m;7^91} zmZ#ir#C5*X7ICtUu4ZyZ6e;$ol#Gm8g1TJO3^j~n~pLmCMm*Za8Dlm&A>5cCV&|n3hJPI7j zyIcp;`n9AZTotwPxfO7Ycb#xT+B61QGf-hHA*-uYo#q^i*|;p0lD=#2w# z6lZL!f;hFHYRFFRIiQ94bs^oicx>!WPMDR<2_68DGaEE}wpD9C1<>1npInqdySO;H z^Iw)*Wt@>Y2~oAV_O#Dv>b%AK>pF0~lGJf|Z09Ww7@&y%mhxw*ds_t#mpa{w{OWr? z0`IY_a!Za7Nie&!0*jHz#|RQoG!oL}IgY9+Hgcdd--5*B@|GMKQas2M*~4ZP9@-;2 zD|c$gVz6!4`Pd@*EM*WRB7WnaL=Md*C{{1tVUdZDM$gCi9^Pd9JK2jQ@cj;EEn;=& zT?q$wda~^7QeH>C>NU+@x|LyqKn97&oT;g0EPn;&Ee5eTBL<_#D?bK#JU^dTGkI|<&wgEB!BcKXP!cUoc=F;G zJ<5xJEe1@v90kwxUb%RpKD0V{$h;`2%pZ{N!gIx=(tOli4g!I=y2RkEef8UXsGkd( zd|TRBg__WiW_?)GDXpwMF?7%j*1YX!GadOhZx4d?+u;NI=Awf4eeiuhZhyu7ygy7e z4w8tpjP2lZY82yHAPRCkJsSLG`BmCUQ$jus1pwcu^8ARSTu?g^UEy7x_}b^Ev|vL1 z8yWyb9ZD+)chi2DTg*d1im$9k7M-l z93L9*HN5uK>;HW-w6hYwR(}iF>*?wEKKMSl?jqzwJTuBP32g|MgvAUB;}Cwjht#83 zywc5X)^phGVNiHKc>_S6E7~44c#&xi{t?#0es;V>O-hoQ|F?wh?xzs73$x+|dT%JU z`$oIx4awhmXw&_KB791Gar!uOs8)*!W7%=b(tKG82hAbz5yvfGAhX6&P|4c)PLUV; z$$=SWe1qzgH7}}`^f`s+uHei*?UV)dr4#yrD>V&yR^;q9W_z4^gFr*bmuN}iGIp0j z)YrNH(_*V-jXFn4|tVAA-9;seR5BO+(Qbi$FH02-RG zr-8EFBI_je!09;SH(NL6e#?qu1NkXIjtKX%9Fag?%B8rGZ-qAZ zkLH&*P6x*A0Q0kU3Z#@*aRzjEJV5ylV|ujD%|`W=CutWS9_{^O%{1^1My!hLuK4T3 zh3E0*b8D?Ez&;Nbw*yS*0N(59M$2`b)DQ3wa(hc^n+9Kh`{$&3Vr7AU8w_U)!Xt3e zdf^W%-HMc_35}GZfFEYLes1Z0KYRTUMVXc6Ygqzyz<6_Q*$R?M<7oP9MI=YBvTDLl zTkl;09NfL@Vt_mzC}&0WCNp%`8vx3o^B=k_ghOsEdS6(GTOVY!7QbKze((H8wg{Fm zO}4qJrP+Qn{2J}NlvwVuoo0h|VzzwHMKOZ!VaS|we2MF!5t|BP1}Xw^`fhO6pGb-& z(uk64iib#+0XHc=HHA5uFC{Gf`N!La24p7W!~5+WiVdSF9GMs?3gFjG7m>+;@B8y(l})!m|wof*ADLTp}LW`<(Fy~je< z^N)v1T!XKO1LzZD&VCB<2l+*emI=tqC25y+(CH{1-5}scjJw?HF{8@7r?XMV62G7w z8DX3Ps|KJH@!XJqD(jbMeMjHuf}%on)UWF6(C9>UD6tuj69uyN|M79O?WstPtlzF9 zhszUT^gPwN%6im-BFz5XCHzPBxJFtv`kMRbCf?%@r|UGhoArA|bnBgvs!@_%VN_FL zgJVgQRL4NCiH@(1j-+L+thRE!=l0e-dLY1m&`{`m(s{vn{AXer!|zQ<=NgqQF!+@J zU^D<=0+{Go;RoJkbY!%;(i`l_l??c^H0-*wmWObT<)r_yUdewKG@OT|#@#e^O z>=(GIj_}oQ?Q&~xwA4Gg3&K_ULZ9t1$N9NLo!VWYFdFPO6>TBi{y5LuN0VtPuD(R{ zju#|^xC{9Nn|vwI$N9QWlAPQM-T(s@3psdl3y0R+l<=r6+?3wCQ&1i?q6JJ$tez)L z9dDve#8CJKLIUEz^#}GE@}bndMa*fbg?uzJB09GMBMe{5$=b^MLGq+ICK{S)+f(0e z+a*Zcnb--pS%AUSpC8ZW4w0Huz+RCn><=Ax_Mi*>jw?>`xH$<8qDMZ${1YI03^RcA z&W%u%G;<@f*?9!&OaA=Um+5R)ypE`vQ01N(fR4)^s~<9~g}?_vO~8*!0d+Y}rSPW! zlEyI)FtQL_r=6#JK`qvw53kPVO!}02+eu(p5bgPBP*Bl8CV~v03bWb$wA2g2zlm`p9B4BL7|Slx46G4)&$|JO-og zybX1M&w-d9c8@?tU>HA(sJpgrHLL$Cy+huDqFrm-ggp6`0XjF)f9FVi_n))s3`xp5 z_y9CExZ0(Ji1i+6-j3RcbWa>ch4%Glg3#9S5W_I=sB5az&txr~HhcFGT+kZ)`7wR# z`Lu{?S4udd5}8&uR~)$;h5^aLT0n^8YP~e&jdLbDJKfV{sz2<)O5*L`sTI^rEK`!HHf-E#b2gjlHAL}mY&EqNSV`9Z=NE8qEp62 z?=!orSn3wcur#>XdAwL<^$OynI zN#{0=f!K`?#S42{v?P2wc~AJjdZMs2!;*PyO>iBsz3xRf(7+vzGffL+p(Rj(coe zRR)pDv<%GhS`p$-FgemG*6)4OFi#Fo6t#^lWcu@_Y!i90tD7F+f`zX}Gsdyo(}+?*bC~?J&He42K zOfo$*R_~uAkXt-H%9MV0Uyh%H@Q{;pNm%8=RXd*so|m=I`U$F6KG1Q9?G^mfL?TxJ zT(+0FKvkHbT@W`_muPdl{LtLwevHM$u0s4`z7cdP_>9TK-v?ZcAJAqjR6$Y z1%={60Z?w)$8@zf7|Dr#e1-As10=B)LJr1#)mk_QnCRVy0=K1hNqTdJ?cVLtyU<{% zb#yl*tBxVZw3y|eKB*#+&lh+MS9;i+nx}+))sigeFxGQXdA<@F3PCDvso}SX{dnWO ztJIwjsr<8xEc98nLXS7H{OXZxtG04tCh45m!R`rgrUZE5#-^HRr)78{0&vkY< zTS8LK?RO3I_4Ru2{)6hGu6=uphz>-!z-<3cAX`C2It~S?t-qhui#=ZZ%M#0@2ip9{ zK$E>%+R>z43A`(l+{$d-P5cn}Wu2yfj+?h?Fe$GO;Jt?qn!@J#@TKs$mjWz%o!pvN z&Cc!E0DSKHyd8h{Cui?Jes>q~Aio0sj~V=b`*qWt`fB@NfPhBvfPh&3-zH}ZI|maR z0~5>t49*5FmS$$I|HHkjW#h2bj`Ce+z$E#nF2`+Ij_`9ps#!AmDR8Ek!)dFFDoQf# zTvJEuDM}TO;lE8XPfYrLyz|{&Lf(`qj+sZC?}$lX^NwfIX_h{$U!Fg@f4FfbtsKL7+bLQpEc=0AMY|;AU|aH`lB%sD zL9EyrKd`>Y9K{qWq_X)_T|%ScWB@ig88g!jPPVbu=_a)A-f53lUcL;yWIT|*r3cF5 z=xDpDw@ENWk@8kyWdY|TwUI7(srEvKQ>-fdqIcGqRwk5o*Ky(4DIZp?7Xp7+I`P#) z37)A{_n))-i=TYVvG8w>a>(v3dvK%lFN7aBVZ9`cBC17ESGYqt>}bWdu!3ziFlrDy_Qi_@CVD8_3 zj+r>5Bji=%%JT>3(_vm(_Sh)h#A%20Wbo*RIFlWHCTTmG$UbP?MvdXqDAC!TXP?*DSES17?wOexOU)0g)q|KdZq;G}_}DxD2? zq!DQ6V7k3~!U+6TX}vSDI;>pyFlfuqjjX4k_nxQ>=glgq_YFU9>}+%P0}z2*ErKNx zelQx%<(#z8NY*x{H|2t{C3IEIxeMZhMi<}$3^;$_1hHPXIelXhW5Y^Ey}+YYEx76! zMw4TDW|H)t(S0q({`wTi){uT}@Fvdh?SoD#)8U=4F!R92JU)0{W2drSGcw{ix<)Xr zyWI!W6~9gCyo?xuEom@X`HUha|4Wrc_136Lg!R?`Le|@x^~57EVIqhCX*g+=Cq5OA zvcAO|mbHO1X*V@GuO*q2#!7Wjwyke4G5;mhN@DtllVI&%W7rv5v>rc8Ng^N4 zGHOUzkon6j5!R9bFGNW()mx?b)ZHeMHPO_7pkF8xiAM7)rcxPlzdGqBTEVBxSwWkOxa801&iXN*)?}9o9$XT_(XA2_uLo3wn!gi@t^&C+2!-qCIj3 zWt0x=99E`(+Z|wdc72PF|NQIiv92Y)kps5~bc_<|g6_IQ{%W;);l1pwR_;EBa>`mp zs>l^8!y;^sn4N0AZJH18ua>T4S1Rg5Tq3Np^it}p-< zx37!`FJ~4gGJT9zO@wL-F6uCbs%7aC(F$U6rhYo_427X1eL3mJPC6VYjW(vDU;Z$$pJ-0lc~pHGgndk3 z+A9-U935IWa&R5bv(MyjJZWH&A=3p}hIUG$c~i3lda8C@qt@L-#lZOPo6GcMLgI(uy=yX>v_!%$ntxN7mUUU?E z%_3oGl}SWX70cPk&<=z8`*867#RPbGvcU0py^GwL{6IM%EjXTYJG~k7QnPm_yw9u> z7wPBh9Q1A*K>;)=x4>zr|}+E zEWc$xCj9rTpi@g=CX;MHepNvN8Pfn4H<)?m$vlhUPjt<6Wu#3SHz+nC0FEe1SU%in z4L0*Z1W^9y4CfGkK{F|R@b5U172Q?P!DaLJd9AhE!ODlN9E61W=({1I)}${xYYepllnn=y39_&(-kH|9XuH>|wnk$JpKE9m5?u4l{XS*d)9}P8 zQT1^MtM~6kXY$84D6U>^;J`vcwtdGLHiTgZEf=8Rlo74oRMk31BCgb+rdBuw7ftK^ zny##euf~jG(4RoSF3gTOGWEAp0Xkh)Y)Av^fCK*(`7q??rs!6G;M)L_SsS-8V7AMW z45h~0T|SZ_;aaiqqn&>dH5)fL;Q9I<~cv$1C8{)pDf_QW%id{o@^3x7CYb1Wz7Xy2D*L__x7v@ zC9ReRp{bD$OBTO${*1g5WEv&{f__%O*1Ry=?Qf0|udRTWbP zaXYuMQD$+$poLmi2_Ic^|52$oAMBWZ9@eJ)V(4#$^47albdl`D>eWb5F0Pd8hT7Qt z`-NYNEr-{6{~}BMFu3T{Zp8O$uKNkrf9(SPMh>Slc)b;8{M*%UZlQTzm(;o(o96;t z;Hh4I&HIazh8>No3ELU@Uk=+6YLl;^LK!vGX2rDI*d1^F zVa65Iq5xPDq`Nt}zZ^Y>JJYxcc|g6evKEvR2%AuYUqpVsLmgUVA)v&R#z~I91nXy3 zV%%z&3{G@6-F_ker!aQ!>VKxJ2Lei92LWRG{}#p$4mJkH|2_Y=EWYZwOxjXU1H2I` z1jMZaL=(<_gX!EGHR97Z`JVXT(4W} zdUDpGd&q}OxB2)8((dY?6Wf(tjV5+eha8vW+m#cQpE5^jJ zlWW#Ixu7ebIO$Z!V)NiCT`RvJDQ7D+x8T7(A^WCQsAhZKvOUw-oM0`*ZsUqASb;{9 z+dO`3t&p}AVXl5$IXh;k}#TC1+H zdZ3VcGjMs=$XaNy3(-nWQ|p;ke{sFCNRjUgcsbu==ne4wxo)m6YcYH5EJ~FIJTli? z9aFbvY-*letNpd4xZv_5b4P$3~8-cmG$f^<^dF8okPISMMuh#h!nL ztDO{+)?sZqqYnP8M!(c&+pN||SJCX`?Wcz1WI9E@0Hl&a-$Kt+yGJFrv|!0yKUtQ$ zNX#kUSDw5)em8hsQ1?XtZItwr@N1^C{3PC3VkWcn&rN@A1f;9ywaKmI_IOp}y9zq} zu(QDGBYi$xKy`%qJjkcSULVs<#%1@iqUM1^vly4hnL#W$l49`t4YO;9m&AS%#S2al zXmJg8o~9F|T}@lPaqG$$@1aEJyhf!)oJNp zrxV}mJM(!>fbkngk3&7vGY?s*(uvpr}hz_xfnQtyk7^pJXgK-;r6w)2g&OYolf_4 z13EY4a2VoaYMEY6j%`zszaZv;bqc1bq59g!DKHxc1%;g6*)rWO&wPPXKIV$`le7+ZPL zm(6%4%Ud!(h4AuY6U+CR7a3eD;-}1PnGO)dDP4bngh|kjM=mLH`F*^B5%@}H49J$o ze&4_Di(S4$0XB2?JDllT%ApL7gh^buol7qk%u)~mAZH{+ExpW#jx2?w*53Z9sp*S= z8@~@HF<$%7v?kSCfjuoHid?Jz5T*{yDBKTq-7OONuJ!Z3+Q|ifp1Nlz!*1%I_p@z< zjIkyrM2Z@^@+qGR=})BYRxYCu))Bo#&YT%j+B^e?JR<0X#?MB$16u7Mh0St)ML>jh}defpg}{f8S>+bHtkE-YmNR{sGfEr4MD zYAv+ODp8y0J!=HEtEXZQCKU?i}nZ5Syn9p)=(v2E}A{NkEDaFJ{^0f z&fjP^yK9(UG={>zgty#9riaRZ;`-0z%v#4)o>K6kjO#KOQ#zkXFVO0)(db2 z^eE8?an=Qh*-F;aVRd8$s^$=^2@9C zqy~oPw6n%GhqY}fV2kEM);hNHSs||Nidx<)XwFKkPv$yeF&9P2BAMRv?HY6*76pH> zO3nQJi2YdbVLCQMR*l}C!=PS^R+RL|)oyMESy#ps-d`-Lp3TFMUeEuZuwE?;Fzs@yu^Z)nr z+N~7sVBQp zkukV|q@G}#!aK9q;`?=sUAKe3Yk3DL9wFf_a<8^25i-Amg3^hpqvT~+NAPHVPq`C| zyb=c?9&%U2h)$p2amgE~HnBr;$S%2cNz>%Sb4tWwSSv(l#lw_4S6>yRJ-2CE;tXL> zRqQHQtzyS+TNzr{PX7*^sQeJKs)#9ceK(E%yjgI)T4oj1B&^v!nnoEt;g{r#NEnp$ z+Hl2#Z9{f#X_MJiFyeh^OKo2JUx7lDiW3KQqjBGl5T@Z|iw`)?NuDm|e)2@%4(leg z#DL#j8NTK2{dPrk-VSEC9Dt_59-p4`(?Z_61c?jR2(=uVh5IG+m^Dy`Ty>h6nA*XB>jo`^{oI2N!$vLF> zG9YzswXitj>UC`g|B^QLbJHg_zB|XL&Fq37)||4C4!+&cuml?{essN%_`AK3ihKexRFR8-}0NT{iaYxmyvD@|qoI8@0K&?veL?Yj_{{uM4(l^bie`Dwvv=|+7ZxJsVc9VID+8f9d@!#GtV z9=~U~!;=y8rI;6zog!5}S%|&Z%KTBC^CV$}l`HAgS7Gt6+puh8JE_GIsy;iSeBV`L1!#Vze<%CyY=(bKsJ)+OVAA`9o=`Rd6 z1bS`3JQDpI_zOK)oks6AhTFYcw;9CgUX*TM!In`1#JwZQf(2v%8D|>75e22dJ<{lx z(;ym$;PqZ7SV8e!e;{L^w&n#-lV%d=Ll}~_cD0kYp<7tqKL>9$$R^q}(pon{U3#3{ zt^}(=rYi1yxD2R`Eex+euThIo%+BPchOR0SstOXr|M6F@|;HWzsw=hLB& zGhpD&EWQxM2Kdo_Rkabq{|_r6^+bH6qC zapd?N>I2;D&7?hk4l&t?J3^kWWA*A`Sd$Qw%&dYli4`#s;QIPhqXY8RxW3^=1sTSc z%+9=%w;-O(vJUTh4Qg|*G0=XEoNIwa?4vt9a1Gk4g*^*VJM^2w<35c(WSeR zH<+WaRRTU-w!k+{4%=KeNR~sXNUiOW!l>Tn!4cH4l6dEAN#?W5Z}I;zhET3SkZ4PD zmmW03}tUpXs^cMvD;GL=cp<@ItRvRBr}j*pV9@0a3NgfDg4^amL9!AT-I*t+8f**r4Z!>c z^IWe`e=FEA+yfD|M63J@@;7)RB-n@GgqPgk-M_3t86%{V89E5&`HJ#e-MU)(`oN#5 z@(A1NE!^3a;xiUTcK)(cfu+76WD}~7>id;7i#z;@iLDM;O4HBzo!edBa~NC@{~ap( z=CEaBAsa?4HS7%70!VyWG+-)~kp4*2guzB^;tt<&EREkbDl>U~&1o?_2Yt&=t#%m( zK$blSSOWk4fW3MgDg6ek-*Y4rf7g$b)u;*b`f5+Bd3rA-t1#@fBW=4OvfcOhcsF$Q9d0Pf& zSRi?iXox4BmxV1YcokD#>`PU4vXS}c0WOF&YDcTdiwLT2H`{oyDJI%VCVInyL1%5< zZ@jn4wb!Gkl-;^1Zn2xrYbFkEjrOfay5v4n*Z$j|QDI9Yuxfk@03qP?^uAA0p^sp- zcs%}efv9&I=y>*RW+EM#@nZCrF}$Mx@~h^2|J8Dz#T(?f=+fzkOqbV5fvVLrIYxrs zse$W^^n1yH$nd<{I7CT^T~P|x3WF;aU*%S|r`)+^%GaJ)N!IORq6EW*{HP`r^HyJJL4@C{gaKX>o8P_`e^Rnsx$|}W;(`3b zN$w7pZ@WhnKV9kRTG4a*s`olzarAUv#kmNyFJXJN+_v33aofqYf3Zc;Wg364`o`{k zjBX$0)+j6)KRkv@cq%ein9QUjHO$>L9fh8A%uy42YvJJbRosWGM*)ydm?Oy7gu@9z zCGdMya=fc0wHnIxYs=#skW^q1Aqr5PGA%Lh zPlRH2jSq{1C&9;76O zH8OGuh`C8$ga0<(b@7ctaxA(-j*T!ss%c0* z{(*Ezk&AhqEcM!ll0jp5nQZ)a+?hTxzh{KX>oS*!3=vVS9R5U?{uRrP_zf-o@8nwl z5Ch(H9VRbBTx~KtRUf_hd9v~wG+&IoqtB>Jx@H)ii)JyzR+H!bnocLMWN3ysg2Au; z%7yH&56}gWc~I)lVCyMf(`f8vV)LzO4J68JU4n>YJazgARSv+vK zihE(Sh#scooM>!Z76kz{kH16Xq+Em+5^c?Z5IBVZTZ@KqYPaz4e`C+mHfPC}$3(^@ z(1$jC)8e$M0v$uS_J6;MYmX-muGm`czIY{D333KHs3kF9+JsK$`5>5 zm~T|oK+(yIKAC;X^>D&@<|X3`oOy}AX5}4J{{2YAsE9cW-|i}kKp7d;&0;?|-9i7TpCeKv*TN5`EcXIm zc(j5oaKx#FgsT$ZF$O#5rof{^L%mD&6@+OYR+mjwnV)^1 z!uV?pwXpZ;Q%RdrT?k~6xP-~35jDH(S!ZGM4ck~fiJajmL`^t*AbK--9J56{_-)EC zCmiu$J5RY8)Lv?{ zSMJaYW*$W>+t;7^liQgvO=ATS;oux=&T9QnybQ74Nd~T~rbX9s=G!o?OQZtpPbJGD zYu5?OwBiUQU%%)FPDl|X3|pQ=Y0rtvf2mi(6w``$FN{>2oyIdPAfb#)wNQV%Jat7V zUMCb>2Y9#r$a$)mkU+anUK2(I;7~|r)#<)SD!@RUp_wpZPZ^o>?$M2#Xo8Cby=@;> zll^Hx z0zV|E$=RPZxOjS-Be9QK(Rt*=(^yE~Z+>M?IDV0Y{38&~J2maDtq0H~&*XKGWxncc z((E`6G-XDuKp9#{oftjK`pKS^HbMCgJZ_>Yp7%LfPKD}rdbKDjc5KBmboZrV?bo!@ z16$*y_0ez#^cVR#d89HK*K^8r5H;iXcV4SWk@75dV0q*X?!twRl*#Gq71JZUn@@UV zRDU}vX^ow15N?Mnp)rz{!8qYhSKNd5n@!V}vQ7?Cbmw^pCrwu8v)INZmg0-Sf!-~d z`P>q~w2?QRU@B_x8}&mbh}C=c_XRy-gc`Z6lfGBalYhLlM3SpTC~Aa)G=oS=k(;FhR=19^7%ju&2+NOVo%mIiOutkL?@0mwNEHz?5dzFw!fSOvmT9 zOmR+1aE^BeRHq2fe(RP2raG*y#D>B{&dt_e^+9k_j;0Oatl?_%n{Q-}l9ku`0H@h) z;axNfx)i8J8Y>>KAu1g@7}yTdtkTc}BFFzuEs^ifr7k`%Uy&?dinL8D+`!tbNT!o% zX_vl#jkhA5EI)#7LoyqL_*;so4ExE(j(Kr+P3h)UGaJBJA%$yT{{k>yf3oE<>#voc}y z$mYTz!MF4E1TU0>RzHBT|A8~7fZ(7Ov)K1LW92ByxwNHBD&F3@=%C;5fUks<> zgd3Vns;1bYoIY`7{PNAF?ygKGq%qYyjH7Q;EY^^wY{)kL#L9&GkWU<@Mry{GRQ^sH zY>r^qZ&J3(QIgn+T_&ZcpNkWV)F7*-F(}517SBgwo6oT zuv6M2wlvMVvvFej#8$dVv>M~x3pNH6anQ}y34Xu{E(M`dEJ}@k_J6eQ~n-XZ9KSdffkm^iZ%+EiFCWFn%-leBWO`k+t~G7ejuW zXAqRO-R`=Z7rtV-l=m%!A!k}Ek3h;%qC!Hm8BJD82NuGslpIr?fWKSssIui`I*33< zit>b1wsd-`P?l>UC3);3tuVC8R$bLH=vv1Xj7XLsT(!{fX~`qP4Y-=mB%5N7QpZQ$|hY`GS3xxqo z`N@Fm@gRQlo`QRuc2j{;U5^~S@p`_!D(ACl--rjH1jQkup{rH$g~8nb?G590tU0D? zT5D=XDO!H{9mOiflyerYrJnf6G{ERZXr5M?K1gQX#40L}|qAQ&U!HS-QVn6R1_DV;!`0 zlm+gii`zB>$ZRv3!UD!0s1KPBm450V{uWug3jx0g4xDWce~*ABn`CMLkv5y;MU^qB zD;~*&J4x7Ea0Kf)XugS{|iq*u)irSq=JZJvY(0P<-0}E5VM4*fTdyyG6dc3 zJ0wILMUSfV+92C}wTgmmRHasAD=`lcy#jCw9cJrUak=Ga3T}=sEuUg7HVlz+Ey0ag zlx{|))N3t*0IpNK#dpRy4W`GCpXtDz+0jrt7Uu+aeLA?+ z;ReH@i}>Z8>$Jc3x+q@*5H3u0VD3&vi-g{?7cyS$yG&&0H|@eS62JdP6~&JDg5 zD^XzUY9*M2K}?rmd2cr|zQEov8YzU+Om3Z`8I6J{Gv-|`Jjg@Cuz}f|IM(@skx+;f zHsW5ejCBj-avWFz-G5-nR5J+@vuBWt;*BCc$E!bPUUpmEFsu*ab#Ko};DAkMM26U$ zlQf9jcUDh1i7$3E#Mg81Jr9_$6YCdHP_cDd@atQ_Pzqcp4h_zl)c`SvcjiVixyc0b1F)!`u_~iF zr>cK?h=qwZ=|BS{vC6O$w%eITxaIA97$(MW!gXSLu$pDVr2LkJ1(oa>3rkcf0|_>} z;vCnv9RDOQ*y77lge(pNK>-J{Si{oG$F7vTnI1J?(mp^{c!8*=Tqtq`qkq&I>ZWb` zNJ@#>V`B5BQa?8iQWr1@KMhE2>!NA--17i<7GOVHg%9`c=8d_n&0PqI1`&`=j0QCE zu#hHQj}~r6kK5`PLl^~e6m4%_vT@Evqqdln$}>~#>;rrpeK@rx+b_`5}VsYq7cMT0W!~3(g}whTcRV5=3tENJF2H9$T2`oYKicVqz9O!27$({o0Usv6* z`-xJ@;GR!}0X0fAhw>bUOr?ejOj(lpm@gubY`F_gD07B&rZQwLp$6he_VAndH3>4R z)G{J(b9Bqt><#{R4=AGOw8FUga!R6OkAY=nbDh_z0dG+E&NZYA!{uz6ONIGyfF(Fo zetyYifW$)}t|bg&Rw1^$s#lBV#tZ5>D_0TI3_#77bT2B_tIRby31Ltt^7!VS2g z%S3om^0YaSFV4$EI*%$IiV7Bk0=YP81`|W0zzG|}#_LU~V#tc*kzo`l_kkXP2v1kR za_jtnI{?3$Cn-L~ZS7(8J_IQq5Wx;GhUaYMTl%4KA)6mE-9~M>I2@~mBLK~A^lWx% zuChgSo$vL=sJ-@T*YexehtPOm98AOID6eT}1fi1XvLd4wCXvcyjX6~V0;k+Z5S-My zgPI9Rq!{%geu|J64kl}vng^0Eqlyj*N!8Uc9a2OFq23LBYC^J;PF-NBV)c@|$IgCl z_6&PXB4}F&dF7m(2bYQk^3ofzJf#bh-ZS&r_d{>MdU=bU{MK;VgROWIcE+YZ zYMB*@F;&b){0l#ySq$nQv(=W)=i@gSV)8uInF%YG2d^~vHO%#PcKc=v_R+UQgw@fQbo@GsftA&e{bk#oHu2!G_)}{C+$7&2+YOfC+Rv*~u7wKn{zkRiIoDw%It!a;H z5Q{t3*pR0`e)pY>ZoLP6BAu8@v+H_}rd8 zV!*+W%F|yzazEN{Z~ZRMwgn3^Ac8l3zgb;&S&zhx&22h8qXk{UK%dB8&+0ncvB7?N zR_^4H{?#6dWtIjUF|~d52hH`+#W!uwkKbm^i!GuSd!9Yb`+lriBdvp!lYYiS{iiR| zdv|Z5L0N-uTB5}MjGFMjr}^OC-QloPwuTYp_DRTq=@DfkNgL_WY?WOd9UKl(16J0p z$3Wg6-Z(OlsiPZ5DG*jY%&eFc6!21N7S_cto{SrVZUFHxC^q0XEhNIQn}#5RiBn1rlj|eds-}n5o+}%q9WP3xVu=?3Lrb$Q^-Q}3G53q~rCrtd z`Bu7=i&`&OYi4lk`yFc`Cnt9IbI*gNN|q7FJpcCWeDG$heK>LmnM5YXI$#kmvSqIS z#8X%KVI9(j_z*aJ5GxgWUM&F2dA&qT!;K+j8pJAPz$jumF@C59IrajGLt?NDvwDJ$ zrjP$Zhi;nq`v|TLoRg_LO{D95Q_&5q(PaM=2;D*2AzFNeM1gA+$8N(!QWZ*p&V=k{ zgbZcHUS}|!v{_{+;tK3{v#b{ZtgT*+Hc5to|YG()% zy3VyKF!&acEUlrekG$(k_(5~ld9Es81k?ZTv@UK!3n=O5W`feyk$eKh36KCFr~_uO zi1qkshgct+pAOb^%Xn7vq)p)HYJ%mTio1ZR%T4|Kbjp5MwN^INE>vH%6nKoKiYiMG^tl%VMVZ=H849EP#3rrX zX1?m)m|N1SgPI!{)Z`nerI=%vSDZM8Ms15V8)`odHCrs|puiyd<%uX5iRF+4RX8>3 zM89ZwVvF=u$1>6LN6O*mgI|<6%h}(|T5r|}h9wHAO;vKb}e6GKJ zMc3JDnxr$F#4o+S4Y}9+$?kz>~(PF|-$P#8&1U1rA?)y5E450t%b~#_Pj(ry4X8 z)KkHAfu1@M5ymJ2et?|A&0}Tj~Y=J?r=NpKAIFMudB8O1R&vMO!7r zp;I+f;Xweq48mSHq@&Yv4A9HIo-RvF{S2dyw1*FB{l4QJ1HW?tC==aUA_cHE!e2H) zJ@lYXY!y|ahM}oTS-s^solAus7(I~d?2h%G->61%Y8s-Svs@TN_UHvUHedE^ z=j$+wbJh$KrI(HH`6(;&F38VIQ|#nO3=&;{)CW^YKa0nIkx#`65Htg)&rRBY*`rA5 zV0xZtU(vyNUQ6JTJ3RKoJMKGv?L)%7?E{WPoA=#{96zhwOAIal!$;BD&^GcX+Xg~f z*WdNK0j(tcamv=7P?0Cv7l#bLg&w+xrqhsZFSqtx%eFL)I{mPQY_qWjr(##*p~Vg1 zsTe-=^NIW}KF|2KKlJ>Dc3pTY?wRLOvIErMQ_jxxP(9>eFlE|i&uuiiWY0Vs-X$K*D6*r+TUi6%s@A`~svE^0ysRy@hZj{h2V%u~O^J_NO z*=^^1JHOIoQkR1FuI80S-_eDbbuAl*O$O5-COd?0HB1xHWmaMNuGpGM2Di>9xyV_!YQ}=)@&}Nl1>pbfK?;r$|ADl8E->J09^HMgp~t0 zbRrvOoLpnZ?`u)(qt{+r?sx4$FTs=Y2L#6sp5}wQLyq0|ltWV@YI20qKr%kGSQ3*f zZ4IZ9jsLFLME906>0M4E>f zK&1Ng?B0~4Rrt;o>w%dmoZ9O*##eQ5ZUD(M69?bfYK3YstTlxp%4_FgolbQ0q7=a} z1*Y62=-3xK5nM%m*;?ftkn78phiP^R<7tZt{VkMv$X$U^ei+R@TxC}=nTmsf=S$Rf?^G6KoboTU0QdEm9$KEF zwLSl;@I1F3(>D;$b{Y{s{bg!|^d^0f?$QUzFH_VBvx=jI*6j5bS-7n=R$vZHDMZ@^ z66mIC3JGXT%z{jtdDckK#p}E*Sa{|jPHR)-Z8iBT_=WdJ(Kg*b<_&DdNm0&MTNeR6 z{f?z~J3b6~q}a90h>zW&HiP%i11G@WapPMrKH}GDjqSamh4CihAfxpF@YN)&##$_+ zz>7_$fZc(kwBoele1U|_+~6xYA6)=d?S%O4KCibcHv2!f&v0hgiigNe*VgwxzBtD& zAHe~CiDQZ;&3x-dG6`ME-l5c_ zZUQ8ReVb{ac4DLjqiSL{S?CvK*F9n)3M#-USH`4p4btoPS5R^Ynph=5(4~an(l+UJD{%U_`p& z?Ea-JuA_Upp^;%_eMr260C61Y26lUmE?IR6X zZ%v$P$9calDMW7*mW8~fyqEobBpEOAc|*4Wj}UW=`S|X zZ`AQ>kyl(ac=sNDZ>hRni`!d~eWI*qFvG+S7lu?mO%x{z6jSXV}ti5R2nDL^{4OVS3gy zd95{A={`tbP6Hq5G`s~e_a^Rv;H{xK5rVdUu+Ji{_dMb*KAxs?uVtLni!fAk??jiJ z(?C6Y3h>(VMI!p&fB)D2X>vK(FWuzbxDMQJL&Z7=#)voiPLd}jYhm7o&e5_qJPa3} z&V9Q%M9Epv)?iD_oRSW6l5(|67L$opBfb9sp7Nb9#T6enDp`{W86mo}_m_Pv3f# znyr%EM12v3$e!yJ1=Qp7p=umfylVJ&Y2MTzrY_G~IJvNR|M< zCR-6!>(J-UHHMP{dNFu`WJ;Iez&##9Y@c>j<+C`R?2KrWrj$OaHalnqAsR)+uIatH z5Y_C@Tn1^t@oiHRB%2KEnLQj3Iya2aGNpH>ij_X)*yhkM0NAG5xqpdiXLTM6b5dSc zzT?7?!oJ~#(=Jl&LJ$kH-MA;hRgj+q8J=I4#F9k8{1*c0O_xWt!!j>h4TtY!Ps_!h z&$mFma?2CWzIR)$DBulg^| z6oZrk)mq|-XCD+y8Gb24FYyjuM3F?cm%d!mZ`yAJWE>a(@w2H!UnV|}?{nvyDP6weGfilYOzxXK2TkjVtjoyv!YD?bVoRIO#TXJq1tNz65w=_cp_fKA#VpJf^-6K0c!?j)CC zM+B&`y^2@Dn5j5Rn&9e-GWamyO9puiD(o+6%C6})X-JXFk6KbaG8eC`h;YumF=dWTMy_)oo~Ql) z^0)N=i_feN9FBbJCftA2W`${C|3s;H2H@(B@wAJ??A_JRwazCa<5hK(sl|5ja< z>CsJX(>GXiuKuB9m`?RO>g}(Qm8ab6llL1Lg440>o7+Za{V+L{zCd&W%ARony;W9= z{G|TmN%|EtFt&0AwC|3#Ql@twb5xooi~+stnuJ*wS*xhc680n(VE-u`wsm%C$@mI` zvf3q_Ql{xbD%de7Y}bH{6L9djdTX*6Wj8C%3lK<&#`8l7vrQc0$Km^oyErQ3N&`&kh6SuCLZzoxMx0toBuP=?YPeub&3Fu}Ai}ID%iMX@ z8BuNDQ0O@9T8cL!@C7B*d8eCH1$vg~;4Atvwc9T-X#6I(!2Ur!O5F!uS$jaw3_2#AO{^v7U}Ug|j5ZfaLM$Bxl|VKM1U?*Dw%s#6m0s zU>BS-kEsM9=r_dH95T-zBB#Tl2K#Y)=9uAPS5G+1T5MGGw_AvoiNd&Ldt{-HVAj6i zr32s-6RrPAaHRad_hb0A6?RB=nhAcBc7h)cHUzhKryc*3G~@q0j9u}8l!VRXw5jwt zpDvamU~JNV*G|t%5+r2>!B#9tiFwwTL};A#$fkR0Ofr4aND2(}7?%&Dnv4PULTW02 z&fb&DWL*lH({;}&Wlz0A8RV)1k2Y?OBTP~p9@4vQ2a<$)S?_+*gAD4hmn*9W zHgMt3PO#5aXJD5-8%m~8#GkqB9WoJnL2T5{mw(AX`OF|$r_BF?gk*Z*6IwKc>2pmk z35-|m+Xf`sw5e!Z5tl_Z=KiiF%d4=!P2Z+?8W&FieW@>#*~+tGDSI##jZT20Vs9q4YjfMPx3t>Sq0I=l8~ zdNd-M9F3A@4GF{jJP<$Cmhm<&HZ9a&`H8WR7y1)o$G(j3QBAK1z^e4GVtKgS=8WV< zyLlX)tCB;*lW^by=EI^{zTq%9=QUx%>bObVr}pP}EmL#fS=^)4o(Bm(PyxgTXMBR9 z*5V(dt-GSz5W=QvsOJijlckT8m)Oo6a~CG!e6^W`+^QyNw{<_88YfyOR4NB> zMN)OOMXC;?Jwdmdgy@4X%r6uLN3Z-QLQ{C@lEt+(5?-F>*IsOiTC*hgIEfSO>@T)2i5>y*G_TEIjTX<+dP zbUTA&k|%-Iw~tOI_B1J4LgIdCBY=}g+ZEooS#8D1YdVPh%z7w1RnEMuMx;b>wPFk@ zw~e~EH{1bEUUDf4^>Z4-!|a#Gf6-@g+@-;q_PxpGbaQcBG~2a>L!3mvUJRmlfK*NI zG5#JmbXG1%`-PO>k;e|^LNcqV8Zi9zD7`ac|2{OLbaY2y13Q4zxT1LF(~nd6`!9$> z{^E;xq#dYfbyS~MgRsY2Y1PENR89KeL3(5zaN}~1HR%x^y+kYwVE`L6Zkk?DsQFB-s6H2=B^Ig9wgW zL2h9b{=R=01w3q-2o00#kDkUjnk7VM4GdSFUdA;TnhK2;yM*u97aeY^XQS@mAJI<)*xS}p(c zfeSw1tV{{pBi6LuD)3a|cOw13oj4PhNl>cKSe?KRcY~xM4Iek{4wg;Wzs#4Igon+6 zQXD#Q?ggcQn_O+3uRff?O=i?>F!0$uV-C7ME^lT_T_Pt(Z*|(b?*>OCbzey8lfQL<_XC>L02SHr zTK!awUOJ0inXMIBiUU-O-gwF3a6cOo;F8Njb>C(cNRvn2lSTJ#%O_)r zzVo~DBYQ2fqMoX`R%~vp6>b`wGqJ_dRangnImrHYrgQ%5KeMgipWhw|IP1B*ye)(} zw$);BmpXkQkPw_7f10jAo4+1qN8|L~+j08q(Tx6fpZ_+ezkTvHBvMAtSdYW=J3to$ z`5wj<{uj65{>AP16`={`<-+DP8l8uL{2?ig%wu9PHBJf}5pNs?tXE7^Q7L1V;UOj# zt%!nFG(|%*3e)4o%XDF{Y4&kusLQn$$eL;>s|82Y9Y9?Nw;r5YJD zOjk&pn+wLyX$ZUAq(qBW?uLM&0F)M$H5q_g(rHax0mRsrv%jKl74?O|n&ZG1B)@VQ z(rh)1huF9hUh#$JrFqmtF#D(y!>zQtoj@CTi zW+a#)oyj>XNXA8$CD51qQ+!`1_KIuSc)9e$A6c}6sxnielB)|kHq)W2cc>;Ac1R*p z;RR7izCdOPo&9*lEu`y(RweV1k3X_RfEB%}*uIfQpfYAa0d*FQB@qP%Jr1NeW^R)& zl5WK-2`Au4vA_bw{!NRt28lBgaK2m?^MYe5vW6|=v30)Dpe7B=z%#f#VzZXpX`#<} zJQ{V8E(%eR_A7J+5T`Q%<83+MBJu_(f1%JV+Ee0!AS@n>yLP|UE(PzO-ZO>fgV4Rc>r+yk#Ytu6 zP#`JF3oeR4tUd(ilE~p0B-gzfg`*E}RUpEI60R8x`?t=>RY6pqssTSPBTiCPQ#Nmi zIIs7;%Zby0+-?jh+ZMR=W$j(b92S;YwJiO0xL3>|bFo0UgapHs;Yd5SVjq4b@dCV-)^lsaNJ3mt zj>eFxWCutx|wpcN`n+xI`aWK7(=iG%G%(BKXz^*I*cB2KJmL9O(;Whi@P?_mT;)W(+ z2f=~c!&&(<^)Ji5HWHb71$2#4pk$MS$=$FeJ;>Lm7W~W>uvF57e2TZGjLYYV5Tms4 z;0}E}iH9f=H*l}ofWqlYpBw_yJTRK{3(RaAoJXFzq zMjBut@A1_?^2J3$?S!8tZB@auB<9C>uFRR%ay`ikwpzql)Ofc$Uvl8K0FF)4$GB#a zxG7SWGy_oF8m+B+NGYuWGKoEbU65L0CSmiU|6CnqJ_V8XeKgCmY%wC)(nQimqidAG zVQVGZItf}bmZPzfB6HNo^k~b5Musmm>>OXTLqXJeT(dmrE!lqwp1m*AC%lIIlSX0k zj5$wQd zal;hZG^~NcK@A%s_2L&XEt%=b)#?GJHTW#EQArRgh0Q*9>Pv!kXHm`?gfM3xh86H?4fwGfh|j8TT6M46>{tX*OBQcTzVq zBP1&q8Ro*Q3i-D<=bxa)BBFgqBQ0Rd`!7~7-xSY*ztUn+z6qfLi6u;=o?%8T>{7Ur z-Wsxet`)GM>q<{TpbssoU%-+FQs9PdHj*KU=1KX)y}8J#@h^vw9>d&H7xOAp>$!pj zawnSVxnbjh#F>eG6440PYN_1mY`yJ9Z2g+T#~}gy^6e%OL`2ruv^0z?2kE1i8m+@# z4^e^K4Kxd@Ygmwt08@sX&ew68w~X4LRp=7GBi_6U>490#q7!N0JS^(0n2~I871nv1 zHc41y5@g$QtP)>6X3$z!TCc~kS&6OS04?B?>n<{z;DEzR((*PkL2)V#nt4{wi4cYX zR7o`DCa&o{1pv;)*V87LaR6r2NW4$Lif%VK@aPZOo9kZ6q?ogs94d(*y;@X=@S0D%G&p z93LQIpshkl7SHb)FHm&M)Sj#yL zYB|Hm;`t_BPnV?JY1|6U3~^KOq!NhiJAbIVZDzPt4S6kK;#Q^fEH4A4$NQr&Op11_2y${Sj;NK7F)!BTAhzksF=pz0)~VXc*7F zX$7jFQ{^e(Sf5)_0TvgKD;UPgTGU-k3Wj%kh$5Qg06DPXmMtXv?CN#1M9*_(S zm)KdUX%H#~MiqGGnM!f?*@IDUS^eBEOD$?}4Za9&1fXNHN*u)!4NxRl;VW@fO) z$*B`A*qxQS5J+zhmLb`PUhb^Hz`JCNZlQC5{OOnsy!41GkTo3PH^a|8lslUdLycOh z7;3t3w6KaY%eP^`$L&ywO$l{vM`vZ~m(vO9n)hSpWlZbr(%>VTh3k=}+MMm6j1pqY zWijuCdd2V-cN`V)E7ORE-8dLeCLRPeL{jC70Vv8UFmCu#=_VJ7QDwmA30B#wVpTQO z=4$7H;EC|iox;c`77^n83cmTt&`LY7$-v3nKt*9=_gF_aTB91=C;^(C;5=~H^$OU< ztn9nB$+ko-bh~o(I2N&pWG*X(ICA!@ESMxq!lj80UH}yX$6LX}YGCV`DdPKKsa==X_yZ_)wl;+)uKsIP9|rs_+{ z-q-jUu*#X`FUqt@CDHn|!-bBhf@wN0!>wNAh2Lmc~{_iqkUvHvrd6 zty3|nTWfUUZs=D+zEMXzl{oml)ECBa<-kq^r5aT|!2f(zLB9VXza&AT-ktKuFKYc~ zU)YO#$mqrL`LpYiuJ=EIWPgLL(c+O zZJfZO&mt?IP+vh4>v2u3eJS`I=9G$R*@BlYP#EB7ZpfQQ@$MWd8Fe$&T?C}oCvh@S z%`K&cW~?c7Ug$2YI$tlM!-taldlGvD1)=MIF*Sxq^s$%+e!VnKzE@dlk_JUli)FG$ zf#C={B&cPjD`$4pIOUGyg0u2DgfMYE#))kExZZm$CoWz(-EVl(1^#hSB+TZnt3Bgf z0~1$O6M;z#1XpAvO6-VRY`dbHX`U|_zXG~9=en#G0*I!717gPNlTK(s-BDBDalqQ? z7XW@HFONX);HM(K$p!6Q%}=w-%iR$Yfan!@$UhBlwxxJ9p)WdzF7( zRS`h5FGqRnA>vNxIS~zV)_jn65!ajFiGLoZx7Q?laFB`FBAua%{jLs8|8q&)gA&&! z0n2t~ZaI0G26c*RASvfqfO=S$xLyqn=B1$vsz9ZcgNf9o5@Y?u6%!t&4y73{=UNoT%Az@^rG@>me$rG??tE-4 z%4%O9hb40ejbboZRhPvaxFrqB$YoY{L?e*={KOR)HY=u-ZRynvi@Sb7uhNlJ10P=+ zFB|(@V^LwvW#Fwyg~M{l$A4t?kKIKEcp*+IJ7DVFaV)j4!tmx&bd{5>#F$U_kdPX7 z0NEFYJLO*w@sh!N9$Q(@^qB;YJ1dC(oB#P1d9#u#vu8#QjW8})MHXR?1M@Blq$sh$ zJW5}WZ22Bc&eQTZa9HWZE%rjuNloE3ZC#kyVS5qNk4A5HTvf#~iAl|4GW*E92yuK5 zmPxD+;ExrDX$3c+Tnj}lX#G($;mI}O5W1cBjEDzPy^mtBchYM$pKt4U`g(~5?V`T? zRxacl)`o4vvlUylld#P{NSkk6z8eOYTnKp2|HN8vA+XvXmbi=5 zxxlof(Vg@-u`+yOA{HEq6K4N3?bk(qedCn|v2u|s|7LO!HH39;x=j~w zIn$CQcr87{fcb9^g%3ewJ`;O~oKZbO4_(bnMj-(4kk*+y(!l{vj~d;tBfi#i5Nzsb zl;pZAhrQ3=TWynTh7psxyWAR+X36rbG}w$?-FAx{&}yd~F=cOQFh#sP$t=f)imy_` z2Q_uWP&Dh@!&}SMSzH2AiiZh)HtwcDZG__)izxRu^*VP$g^+h$Nw5-ar3e8&4VNt` zQ%CD@tzs4sIP)>IkK!l&iaKr0TuEL@WMcb^* z_sl$6LD`yn0>E~b9-pQUtyD#GKlt?#{^zTymKAIBH?4^+A0Hp%EBohPfs&KbZ+{Jc z315Ab@*iIX>S>S$+k3!yK#ycxk9uDCN+a@bH^e&F1r0L>;{Z4Vf}V!f;^pyUW4Ph~ zB&aJc1ielT;lY z8Jxm;^fi}WM&VErH1o-kl{LI`C;jN&VPF0GpT+)ezsg!ciH8Ke-n2XI8QtE0zf;@a z@Q)3xG9-s3%oFi^KDqJ0X7J8RQ70`T_|bjD(tPxZgf4R4#+X*c1Y_*G3e)PcNvCc- z6J1X}$~4pvRk>)qDKw5u@D|UG!Nv@D(kquzU%N`>On8NsLD<$=tF-kV%(yo^rFUg7 zI%WCXe?}?4h1NcIE!^)ZSXKKXbXEtvVzE^g+u1NIYOZJXCzkN2sH5VVIfOwb)n7%Da^sjf#bHDIt{@IR@L8cpdu4Q>a?%N|MxIZPJnyZXlQUug}|G zUi2L$df$G2W1Zcb3+#sW_Wk;{1_|Oa7yTxDhwJ%|YJA<_1^8ubz1{%iKtvWTr{K#R zyqN|DW*?>)2nAMr+R&_>^eicV&f&n!+2iKNh;;$LklRtC31qUZXf~tN)d|6{Ec?CD zpDn-&`589k#1DC7U5_Ti2|LmChKtCF14reD069>U)1pZ>+Zwu<@wfbg=~xlbeTb{? z{EgN=;JOB;X1F2JY-ij zV7O;c-K%u^n~pOV{iOrQhv%mAjG(JG=@;qU&-V{^--+f12k$C!>gM;xmF)cq4vK%G z&(PbaVM*@C|1tRVz5w_J9T;KXfb zCAlUf!lddseZ34I;8`POTBET_B)L|JPXgAE4p=92zQyYd@mO>QN@t<+q4AujywuKY z(9|9WyuI03!fzKY6ImWTp@fIM$a zMI}o*Rv5I$p`fg6_YmGR4e`%)>F)xRIA)Ftt$_El#<0XC4WwGV&NTv4!~eqK4qS*R zyfPHuGQyRfYV*@*Z#&!SHt!wWpo6CScR9SaEVtg+(N%3GPjAV2`+!5Nm6W-5hNRNW zb54lA4laBL`|gFYpFD1AoLVSe2367bvknlP#HlSXzD?5USJfEvv1&yC?M4z|h3i3I45FZ%C}Lpq>tZt{am`iPUg=iU*B7W_$}wQATQIe(y1uMSXdnbJb{svs@Z;j90{q(L`h)XLDL?TO)z8*Vt8T}c*>W`8C*qzY)%~dfgS^IuQ;8(1js$kIh zII4I8>u{pLFI^LC6i&^u%H^t>kpQNMCJ1R-a9n-~mpMWve3;xc*ER zi`o^7(;H#7^8iq6ObnB<_!Sp7H5Dz)REWT*B+gr%fg5EIgNea52gYthZARD9_dv{~MRZq_{c!Ml5~NUm4eAKvV6XLG3>?UN+r6_=jrR7Y2kU4p zf9}Pu%g@%+0M!NAK(=@0qRHXReHKDEb|OMpHrBQ$+H@Rid#xA0LR5XGa(`k1u13_v zqM>86AKgm_caLWoi42Gu-QUfqTJPFW-C3^W3~;q{co`JbB;~TJq-YVzx~^W^<>S1p zKzQ)q0JE1`5*)2;#eS7@1&PpDw?q?}oCf5-_Apb~UWr9%k(WjQ-V_kJV}r2lGXw@Y z)J$grQwxa%p?gaNJJx%aOlq}xYnqU^69{=pI4)bGRyHaD1fTf8Hwb(mczR5I|J{$( zJ`AtOenOW|z#9gKkJN8JOw{rXVq$!r?&3Thk_dHyaW>=Pu;VaK&X><{IMnjtvw!ER zX+bdp^TD|6YwV-OY&vxgs@NWpxS*hBL)01tQdb&x?aWA=Uf~F~!;jferm(bQKVt5X zeli*M!PCA5cT1jF5Ov0M9fe2C^`D|eQya*#eDy^5RxzC-|xODq8!=K8;%^_uRZa3*eGvqzY#I2@jC`67<1Kx{R4Kl_Kg4;z^ypm~e z*zPn8j`9I-)@EZ7Bz(hL9b4v=HxOwU6@2jGR63B5;V5P}|BD3p#s_tGA<3anny(73 z3m9Z49xzkO6?9W$U$2NV1~7!xJsaAbLD8fT2#b z4?+x~=S6lk#kC4xTR)V=iH3X=Ih{Q^fAZ|<#q-$AIZijj^j90rX!CjcHZZQ5>q>4N zv$Xb70kMVW^tOPvyq|$JZhaqf!?pe624z=nY}!l&#BX}rHNyC+Vg($=p7SbbH}>Q^ zItphs=(ngx*Oe+EkV=wi)ciD60qUawFqA`;HRnUzGE0Uwm4!;r;jH^L!o_*JkMYvy zvNX*&MF~g#8JOd)grd(hu{>RK52#PYaB8JMi?(y`p0GK1n#Nt^DL7b?a2x_??lM{e zZ7A%}y>aZ`ARe!lj$NV;C8vo4DolBE$O6vpP-wV{bt#R6?y_Vla8PlPoNjR(cXf2z zGBl~^Z5>CFb^2vj6Qileu3HZ6<)}iRsAcuF)#q^)Uq<2fPZjt8uBTOYW3`j;v)>*R zF-9H)jKyt!FfzifDg;C5B3x)t#GN~!brI%mePYh1%Y={7Mg$i{zbRl;(5&Q0M&2Ij z=%-vWrVf(`+&5#3!8c3={x}+x2%{Lfhknn$agI}+BlhmRFOdhU~FCMypLdYx-+ESFt@ z1kpTWJi|Y47sVXR7w*9bZoGSN;(D!9g$0vL6q(jEfElV8U_{V6Mb~3jw+1Un1d1eT z-oRqjy{3~7f@#?DeH+;k)G<MtgJVoA_Mt+?L=QvDFcwZGXRI@jl=AtNNP#+JB-GzOvEDhjwDb&NT0%DCw{Sy(s~Q) zzPf&QdU>*ln4w(9IolvfK6WBr zkC`8;4phe08=0$(T=5^h0YR9>MZb6KRyfr|DyMAN;AwvSJg?VTNrwzM!)!*w%u$2t z0FY!bk-qM=*?N*u{AL<@N1LcJ6M$azhjzEo3r~QSdV*hLxrEnGIU<*`IIjF?x$b{Mak7Z z<%mvvFe9szVd0X{sV6$~GP+KiCY zn1qYMNe|yL%oSW{+7BGCYTWAqnC&Sl(Oguo(l1gj!mNyBGSRa&;HN`=7(_WjbJk&` z>BE&oz&u)2Q1nK)gmW#1*m>61fiA-Z7U6-laXLUF!>Hq2*QxOZMkclry#j`)R*&Db zbw<4{t3a+0-ryw2s*=FB5Ww5?Fe_%;oXe|ez49OIYUcW-m8b1AGapn(HVYn(Ew7WdM%ULAsJxqnzV=odR| zW>zOSj8CTFN`SI&{PXx~cI$$|wL^z9$tZ4kN4#@(id0HBAzfwkJ2n``?L+dk3t&x> z;LLEb#-0Na-Gq9##TPImj94i(trHVg=*Y$PEFS_ss49{75b}OB>`GuVUX=(6(qtG` zy$|p&*pRirEH2~dNQ;t96hy87_MMcXL1A%@);E1JfCAHi-4IY0mK{ZP;7c_K_O@a? zaa?AfxIx^6B?IXA3dZG-Vy|o9N!4Apa#ceK&J6$9x33G36u0|2?}ww zr@=^oz-LMw`0+0}Y+v4e>>xeUC%7UWWw{Ri8MbV|lCxUjJYiNItEHVbUzs%+^8PB)A zd>%6il@kyzaFs38>H>@}BG0R<7zuzADz%t#oCX@^B}r3U%0OC62D`i+GO9vY6tF)X zVUnI457K8f1RySL$5k)COp>2Cj9N6Bt56j1nU5niR*WJs!xMlU@G!WQ27YmGjPYO4 z4MH0!e_sz}k@=)K>bfB=wMS93{ThqDHRY~|_wrxvPpvn&1-Q#8FvzU#ZV?Nr5+ve8 zzx{)5C3cmnCT^Wd$aLazlyDYB=XNl!ENpTqy5A(L_!!Lt*?Ko0oz9L}Uc*25Ed8X> z+jdb46q}_jc;XI9(xW7+%MClW`t;cb0XhXEK^@4NKO7K`c#SRx>~PNeo^y^>^%Ya| zt@mf7Hh{iOK6rimZFb{-hxz^klQ%nrfPj2r7`A}Y>@XsY?n7VS+bL*nx7gjT#(6BzdSx76C9`pv{5LLb6iP^+YZACzfDLg4L)ml4H$DOFUb@xr*6wvmP^ zVjd$i^7@M$9f~%Uj-pi%(=&Y&fq-_F3T-*qK@Ft}76UU@pDfaj)HAx;F}v9v2ntVp z_C2@wJ|{wOX)XV1Fj@`=LiCG@q>ua-Y(esa#8=-+oBvOU{|45V^(Ue9ko)BBSf?>K z`nEV49_E9*5c}^NJ6u}9hOS`fn=`;)&j`~ru6m%s|I~}CGhiJ-vG+~+ZN+;FCMYH& zY9s=P4APTO$-KGZUjLN0;ThCScs7D+i9{(2BokpD`50Bj=D9z_!GL{Rus*zkcCXwR z@5HO_+`e8qx6%iY&Q0kT4jjtkPKXIa5W$-eXoZpUsEov2?_?NAlhSPZaMiq>bP8O9ZujHQ(EhVhac;w|F@Xo)o-&krZWf7m1@i-3<- z2zv|A;t%9le+YoU{;>=CyeUK)>c#WAf~uvA;rksB{%)lU`d>OfLbhoTM2z6O-=x_{ z7RlLcPVA_sulI1=|L5+P1M!##*vdW{>1-Zw6C(0GE3>Xf#5>L%+6?FS$3VHio#wPA9AU<8n~A7-Ck;G zhys-?vjje6NlEtHs>45~L~5?Yr3f&Mlx^I1P)P%c1RX}R z3wf1lN|Jx9t-FK{k{D{fwmC+Lt*23I?A}*1`c<6=w(Q@em^jsb?;O&=_GAPWFkTl8 zq64}z1rngd=j6g-y5yrAVV!LrY_g($PzcC+ixe^^tX$`aiM4;DPW^@c)NRh*$lhFB z;{}79<550o{wU*oQvSy_TR`N!*BSr5o6JtEypi6zh4_&#(!2QEj{oLUZM)T`c*PF- zwfcr*j;bH8#xc8LAousjhr=# zQ^PhIB3}#I)wAi9K)ND>qU!5v&ks6)^H?8SjC4m$6W>2EUe{;yYlm!K(kF#5;HdmA-&={o)IWQ`A zH(cFZ!Z4;bXvmk_+N*}<>{2J80(UKmas5A+%{4@7CMYsmS>`$2AUOwwRmng^1dPyhGXsVq_4PmrS$RYeM< zE-u;Y8~lW+_+Hf7xw-(|@o!l4%Y$$pHaBq$pRJ2892JH=iW9KA=4wi3ga^s53PSui z{(LX`FwxuTLjoP6PCFS$Xig1npB}dX%vUeR6XXE_uwkqEdUvr;@mV^RTMm|ZJ4v6O z4&2LTV8fid6%oCtU6=swW7H%N?PX&k_;FSqXDXy0yJ@5PS}3Fs4P_P(v^i?KDc1Nd z=~Phmti22j2_nc8r4Me6$rbjLmYTZE;RTe`q6M)uwux9M3&)mN@|DL4^b|;hcWR|q zsinliL6&T8sBj0^b!cHAjjs~MW#_?BC6dKWWB{a#{>c2Xw`K?C3kloRV?E;7jxd7m zQ0&i=6SyO-CdqvC2)nvHXAvZ;MLu6;n(G!<;*8=0r$3e$7#+$W{aw?~Xue{!;sVpF zEiMeL;3q|a>g*CKI7$hd9BfBAxv5{_Ad0;L_YGe;L<6;#r|Fe>2-}$i1?~9Q*14qC zL_lOBE;z$%za>P@kLXbG+4gEa9jNdW$ceH+k z;50bOX7eM%2{i5FY1BO2WCU0ER<;}L9j{S+X6C?#0y3`{K*8`5YV;@^~^#=U+?Ln$Tc0Y|GByU zBr+=~bII}(-zADFa?k?C*=Z=vtoHEPvQmu8vuwV#d z1WHVp7d#wDpq8ZN#Yo(*waZ?5Uk`y0;|I72-WRe?4yH8E4s=H98lED_^J2NmF4Hg4 z4@QOS{wCa|N>N*lo)3&8uEZM~@r z)|P~Fn=2J!lIRpq(ihteSGeo(Wm$!4lC$QLY4wN?bv=MY!)j|WzdB^1DC{E%7B-gx zoORrYCK<7CWZq=}xKHuRbZnR!*OlW8iXrdQQ<BCiaMRdoQ z44Ge}eX6JLYzx``#gG}d%_2vn+H9M5AMWTZ76@oK^&~^*uxANwipV>-l&;O+wiEH^ zf3Nlbgw|hFWLa0v@CW?{KIwB6|IeCTIlro_5_*?GtR)HRsaDJOnC?Dl1jQ{w$ZEO6 zP1Ey65Fm!IiVgtgENt9PN0&(~pgccDN%;TR<^i-#cn7lDpR}AlW2%{*Uld*gU}c+Y zGbEyHMB148YVEMgx+YovOSBBRRCPx++cv`Q*uTy-IERO~ELiE1M5%-;+BfW^OQBs} zS~YnX@+?zeoh=j(fNsYEHJ==Ux@K9iSPH9GA_#)%v{~i(rd$8C1Te`acV#SQye^W! z&kzW&3x(0q-SPu)DpHTYJ>t>BNc_8R;?@b?#pi?S*!vaC-)X@ zw@kE>ZD)hEJ)*0-Cm6W1b>4m6eei34Opm_6Z;N90$^Aa3II^(@p4=oQ>v8!P{DXgv z)3dt0gIX?lyDt{*SLOw-$y6S5i-TLeA4o2NOEUZ9ekvV3SrD)KQN z9#1-V#(jkkyJks-OG%eiy{4;Mh%YYYuHY1p3(>pobw;NF<~TS#w|W6 zCcYTWUqMI&2L;8(z9+&x=E5id<|EGdTrvNh@uJXv{r5iiV^2o$l^+f2;OIKfHDT~bp z&$Ob;fB)D2J=^~BOWyqVfBio!O2}M9`fgF5ShmWmBYC-9t0Z$ahu7&lKzY$6@al=0 z0LJO7=W+qRb)jt!sgpRAjW`N>Y536~Y%1fw`_w*#HICZqqPx5F3iOI*DNXrqjWbJyfRiVB<3I>gAJ(o zApejP$M>-U#wW{cU95_%PN#vOH`SmA_(!-d;Yp7asZ`~J$37|xg~whR7(1FG`Eie` z-XkQ_(b)gn-nVwQZDd=1$FD#uD=|rvjHM)<8CiBlw&lcgZO3gX$@I!(2@nZMXh{T{ zAT2Rz_ivv%`#h=&044c$-?iq$&4+G_01AbAoH~zv_EA>wd#|#4<*L!FaDc7wbQ2hR z9tegRa5)a;wqmR=&sEB*SmLX=Lt2OuQR6w+&g!a&UnA|(TJdA8i$5VzbykURq=&2%3u9d z7abqe6~NH>_nWP^bzZmyxh0v_1TkKeXJ=G}f||7YsX0gzbesagJjg{2|vy#&#LeJ{*ZM(`B8*3 zF{kJb^CD8xWI~#{Wl)~w8T1bUzoea0BGHYq4i{XwcC?ryR|g4NWKAB8oG9^VyXM%Y z$#e?N<#cOf*<F!7u6i;TkJ}k0^*KMps3R%`OB*O9n$+xDe|`@xs){C3*NP~stS-&=jm;eM!ssn z$Q9FwQqyhq9*{e5hEdGYNgt<#Y~a=p8}C2P`ri>-LLprOW?|?n6i6*``hp~g1~}VK z)`?VG5k6!QLnK^Q)Xg4e%#i2)f;sUiw5-NS%?b7ivYkV$Nz0`(V~E5?VPxj~+!RFEwDE4XHu|4`{jEbw z{=;+*kwy32l9~+i@l$u^%~ll2xc3v-#|KuPl%-nCekw992f0{>zH4iky~ja02-404 zOh?Co(p^Obw4!weMjE2mCLK)~^l0K5(z|{PLzwg#*XVWODTkEeIbkh1e%6fH?>Nz$JX2syUobUlV2`TcRN8$S>3nzV)`P@&EcxCGo-j#>3{%!v?zQpFeFK1Wy@$} zk{$l5U*`h1a)(}yUsr-P`mv2W|%Cs0#4 zf7E7p-qhdYMn9z`w;yk_4|q@lc24>^{nL|Fwu`dcNDp4_zdqdfmA1nk*-m;xi=f4j z+Y52oA<{M*W-kC?AQ-T_B(*k}a-g4Z^r9ptV0S8@?y5R#Iu^D0bR&<>Qj&kEI;$DS zB(964Ko|J>i7>A)hp!}joFefoC66MR=BG{o*f%ls718*t&k3GOqAm{By<#6|C-Jex zSkxK0Koh@bXVq*(4FuBM?QqwT2RQB-he6v!HbZSy&EQx3EM>n@8aR_0-Yj;j{n2nR zQQlRj^Q(*Iy3_rY#_lgFy-pr5rq=H8fLZX5RRyyaea|ffMSicO;rDXp5|h?c>IgP~ zv(vJ!iwEEln_RAd;C1)n%q82$U^o4LhmEgE-=S4b|2L3bc7&tEOmOU|PjD4A9{1(< z_*|8p8@#?p&yCNh(7`ZxkgFkmw6aI8(M2gS)(YUEvwW#l609vVd;|Uz`Jt!QG{PKi ze6z3@q3`d9@8g_g_4|hB&W$vEuwfan;YE7_d{~WnNQCfAXxjEL{r- zj8kY%?4ZGi97$q-tDGTX3=yo2QM%KTMv)Z_i6+qO^4=BhP*e|I@|KS&^EuOB{~TII zfY?O|NnSTfAIMf)=Jkcjb<{i87-`iCb=Cbbtg{D9lsXJooalER!($l?b+eELOJycb zUe$bjBtiG0xHS``~6xgCWYAvaV-n!uzYRb&e$IsBK^raQAV;8_x>^Er@J#K)CwOs;O-I zM}>EyP>;DxI8B1f?Ly_ftf~tf75~<$Icm&7V~KL|3#MyofmZMNr;!b)AA0>T4))LB z*Z;2unUF>shj20(Cn^Ebt$DsY|8iM<=|^}gNo3gk#;T#mk_#?hq;hn4%R?1s@W3#t z!5Qc|HFH^sxB^a#=y07~-P{+k#MkUGc!j79#VqrBRzA!k=5>={7$-6(ySp|y6#TSb z{~7&kr})ciG2w&u=im?|HYt*uOO%qK>*#2;E;tK*AvunUehY!>`D$5RxmG3^4;-!Q zLKjc@Q^Jlvdf4ghzsdishZUccZKeKlo%^dgQFvc=O;EqW1yr3jaLG0p+3IGlMtE# zCg!B@1N~jf%z{qXU4aY0JDpV1JTLM&Qy*W?LhWE$SkJ{jVwlMUe$xkB+wqK1NpL|; z3*p@{OurDp+Dem7&lgm7{*p|vHMw^1m6WHxn)4XvNC(I80t{ruo*o4IM9u7<1Rsr0 znVc6+-CZ!NpquY0AA-!6FpD5Q*hdqmm?~N6l74%ieVaqQ@uM8_44g@vmM4nVokPA)2XaGPm zd1i!8mUw-f1m+rA(LN>-oCvcabugvcl!PGz#+cqMJ(uf*b%sReKgaSZ@*%=onh4pk zCLy|2%C|qL!*dL~@04m(FV)OllCPmM6{8dvrc7p2xhGGiQx)~FyLEcF-yg$IRVHNG zvQqSP>DDf(*sQVE6N1|EdD>=3U6%8Y$zX6)&UXg`F0glJFPzOAuz6aTnvPQO`N0F=RUc7&Jc<^3a zq!bc6C{n5h3D=)71hUG6sOCR}_IJ(GCgvqGG9AEU`%A8G|mx^QmZ-2@R7s z8RZ_*)7{}YP7b^L4SbI;09o7=?lg?b2~eMipPoZE20?f273r@mylB2)LD0Uef9suz zO0hVeuCA`iq8?vOKf}Hp(Up2sIxCcJ?Ta67QMf5116Az-UuonyNkohw`Sb7_enKh` zn3Uo&A2=vfoN*n1Mv1ww{2Z#t)sp#Am%kTv0;4Vm*nF0s6**E}wOnn~I?W8Uv1zfy zq&3EtPSk`Q8T;>EiMzy@n1E*w)5mN0T$jb<9Il8cV9g$^xoBO{YhYQ`TGE`&K|;PK zLa;-YAx*q-P`AH!g;72m9`X{3gh|QStWVZ4x z^0K)TG|BiinH~RHFhZh<-k86Olo#iT43OgGt#*l!*SnWLC;kPZauBTi8ouQ#99Iyq z&%Lc9t?j*hiVdl?pGcbvl;CknIAfAJgd~zia`NDD$^*HBh-&_&88+H3F`xB>m<`M1 z80+Mi8tOmgpQu;tk$p8g)CE^RW-j;cWLO$r337%vpt&J;ZEO4PTXs5c>3Ge@Xx*TV zvArc;O5w$wt!Q<9^bX_@ZA9CI@TWm>GY_UH_F}f~1bx|c^9QViG zpzfkG33FG}9N|JG94A4gHp(fyY=v>D1G;AI!GI9{U*9+A;QFg#L465Tw<6u4=M2}{ zm$!@Yqg?M;1SCiFs2^p3uxL|rs^LxU5XrOqCFGv_lizMId7QRWTa-SkE-GVS6@Tb( zo1DYT?$b|CPbpI+kqS0QcWLq~z9<1*T2?JLs4~+j+VfnjTJfh_IHN17*5!~A{!sVH z`%|qKs6jy5phWy>)tP)hn*4}7kgnT2hVE+M&G6x}6d(3D2!iz_Tb<;%eK);=D*Ups z8kB6U*H3}OO2a-vs33wm^26>hVQkc#x`hxcY$3^L-sBHXKXxcSgFK3JV zN+32ATd-bmi{7)L>VHr~(`0cnN9disZve~16}Y)gt<}IJTL!L>y7N?%-gWK02eA>e zZ87INHS3+Wv|GR1PBVKB*Hz=Z%iL;k$LEf_eptYZ(}2zLz(pFrR80)3gp)!*D=7qW z;aL8P1E-S9GDFT-A!&QHIglyQi~I4lyZ^^IC(;m#L)|}scu5!<{U0aaxLaSa-S35$ z)1~9CtnRvRz}2yg%qPxhy{v z3F%CfzN{QvLUMN?WbSx;z{BOfV376*5&|D$K%q7*#6P?Qw^g5Z2*~^JS-Ow{4l2LK z-SS>@{_iEiiuCdyPk_*-u@92CXkDeBZ5y6musi$+9Mw~%EXI91_}tIF83tO`tP;1C zWL|=~oxC4dN<8_ge?Kj5DGE!k`0Oig@@q}DLz$+cM2ls(XHvGSu{CKbbkIlQWWq~S z5!4OFIdYTS*ZP$YG&c+f*Q`EG1@PSnjftaL$`36Xxz75s`nI&B<-EH zjnmF#3E8$z{k<#_JsAC9(mK_Eylg8WY9Y5=hyMh!k{RBK0SsR%Aw*8vlT5p2?Ti3p zdd=s@g;4VSgTc z?pg`p2D}B5-c)JDDWb-K44jCUETZaQZaM0vmcyi?fP=feuacy2%9r=Z@CQm1+<#@q zmnkkrvz-U-H3Q}>LZB#u2YLR95i2MTvs1kn;RfO~SydH4*2w4FN3$KA1?s2i~8dK7x{n zilEZ*(8z4(J>`_D@x?eFbCJ@J^pLK5m{y|XU}S!W#WE-^QNiL@&jSVd@|mH*`hWq< z@s*tZe4PshoPdrf^aR|+i( zo$Z{^30wly%Azo@egYKM6jej4U~1FPkt6AOcIwQs*)j-z!tE_r;r$amc+J(1=5vCm zxSgJ$8n2Hr%UEz#Ydy;8ZNq@bv!zDUnoP*4!vvq?kj5C93taI;9RX8~K-cF1;Y)Rb zppRfu*j{A@mt1{TH8F?id>P{@!}!A)O8g9^jTv%c4ly6viFBBeW8S>7r(jZ}f@#Lv z%R7mw(`eX4t0+jv<*MMicCyikgA=a*Cr*+-d42Hn!Rsuc)PC2I5$bRdCzzJ($@m8G zr?7ui65OZ~f;$bEx1YaHIi)F>k?jU&5HIkQqeiyH-7fWuT$a69MqFM3M`aI|k961# z&AxD}3xG5{>X@j{iD9eNYXxy(9*D{CWt8s$pHA%=Dik1+hf_it0X4DJmI7PWb=F5S z`Lk;P;Dp!PgAXO7t&^|%k&lf8gWg$PmCNQ5fjqsvGlq!>auKD6cxhMvq&L94^#~Im z3_P7rQDI}tSegQMjc6Xyu&}ErTu9_{I4fw$=y}5%6BUo^D)emx5rmho_rE_pj+Scr zB;7*yw&LVVkSr*>zWWA7byN&`#eMJXjzX)~-)hAyTek21B~ z13xZwfqNr6VIy0VO>=%YJ?-o}Xc{z=wsQ1Hm{6iM74wAF!7`W88o(lqy&Fl{O{}#+@y5(kZ9*m?Is+&Bir_qz5Rriv zMEw2k@JaZ96|D=!2P+#C<0lG*Dn;CLjRR9d-}zI`*|pMDXIWH~xJHEwSF>5{D6?$q z*3pJTD8Y8?;F9(_xahxL5_yOq8vGLf3v}ShKus~ful@2vULUSb+&S60Vx_@ifB79% zy!wWk{)r?(90TCY$ zK_0^#Qtrhrrx@x@BPTrVcxJxm2`O!E<)<(AU%ftf5iWdeF(uT5bwsexz}=R)-kSf! z?Wx7Iaj3vJz}Zgbrus=H9@3h*;m*eCFDk3q2_xE8-~JLi6o0fMW$I)vLp=l zDqw`LYeTCb$^FjjgxM7cj7=3HnYowwN2LoVl#?l5VC_lwS0`Fm2+D;s+6bqJg5T3P zNhYrS;6t4-9dQyW{JyE?d-^(efS!G;EU~n;7G%x?$DbU~vB-Ir3@!(@lv%LeFhNl<^P~<_Uyiz*Y2Mpo{LypEb zs?*bg%fn!xoWAMJ9yWRiPLw?#-DL3Y{cUwM*Jp{bg8L@aR^(GD8SO2hz0ihgM#n8O zj-k%}`Q^BvQO+yK0?>~U3abKzq$5%lCN?-b`C_i|3k9@d?vwSb!%pIqhx-DOt9l%wxAgGszod*+y^B z)eph5q7rbF(iq9-GW4Mo`v0=lo^2^Ava#l*M!+d?|}3;Dr1| zs?ofq*t{4%>0egm#rXhKw&XbKPJEIzkmDc?e}V{S@x}kO4tosHOchJ z^(h>*nz10dLQwu-nEJ!k^$cLF6Ypb$M4uBSVR}fMMdFFUwcmQ5y>nNz{~p{b08vo9 zK|1UoJ^$h0{lKkdqG@9q33y>NzNYCeQtnJDBwDYScX^D~nsw}?@g5g1oEG(DQ6i#y z%o_8t=VvEc1kZ~6Sm6d39Ifsc44E8WY(C6#iq>}3=9ESZBk1|_6r-IQMq8Lw zSy=!kyO@Gu&8kBOjV8K*kl?POhTSe~cm;=ImV;Y?qt|jf*^JnHC+mc+AJZS1%*-Gd zE-^3$e7a}+S0>D(0mr>$fKQY+K#okc>ajez52a6I3X}X&N#;>~z+=OCNKSd_ykdgz z9upVRN!<@?!=D$1;*v48f)Ck@^4^KYS1=OiOx{hShCWo{BJ9qqNp_lF z)&&!ofF3P=gd&@Ad*{=D+mE?opXDq~n9Vr1$bNe|L>nxw=F4^3%eJ;iOqDaOe2^RU zHWsn^lzg=Al+YYg6NmbNSk3H(NP?G22U`^~bdSBNUzAd4^V#}ar=e{HOd~zFy3)_n zZ~N&JBEHn!g|DkM&=6P9i9kq}mq$pMh(dZ>yz8P`N&Gs+`88b1N3n=!`k{IbgvFNkI>fe%L?ik)I_HO2f3($;Vw!pvmYt z*U8Nvs8w5_c~h~@1uIp|yA1DB;0N}8GoO{p#&eqfEI!`dw9)eT&bKz2 zjpmx46*WqyT(8w~KW=(kq`0I8N4v=Fysg&rTN0+-+R!{*cLrY!$#MTXSzX5EKcd}~ z#Z!@W)UYJF@kzl{WBU>0TkS4Iw+S)0p3}Fd@^o7}^O66`WCc-6x?5^^zea zq4!Fzo{IJ)5bBbePbpk??s_vvnQs1Yxp=(K?6Y|!X;y0@2ZaZHhT<)OefsUs{P z3$Oucz1{0#kO~rLmcYB6!}{dd0aYfOb}RtT{OJ7zx?HZ$*IwZ<1bt6r)TMj&yk^9+K(Z)l7Vmj$!B?)0tJdZT>$b|j%vma}Ge2vV$S9TTg&*i= zM$4a|EbTD$6J~xCTzM?D+w^`SL?nWnVhTpC_LIp;(Y)ueAd^$W{)9&GJ0*#tYR)Z_ zxPdDnAC0;NS{9lCfkNJ?msK3YP5dHr24_n`AHNgB5p5iAG9ouwj$Jy3YVI<(f*K{& zoyiaN{B0UlNl-d4upXeQ_}*oA=;-c)e#q*aLewd@*b>Z9nR7I&18O z(J2EqYk9fsxa~*LNi+JNOiKsob8^}!uob?RTfL(;?k`ifZ~hlu-E!G-Nd$Z0nwNMt?u zuU4l}$I8Em_VTv0&wpKf!nS_L?2xmljEMN8IySoaSTQwAD$bQJ(g88wQPtCd)=<9E zI!j(?c)1l&qMUFYuu3ES9N-T;b_qDdFW0er44YF>fE;P$Yn8)0wDrYHiHadYi@}>> zZEH{c`?`RG4$Bg24@Y2D#G-1rIe{3U&!dWoh9CP0-RZrWJ-?&`g!jy#bV(?h^D?4U zH8bQTG``-}=jh!6#qEFnydI{X*S|S4WV3}5w$}VF>RQjezdvmJc3$>lgN6j>-V@Ts z(l5Ti|GB@;ORdZs%FeGSKRWor-q%B?`s&@@diO$+ zGcPPC6Q5rHwizJxcH{6n+W@bSDd3k#84ICG(=;pEsfbE=S^S|auDhfiz#nsya~nk* ze?5ESsIVhNFeH>=%{m!4N3O^oiFM4>d>evan)g3n;OD2V=ar~$?=JS@o5Op0aw+Vo z{BY6e-7gw4lGBHt{-95NxaemwS07nsSg*KSv~2iTkAQn zF{ttzJ;n>!aobFx_MJFchv08M2$m%iSW@qFs9~A8r9q#$N1F2xB(hJbq&6&fviSC? z1XSs)&wO!d5k$6pm;fi~5!)skL4CiIy_TM{*YZJ!S(diUvd|*(w0h=N;sVUk;Dl;y z#?x)n%sI!ocg^$SF2Fr;*V@U%R`XVtn#x!J6&)gmB^-N8LIM=NNOd4$C`LxV0q}}! za=S#oCmK@V+E+eW%ik^8|NKqCCuCNijX#rN_~AqIj;G%3&E-QIkB@01P$*nq@0U}CW8uyo^<+wX9{ys2iDIJit?5)YG(1lgGCMr6>& zQP!wB*ReY2M5P;%^j;NpLR=3_g}DoN5|Bg6PL>DTSYM%VzsOV)$hCwhPYRAUUjWB_ zs`_HN)Q6e!;Nl9m z0UPwLZ1R-#G2^wgi6<%Hegl3dv3lzUIEeEhsXGy4EGE!~6TFZXH8FoRvn4y}$I+8< z0;YQ12~YHM#!cV4IE}9I^+|DD)lMZg0$#EBX>7weq*Kq`lj$Sz4PeBVP7E@&gMA%v zR2dU+1fss6L={rU7NTy!8aG+U_|TbBsp;pukTr8u_0aj|?{CE%)a(A^ZtwUwvYcj| z78e6nfbPqV7Ar35CZ8Y#mpnspB6gx-LJ8P{A-*_Kx7C(X$r~%HU3S*Xp}gWeJDvagl0iXE&vZB8|<6D|n^q09e`uWRm;3GR?E ziBza)?sAG9Q8s?K#`}_T5S63o&B7opakUUXv}-#Jc3RYolQ?lp1E-)+0J9yD?`|;I zqW5kXoYq~9Q_6%4+@AaBr)eBS2^}~cW6f2`lgNJnyoo_gHsCP+Dm&Y4iG_0F>)fdN zd$N|uHgvX)!EMsyA)M@hCgZUk5^Zud-MMt`y)aq>Z}sSd@a>ZnD}}j!DA4UM{mHEz z@`<_W@+FCUIWe8a?f|#_!YzLc7iaKxTb^;@-6PZ^$wJr9%`j~OZ@Btx;P25XYHV3{ z@%WI$O>%p<+k)L+bp*S2`kQECi6j=fRRkI9ih=`UD^+=M`919O*Mb`uWJy@%ym_Lv zgLJ_u;k88fzMKKB*HYvaxz=<70zg27%E9?E@Omva<~2j8bES5Jhi}Sx?qbWD%aF4o z!OuCiE&eGwPk1oF5s@a}YE#$mO@D<<~hLr{0=*b^Hg zGwVr%*BCT7(c2x;{)mOsI^{ZEgJ5vA zaI;0lm?XOFRBANk3pkr=i_TEO&6>?!;=LVi#-pd3M9|S7o!{qZnui6>^dxcJdSMC@ z9IPPmSgskN!74MRyVP^M!PY!`-v0FZ_15E0=)&6{kM7xx`y7X1cdRRP^ffk( zUu?m-7vB>cd7I8WYejhuk3tlRV##w9K%?I18Xfy`1X9{e`}HcKbWf5O>dG)tqG$`? z-YBy;U#brPD2g1>S#xNXOQTA13gZVD^kQToNKX<)@@KW!g(oO(N(vPxK;x;^;}ywE z{uUxXwiIFj7Z#-!Db3_VU#Tt(iWf4RkQ{{a)aq4aDjcaD!LU+zxdgoJt#6|3sBhtF zY@Y|Q&@`CqAr@4f-Y7;IASo^=BdhJP1E`1?JZnfCklN{Ki zFVY+1g?}%+=iS|+m&Kcc|Gy{6vfUjC#wVDPcyN3Pl*VnncGngw!24l{&)D-7>3ibi zxOvQuAhFN`rw6wuzI8VT4;1+KU>tO%TUb)6aM#hFY8xsfpdq!zlb1Yc!(rgxd|$D+ z;T0agnrh|0PkZIvBGA{ocV^sjHAAheA+srlrN>%!U56GRc_%oJ;a3EHkQ6A|rh$%R z5;L=MP3MB13Eq*JxTK&=;%hwJY6f<_=98`0-KzWeL` zv)2bwT1<*F7>tE8kHbEjf1+rLD*U&8)~%oM7W2pbhAqa?wwZatq6&G`2(iFy5KiM%am~gWM$2KGv~S*v zrNPr~eR0E!nrh^KxgObpT^ntrU%`3TA>3K)G1(#54hLrJl{0sP@ZKdYm5p(n zR1JG+?F+ieahbp%BooEzP*Hb7l0xJ(N^W%;rI}BAxWjeS z;R<-3L;PI2UkXHuCicTRz^OY`m_WM{9w$B_0i8E;Qt7)myyC29rPZ${lhp#OL`tQg zy7NiFwI3P)M+0Bv>m=J>z9#0X-Zy>D1AfN2xxJlX`ZYdDa-n{;!qs)L)T%9RwDaY0 zeO?qxs@meec1`jPeD{-R1hj|ss$6n0X@!uS(uwAQ%9>C^Gt~;P+BxOD;*?blh*UkN zzcM+rvsOjpppSRytX;R>Pj98EIc9nb<}BhcJXj`#M=)3jE$#GGeW-*K&(_39^_-f5 zQ_;8Fp)LNWy0ntiQZ2N5XUFisr*+I96clRtH)+U$s_NG^<;NSQ2-$|dOa?XzAMrlm z8}K4>`KB<%vZVqBOQJ(T>{>9L+U7+OH6%;(!1e4cIu=~@MFQ?#xu3pxx{GJ`g2nQA zy3+_-eELf0ev9N+{Y$|RNpS6&(;#vY4yPaF_Hi8C*Q0U(ofC3rEaNNBTFg>Cd}UY? zIy@-$g~`{G8{l8=l3e*{lGp^Xvi~w%%j#>GSS1-RMp#p-Rzzg-zgMBb0mn_HC%dFO z_Jp%?ZCdcO&pS%}4MWrKm^xMKIa^kw@z~0q5*6*$Y_ec`=#N`;>?3AnFK5f}M_OU5$RX^xOMirG4P^$665IFdk8eK)3(Wk3fH#d8 z@gmEKDvqNr#q);`x3>kO%;O<9>gu{KtfD6zf5r4Md#x^~h^<$r5Soa-=_9$X;hKXW zoy`9I=SQ!8d^_+QqQ4Lu$=MmGohz;cK`mb;bd(p@z|%cuz|uL_&XY2+OdWkvoR@|~ zaxD%+N@w7X826Q&Q{DK*XjzSdw8a>Q*w!HZ(kxQ{5K>}*4S5>&+VXqt)V*zVOp+Me9(CEdBDuPyg%ax z!+qFFgtob&CcXUjX;AHC$~LIE`h_*!3_PSb&4&pdpX1=1T2#2HC8 zS_H=+_ELI*(cUUuH$x`wsNd&V)?ZIjzlH9uXS>F~l5Y%rT-Rl~#*uViUt{&t0=0B`EY`8x z(CDsj5hfoDo(+5hkKc`rPP6CUlRcl@_B*v+o!n5??xMHv-=a~&(N~ICl8U5yoRhny zLel>n9pi^aI(M7ye*dOXnxb{b^;a)gP3Lh{C45?UVV`mr#RkGmaYzrm#dW4W#*EHx zB;#O-ZL!&H_V%;BxjXHhOxR&Ht!rO$tlySv$4teCQvjIiMPgYL-gXJT(?q|l)-}a$ z5-sb&mix=U?4Ruyj?a`RJ1t$YPzQ(KfeRy-p{0l>{?pQpQ*0jgA|d0Q`#7q(b2BX7 ze*WBeWzCvgekuI2=I&%F;goxCwp!O&?`F99M|Wy>5tk77!Q}BNQ2^DuKhb7dGe)G6c&0(n>-RF|@A7TkbFuNC}8HW@*TimA@59z7A^BebR0| zZHEVe7)vH#1e}qiE90KCRco&9;GKZGIO zTgmI0^WAs0-@bc)JrG;<*SGOT&K~@(GyJY>(B*bApN`-!dTiTf=^lr1dHc;99#gl2uZ(%f3r7nEAm#ppfpcHL?C_`>Ei|p zq*Iy6M56+GQxzx_JW_0lAJFkg@dY75U6g*myi*wenpQo0Xp9?qr?X);F0OeD5HJ6O zYd%uiH4}mp#g;typFWHoURgPJ&nps`!RdwQIR!F0!i`?9T`Ge3fkdQ~CgtBDjm6st??(P4d@SbH?831% zC1Gm$H_00vV9}VM2%`$H9(L;8c=){@?_PfwK{KNS+7yObez2mLQMPU#AZ9J}X24M3 zlB`1Y=yep9!^8bWk6go+4->+S_R>G}U?9OCg!uZKwPW|s`?r1EKa_^n-Vw_H=itlo zW164a_o{t6%ir7R>Yj~R`%dcLd&^e zGdd-ZnaYRi>y$!DWM7l zB6=2iCReSafe3;JSdo-A3hlJvvYaIh4!xP5btSiTtOD+`3HM=|#flr!4rzCio86dY z5(?frE`{}<+4>Gb`s=1~DkO$^2que23Up6+g z6;h{rPL120PVNAj_7b6d(vglUL$3U9CC^5W;K%X=8j2_$SO2f&sh7r!?jto7Z| zc__q;TOgk2yq$Vi`qjtL+GcdxU_2X{K$O7Okr_K;&?;+#~UcSDXD>M2|nc~x}aDw=#S!nB??1P!k z{x@#Tdyxp}%`KovrJ!ao9IO(IS~@h7-yT32Pk1c+P;Mc72P-|MZ47*oi0mm+X^FJr6k-vFT_-(o*jKJ?Ty$}Pcs^D9u0zx$ z;U^_Bw|(ElR8+0C5;(y-5mcvgv2R;pEC<=9-#P0(kv+rikC@ea9o&{Jo$Hh2-SH@8 zsBz>sQk3kC=6e`-J$*kD%eud4FN)JY%;iZtd0VUTMPI-1=(i}oJ-Ghk_qKl5qNce{ zOS=#f2$3^0!N5@K6$OHSzIjB2A#Zg`li&~Ae zhGrOaw&^p}hvcCdT4S0b+_BcjVftScv(gee-ISGh4!Fic!D!$P>6v(7Q(}Ieo-#Os zbYRNgAZy^m5kx=KM=~}o?G}@ zW!ScClOVVZm!9zPp*^i8RyIgW_M2%WKwb{Q8aXDD2kBLv{Q^o)_Ms|6T-t7H1p zde4#St%0-~1tR8o{oYa(x%W!w3JTyk8CLCu9gmp4v^YQj+zq>SBr_M4pf{rD;+|S- z8A~DNirDG2BKrwh#BX;BTIr~(+qveYU;Ci3^0JILPjx#DBxM9xp{2yX_KUgb8O^c$ z9&2uT9Ma{K_2pGM!)i)_eSQRYc)>Sv1Yd?lB6>%3bi-0??i|9I<%?a%=w-w&FbF`> zT4AyppycYi7N4s*k}yJZ#vXW!{t~Tl0CcjV%VN$D@V^L3Dft8N?0lVYcqZfjWA8K! zxC4^^+2i>$Fe(2Y+mrd0`{B`FxaWMByg$i%YA;|?M1Q%@af8PN;Y*rB?hl`2!BKiA zagM3`aK54R$v7yb;*d%!eCsZ_sm5wiX(>#JSUt-~Wk*ReHU7am1tC&Q1rH*X;U+ya zLV9TE;CD8Lb^^259wKhBCIYzjb4MR92!4k~-V zTVRoQGxL?Fd)UiNK)}}mM`l_`=HLdyEYv_@i(q+5ir@^qEjLRmtWj9UWAJ{JGzi0~ zVozVUW_~a^v#LU{=X)`agt(8Sb<8e2_9=9^DVM57@P6;j{3ZD|h7xr534Bgwhf{aC z&NZrwP6w1NP%$A`A;7cFYgil%+0Nex7z)eKBz+S?R;j?l#?wqAm%>43oSOgioWD3r zPMdvz)klf+^brY=RBkZk_+)_UR4ob#Pi%h@a1f>CB#+OLvZ}j*6oqZTQ(J1yhzG5N zJhVX@rd9<>mhln5DW-^sb;{>rsphC&b~ZjPY*;RFWo)ySRh_aYToBIWX2OSPzr>nI zAPIj}>vzi(du_EKUjea>LTLsAe@1`@k079r^L=|ghm<4ftcWH(eHrT|M4W(|K#EJt z8GsxRbHEZKXNQEhoU*Wn^7wcU?PY1ONb!M8H=RUTCgrRgnsEbT_4U3n7iU&g-Yd<& zz@w6O!(q9pI>}cPh{oV9v+&?Fc4%RPn>Ozdo8nMry8UOoK4*Nzoxw+Bor#MAhK^Gv zm}+kCu~_W^N45@QZpUOP;ze<(E-`MeP|SW?O-ITB6IGroe6n^TjWsfB`zJ_pNZY7i z9f6G?sG@2QTQt`HKX8IHlSWv$c20Yo#$)wR=Vc;$I(K-uZ!s}#j|_G~f2x1()+%Zz zu9gQa_2s{hJ8Z!zc-6^q6|9v{+qL>`fX3_#I)cK~Mz?bP{=cfJU27X^!I z%`UzihWj^0_wW`GKht>TVa1qT^mC8fLfd**EChxf-uzfW;*4>sSGwEqa4E|MB>JV@lW*bV~Svf`yO4D#c{!df zD$39pJXs%@n0p?rTqLZvu=i1E3O+h0sb10*qJG>jGL?~(HA&^A1+9-aG*_K#HetDz zvrceR^S_2+zA1p84Sf$F&K)DtM>mRaHkYOZ6H|WSQw58$R_d)Cp>5ZB0{#`j#QpLLYrt^n6zF{Q zF~{jNRv0?s(WEn$p8v>r^HD{u{Ygo$d}F7OTENQ)T#{My>UQPdYs>vq`)*X$b|>SG zCt)GXx(oG4nfN4mEq+EJRLoYGSCyP&9;#UB{}O#a>bWH&Q!*NsT@{_A3t}!C2Fh|u zvza9XvA`Iw-;tK%mP9L;&LQUI$kmC|{oelAvHUdV$aVAREW-4nJVOKwVX z8Yt|V36h~8srZgC#R(g96jE5F9j>w9u`{OAhUBb;TAEzQU}v(C@cs43w=~b3Y?7R* zV2axmz^`FxFvzBNQMrZI^y9ppm=yCldai(zg{Gy%Wv(EmgN8CF1gZClNKUFQ`+MJe zN!?3{=AY%5XvjwC60jCZmJ}BZ8Jxzi0Y=8Z{G+~x&e$e;O^`=r&EFpmT&wUNt?K<5 zz(C4@99d%K4|_Ez4IA6sQ5aAN2sw9Oh zB~O1|owX`Z{~eEsIox59&e7kUjx$RoG=piBK-@_u!6{DI3Z?S3I?51N@T=o`WwVY4 zqs7Jxz8gs*JuR#hs7z`{W!Y}g%t<-5f%VUSt3I`~@u`gP{s|9Zu+W?3+*jbae) zrzqTBY`+_R+{eHwM}cw{j!s4@101B^gRSI5_ll_d88U(+Bo<3Z7(xK-11awQ-ib>^ zq*;=?=@BN9C3=72PDZKC%QKDyA z35(s$W|e(UYN7PQ9>HVz1bX1jPd{22mO~}$p{LL6wn)4X0y=b4&dWtg<>xuG;#UiG z+jk9!mb!`inEVA%lmP*S1_AymRxV^z%ErS00?Ob90-^ze0y4L^H@7i$F?DvK zb27CtHFP$mW1?qbqGx0*$I;G&Nj5jNWNvP~9m5#YFze>f z_F81{Z}H^exE&iSr`dlPA2TcE=b*>b*nM|z8}JvgZYCaG)AGiBU+sFFUb4$4ofI?m zQP~J{zeKR<)dKJ@pgSJ}ns0?=^k?mKmff_tva{=`Z6VF>d6vOsw#oPHcf6dHx6MqU zwYRGp&?sHdbSDEN*3Po0zE?I0$gQ`&xZi$uUy*-HwvULIhSaXt`##j+Jx9}_mQ^*K z^N`FlU@|)=vD4A$IjZZ9W`(BRJEZf}Qtbua(=t0&$~>0*7tLHM8ci>+fZF8HEwkv$ zq}FP>YiqX{*+Q)a1*K9VIvff)KrkXV={%<6ZB4UlO#ZT_<;_sryKVZRWAQ>Jc6`-6 z@iaenn`EnbFXu=0H~69lnQA3WcqxmDIwz}zZZ0;ywCH=Z~xks{h;Nf+SO^`ML7%}Y@ zJe1UuBIXC=;b<7t<7}t!(+tRbp*fTzVj(d=N$ZJ%aiRuQ3l>^8x~;y~a-AB8o4I9~X#)*2if#KhN?sJKvhQz|+i=cLR?*wzpkA zt#OQ8mNa}z>}h+*H3f=)(4{r|nQ-heDYTUYyA;v}tdoWtSP=vT=T)Kgc76QWso9Mk z#TjWUBYqY5eVfPk6>b_O@c)MO8r7?4pn=${TC1{8n4VTEES3wqw-vcFRroO(#RpEW z)|Ju&#=ZRy?{Vrh7Qt^d%U(CY^_fq=_vK>#?5bK}F3F@(^Tai`0g#oxmz|GdY!Lmf zksD{ooNqcS3Lh?y&B5l+5|2;O&nxdjg+)mxz~b6YYseVx-P^_cd-Smy&5^IqpTFSe zyyajA-!>wloCUtclKZsRk@KET_hMr!#--6m`yFSY!VZmQ2x6Xu>+oj=_qug%&SB>< zbMgB!R#Nvqi8s^sP@Tr2x?O=wlg2-;D0@or2bl#vG^f6vv3`vN6JIvsTMh zHlU!Pr9p{vBfDh!N$31;4qu9IzO6N7G?EZ`NpJYm2SU<%PHE4xuGY)VJ15G|$EGg% zPN_~OzBuaqVa84Dvu=lRpR^>1S)|g~YtcZjQy7zs;S|B4AtJe60~XOsB=)!FM@~sgNo9#$5o& z&BKWI0Kv5NWRZXulN+x6Skev`Q2xSF|8`9(XCs>~+`a3m1E0_IBR7uQ1=+zwscDHr zjO+ol1f|qno|NR)=E*=HyW2GEIcDEWM{PvNgl5GO{Y9C>is3LoA&%GDhhmUYNk%4V zy|49X(LIesGCS4j*c8^Pd2OAdw72oJrr*1syada}x5c{N8l;g>IS{y|)(SI#2L40y()QSc=ysBl^%2{qFOt@Z!(Xz1ECJXf+ZWUm~4t?tZa}qg#@;J#1 z^03YSNzl=_QJaHeFgNBKtGNv1@QB%g+N*iUq+(A*k-FsQ{=gxuW9 zD&|0HdTrk_IpVvazLvHj**B7S1cGN}N1v!Ls&M;srIazhynTsSg|+|JYx`M4IWmOM ze(MY_IR6Lx5$rmFO-KFQV3w6_o+nHjiv+NMFKm83U?|LZ6RJ5;Q(*faOw`NKLrMXs zT!`@eCB7~Axhm;NsevZ2H?3`VvpO%VdeU)ku%ev5%P(b617G1So6XjV95?{lkxiqs z-c|_kSgOw;Tamj{xLQzN6!60EpQT6{HrzVMYD)k8cEpKxmwVd3m`GfqAsxA~X7sug z@*F>ll1ZngA_Ne40+CQYbwbx5QEz+LLd0V!MP@2$s0P%fck?XiX%U=ocH(JdocNF6 z5}fCitvW$Ld?je8Bpn$GF44rcvN+AhWJKn3nHvbJUW6po^GLsso+Md*-)LM&u36k0 z=Ofgxln;w&t+0@%jDsGka1l~2dmEv29LgFRz&e1xr(`MT7*ck#%-0IKd42-3M;Le! z84!}&KrOyCc1L-M*zRP|m|{v~K@mK>xx_yq%JURj-FPk@pr{Rx<3&7|z`0qdG5K)CYkentLD~yX$jNkXG(ZAW(&*l1l zT>rK*$eu#oIryinUcjh5QSId7rJH|mkZY-@A1l~XU!FWlB;q9wM5pWrjT~h38~%^; zNi>%RC?z&~Eu;{ zbIgIsesCNaJ&1+R+3o0OjK?$wlGR%f5(C<4CbJjhEEr}-y`t{pMsmf%%KT|cfo0+qq(s#~oD|5X z^YGD;Aq7Xl+G?Uf4^hDrTWK3*k7#1q=X=t-l1Yh^;PmJhiPpqyFgbTn!Z#`3*ho#O z$oef zVzEn3eZ5V3mg{9)>H8V+OgYboXV*)-oMb<#X(+Qph_l%v=Rs-lXemkLZ|a(C*_rv& z;tWGpHC$`dxvU=33iVyyU>?+%14wA`d?DT3oFJ_RJfxtm%%cb|W-WxW_>#t^?#_>6 zJ_$M_!G$fI;765pgJT22hc~lzn!0Wo;!E`%GJ!}tiu0%c#;s_*$bW(v-Vpa>cF2OM zvvGDk3(4pvpnUu2!&uRW@O_I-)jMIY99p8toUV=cwtI~tkqJR7dkuRM9!)K@H@#aB zTI)y|#`a)qeJ%$w$`GPW4xkqLPGeAVmWzoIUC zY^uqw+M}jViftdNya>#uNA!A9aHG0SbDl9i9c2coJd>d(`%Nk$)2|Z;0v-4AK>qc;#6RTg_x4Y}upOY#AdJ>3NBm@gUtVQOXP(QD-F2B4*H#vAE@Du!l-^ z_Ze7>8#b_1DbpC$A=NH9<;qy0gCv8ROG3#YY>Dho+sdbvHL2M06Xd;q};6?>U-OJ#5_V+((m0qisK~ghsxaA_xDL;`64^+Wy?H`dN+>bVq znd;499^xzdn}U5AR;n9+-Z6~-Sk>j*Z8%2CpGHuirPepS&I zjMfeZcINTw*;e-7fL$`c%`(2!Xq9%A{K4UT%`V1js-5|e@z2?@*^`pU-;CF92KJv9 zciXS%jYCRn<;*`ZM{P>{ZsI{j;yWMdNYB5M3g3?Pl!2KlPJ#PO5?*6U?3TGWMiOUos<*-|mo&JIcTn&Z9D7!i zrqju+-}Mg{Y86)@`Y))cI3iF0x%FysoTp(c-!N;_KIo!zVWPE10YU<1T_!IoY+CO7 z(%#)<>{Y->>IU1U6x&(Bq2PdF38fCRT0+O>9I!o+lT!?l`>58V-$GE)xnO69?N91 zANGY>zp2it)QtVzz8wRf_D#f|YeAU<3jGUX=PAhsxNnHiHKlKq-nazBZS5V`!5btd z^U@P5^>K0tER8^ZVo_r{=qtpt?+D4*Yk;r`^r#$hP|2pZyTf|6MonYS_qHABW^m_TL)I58#uujW&e7 zB;h>ulDrpS-F}GA^b}YhyLbOJ`?Gx6U{>=$t5tE*dUYbi)&_y~ruYoG;#0savux0} z$vm80YJDjF)~Iw+tr^)RAwA3pWep=mx#2X*6?Hc5XisfF&ZnK}bj)m}vEFCdsaEC4 z6X%4az75EuyNZpttLC#-hqxjZd!Nuz=+jpm{<5T}w0ayqIkfKfKBZyM2mW{$*Z-JG z_XdJ85&c{Hb}8laTX4Y;NK;(5=cJlh%8woYq*Q}`>EGXRU~e*?{$b^Tebjd;v3fe^ z-n4zcRQ&OFHOCiKobFe8(rnGMkfq^`r-%eGrly{rUnkR#D;HUEEG4)OAMCGOkA2># zOiFsY(2)D2DI!pM?k6(n5~Fy>gl&2JknYGq8~GvfQ*6*M5lO`hkbz?lg6*rOk~tX3 z)ZM6Rxrh3lJvBD&7Cf-ddyq(i@jt=tCavd1+z3EGwMT>fyDE*U{ya?g7Gb=a`lULQ z=+1k&Hg1rsxspzTen?+~?iC27+qq7q*kMPlYGQVYY5stVBX5Uy`qCJ(^C+t$m&r+l zIiO%fc_8>xw^NQi_;dG-&3PM}){viyp9V&|_`|r_Vv9E?ub{@V%+}vEf@MapU!oBt`%j9#H4{ zDwuTupf-K=QA)V%_D7#W+x$CWkd{fStoQ=*CLPM7_b9Jbs)ZCfRrSSAWN5V?eZ*VK zoy4u?^Jw6Rz=CVM6q z1PnW-mUNe~lDflw9`(!*j6nD2fZwIFux>qrK`e&36w2`-EHOnps55>EqYpHz`sxV^ zAADtkEK#SBP_lO>zeiOTPQ}0bLnufoA=cJHRuWv71~@>ZVZ94lYiFbo_(&Wgcz8q> ztqXKizDfKJLjXu(us0G5RT{L=%qnL%Fv;W2qu&X5_>G;BT@&CEe5{Nl?-Qrj5mB#2 zOAbrZ&UThG@282#ER4vxGhus5$m0XyaRRACrG!F@juzVHlJR_@CRlU@b3pHXZaH3z zYw{)c_B|6#;Pz73pt!f*VQRe?i+t`Ye}@{atDWtcvnMX)ha%g=rahcloXb;7XkJYzXxYw2cVxTT%3G?IwAZ6zl8&V7pa))RDh&Rvh=Xhzao z7#5@ilX$rfmBH3||I;4RdEepzG08VUkD=Gn8cCC=5XVzm`otj1P;GV8IY_dC)+RQc zqV?Pi?^zH8QIUzo>3p~N7zTN$2Mu9u%!6aC-&{Qq$m$InIhe-D{DaYbx86{{1W&4h z$r4{|U*$OcWHw_QS2Z3$JUO5q2Km5<9#mY=l>CFJiv;>%X0o8O1E5i0I&_ zLn5|xJCR_BMD2eBz*SM8ficl>u(}cIW2+(lUoFohRz1X)HREr?%s=Cx9-}%IRZ_-F+WDaZRGD5C zS{7`IToa)MB?gd~i+(mGmO}g$i+3j|<_j_*nMyQ96oxx0v}AJcG};%6qgEic#8BVWQ>ctIi9vPJnRNCWnN zafI*)xrqP@A?j9~Og=`{g;KgZ$G@1mlHbO>Sp$iA*htE z=g>!3;>$|h#6N5J`wl1NMXl^Cs%>VDS?RMz@4X-h!O!+3lpb+$W(V)*`oBpRn%O@E z*FV}OBu)+l)R7=gFhi*X;gg+{wXSMo6WMdd8yV#PS8hLv7hoBn1_AZ}q)R!jWj&{q>4kVjKb`gne(UCdlgqfQu;uK9Y)Ru(UJ=Hwd8x zfi2(`;9Ol1BGe`h!yiySq;e=&s=Kg*3ojn_aNOO=T-<%n#wU}t*br{6Y}xu7r>oi+ zwr|@W1~VWKZsx7mH`ayn_*u@*TN!Q(t#141vF&qrSJhP5!gJeSOpira+E$wi)1%G| z8%$R>O5F=HY~MqDk$P;YwLfPE)k`aTw>PZ*ROfRHel$@%7#QVmFIq$&P82Urpl|Pv z*%K7fg7CHwXoQ4A7FTtQ-3?ynA;k2b7Qw=&5-&>ZAW|+4(ltp$GO0 z`a8F8zK^nC7o=iTc^zJxTWr|qdLGyfv3T`s$yC?rweohGKi%&j%e@FTTWxjunEA30 z$j5lfkrbpl9R`@@Xq+~UMlB^R0Bmk8F714D77|?&=u9#;>@PzHmIv<#J3N<{91vKc z05#hB1UE&R^uBV%g>KPKXp9Ii4szYzKTY&@mhSo=+WnPon9X=P{XSf*&sN>G(?wi5 zm@G|cZiu>zYooWi-P-nVYQ7@2Zl9M~MbyDJ(l{oRaO6l;wHzz(Y29{bFCGoguUohO zne~m*V5*7BN%GWo53`iHx9{MJGPj5w6DA?LCmo3KNT85%);aYu{gUz8M51e)DmwIHkn3zX}rw{F`> zrFm$GV_xW#3q%>0KHB`_IW?Q0JNpHH9Bm3W1wn#yC$LvYsaJNETZ)LMtu?+Ulz`s1 zYc@=EX<1lp+2*lC{$zl5_-q(RSk#^Ge6>NtwS}SYjNWqWu+vS>tS9t_ovM{YbyfZ; zl1vzDE#F_5i%?sBEQ+&O&FVFeM*K3fB=ml^IxHna)<F5t+V~tl|DM_5ZKC&Y##GK`(NTopfCs=ev`nL5<2;)fNvT_B z=*bc^kJZ>1kQE!wUq@~0zBATGXHv?W^KIrl`)Sa6W{hQw&j*dQMUck&SNwyZ{SoG@ zjOEV$E%lTRrv8?|Lt#jSr)ihik!cweL$Rqt`*Jv&v_n;!B}w+=p|ljCmOYaHkSc!n zu>2AJW?SU?8{d~Vyox)SIpJXkKYIO$Dzz*LGRgaoTy`#QR_=Tk9|PK0WKQ2uva*5^ z5`%X}6Y-Gm^_6)JSDLveyvU~W`$CJ5j+8dRD0&X#6L{6vWQ||tyzcLCJEm~ z6##q~hPe9csxT>6vv_IJ^nW{(tDc#QPDow#fPuz=R4y){) z(2O?dDr^V@8(>HxXCvQSG*YSCtRIymHeFQbwtbXOnboM7E)bhsNz4Qww&rSfG0kMx z62q$S!Kq_4^_LfZn29`C1ddj>XPl3UT|=Z?-S&ofO(!=4M)<%RUO z*^sbT;UIK+mdW0gtBX$~X<|1dT1^HJ{ZYFSX67>+#9oB!?5pTqQ+Hu>*%lqrOpvqoy-<8pLJ4Y7NfXs+5RFm{cQMv&>QLRmJ^WHXT;cFi>hbWAkZ zkWlw&V&3YD&Di}*=~bnqD>r*0%T10&dU%Fun_P6djbtOVBul1n*60nbAf%_?>Oye~ zxUutJ$Z;hJS|A7suFplNf4y^e3&5yo#6ttMd8&8oG;`#RAg?X*85OfIZHPW$n2git zD00Ya13a`d*q%%t6rf5Smr3PU@H2&Y9+Fo>$h#d%_UYdbC-2M}5O5gOGhX@p=0OA@ zJZkBR6Ia|CVPJuwv=gXZVkO?jeHnkwZB6bQ%hdJ;@{@1r*lll@39$&6FQ9JQnxnCe zO5P~~UBd$#>BsG47&c-P#RRu)qE<5Lw_>|2A=U?-29}EEi5b(`Oz1YdMb>y|1+wbR z2G`p&w=qoIA_=UJU>&6xZIHkwB$S{)EbFV>1RF;1k-BL+RIz8e+&;7Uyxffj&06Z* zH9lo^jJIbPa)5o~6 z@+9!=!vj?bB`54gdO!5AwIoFOR7d52amKx;CNlX@5`fbmaTE-(TsI-4b+461rCAWE zd4q*)i|1G%x=B(%PL+}tKJGL*f)Q-v+GP8eUh+_@CA{Fl#wI<7mfT?|(h5_vER?g7 z)=+CLLNnSNFrUALS@P85@%!znm72AT-1nGRDXX$0^wx!BZ`Ak)NI5UemUTYrNHHWX zL~Pd{7Oy@v*J5UbZV+|2yWj8myxSE3zb@O<<@FM+?q#rx!aIcFsJvPw`Pwe#Sgra% z^o3yiGCZDAlld3@*+&hT&ij4H3h$}FtN9%H$-N05iKb;>q>5FB2zuZt4+FZ+{LW0| zKQ__8en1Qj;B|`R(TF}mb{U7S;LudV+3I{Zrlg|P(~u+PCSFa z3dSG?oLgqhjIJRJ;?}KO4)z|Wy)&{w0Sh8xHK<^+XYl>4Wg!CS-TYvQxfwqgs96Bb zH51+z!%&0T^HJ?T%;ig$zHKb{W!2%E`;v#`$q~Yv%0Y6+xm;QJb}3iyy^ZI#c#XSE5@AAI zIE|KOti*w(>%<~JnIm(OI=U$Xfw7{H=SLTz^u5b0w5+4rCA~0~vj1rY#E$SI=d2rK z7_{4GbSOKe^cbwx8HfQj&eRz_CPd`(dq~RF`iNXBt=Ag4GUc}zmRK4|rI3*15_52| zo?$fVAr~ba7v5o2F|tj=5y1wVG zWcXo)!raSi`MuDvm~vssPm-gO35$3Mg&0lM%8UJ1W+E|CG|{JY5Pmk zag}6|Fq(FW9IJ3t5IwLYTpy#5xY*?7i|#$d>LAI)tzdQ^5)Vp15rakq^&T6@C<(h` z)`H7nb_NFV%y}T(X4fa4F;&-i&csdZI`r=LD588JLpBmuJU1tTHS@gG2~ZEo{_;OTtPNpb}l8=rRwj z9jqSvEVCqyH;M~aY|4&m{2+cuvWX#NGC>ErIXo7MLu(j15mwgkr2Pvf1UyD=2V#Zk z^%H;&1QfpKeVM86v5WbvLdwlky)ivUsaFiO;I{>88B$PEy8EgwDPkHMrr%UrtQ1+9 zZFJCx!k*SBQ>uq3g9NWG!#iYhru4dWkk9>$BH5-zzHnK$(AS zxzP~vi&^t<70&g~zQ^)WKk4>(Q0qXvuW|aDP`^JlKHOMf^|Em(rL?Dx({%i=7cxyQ z=WYwjFgUsr&TsGd*K)<`dAzH4x&2=6>odH)zV7$u?$p48>(s5U9Pd97dVI)jDbA+O ze+yEfurx#zq}E~`p|dFegVxO6GI%a)KFSyvh)7XK zTMnKolXj4O0xc&=n(ZG*@wjRdGO<0fp!9NWc#Cp>vSK;?6XU5k_mc{XC6^8Wfef7{ zL>Z(v8mLcp9u(X#1JX->L73SXw)?veco6C$&#D2elB2OWxdN%!yl$YC?MYmmT*-G-G<^A++fuZk{a;{3X<}g^HfKsniAM zb%QWE)=Y(lBUb@Px8O)hV}V@5knv>1gS{kjApwPxdG*<#>L>7kgwv}lH8)3sno`bX zl!EjlSZH(50iUp_A4q)dC%jcilW_JuaQ||-4L`LFd z14Kw$fTJ~DipWJo(R>Pj9nbH8#hyScL3E7g^U%(TIBQke>I=We(&abvm19@B(Sgy9ftoKB&gyN&B6$cx8|cnS(N5n!_}>{(8UC)qHkgcBX| z1o}=N6~F2fE;v%>tR1h9$K+I&o15U&Q3LC{b}J>-?-CcgB5B2r^cWGC3=Em`&6Lg4 zQ^&|rC~o!{&bsE9w48GsKtKrl#JCEiL}fF(*WYIV?Gsq)L1nVfd?wb1Kid1KClVU+ zeu`R7x0zIONeEjBW!o>EDXcMreT@J83O;MsLQY5-Y#J0P?%x_G?JhwLEWF5%0t_J% z%IPBepmR9U+AvK^Os?_(E%V6RGm;-Obie}L%iIjuL-P!)%sGL?m_3{kSDNpnU@>bD zdw?bbTvi|>@4}R5wkO-ca3tD$iilii%%SuZv1hio31l(57LV}1 zYwF1nU9Q#Qn*U-Uo}VkJS?TMcHhnR6adv1~)_6T*rEykP#I zf8CGxh&3BA;9908aIz^xkkf!Hf^wR~x$!4a37ah{B%SkYr3f!8<4!<)@CgP;BK*js zqv-fdY32+S@T}Jmu&t87-so(WzHassviS$F`HuX?LWr|o90{NP936Q+hp|?6w!D24 z9PUCW#B}<(y7IjbHr95Y5zk@N`Dk^2tBEd%kVmq>(t`B%pRRnVeB7=2e?44{zJ_DW z@AqI$gdfLIBKPT&RL80R3Df#-%+2zw`(H65qn#;~-^yRbP%deIF~- zgMU1Ns`x6coJ2yzkEi|oP97WDKoR(v{vfve)uBC0)AHMUR-67>($qo)=gL7rPo1Qk zk?q54Vr9hv(H_boH0*~p$IjdmYXsuVDtGF`v~>%JGDXj{T!hCAL<|s9CKna06JnA| zY7q&E!cfTjT8H_pHEElD_GEZZj)Q7Sm7`YPbV@}<+5)A4x-U+Tt*X{+}5q4MPd(G3kXY>vqBz!Y{8N6Rqa#v&aH2_feFl& zS(u?LyM^Y=1Yxso-zF;e&PBdYqPxchMSvKIG%9Iz=Ru-O(NELrnW}=4%&fHwv=)asFUV+Qj^#k#2Mo_s5+F;gyTIp5;x4 zO(d&hkz38is*n7Jb;*S7W>5(Zly7c-bPi2FAbI@|S=4NKwHlbSlFeb3g(Rj9U3U!2 zL}e9F$OeIuWT4oDIm1Ijzn&_QxRh9mmb7&L+wfBv7@cbM}NNT zdc0H@n%`QDCQ%t+6Xb$~L|8AE)y8!~j!}lzNi-KZsUFo^L^t|Y1la%|G(*<}U(!Jy z+M&FYWKmNylE(5O+|5Iel7@Yf<>!Qx*Yh9b^8C2sdaXks7%T zA|XPX;u6>pr&$;TC3*}-I9!f-jplO4A3zPDzGsI~JX2H~Tc2-9!zy?hQ=uCJgW18H z^5Xc38p5K?al!FZyOKpjCvYf4?cfywr>P<h87y%WhdLNGe8rdk9=1HA7Cnl?r#in zQ<*=E5Ku3zZxf{Si(@zyT4k2`9f@bgIVagS23>gZqR?C*N1&}78FOW+ys!q|#bOWJ z^BUJ*t`0}O(Yu*1sNp#}zn0KL* z5`D=$LHV_dJzMO?2iP3jnChWd8rI^@a7e3%B>@`ChOExv;9{YjMHd?-NhE(Dr7^@Z z+KC*rDk<8HOO8c5ywgclWP7q8 zl!Bbb#GMo!v6 z;nKK3kStW}C?=eR{}Sm5tfPkB9ePG+;-bnU+z7ONu8|1vE)ETKdw9Bnga7>UGo-Kp zT4MVj#?GlZ)NotYv2EM7F=JaZwrwXfwr$(CZQHi(lYO_=x!LhX^5rvXpD z1N2^Bpt?biMQRSX@EZ^el+K~vdXdU~hqP|iv7X}RGy?e0T9*cZ!sEo3CxS(bNf+}) z3rQAG_j)N&(xdL%x48Jm+ishdN zWHEFkeQ#=cWAMyd2rEM4K?Z5nLhPGZXvqr^N(lPRqas9P<(QJ(Lb&t^fjCD<1f(a| zEY^$;ZDUR)%XpMOh7^j7f^Q-7vJLJgyM^2~_@hFRjKXdkk$Skxm8VA6mw;-d)#3`$ zg6OWda!MJz&M9{3K`+lZd!K{XP zO4CTLbbIhL$C{>@=^kl;!1LtKR@vA(=N^)fidCi!n zPV2upZT?^s9&Q!9ZWwjUI+lXCRwxQA{}WOXUg_&3|D03)^>8CQOYMAoZJ=;yWj7nR zg8Xp%3f?Eo4m1aCwvt}Qpgk`oQ(^FXDRHz?56kP2w{1SDt%o>Wh36$0a3w;sT&1j1EeAdNif3gJtMgY209Q6f@7K7yw(N) z6|+(79B<(c=cc?RoKkBa)TZn!18}3)vmbEgkM8wfb7n+whzglbJm>uIWJU#rBHHTb zm&LojFO9(Q{TmRWZI&q_>oU+Pvg9bq;b9%&Sp{r~<8psyd2w_lw=d3}!MZr%3WiXJaDoO)9?Dx8#}Gmcj8q-Vg>Kw`oJ5gJ#odGREvgkk3& zzt)x)7yU-DCbU@SSDZa;r3(2IPYzLM&ZGMSKp6x@CPHS81$lxrq4|s zeLb;)^2eNws{=Xb4GGfslD`id5Ig2sbfS7f^@l1G*7jui5EYl1xjQ(T-_4_RZj?GqnMTMYcdX8odOp~ z-7RX!Z3;ijrB;sU`S9-dP#3u;?sR#1zYoKd^8piMZls-NO1>VJDE#N##c7$#nOX^a z<)ug0Mzs#47qC@$c{~mcsygGAgFw3%Si-PI;3>UOlp%eQiTRFj7mkSIM1U^Du|0<# zhyTW@*t#e@Dj&ZKVQVsOi}7c?B3_fmcev-jUGGP_jdBe?UV}M%|7r9xN43(zC+;;2 z84OBrLica;XjX!p#sfc>Ou(4!U^@y``%JM5$;pSl;q!bCGxg<^K&6u52;1C6q~thP zlxTWE%!hrPt$zm}K&$#}D+9QS9*+#}AcQceMGiA%BZP&p}yNH?@$}g5KC8)@BuLWrSyPbMvj2o5tIhMie}(+M`1Q`Y4M(zkcA^HU3EP1f+ldrz zT1PH{7^2#bzd2N;lp>(ZP7-(9_Kk&;Eg;71)R#b5_fy%v%gKmo*-P zNbK<&bP~Aa6Eh;37A4>Skw0{*1Pa76{(YhI+=EU8*?B-0Rn+?;ruHZnQ6GkI4&+&P zglp8#&Cgr)H1iK4%T$Dg(YcQ(FoK&lIt-o>uBLw1h(ARe z-yVqS!VnHfcY=F>C>u@&@u^n=XpmTFMN-tHa*ZCRm3{Mh2y3huoM#+A-84@QZVGjg zk4@758o3(}D)k4g0?+%;%^#%Bo{qqbii?&u&fqGcy5W)%< zKDZemy19l3?o`KF4&zo~%JOGloYkaUKPL32_0t((V=wXVG zZh|AI{%hTH>pdGAetYTRY0H9f7(GGz6&JzpR)Oc-#~3wp#|lq}vzhN93-aCR3fE#3AzBNJ9Bh}E_4ZNJjd zBB3uySq10t7H}mzJkQX4sQ{EVt^YmqMvf~5OWdsC)(`n3%;D$5Avj0U-)k4kiE{48 zi3x-Cv2K}ft-3`0-YC5*13ljqF(#9^qT=fnqg^y$aAgOJPn$9N=^yr==Y$C^w_B&u z7QnHx&}8VgcXZ6u>WXiKApH={E$dA!poPcbg^}^?ySWG_-q{XceBy$L3O76+388M= z9sZhbqNKTUvRbuyDmNJ>FpOV=MQ!ydjn#0>v)9B%X8p$AzZ3ih{^8rZEx5s;_LyIt~@+6!_8OJ42VQX)odi z{V2ux(2lx6St2Pc*qpO|_Pbo5U2b>Ml5Z@1j%f74M$xE%gIS^-*iw#ZaWl8|$AlS8 zcr2o^LMz7*oTDa zm5;iuBK=VBu|H2S-7UQ1+hdHf-IjkVwea%Vm`ptGZDG!;3hO*hChW9B@nVYh0!J?m z|Ey_;wE`fm4MFq_iErJVRxjZ0aU2Y-9wbtkYA1O#UtZslsFtCZ1Rb6Y=R)zsE_udS zwZkBIy^-@AUfhrWEE5r-tBr*$QlP{GTX58)ZX*n~-cv&yFm(KWyi35=i_wqIfsmoE z3)0p7wrez04c{C}b%R%8LBs^*!ioNlkJerKKLK(bfB{}N8L&E>MwtVh z>yX+5rawph*$T7pVp}pp=3>aoEbski!Ee$W*UT)|&o!=474a+~>=5OkATDk%V2;Bl5<% zoT*arYGN@CCSMX(ck$FDpM0LT!kZuVQbbj_-s!6v6P;n>xV1fHCEVB`$k-u*Nx_j> z8{~~K;}l)~R6!PInTia6SK86T*YCWO6TLT`lT1DD4xqoT(Rc}QFgvMC01SOq+StrG z1h7Q1v-6hNKlx{#u#8Yc3E057+#)yFK98eDT>FD7R)F94D-Z-y2Ok!Xfs)*|BvPUv z5c`T6;?pZf6dB-#A*H*tT~4QLxtg1(k`AEUMg`7SP;u2m8HXDW?=gE@fpNA{sFH5- z>JCpn*N3W;q2-f(-vu&wq1_}2u((V(ui@EMb~LKEm{#rywkM)E8Q)CH_KxX+DT)`A zoWAALK|0MC(jqh6>B8{iQf%_BVAu7NkHVn9`Rum$VF*1&FPNAe;Kjqj?y^|%x3(f{ z4^sbCip}ZnAfHVgw5)DNAdcaL4Lp(6)|Ssn^PC5lyUM*rB=}^b->!%#Lk7W zKQ_uCH3I_ScY(1@l|3J0Mf;GXyOG!CS0HgXKXnIEWk!G8HLffkylapo)ggTPkYhml z!Pqn=2|f#Em~I|+1g=X3*$gzOoI733I7J->u<~R5gxTdldM>bsxeuThY9W42VDSPL zhB>e$Mhs*%no$bS+2?%;vO7{_x8m?<#^DXI(br1*nnLWZBdz$s80o3Yb(Mp5ao+We zT-RAu$-{ijHEU-@U=%F!oeG&!9&4Gh=ZWU6`VrxPn-MNynxJRRef^A;R%u08%FYFqW(r??HEdm);*N80Mdoxari7CS|@G>(Iq?0fh^8VzJ`Mo6)WT2Z01=j6xqJrKb zvTH+<815BJq?U}^HS@=vNQQWPu2%F+BdQDJ(v<*{j2%-mQn{Kgu`ASfkD_R(;~Wu^ zo{w4M;}B0D|9&!)iB07mhXa8#1la9Z7l(%$rCZ92^s4_S!#>zPJ!JY1sam0Bt1V2uJaakgY#G>iwLM;5?0#~@k z4v9bmn^H9@ggj&1>L7>5U@U@1Ea%T2fWL5unqJDe-C7z|3UU2f5I@GXD!r%k))~%b zob5eUz7ujyCei$Zsu?+S-#h4H*GGm-drw+TRrFEwot6s`8L{&cKiMG??ii_qt7YF~ zw;L~ije>C}kF+_<^2#+Hk(;9!5s7(OB&`UFq<+VzHfC{k6W5xvL?A@OB6)U_O%o8y zf=1)SXEZC_Wl+aQcdBRH3N`NlKC;`+!NUSM-zm0x#!lYVPtSjYC~}s*58nX+0H8ns z0LcG$XRNu6k+IuI;!(_Op>_BVwgkb+Im7e8-E#7rsKEAQZ0Gj!=(}WpWvEL#Bp)jV=!+ z$;W~+C>dj*BH+OJX6%5$vOGpc$5e3E zzAXqoWX7-QdAjZ#6D(61gr*u`+8ZM%X3j`#R*(#`9qYJ0SA$r!Q|_dVmo%xPx_d(4 z_n${%#2>{~A%N2ef769}4Q7ccGjhjU4)?_qk^LO>BP1QrXt-RKPOUknV$SqNO4n3YrM1YVE!okOG+v2NWgRw_nB>~NKDzI+B_-WGZ`n3a z*{zy^fxWLqmsnY)F+M(8RIZ$MrZvVPBT|iIY^`N;L>0B7S}iSs1f3PnYTupsdXoG- zGMBszN89!Sov`TwY~Q6;T@_hWRZB{jlKzNhUiqL?bWJ@U8>d26a|;_E(iYoH2c@KXwR@q3HTXieEg8r> z4ZDUq%IqO9x#XRRnuzB$L`TxU&ZXpFX_4s%MB&0IZv4|_vRLM$Fn zfv~^3`v;D0Uz0R&K(UdXk|@J1F1{h$InAah{OVaalp;JnGWu=@VRlwME2x9P#Rpr) z^q@lOjf~?Os;7*hOtv{|%?z$=Wn{$GH!h`Mrz4+Y$}~wi%L==CtPz3iHTQB52YjT@ zl9RKGr{_1%J9W6bKprYWm7v(^eQd(oi8Z=5jh)8D|rN@2T&$W8%rk z%%16H{qXh|RAKuw5jDL<7wpvF3+LMkTm6@*6s&flr+0{n%F5sUoP5& zV63Jvw@j))x?Ka>mCr8ok^q%KmF*R9pExz&AbMlRbeAI1@6Hu<;qFo(l!P;9K5XCM z?Z%O|2`;eX$etzwNc0mgiWvBgO#*0s)f(8|c2l#W4Ih2gE}-{msMebROlf2!W4U;MN~ZrDYhR+X>TE8 zDA!m3N(XyyBj-tRxgR=4U;Hl1){jO>Fd%AZTCrFF$c@LSkbrs^zZN7;RGkc3_aI%f z|3TB_R=E(>S=BrbAy`Z+qO)N`a1sr<$oIvVg=krTW4%&+>M9>aVw!$AB|Ua+Oa_if z9?llUFD+McFh|1`?~0veg>alNpQ~trxK5^LGiZkNHW&~85$oRkRyw~g!i{CdO5bZwXnLk{;%WqvBDy*&gyw7avF&DSRG@F-gqcVyY&P$79xP zC>p2L93IeNWR2j;C4Mx19Z7o~?+7D~M19x3{l&XLA6vs-OiUjHFcJ_a2Hg;GnxXnNGfCGMOpdlcVWS?Faj)U3#ItLrxlEDz%=F27Z%=xgdO;ZQG=;hAcBG z8+^~vK>HGNI&=8^Oy@*>5!MxKvF@fz?kTQf3bq$;cna|%S!vw0JrS2mMF%C7Al|bV z^rv;O3M81qOKaos-b71;+BWDqBofOnxh}7t2YUVU^}V$3W9kZ1rt zUP}bs&@a?c@249g_Ks zwf&TQYzXxWe(-Ii%aX*!vr1T?vpaQ>2zl#$6(>D$;f%W$2`S4?FpmxErR z*}GoxA=O`Y+d2vKDxX@#$7Ex>0I)(Z>zGdxrn!Clwz&uQIS9FzE19@ zy$Uctx~(2?=f04Z{FMp#2Q%;<&Ds$%)p4Rf#1f8%fG>u*4OkCn?aQt5fUqpg?%9Wb zaD9y3d=4VCK3XuP+0DZRg5E*SlwKhJ2=?rN5D!7@D;}Ts4gCT9ZyBVz=%4iYE2r~-|8FwLO5e%E*1`I}0%q1q zeg7k=yDq3X4(rJ(Hmy$cc-eZ}fv7bI`q*+;1(MChN@?7YSXVyY6(o}j|H`3>bdQvX zd4OH8!0;ik-I}2`@jWVpYTj^1U`K)g`jR3u_yb*GSE>lhSMTNGM-IuuEmMdwV66jL zBdSIWIY7p>$_9aXA;5{jD2BqC%8fD;r$TgFN3o5sL+%U2xCT`|Ex*sT!Ug*R6}e$B zP>iS8hX?X1fe_qSgPcHChW+v@Mg5^tMV`kn)2HD-k@y;F*^x&0@b%;iTRz>^sr-l0 z@3#V)h-lu&u{~Jr*-aehSTItxLp#vOa+n5BFV{eXZkuQgv}J>Y$Zd=mxi{*Iw8pas z13ke97s3o%g1ZZ`t|fht6McqnAHI^!LRVCl?m!f2)%BN9C%=VYs-R4H680I@HIK(z z;-0t_hmGkqAL7BMe4@`hcn|6XUvMPxxuzrhr!Ue*v~p%mjXSlKBoNB+B8g$D zY3#l^Vc_X9sPk@_L)@BH!c$1+Ih%RBfWAvwC5Epk;iV{tbpLyr3 zDE{~5%+A5w+SuX06t&jJFCsAh8`pOzQ@bS@BfLIqb2&M4D(Pw!dy8~h=-%W-ixQ9| zgk+hZcb712?CAUXqx%|9?~laV)N(sj9Vm>+Z^Q51li}m+S6TUTkgfMZyY0Ex#RZA` z>ugqvwKi>sNQT-`+J{er>xIvzFWH#UtNA`#_bRK6uJd*AwC2rmx3%|`j?ZJ8+A zeAepUD!}e>^y+7R7x$}{ZmYUKZB7y8R_k07Z;m?c);e^itDz&CO-K{Q6-;kT^d0a@ zFT7yN>{E*>tPr16n$p_c;Vwg0H04D(qM3FPm5Eo5o0GgF_3jxgTQ+J-e_i5}KEga> z!nB(db)>b`o33qfyRXJOuP~hy+A?I8+pV9s69oPmQqq^yr^z@UB%^K%Th`pV>wK4d zWaH2~+}_YgWKU+=!DX%~YXjPNumb}6oZR&wl?w8BI#>rK zq`F#i7Yy#nN%g1O)ZO~5#qw6r(BFdcmwPXu(zd8U8angaIBl!M?dkF;XUUEZP_AgJ z-v@d(uR;W{`9uKsRZe&{-LsB5FMZnj%#HUYi6+qTC$;4}*XQ@%jrr*#r*1&{T6u@o zY5F-qjO};X*he*)jxBIwxEw_E%anU$CB4b{l<`!2l>_{Wdjy(NQ8iCu&C`1+!Z0Q# zgWmRPu2ZqAvEU+Wd;|3}n{+z0Ya=SzDYAi1smy5Uk)jNnXwF<%yvnZ4KLKb!_=|%64^eZ!XS54+>G1>y zO`F!j^Wl<%(k93zN9{$ptKkV-*@@i&-RLuR*Ud+@lBz7IDO@;M_z9CD{n(0p5W6er zc#={D$h;sQuI_smw_yH5J@%sGNAS=+1*3bss?kOQWBZKIF^30}+NRFe8(lUvT1OYv zXkkJ6uOK+cYb*4W?@E%Je3!7~c3Am!U;QZ zNfg*78H;`Zs=lcclO|(6j25#%q;h;r~wE8-Zp~0HGp;p>|D9k?C65&~MOl zCP31&<4zmcPSDnE1;say^Z&CI$xy1*M;TNzs`j()1^yd{+%vg>%x$M~`vv4B^&L=e zRnG5X?7}3%_rf8Dn3QS&X;)WPo29d6k7fa>wv>;o4+AzV(@KqX zH&MDk z-VE=7)V3ivTYcRV=KI@lxg&ViyU?IB2NLK_YH~!P!yis2;U=*`xh( zQl)3(ECS0X$94xPuI{AQ%Bo?v29nrP*0hb?n`^3dIQy331AE)KJkoWH>5>mn9RyS+ zK$t%8%R+lD?dNmP1gLS^N2d}OR;899V9=$|UG7#1xB#@I;|SI9(*DZmZ9)Gg!|qgq z93Kab#1EB=&zaebtnUvp$?gA%*XruiHC0PA^=dkbc8i5|6^>YBeaxv1$0t-?=7D^&~C4m_dK^R5Ktr;ceRJJo~4l=fDtasn5n0eF)uJ zQm%@LPsnfp_$HjEs9n}lAVSH%A4G{s%+FI~Sh0udc~N(944TY%0ZT~9MF{c_BU?3l z076^2BAJC8u*he_7}UPh=Tt{oy~|1LW}2R^$NO$zuGreuw4{Wcot^peVB`&Eb^q}d zqd#0?&+JGXxg8J#O#V49OD)MGe^?dBp%03d4d0fz&4ZocA;gu*9faDam1%1%jM2O* zcnchF52E%<3+0ayS~wo{RX&hmy0!|P2nM_wS%?@k{p)Uc2xUeJGI|j-iLg`$-Z;ws z7l30uX{6jz75nUS{apd^u2)RD_%4zcGHxS;k}NO5D4MJI1G-nvfx^rt^h0RNAc^S}eyiHMktc1Z)GV^WIL9U+UclclUuA(HA?o^|v1eU$bAOf-J9R%y)s@sta zs~QD}PXhjsXVW^!H&*8q85Rh>_!=*=&~M%M6JJB;9+IA5_MU1zCN56yx0Rp1`4?%= zpNvEm$PrYK`ZTV?8`dAMObmd+>@(z31_v_}Pe5G%k5*p(z+{0u#89 zk--&6QoQ+5t41sCD%fFEz|PCPPh_j1!MY@A!9>!O3Za9m$YCSoj7eTtNMOhaPn$Ae zb*T`05PWAlJnBtT+p{4G?<}6dii>S z19lM&tk82fU_dnhT3AJFSMxEI?TM_FHfqq5u$g3D0KW^zN`mlRDB|-3g~rGue*M*+zu_ zQ0Kh#v)tRpMaJoC0^aWFVf6$ZT!F43cCTSxjErMSs`G=5S7P|EH1!&QJqOfUNKz=y z$6|z+ZY;(B5EC0{FNXr3D3t=!+oi)1!UM6XDMRf8M1(`R%^5uA)@xFDH$S(B(fT7t zX?JYF@!@^^{_!m#1ycx!=j4x-++)LGnXrTY)eLPwMP@(HVYI2Y0vy$wOI|?6c=qIk zcpPlt3BB2?+Mb`l`5Awe9nCaN=)8UG@6J0WDkLPK=SCeYbuAuU5geq@Lf1lskrCr- z(?ZYM9iJg5b>7eEcRD@XXFmI!$n?YX8d6Y&7Cua~+gfDE0c~0M0o~yfL6#+pg_#0u zG$kT4k_?>t0h{76=1Btj`BX~P??s$}Y0IW&N=5P&qF#ga=<(~xCYvxR1}pnGUU(uF z;VV8@8SNmLHbx4%vZ7SWcq7Hl(*io&_U^Bi=^by8>l6&qZ~>-Y-ei$s{yC8Xolv-n zx`TYt=@O#+7>JHEx<+*@beL} znK}^Zvmi0u6An$Au>teVxSXd6pur(7-2F*DPBT~c#2dGSq%0={cZqrLqe6m33|OHd z6gOBkz-0UzOy?$fR+3X(y{^Dh*SQFU6|=B^rZ*7}%Yo!~^jQ+nKhr!B@|Ak9U9K9&Y2W8Jttkz0npJ$ZU+_zn z%qoCyAp04^#})Fq(jB>8klPC2_Z0jd_C^qVo@Ve-8#m&ZcG$APuFix$&MnApPK zIxu~`P(mm3KIVI;;CJCCpMFxt^L9)5`L}fY)1juAA>1?QF$n(hui)NvjGhFqyKb`r z@q&5J(H6Wo8A)zl62I`J^9C~&VnkMU&f5lm{HDNZ6i}Z# zlx|`e=yANO%gg&7e4=w9=8bevyI@}G;SJ?Obk|YUKRv(D*dr^n?r{uLO`9FBY?xO5MNMdvx)nXbF52GhY@K9uwgE>z@AqKuQ?OE`C zBBAlcUs|gTh4UYjrq>q;sA0t+rDn?+R-99OX%Ap0?5F~}J&S|WCd^s(I1TKs}+1O||UI}u0H zNWgy#hWVOiIthFd*&)WQ!m z>QASwJI)|LZ{8d|4rgfX{AJQhFAN#6#(1t4k|;SBJ=XCG(7*ISwm{J0;@WmHq2xP- zMQxOO1u=#`3pGKBpxnnh4hh#?h_97jLg*s9vFh&|l3+~71m7{6Zq;{Cl(lOPzB)f{ z=;X3q_ugBp1dtE1M&$qTY?I2G$Sz&ls;~|I3k)GbvXP;AB6ZG!< z)4Y<7XfeGz1x(OE@RTz!#Bjuk@+0Ee1I0czIWv-9r1 z1>IBoFxY{O!AQUNH}JE}f15s>w8dy2eefz!rG zV?;oUD3yhvh*B^MnYn=@S7HtsNo0^V80nP@b1$FOKU?EtIx0*|^NQCv)&|K}TMm&~ z@aazFt$sfW{Oj*y38Euun40rIOpcEfpXnTfD(_CC2!_be3(5-^C=nONlqX*@4@Bpe zz&+=h0W)NP&5~Nz$PhP4EQ)#4u|PHw=9)Ky7GGs1!}Jq!Pv>l&4rP{s+g#&CxMmRG z=fY4Dp86M=u9=p^NR&Qs&=^qIgc{B29f9k()o_?Q1V4;t0LARP+aTts_&rj@q$>O} z21L~HtkIqTUpdss1iM_5l4RkJf-hRt7pt_MHZUsA>vwNWs=l&vQqyCS-U+?0A^A@8 zl^ioKPrhm-!!+H)R9=o~D4YznKDI1(!&ej?X72Ws7N}I?9|vfN%5B(7GY4u+ip6*Z z$rZqwASQ-{ucZc|r<)|W7v~25a_*{+7ezq!hn9aGz2Nj}YJ6|-{-OkV*}aOV#EJi91Yyd=qzkLEA& zqwbRpY*lB99bOC-1G1ipl(_~-gar2dM8z=0Is?i_(Dmcz=W9y`Ew+Fe36Tp4k-PDD zt>Xa!L!+Aj3P2OH9EBi!Qwkk3y&f4+n}N&bX?r@P%m(QWA;G}LD>lrHueejok#+3R zBW@#I{4Iz21yB?|#y_&zV>tyrQR;x`iTMa{)SbZa9X5g)`3JZG(;HH-&Ev72Afm}5 zC$q?KF>fEO~_*?r+nUiw3MS?2ybC(plccsPjb0r z?s^a=$t}na8jdQualBd{p~mYgGCn^Av2es4i*hkXCSwKwA+?O^H&Vla%aSlJ|9}Z{ zDoD=;l#qs(^u?yUWJjwTUI`Sm6IjW5E=Qu0yB5zPAcTl=T<4RBVO<>LH}$4qCdd#S zhB><}mHMIJRo;J09h77*^LYxB!O5Vnla{efH^@~wmUggQ?1yC8s>aS2d+kEZV}hlx zThKx1GAb0wt5gPd^?Xobl^wLlT3oBj{R=UeSg4x%Lo1Q;aNq8MZ_;o-j)0&rm!AqL zm_~oE8t-7K6H>++V*>8OY-4J=^2Bl``HO+bYGgcP8`x@@8v>Znjp7x&k}Dh!448M& z`ZK~C+*xqJ=T2u@Se0r&PGcbfRRC+^`|>=s^g!R!x$i>{vR;lBc$(S;hd^qjZQAyL( zv*)}xumJKk>Ao3RD&l5?NP>vc=m^Bv0q}!;ftdi4dd=Idt7c?5Jvm1Yt7huj_w?=4 zpBwbN=3ZDEQWpyQR!v>Nu%baT`~Z&S0UH%Eni)s5u{%Sn7#bW5%FBJ`JFwk@%xaTw zRafq|+BAp>Wq=WlI_Hgy=n&c`U7rxL6=On|6l+s$jaD^}fl>QAV2Zp)2*x}gLg0RKq0jDWmt+Q3)QBlxw>5lLKE>VmSZT}!|7raQ?b%jS`oRPbkg8X3@nM|hl9*#K9~BY z@IzFbs@4~EKF|{?Fnpq4C^!(E|5&5n;5#(t?d=8JTXn%DCkwZh%02LO*U>;*16DL5 zR&Y1-z*@2}$>4Aq*Bx!P+&T>u=D5WD^~E`P8clw;D??e=wf*1SyriN$-5QT%&XTiJ z>8+Uo*rRWSj zR4F2?f-KSm81_jL_|iwkbgw{f?={=>&Z#YK5*HiL)o z@TW&VeZZ;Tt-Bjh(WKD_-FiDvB@XVw&fc{XsF+h%9jFm!32a|c;A*IG^@)_$si}%h z?Se$Zw^52ImpJ?~XrHHCwhX+o&lsBL5q#)ejA;PyHSSNw6R{$c_PC7~A@*m59 z1Swv%z*>iclNj)2f0TM0&-Seeak$LAz5r9#>Eh}i{B+rn=wskJ8`f##N|Vi-)X}p& zCLuDjN#<#CocD?Ek_{Xp!&^bj0pZH65Ji?y_P(2i$1$tG$Epwysn#5*Y_Y8(wIq89JerqVDc{CW{ilddald# zr}b|(AZ!dcz_-Qft2rd8FYi}tc&UKPf_X3Q%~RRKYXcRWP4qCEA8``I_B$)ij%EVR zVbCNTqzc@r8CdhLuq{O5UFXWKf&@r~W21a=`^_LD4{OwvjcL_>-nxGzz{}}q9&{%i z4^O3oLZ8phi(VPqCQVwivpbgrZj|RY)|bO(R@6w(Fx0N;|GrXO8$TtN%P4BUq1#-# zb2OpPgXgMB|Cn{l!zoW@Md^zdh`dSOl*fyHbES}Iu53F%?W0xVCMAgt)y3m?uU(3{ zDi^ruwUK9wr(jkf=0Oe+R6KH?+(R4D2ova8UW%rC+F*svhKS<4WpN`Zjp#Lwp0I9+ zGh1^Yf|vHR1g~ho5wmrfe;;2=sF~7z1uOoL>xB7E5jTIjJMpuc?%!#&C*E)B@LgTQer*o+_BEDZ2YptYFWrU&yvmD5NC(Dni$A`2SzzVSP@# zfgu3^;C@+2O#k~0)!y0M(9+RK-@%F2K;OgI>OZfkMZf+;Z1(^0Cq7D+1xkJb zR*%+Sw#LV!O3|6B6(RLu#tO5vz%b;WDwjXAKfgRnJ+m+z!kBY5H+aPc4~Q1fm&mc# z%Jd|1b+W3Wxron5;)-!)&1-F7@+RD<&`E{#p!(sLLiLiV;zb z)2q?CC+p2C>5}S{v3x8|%jemSaYtz)RV4n@kX0UJ2&y@41Fty3^1q#-?7Vc6-6ZmtNh+8;z#QzLDaL zDaIdEHZ~%mz@oDQ_+@#`Q;yHu(u}prGil69Z>u2q8646?t1J>0Br?BQT%q@zG%m)K z8zLI#L8b$?DFyjuo{@&;Q+X`y>zO2Av?2JyP(s}OvaIJP%lU^ezv0f1^auTgOMV|b zpkLWmJ%P1NlBfJ?TFSad8h|A4fowM5h-|Z#Dw-ZDTZ?F%AM8x zo3Mw5;3tlh_B7+b?#xx~QRy zT-M=Kw+Cy$srr1``2jR4_g)PyZlD9Jojs&lOaNuohTsVz(Q+{-Q9T6DIfejJbvK_j zESPM9hB}d>Q)rBoukyJAb9sQTDxR--dlq5Sgf8Vwfml{GM6mru6W_kBpQ4!N}V z=ZQSw>vm2SgKwStyrOHjYr3V{9p4Z-YsZcmu%qw)QT7hOqD4)%?zU~~Y}+=@wr$(C zZQHhO+qP|6@6?N^c=g9?+*_+LSHx^&W41wa{o@tC^s@CCkO(H6wG+w)eKhT+@bBM2ADdwNZ`|Y~w0UKr2-Ng-Zg_HPP7&X;m00;wpw(vXPOCdJP zGa%sijimbVt+ji7C$D6C?et7~;b1_MG$X&Cjv1^vJB;Vy7Olmab@)Zl52d0xOQr<* zCO}WyBk(OH<^IvT&aKnLIPbm|R5MrC7Z>>By)!-6g;a@~tAA9Wz(4^f6u6O2@P=M0 z@J*=DWlQoiDYhuV@Ad6llU7 zhFW%y4YNZGr?%715&nEBis7HBW!R>6>Gbrb+gTvc{y(F(dc0SjFnL8(U8}HF;`ZFd zMr={7e*TIS1uOwL;TckV{2#^r-`zA>VRo}JwDKLFV^Bx5qumYGtJzxtm$}Wg(8?pKP78xX zvqDIi_7vVJr0JImIG0Wg>rcQmWO;gS@P#KDTWfuMcr{+s2A#hNsfS884l7DL_1TY7 z+N^@~&*a8<>O8C#L}3+03I6uF)=CGMZ}(CRL?~qVy$}P`JoSFx>7idghrs2r;mGLJ zU&!Zu%Ns}KYFzvbG3<4?LOukUOCe*{d?`Fk8SWZFqk;E|-+^$;?+yJagHvfQbEorDse+ZMU{!bsV(+LNte) zeLQQnxjW=w92lQW6PIl(+`w=;^8zc_e!=3i-z39mzgh^6pSH%rc(n5l~(NfsDVhZRN%As-thbV@bI~#%gQ7ee980g zd)Q=XoW_ZErZa<}!3vQsyf(dTEm}E(8`fkNo$FhOl~||1uNin~VWOZWE)nJF!c52$ z`Pw?uazH;I8v{-PLkG+`g4h16J?;fQgLm?)cAy8Y>8oU1r)K{$s(O%JaF>_D$iK{q zxzhm=#;0~&*P~mnio8HD*MJ^G-`S{99#Q%OkSo6uwGYcbkMJL4C!9C+(Z?|*R)z+a zjNN}M>p70@1@HnPI-+~gyExO!?@}Z;?O)q7A+QqtGuyX~iFYqiYpmYEAZ<@U2WQP( zrnYD9Z%R5II`6ozNBQ{B_4dl}R&0+d_GjBF%R_v8&rFA18|EfD6dfKbP=Nu+;kka` z|8qahDCN=J=b!1L=b!20f2XYst@SO9|EIP}R0>+&VlzN4TSNi$P@$?MAG)iEvU^L15eDTh9v~d*UOCjxOp{3qp z=q8s&%Cr)&JWOH!AnaO^(58(hQSIoW*B8tezfW2e>_AgVrB!)$r5MTPn5b$6Qq3VnsX_S#H(h>Dd3iN zMx$!IOdnQ&46?3uNaWy6=%zMPKI%OS`<_qH3F>I}Rn%soK;S#Nl+D&{&BdF3 zOC*TyG-AAT!T^`R#anRChmJO0VYiMi%i3F~oR7I~(YmaMe@zfR;83~X6Luo96f!k| z6x2Q^LTSAQdr`bN(?gu&N=$C$kr+JtZu^(*Ks~eCg6-Ag`!vn=V1_hp4uiYy&^!Sh zn#3;Q6qaQ$ZFlynBhJI?oHA2=W#5Zmtd-NH_SC5`RcGxv!s8!t8cuAg(h6Y;*K#oh z_RzN?`uU<^L@P0|cDvtOsg1vK>0CD^aX)b4*a`=|ZQA>>tJVt&wFEnhA8S-u-f5q6i;4c)MH&bNfA z6MK#X;nE={4aUtVArD*gMT;{=`^b`UC1hfAuLF!>R^W8(VTM7LWBpq5c#!cR)s_#$ zZ=HseX#V#b3yqs#lz@b^sDmQ;0TJp#C=Qx2HJAd5A(?Im^U`Y1W;=<3W}>lOJt>&D z^kN$-Rx3wtxmxD;(Jn+CKOG|k^m2ArALoU6MLxhM1iD_wzugJV8X3i`4Ve2|mc!y4QLnkWFtQ#?d~1l=lXuX580w!^mmFI=Rf8{8^nAG@r$;8G~GITm~_8|X=c&_UqC*@D`hlN)GaOT#yLH2yNH@o|oizPY) zGY)9Ki5}fW+mx3!S_Trg!9qYXFFbB3?2;O`M}#8 zm}l31Ta)6BuxnJ09-uD<=xf-m{I9?0!R5!HDt55BDirOetypW|ELuWPh&+`Q$;{Mi z`H*!e=i%B0mfYcaZ(r8a%b$_+=h@tL*0MH&i9rOrGRV5Cz)|k- zMzA&297Bobpnp8kMXx8SQ%N6mxiQx^I7jc}#YNI^^yB0KKacy;XL%8*y%sz@S zvjQv-RG8D z(pG=8Hq^k=+<0BbDk~F{Ue4yTK@7$j+6~FXb^C1gXjGnrJAH(I>JzZw*o~8(UA2;fNxLEYb)y zpNp|DKfgvbYLpK`JwI9PKmJ)solU-YJujAV9P{eWS;Jv^qi!M<98y8oVuc>z#?^J% zsnf+Vf*)j5$+ALsI(MA|mdf6#NfX}2syKrJBh**evzVP5?lmYm2)}Tkg_ut`K6T8DA(uN*C-dj%D_#dV~F*S zZ|j(#x?){^nRS?cP>P4H*|vX@*))XO)-kTmYlg z?>|;KjbBo+aaX-@zdZ_=N@aqA^aSHj54Q5pl%MiKWOdO4k)^`fZWT z$%#}Hl>to&kj}xx7Eec1bo;yxjs+L+*>BhRbvR15g#ZF*n~+P}W$>msDQ+;B)A#yQSod8r!S36KxtrJuZvO1xy=R&Oh+l<>t(S1M~AO&h5BqyU5+~61L{+ zS{#lT%cBMRa_1+;Gc;Ox+06D3?AD>G2h*1;sBlT`x3S2MQ@uX{OM-GaQV)a&NJ0@s{_8xy6HFM z@Ez=8#ikwFW^b~-LLUt(*$@7I%NhUxY2`@;fdBDP{GVG!4#pdCexIP;bZ{**Sxv>itYa zylMfsStLoqD8Xqi-r`l=Ov^y*sm!KPo|q5mp4zFm={z1jad`@|5Rof&R5L(bKQZon z^=lUPa$)zL*Uhf%Fy0(&6%q{Em||&rs-Pth&CzJkzm5I_a%`GT#j0l0*3FHo3QUyz zOcE;CqjtyRdth!{52X3ov$8mOzr2&i`sotPQX<6l=YDfP2s7t7@2zARh_yZ3RPr*d zmKMLpz=f4SJOKtGlMRe@KFLc2uY(aiu1WfBOH}#?I@4)?K1<(@UDA{mB0D;&vcN5$ z87nbLERLuc3F#o?Dsg*btQ+~*-u$`cM#fDGDbOI5*Gv;C@@(f007RhMyq|Q~WxUyI znME$2S7UOqW>dQw{{dUM#?|tjq#DMeMyu80ZQy!@k7g(Vcnm{<90YcevQ*}XuR_8E ze_43!O_C~8x8L8?A#_{HyKdJTwG8gJxuad%? zmdUAIC$Krcp4`j)&x$wD8L_LJXgN!0{}v*PT35lyBK1H-R%+Zn*C% zKPYic3RHO8F=(sT;^gcQ-@D5t96=G#LSq?081mS42~*aJtd;sD3|*Fm*O&Ehjozm| z?6n0n?mxVsclHx_ls$CISD9-|52}>y3b@lE{(5B!SBu6c=bB3QWFbsDnP;_kfPbv_ zM}a70l1RDx#1_h16f8$SF5S|CV%V|zL+X+BW|qn21}Wu4@CYeQTKx=hA8Z}*ZZfDS zMW9Di1v5dE36k1O?NW6C{iPl5^|HNQ*>{@KDrhESc#I?9f`?*@a6deT^IfufalARp zBc0+NDcs-56Z$6A1WP7lbw2#PrNi=1GogP}MeO>&Lyh{GAeNGz(> z(n%aWj97_jhF0LbX!!chFZ=nMYxEVkdVROff}odT<=vJ8}hX3-xm7w|~4nIT>y zBrYnr3_4Yh%})k93Ps6Sj`|C2V@hf1d4^*r8~$*N$i883<2vOVQd}Xp#K^V3R`WUd z5;AWWIL*?fgk7q`{Pj&(rY(|rVq9n~3<|j?b@%E%o%Q6@V`zB^Vm~Cdi=ER?s_G=u zsq;511F+_c9u5N&t`0j|ZUNPVO>U6KvVi~JG6hoto2%M0hLUSQp!dx)d#+&E2frbh zQ8i`iOOz00(`c7Oft?Z~>>=F45jo}eFi&wIc|lT%F{U!yRmS0++0nC(aC*hu4Gq00 z7zXBNGB8pOAIt6v&qMJ}(tB>pz2a~9S9;awVYJP#0#L=-c8Y3A-_0UiO@6^R~_{kT$6AAavANP;r_k4u87$I3S{Zc=l#J&Eej-hg7Qa-CUQ*haILg3)nzXgWKxGmtCj ze~7Z+3(L#Wy4kVj=e}MLs-{L)-$AEIM-|i-LipLE+^G_=`3nx8N$HAULnd(i)|csL z!`s*v(vNDWnvlkXTp4vcKKhY0-5bbUlMnr?O&k?|QZ82)wQe|$-l%`m+t3ga$T;aA zmW$WXyW28&WlfH{M(%8JKm|7w7Kx1h6h1%KF-1!`nBgHJD^O#ew|fSHdm*-UK06?W44^*#+rBvMp~s{=t||5U=bI+|*u9^Hq`knn*P!O5;ln$c8bE z)WW1}ccdAkQ2$TyW5FPTFk3>U8yQG&tqE>6fg-0-G(m=iyh)`*{pu}16Q0|ou`GXt z?<8PB!7GMdKfd7%YES@Wi~_D8J<8-0{A?kH&2GbvQ%+S6`O_@MUd;Uzfzgb*^r3DC zAN}VhFX#}vxS+wW7)(rH6l~l0j-KRxWBtyO>0^upwwgq?98Xz|5?Gu; z1#ajYEVfnNsq)QcP|_@!9TLEl5Fs|yitd;%LO8qdXBdK z3k2Yx5{I|ZcfZJ6n00Uv)B;)oa;+L;N|D`|@AFm{$4AwZW8>-zF8lYqJ#>_QJnffZ zUhB|W$dkACff60ZW87dJV1Md*ny63DkaDQLtovHniU_k0*p9mUS&qE^k#tAxHg`D3 z7NZR|5U%$m@jX(DHPTb}dIt};+lj+{!2eST9SVqcKwts@;41+Du>Nn9mA<2+vBUpQ z3|(_?+H8t7+m;P^Wnj0+n*Naqo2m0gFh9xIxhCM=r|2ubia5L}J zn*RFOtsbn>H-<~RbIX`yZNCWp6=6QF*@^!ApNoGvWEH*aLBx;=yzD@FgU(z!iG*Me zWQ%_}22HmQ>sJ2cvnYLlI$WX3&*1Jp&&*&`f8&!Js0j;vQG-XE<{c}ngRcKZ7yF`P zcshD|ZQbSqz%SG7Wmo#JX3U){*;7)f2QPu?v;+t*q*(O3{7!i=11>{ngprSK3j_$q z<_=B)h8PiCQix>&g>*?696e*OWD1jD2h6kvfrrxu1h|0rB)~7wC2a_BEWUN500{yE zMFF)59H2AFspxbNlq+{c?u~Ae>9B&=F%$Srh^cV@`>4=s7J4%f=YdCYd+ehG-&U`) zJljmaac=i_Z9R_Z=Y>1XW88Da{)y$MfjKl_O`zcB38}kVQy@Y?;=-YIYa2UR zfFI3QsevJb`UUNxY`-&hRcN7#*04xdSU?r$1>6^)Dq5$5{f1^=5w0-f@XNiz%Zz6Vw>srIWM`gFm*I#l>D0Ye6n@zIP~ig2#SeG^5)_M61{NvvS|Ni z)}43jskjIJ<4r^Mpg(+xt??+T_CPf%0B!J?2Dyl4TpB_o+4yeJeyXpz*2v;ABR}Q) z!|@jLu}ReLWC5+Ad&q3tWz{n5zQev|YoOX7hL2Jk9L2NLn}SHNi)|J~2}Z&p(n|o< zfAe$**><3K5TbG%GcV%WaAOhhT>&98ro-db>gtjfKlE2>Y;i_y$nRaxGQMcTaXCi` zZALH&;l)r=-H5`@$EelVYY1)%Q0+1&7hT7R*kva)Z!duv>Zjq*uM%`77AD4OA0+}( ziga?Uj2wc*NhwHv2hbQlxDcfpH%`hH?@oeAoOI*eD9nne=7JPB7sZ-|JcSzZk=RfX zqOv2DKrBK;p$Lc@zZC3qQPeHksXgv>VCr57@guhoR2>P)!)`utb`bF^5DfI=qGp=5 zoIPrmdT6|PET}qE3#OrupmdM3$v?V13R7f|OAeMM2sG$^j641)sj3_N7SN^ZkfF?d!)No@h4C_@S}w+2*ZF#bH<={=I>u7<$|#+IEz1idCDkwfjsoPdWI4lee~{LgV59HI2bCR`ZiS*G%7EE{@|^h36hfK7sF2j)|N7OZ zD~?WCfmssPp|-y3y{?xi=Ka;&?91CL&0rx!T|rI7s%*KgK$4@IJ+{ihj)N09obbk# zXS4Gbib!;y<;n$Hc%<-a@#`Mt7AC5JsP@fkAy`hOaZhZ=+Df0(+XBH2E9Z1yAOzto zv*4V{AuYjx(TsD}0Xg$4?t4Y)2@ovJV*q@!hDZTW-kUz&O$Mu5&mfyw>J&00hq#37MI}DANisYoq)itI|q@1{mAhZ{#K0z0gi_E34pAg?uR6 z`rFIwGWxNNv&%xIK{@|9QvRagQ$2yCFX!KZ%nCg>^g8w$q@760-?BiV`cd#JR4)0! zrxsE48~8v3pM(s_2Y=aNNkQ8yQx1y3lWh$TXYmDi5mdV0F|QgB_J z;G0vp2zyQG@J|dyB5f2_1$L}kM8)R`L6 z@P)zcAbmIa=M7PPONI~MYHwdV@93&WH$ZV-Z9Z5??G&8}w_3IhSYN+eV9dGpiDks> z?w1UYA1t^JN{)}MCo8ADdl`CFs%5L32lca+!96v%)f^|KGhU1GKw@6{IADx-!3r?L z+|dvg^cZP0%8qM*|9XTg@^S7Js7)%=edMuF4dDDSne+eXqdQRCqBI&^i18!NCNXB5 zQIbK2Hxi~c?gNCNc80Mq1FVrvxKrn)0~aJ#({4?`Jw!4=p)5^|S=N}p~ z)Sc_!k}1*taD?Yy*bg(?%Fz{&idZ2_(7}2H3YuME-Y7@j#QE1}5>9POytl&0Oku~=USTuwRI$GMvIkAx>2!woAF zqV>vDNFdDFjYJoAk~!8_@K2;$X35ps>EXFmMYGPRQqF9lN%=P0ZN7v{0CE}0ZM=*0 zx!r*4^;k^?sB-Pb^87lFZXmplJdU&a)UOQ7V=1DW&L6kHI%6`CV|7cJGOv+O5f;%| ze=T6Fq}AYmg+ZoPNuN*EF3)7^$oeg?Rn&ITzbkBM5dsB;;stYe zs4@0I^~pf7DQfh5p? zV+7`JRg=};h6A^wtLtN>Ck=G$F!XwGOy$NdZj+E+^pQ5Adw4>1%H}Pl$iWg+|58uL ztuh0P$c(8H9F2r16rtafHre6EW4z|@rVp!7g~X~k1{ykVfT`tt_(c07ubXS$uwu4x z0il}Gl)tK44X_vy=44%~yTY(S^ODoM1+@E|&046rjSytgPH3j7Q>>TlRn=N%HQ8>n z(?+x0Pmr#O@+`(1=1{buaN5mE?NInyM$IiSi32LT9SKCG0XT#V6z;aCXrU-CbExs4mYB? zj2p8)zkuv2a;!G7?nWIPswRs({szjwKLDk(#RXOQa?y{MZxyV{tqA9fiu;E@*-Er{YVQ!%JNS)Jy5(6Z( zX*;&i0jG+nU|*of<;x2NTVfztom!M;s>u#XqaEY)cw0ebX$7OybOmL6AO|CD=%B{m z5)cT+*kJqmp$18A-q3!9<>vq|2YD=fn?%o|itWjX0g2_QG=xd5{%oe-t|3l6o^Ad)izIa+1<%RDh#8s6KIKg*muS`h^kB2>?Ib~D9XlO#;F3I5^&GYdj)>ECUV;2~T_JM3wbTbXm9Qgy~ zBmCTU)eRNs-UzkByeaUjFFZA3@E)+j-iv72sTTOYeNa$=XcMRsGV8k5_x0U56dQ0= z4M5^lun1QdpG%pmS2*aKgBSEdxsbdEE=kJeC@}nN%pOKQa(_~n%HB|-;h_)n4-CZA zdj#gqBEL})5n`}tSv*?F}#=*iMHIXDWFT8LlgF z)s*L{TkQ0xd9B%Z3En@>4@#xk*!kH$!XX&sf#8|iSjk#1%1-74~b~L+06JeP( z9N+Yb&`AqH7s1Ow<*HDP%>`z0p=I^!YB$%{EyS>*leQ5~02$b8vzD0Q@QUwySUT{y zwK#uH6!TBKJ7wBuoMyX-*2}Dd$mJwMoY+f}gey_+-g9~ky2^1lD}ij>AH>*?ud7@B z^n}5svknT%RItLG^Dn`jlp$pdcC*3-r2wn=aY6{Irvw`{lS@vrOe2UJLZWK)^%eS#)<*!WE`Ep=$j!&$GWi&qnBCPiX_kD0cJ$b4S zxNh{|^RPi`q?f5?tfFzDM$ib4cXD?gC$qyYN=u2UA8VD+!6>x}zT(apU*mo|H;-P6 zyf`OMTu`fbuLI#A_i}cvSmJKRX`OJ0dc!L+>&n9i|Ga!}P8SX3#8_a9AO5`jnZAC{ z%UD;9j@9wwhuy1~xrxwhP4?s}7UTizZ<|bCM!-rqElKi)R^ic-`6IW0KfMy7xEX*PAZ_p*Fs*?#v_iq)8Ut4cXw9sY@Sgvan$Ktm40b=N&1JS z=9fXsylROGIjyzCj*gxF$We)YWPn+LjyBiIzd zgXZhdW0wv@! z5N;6YV#Fd*@L>H{{|}FRvg-DXao^6ufwM#(#g7QDFjhG2fyX!N)JjYJk;&O7pl>U? zKK0lwHF<(2EY^!cH+T8K+3V0~%0y4GY()5x?97HunpfmH(cQ3|>`xTzq~f|f!sK~b z6_rZxa{!%9xGuEBvEt0CP&2;F9L$0$!A-&}QW!m@16=35Bm@{%nB@hcsZub8i6|tN z=xLI13whr|Nw4r;dFLV6Rv2%>!g3Vz?izV28s$Ei%l)xNNBOYIQABF=)U|fD{G4bU z4WnH-IGu;3mpYmSJC&9Q_!X-d{dNe67Nr(LE;L~}2x2$2P|uWB%)%ClDgj8XWdJS2 zHgg0~u#t2U0HBh#_Nkh$fiPcGqr68(7vMZ~86qNi3+7W?0yE zeS0I(uN1Nxi}jn?YUBLZjRVDW#^tBx^R5<9!@^wBmK?sQpvt#oi5nQ|30w@_8b5|E z8lO2ZUUVf7eul*ESgj9aUd|cQtzF{RuuBj2!zDCT`9Buoh^yM$ac5R+4R- z3f;$XWF}~vDZJ#0g8x|(0Vn3O73+UBPu&cHOh+r6@XH{>*utdj3u*<~-Z^WY-dOz} z$9Yt82z0w=Gi;2tJ7KB|Gy9IMn(r)WXu4dVW{-c4%tLyd16$sYY^nFEl|K3cXj4$frgTSXW zQhoIjh#3>a#?}#Na4CE)W%?ID#=G9Cv2VYOBrVsQE~m@%rAdC7*3_g&bB&M&(-jw$ zr&3~TTRWIN&AA2CVLdKiRRMWHDw2xepE4>{yop-Lo9}-MutPI114*FG@S8BR0CUoR!(F`rFXul_VqEr&}E^wOXxDdz4K?W;P#87$QHPa z4)xB9;^a~L+-^3Lx0`wti2{jbXFZ`^V>fxghW zIYy#nd{J}ryCY%_L({~_1$#(!l?2WrxXcvV$r-K-+I$&ppMmc+aX2g5BP>9HzfI{gb|vfQCKRnTOIydJQae}~5ZnQ>)TpQ%Dmq*=>^gBz#LI7To+ zun}PuX)c+10!=c$5@-!35g8TmqfV?&fA>&U-x3!|F?99KRLxl~(b;wSm7%@EG8~6xsCPX0e7yw#ylB-^gw68EC-+Mgn6oD!mes_CJ0y{!meh?(N z8-26=Z-UIBZuu&OiM`QxM4n`L!h_dzg!fu0O3kv^A zGSRnvc4kKBgq7Xaz`*#ZL*1J5M`+4|h_&)W2WucM^XAI=&1DcDV3yZx$S)KP)W4J% zn6D6hIXs3Z=d>6Px<$Zi(*!PG{C>wOex3h5jm=Efnu4)~Y$)Doh413_7OpHxP>E!hF^}UX1 zItg=yPp+C4shPBGK={zW_B5WBjEk@eSfbvMJJ2Uh0J(>~pcWqljcGAFvETWKx&73 zNi!5tj3mVyhbP3Y*-XFB^;@BdyI`f~3dmBPPb`>}E;8IwVkM%;FzL(-$nC#xh3@4&#W>t3~ZB z)9)rfQYddTw>poEFu(&U-6=>gMvT6Is6drxo`r}6+&vE@xaL@V}okO!S2X}>eX6rn6bGc;{cW6SG`C%za{kK7{|M=(?~ zCk%-FsXut}b|-eaWGXS0%oN@5hXEyN#t#5(P~^+3U|&d2ov$S9gk+2atLVGc4CV6a z@v$&f^7HsIgkZEamMe&>lh}=Gm_uV**NC7VNmy2E_{qLgb^freUfiI4s*wv+E2S@C z15C}WEW4c;O8&r;b_QDNup(&$i|Ma0F?GpXd9W}U7PB1}n#Y=qSXShdpkPldXgkH5VlfOMgN3Ra`b#D~RXl*HT5)ip0U zVOe$RMM!b#!RD4-igBZG!Qd?{;zmSx#S}o=fRy)e3e*R6K~Vj_`bg+j*?@mzcPOd!odGv`y3bRD(dt)5Mv4^3PK`|GkBw}}X3VP64Uz-D{I ziQh!2#4*BHdiA@KO%M?PajJ20X%x{IVG4Ty*yCrPJOL&L{~>L-<1ptgm{e^{43d=> zlx}}V1i%@@I%^QNS%nKdKYYDdCt8LJi&PH>XDX3vM5xZq4b+>f$dq@PcSJ%}oHUJ5 zej*qRUEIjs2vJvS=Q871f{N9MbLYdySO)qo^s4h=OYnp*y)oNHpEdK3(D?xD&I%22Dh|2oa!vNMFQv$MuKAeOm}6tXyt79`Ph}4jWXLRMFK3x#z!)}_GB6){*fB*i z0QjN~i?I0nv$$9SXm^Z1W5iscBFM?UJOlHI`zS}DPdYTST+5^n*;fJP2U2J?wo4C$ zF3Kea6}aO>^HPxIqZZSyR&?bN6QIkBLpnwkJ^dvfz}HK<1L`-+(M#TVDDuanSw0BI z+lp5YsK^SCEMY$7jbUC88%zRJY-Ikkhp_;^2{3zX;+Mu^1#UsuGQSBqOiQcjXZ_^z zw;mP+Mn>}1DsCZ;*iFqqBW=4xFYd&`e6r&UmzZ;7O0KOQ%1UC1P;nRvt)ubzZV$Kx zh&N<#Usu@c&jN&k;8^%n*SE(`PtNLMv2%A_YWil+R1J3fw1f6Q`!H!%3H17&W;!wF zH=`eajV1OMC$M`@8#geG4#`3V$4G9;vtV#0AXUR(m$7f&h|Hx!K$SN7TP=p3pPb7Z zSc{yp)PWZ8mM^WD7=4VB^44}rmStli=Uu_#Psk~TZz``=y-1jcZF8dAC1Q2?8}7tn zp9*rAVnO*jfQCqQs_E@BVNMX|PEB{Yy4FC=`H6e286~KY-{1jy&V*Vh%FJr6$Bc?r zN2epN0H*9EKZe0s{#C7{^z$PWqyt<3`fsD);zn|tl;?bJHmZ3_ zccAtaMC+bs&)g#br_4l5ef>B)Be9U8i2mlYrGCgl0?5Fo@kMOPzPxBbGbJta1JxkQ zb9?P^X&S5OI7<*i)~Z#TQ87}H$;*RybsOq}_YVb2q5$nlUYAc5@79-Jb9JH2M6Hkq z$hEpaKy0|sJHl(q=!Ya86Y#BgCp|gAgJ)&m-Yi$W;tjLwkXiAZNaeTo;AK^6${Kj& z9{Ecwev4p$15bcGUB|8coL1mH;p7xt#tX!Hp}*RsHsV5^bUz1_;Bj(+#HZ^(Bof7O z*!)D_bb4Aq8|-HdFTkdVYB9=Ef}cxKL`I>O@!Q?=S~R+ZuDPKLQ*MU(@%Ig zZonH`cRI~)d$JE4b3QkVJ%2)uZVC6o1&|DL(OvycvPB+mut*DgY2r3O1x&vjEvHm% zgrG)QCP`!AB;PuMk!-}!X|^WeES8WrpUishDIE5#AvJ+Ik-}=N6JD)egC%<0KnS#8 z)EuFsRdI>iMzuN^)voI-7PaIq^J2Kcj(+2GfeL6?=9HO_H8HaGQs%))S9VqbJW2m0 z>7OkpWqtP>Z0!4}(;#zm=YJb_&oaqf0R{p{o~SDMQ+X&243I|NhbaiZ=AB?sm|@fv z*v=B7OiGuUEsKTgrCw)baCO<0?A{_yZaM13oTu_-d3X zy7i1}6DaDN`YGc-*UjoRMpmGp0Q7Gg6yi*71BP*4-^>(yr{e8MNG>uVdT$}TpS zO4FYH+*`x;`Wi`Yv-v$a`%cz*ZYz+j{^Y)sg&u-AF7lLY-eggT!LzN=M!k@8u?B+& zTxk*ouG%`L>&ywT7V5m^6&r$fw}Rs{K=T0MYFv2#0nHj)=`gE~F7?|{;4RcM4F!HN zw4I)FN>?!zeWqS&!0%=RxOT8MomI`JJ+|~hzeHLp8qkw=a9S?`TQKv%M~pAq^%q?t zXK^m8wZ*H;N4tl)OkfoCyi7b4-B|Ol7eDzjV7PeQXEL%+ou=ie;421tGD6WSaHTg& zqdr%JAP%$&hn1ZuxL^Vybg3Fg>YZwc!`gNmiwWin+X>C(6Xa)xu)2Y8Dwz$1;IsxR zcF5$B3V=b>knIM|iQJ;LTL&K(=296PVL@iBj8jD01Lf_iNl>`%JmhO3y<_kawv~BE z_g=b$rBQ}aKn{1vJ4f#9iUJt1@CP;LHXIOSN%GS?7f)&_3PSUzgt3a#+YlC78GQy+Rl2-3bt7`Rs<52X5g$n zH^-B)QsbIc%clwnCBRTy?(~vdxL;Lvd(-V!Yu613;_{Sxo6q=*| z)+$@?GE$<$1bs?!#G^@llE+373Q4EVU07TtOD*k<*$u9ncw6+lzJ6Xa{X<={X)=n> z!vQu+e+fIP=0YX-`o+(8Ywo9ePDdZ~bIb0}HO+X}&+=(zydO5@W*?l4~{EK_R0#Esq>5`ftj`M>+lGjx@kJ4)%X~y7GVkt&P_{Fc@4F4KCy}0Sj z2B-o6zpAD==cv>F2+A6(GdbrZy@;F9K?G78!n@G)fQq+|TNeY%EX`>FFm}g_brmeU zXoOY2!9x286N~z10a^XPa$A7$7`5@{cT9PWS886bRJN+?ZZR%2nY=01E*V1$o#;N- z^9;qFmt!RPMHI+WOR|@9u;v(QYmVuqand|!Vi5FgY*-)t0~fP_cd9AKeGBbuDkW@4 zhu>SzN|6vS(Cz!1@U{IfuXTR)K3tgDry?acxSp^eG>pjDba9Hr--H<(woEd!a&}tC zuq-D4W>JE$v=I+;_x)y`o&oBEv+1K(!=JQ5ad&5&0jD((F`0A`b-~ai8GJt8x5}93 z)DI;bjzcWUoWuwDI_(rFYS|b(b$J7j6S96knJEIww0#PN$uXR1i*^UBPG#(;eVajbbs8ag z(y6y*&?|xTzdrF~Cp^8;en=r8<`L@C9uFiepOH{xs68+S5^|Qs--7kwlZP+sm&?IFdbphp;~1VJKAc__IUZvSYh^_tXG|?*30AZ(QI2c^fx&83 zg&J?{KOp_hfOB?dV=L&GV9Y~HtvN#xm>KF~4o!otq8idE1~U!@#yp)O;R*2o2pNA4 zGB}&;qpDfNTQx7v^Y|9Ercg{G`lP(OA!CIJspFOxmLMTeG(4@YH#Yo13$e{=t&u@= zyAwf&I@#swQcc$QeJ7p}XB5>;hzc%e(vCG{$eo5McO4k}b3#X8yV64xO^@r)%A`eN zZT}z2&S^`qZCj#g+qP}nw(UyWwr$(Cv(mP0+t#huyWh_Gh}GJN8PPk7yt489R{!CY zJ_N&pDSPN4Tf zEV0s%_nyDb0EY0moPa^Nfa3y}<$FxUPSUIr>LsJM;-~T3+4z~2XYVbl?8&^eiZ4S` ztnAf*4bU#*`w^U7(evsgQMsd-vkGV2xMrNy?08`mHoRpa?!S!GcN7xWQq|t+m(;a; zL87Khn92LHy&l^v!v@n+kK<*JlJ@h&h2t&d&f`#@8wsUft0B zh;L$ntH3J|dcBs&TUkp4?w9Z1AZ5J2VGwW~+n!eQsq8KPte^el4H~K8m@AHMkfgnX zb^JV6;P@~^Wn`80Z12!`sWjMzpt@oClm2FK(QQahgr$wZ3+OKe{_O5S&;|1i1DM;- zagA3WmOy@Y&W2X5cB`uNk5v6S`hfvperLF(uCrfbYUrWRTn`FLM8U(rqNW~Ko_m-! z8nA`%-RYN!px{>03kF5E(2A8n*eZr5Oca|Sb8nvVt8sRYpQ)QsWGYYvC$wx~qLH=p za0?#Wp9B2qv6T-ig);rQ9u7)Naq_21$=qA2UK(Td%LP0%M&>xVU>*-Q<*qwLwRV1N zK<{F>rJ-Ovl5==Ue=4O!|2}j?gw@@Y?};)yH%8E6KMLb;rF05)5nW66Y$p_!0s^(I zw~zmunn5?FJoggE&;5Lj2Swyh&qMQ+t#uFAAHL83UeztE+0IrOc@rxy{^Jko79dd zMh0fX+#~HUVJS3zHcdBjL0JFTwU#g7-!vxvY6kxtHX@fZxjVLjqr5dOr5^|`46B>3 zt?9{p^2GB4DV1yA#`n$t-P<%-427*EG}_pzqeDxt4%=e=>;oM^L;i87L5#(@KD|=#QZw0k-&htNr)}SLa89>%xko~000T<{lYLj!GE7=z#-V|yc>r`TMt?_;PHYdQm@>7<}n+Q{4e z#5?0oenl;}Lgh`%4{V?v!n))u?{{Vi?Yip3g?r$Xfizir^d!A}*|Ebiws`aVkLOBq zO)@MR1pwei@qe5&+SnOeS=jzR?dP@5r7iYo;?J)9ycIBHg@Q~q4uQWZwt@+1mG0z= z*2D?OhCg$*MPw76+~bre%j$TSo$7NBXE6o!xF!ZQ0UT%A#l=Ns9i8s<=$DY$ZPZ0* zFEX=Y6cuu`?sQZr{UUb%rip%ziXo$)|4B}G?m_f4m`qg>N5Xx2~m zH}-TqyyNKHlPk!n(@HXinwq@lE9KQ$|~9B7@r?3b^D zqw8apoj#!T6&6gQyDsR6ph9$WdAV4Z9@HDV-w%3z#+0vO0aSPYO+{;$oKR z^0zK536rsVjz;tZ(d?=u*ST`2D*P@yGm{bF60Ik`7Io#=#^)90n<%kg3ST zbR++&R$yVWIh0XLkzHq|oqsx*KC%<6<1o;C#1ZgzC7+-X2-W}6F(PjZu;_O$K@*tTH0#r$~CzNDTm5B&lQA&CTE?uuPLI_3lJ@#P{&m@a8_I zclRwsf|{g$b=OYd+Wr!M*QM#!AwSim(Q>2Mje#NXRcq3LQ2wZcbM7b8gUw}{%( zy)fOugZiR#Y@CT5ubA-}*~m!)r^$Es4O$ZGSg*gq-a{ni71m9Ai8h=Yt3L4nm~M<0 zthw$gGrI^I#w|0Iw33<1uauwq`Zq=&3f9qGIHQkdZVS-|9e-iC5e2VivMNn#Q(j)L zr}N|ZdL2RIvjVZH_NeiIA6=DBJ?11IjTvXlvINU#HTeEh)`6Nz58K{V3im#EsTaW0 zUe@Qws9jpdGu<_})jPM)=NTp-x@ol$^@6jpFO(QbgF$lz=*^0FF>l#1U}S60fCKsy zXwpPC2%chf3~5U%$wsa5_#6pmvXQQ@bKiCm(9=1^m019KCpSvWpM@Uu9cp%=1*NYs ziDW!gS`1^De&uZIO?)J6yP2l3Ec&som+Z*l77s9yAhZ@r!|MpRw1Y;V*aLh}!fvHs zBtA9nLN<%vr&A{CV_jteDM#zmXvh!cTDu+09nK%ul9RzP6yTj6k?{HBT*u^=eu1=G zG8z5+0W%)wUS~iBB!1*HyqvhW^tBYJJHa$;ZUX+jQZ8*L@I0k@1I6s<)D+^H7X|W1&0Cz}ghdnx_yAHyc<3L2zyGIa?H>q_UN4E{mQh=`vL&!)*`QGXt zFwj30C{!Q(uptth+}|syTbqUe4VV65G{&6qi028(tJP&kdlbwN`GXdD^K$zPc#BVZ#lpu+8DEntijEbU=%#Xq8l9j?<_IOfB~S1_?_ zEgr62Z&S!&)O&|>Gfxa@Vbld7l|vQvU7Awi*MJzJnVjPo9xu|`qFy^dh#O1--U6PQ z{rnKk1ojL2F>fw(*zg`LZ}X~Ef*Gg~{CW3$JyHr%j*86$S%~-Nk4&hKPiU-g@%AHu z7C!6g!^hMCj3m8aGmkJdGdmb0NhWWXeQ=OWtg|qqGThX@K8DFdWLo{)!j7jEuvQM9 zi?tM+g9DW5YG9|`jhub%kp`e@8wDRG7N++g!JY9QjM}5hc#6KEJ892=@kR7jV4>jr)_dc=942QMBm6;#uxPsLXvoCt5x&+E?S2;yF<@kh5b041m+Hg+l5!LZ z8MMT?X9maOE`9zwIzkws2zadTfb>hh9<9epZ5cyD#V&gj(PI;^74|#9k@>Z}iP`*D zyZEH!c;57}@A7VBX^@F-ozdnSlripkA%(T>3OZ$pM{}lsBZe!_93G5HXF39Z3RN>% zG~vk5_hcmzcU%<-kC;)MRsJXRVx%*cWZV4lmr8I=dgEJy;kqc9u=Bt7fw5r>LTj9t zRL7jCukC`@cA*E;&aogRig zowqJ$1xX(xTey~P2?T=?j8oQ8HpT-`ZD0TNi-upo6(BW%g~l>j^_-11onj+3@mWf? z&^sH&^oBSh(V?@)P$0q3^3B!&C>V@Xkq5Fzyo`zh_>P+4jaWIi5b(mVpfS)Kf~4@F zFBR7-7f<2UnyP5J&bG_s`)9YArkRkHlsQ~@Us@wRk&-7hKbZ@>QIdkP=fzsRWQ;J* z^MD>j1_P2AD8kytakrS-JBdjzDH2((3Ytb)O9QOJy43f$z6!V;o|zjVFcH_nF)Zu^ zrR6^K8z~6O28;(OwDnh|Y^rs4LBoLO!6lWl&6IOU5g+SeC{^e~G%H$_M{*ZJJqM3a z4phEDWq&a{CX|`ebTb~MwgQ(<_f|wiNzQ*j#YEki%NWB64Sm z$;zM@b77Ji_8Up#LYx&$VpXvp4kA?(N2AX_H;(5GB=&}#en^gtq2ZT(JOm)t^CIkC zj0P~V9EJ@(8(lspFwi(LS^eO^W2IppBVc|*DSH@`7Y3ycW9-X)_Ifi$R zl~E|g*MC*`^_T=ZZ|Na*sPv>fDDD66xRG{UG|s?=(ZHllID>Hx(n&r{M>L z85voDKDv25jhxiV5GPIpCC_(v+P#YMv}aCv&wcrC6;rsgKG~UENW~|X>1tpyKad4P zGiFUUL28>FP*z=7k6ZYT<<>}miA)tHMSVgK*9|A(EiC1owIV82;$|0Q4IUVRV*`O& zTOcHBPdCjtcmZJ!{Sa-5_6D+ta_pi8HMIaHY$^h?4v^4CA~>;&Gx(e9P>`Ep(paU{ z{1VQZ4Er|LRF>hp=a*1lTti|!UY$zg;*dH4}oP+ zJc6uCjlC6pbJ<7NN`3#wa31eu!A4`P9};@0^+;(+z}&En@BKM~=m5_%y7vtS=y(X70WXxVOpmjnMdHK zr8pVTC)<9zap0zVTVQ1JRBDr0r-^Cgy=YC*GOosRtk^oDmPZqY80w#Ax?(kLTO6CN z`)dY)JC1jc^yMy{iqV&C*(d zVNtNWNGU(yr+c>iCkj7qrmAY`S%wih*WRf1uNj8ZDNo|SbNV%JAa>B)x#SS5 zp09`gy^mD%OqQYbY?!wN#`{&t%dln`Qh5TBxMZ5-Ck!50BSz>L7H%;fy`ovgVIBD( z5tK7R%k7Mw>WppZD3><4E42MMaAloklgvjyCjh<*i+$kUd!^-WKUJ*I8Tc2J=rvg* zf<jlEipBkFGsfo1Bw>z2(FASJ)Jq$XszY)Ec*UQ&!q=vB@ zZoEse-j?Eny4-yeR5LDR*tYzl2`HF^wzHHe0b^skD@`&amIZ+@*AUYAAsd#WlM^JN zVEI5=rmC>3`hN-{eK*c?8PEx@G2BH_ow0-|qh<&HwUI?8YfXJDV*>JE-1_`4lW&ZU38F z%xAT5uBh#Hz-*;es7k!q_BV`u&#gl5dNre(0SMx*b`vTIdGiKnF|@FP&L>IFrm+8y zW^c!z4wp_gM{GsTFeA%9Is7X^*FoT{%i>OeEcm2eE8PD~=gQlrSf1he3mq+7#=B%+ z=3McX#7~kXJ5mHmDRo%;6#!MWrEjNHe4i?C^ZmPRl%v6j8qSX%m|m=ic8MDhK@bBd z18tgw&^7USsT0yZ-q{uMpE$eAaW{OuRqJ1~%~$rnW51DX*OU={m+Q;W8YjpX;ejmy zoXZZyb}(P56x7oBNfP6#h0U01c`q)^9XiI|Vm4?O?y?b)aE!v>o&E`%`53@-0~f7M zpgHa^lj5vL0|Oxo-l0XXqhH_~nXh|8Dyr>%mgwk@RD#4bnc=U6^QT^h1YB9@qLf3j zbUmKuSV>|fqXZ{yBZBc|gUw`%^9F-S(v53~K5u|}3C|lX`Pr#NCAg?pQ*zWi%CV8S z^`}!J(^5ivonlF!XHhFy!LJ53&5f&?N3iflqOLlF;`RzqBuhwg=_iW4`7;Li&mscF z;q9^pYnfC>3!oSP!BR>615V%P0-cr9xL4Q?E{m~$*TS~*X^3l}MgUF0UVoXEg8reWXcnzt#QbgK7FS9uVm z1#dvUlP0}YnHIFOdr;Do>VY{5GV}~8X1!CZ+mslBd-b!D2Z>|E@L}DHziETUwYuiN z(ZEDdxs6_oO`iW@yqptf2olZTg6)ZVVBVppWNCfvY9h}lI?Q_eM53XeN;sL&XyMC^ z&?<oCD|6mc!q;P)NXrC0j5;ubBippB?nF$<*P7$VP4GnM$0-{= zBwk%%tVma-rs1oVzpxs$tbuJ9@s8~u(b)yJff>!iTzeyGN48OG=sU8$Q1@O=8#y~5BrLdPTF5K^+rfqf`!>t4z@qWwt8D7ZEMhoeWrW}j5Y$kLy7deB{942 zkKx_uK}!vZrs1#F?u7B;pL?_PazUVn?xV7K=Xow$KtyLX*O`!FH4}u)uwQ{5=Vd1| zA_r78f|6xTxH#%}pl09>&Fv*xqXviVi9M#`LNuAGTQ#FgP_KFkN~CCyQ%aDjk=2*$ z4HBfSh^iqLV#pA`Iw1_|RecR!q)bzhr3Jf=n|ey-IaLq2jtt*z_BaCBbn}H(l1)h$vTZO7chJ%IxC}mox5Z^K1h9E>0#MPsoF zH|6C0ClBCsz5PZVYo8!%A;Fd3VZl?kFtJcW-8^hO>ls>CYLig7O20aBWhbT9Q$Hqt z2zgJ;hQ5ihO>F$brk&z}5e0z7@$X~D!Qnwt)@1i^Al?}dsWxFul6?5e8#yGNPj0H} z*kYM9zNbGh=kZM-Sv1v)l655>rmD-*Vv(jqTc^=KmZd8wrLueM$d0=7x_8ptsU~ry zLo+44smvC$s0Y~CR$1@NC0SImwu<|a@`XZ4lc=0RF)nyh&Hg7|$0O4?C*5Dnx9n?3#j zb@l3)#(pQ$o;;N=Fd=d7pu~!tjX+2m53al*vpUj3la)=;$n}=YX5@o9v!jbu+II5Io67D`}rrd)LYSxp4zRYcYQirK{rVKUpfIzz)tI2UxKItWuqw zfFk3Ns9V?%KC2w@n0f?NR6Cq1MPu$8Wa>(R4AdR$qfP%Hl0?zzl8k^cpdiD-CVUK&|NQ6k`E1ls@a8u9;K$IZ^F#WEj zCO{k)Pc`~jJw9@IT{+H9%}Msc_%%u}-ImF+`%(P<(ncz)aae<6$7JvZ;q#Nn(9tu- zYEh?^48lFeDz)*8akLT9NCEj9pw;`Vh5ShBICIj53GvK{N8@%tWEeye9gt-)8w+R2zwKY-?PyO^Qac zra?-fR{Ux6=n08k*^!k0VIg_!rXW8g+RqGxv}ujKksiSxj`p~YqxuFz2>ch027J_V zgQvA7q4ji23k4^irg%lYrq(v)y@8DwX&TrP4W<$s(~#;J!gWmQOjU7{hL_KFty2;? zxP1p82q5+j=LZ0j_4l6p!oYg3s@LoOi&8C+hmEHtQ30!89d6BCw=4`>&E| z=`Nycl*)X0N-aVU(YFC2kIXWOAJyct|LKyR1*|Zwp>ohshy|U$*I{Z+>q1sx=8;9m zUoZqPcK;acm>6ua%yYOG;(Q-Cl%A05oXDaBa~Z!Ck$2{cAoebdY%^2@U%1799+usi z%z_XLKa`P?l~F3N=es*Yms&H!YnWi)E9Vz^Uk zS*B_L1gd<dK&l;$nM!3Ma`7hmyIz6TBswvXS{Sun-qmY>2($5*d|#k#Oj9!!M|EL~ z+xHE+siS?t_OyKD-A=iDsAUY;Pk4sI!DoUrq%sg|irOl76XkI^q(?5FiswFWd0G}U zzX6ed{VT<(b~?l`V>N1)zj{lMYE^mj7xEyV$?NpKA4aQQ?Xp=tJf2^Uw#P4<&eyx5 z{DSn?;3W6+;hU8>z8|$!2dbjkj1_{V3^dpzh*w~$%<45-7Mh|3CAepmD>ksTHraH^ z^pMK&xA7tbz%8_Or{Z`9k*0E|sf33oR)GR||H04s3t<-pIN6BWOX-nr9-n)# z)NrDvUpzsz`SU%C&1yN>N=IA8D!oBFaTQ1rsXnyw}`VJ|cABegVeqzwsSc0M>(A)r&NvY!^to+{cmn&Dtv}Yjo+B4!9Hs zko|3BcE8W2F{5&ce}(Pn%?maQXY4eLtqcNbnV2bX&f&sla1fc+=sZH%*kC6o02Q-z ziiNWs3Fl{~D!q!d+sZj*$CRU;f|u(ONYzmHOk8gNNkO=U^4>*}h~61UiQ;ZOfh4b; zCOvWa7B=E`3ShHy?Bg?;#s_@ORrt(FOTOQFxd}7042eY zP)T|mRbt&0cuUz)nUT>PV=_QrjZ1-~PE2DbPH`Q98o@jO6j%iov)bD6Jm0D3G@SMT zw^mcle6m(K;~G;htwcc26jK|vPcqzrq7?WAS4<124R($1-$G7gx6V~w%P}$*D}r_r zH}X~PhBTuO56LZ4O;Qg0L*BOI2CR(U3NdGik~)NH&RclXP4~BpkRY>C<>Ln_x~CoD zu}W3xHOjzpyp!q-81sYNSBH)@Ny)?CXUEO7>Fa8n)<*>qJu|pe5gOP(&*Q(Y=xtF) ziut+!Y&`VRK6d#~7sN|` z1k1Fa*%1eha5B8bh)m~}fp*6w`EqeS#}SkMyKy1#+>{tMPEDXm`CgeqD)i0}QgU(VM%d(o!ak)Z12 z2ecLFKAh&G^=qO{?Cq(D6IG1L%qaN*kq=yMpkQk2oYOC&Uer5m*J$%02odL9m{rz0 zTrkR9tDo=k^N>QrGw)TRBx2Y$sczr)%isS#>WFuhzZ$;#u=$DRdY!5A1ykpmNxv{IS0mIGc3Xy zh{3lvJ^?o`Vm&3+zw9juYpy#JITS(=yeK%k-e*S>I4|oO^h3MTbLvJi$&BB$ zd`Pq0&}l3uPArwGp1uWzY?1$!y7WOJUPNIo8HK&dXfb-%oj( zUHLSc-i~=sGxQS7eV!31tqJ%4o@`wrK~1_A_o?(lF;87!KZ{HCK4v38PC!+eGm1h&I*%OF{G)d zj74vMY7vWN=)Lcx!d1 z2JGw+Qyp9O6=v5|VFtZ-$FWvGC}=4JwH$|>6rxxPpCUmUS~>S2!8)|14$?6ojYvju z%?qAWRVIgBLw>kxwA^hX$zv9yzdbBC8e9Dhz>`MO{Y%+XFJ+x}6AekqRUpJju@#1F zx9`+%&LnA@O+8#~zV@mc4p1AY_# zfCT}xgqDnzZI7Jtq~teH;f6-Jzd#n*AwTl*DS`ks7-)Fa2X5dbwf=-xRJ6!W_X)^j<^cF$XSPoKQ3o zw=m@n9#3fwS>2pI22=EiSva(Jc8Z8}l}Je&)LZAFY(S%=B*9r$qXE=g<>)d$5gk!1 ziQ)}AC3iT8*p;Wti8r%__;yCGI^(|~;eaUR@SsVK?|Y&Z|M&0}+XzEBL-jDNeuDOW zgg3^@ylXqUfEI$woI9-5@*6K8REMoT!a%!6?eU>+WKOB}cL1LUiRA5DZFE#6+$p#* zl#Vg^U8gxK-t{F)^pD(|X)Q(SF>VgTgqStEH7(cU>fxccLnk3bXE#37wk5s*f;LbC zYM3Yo6;&qii+cT9tuM59TNJh?qPS;MW2Y(!<+%ZknysbUfi^FqJ1jJ8$xO!-4eB8oqa!kGxsa zt=Pf(>n{`1ZUtShlaC%Mqj2K%Q-xObMvs<;ZB>Sewq4S`D%M&PqZ9r86t5nz@q;FK zQIDb!I!&@xwr*X#0a9!WO$WpCY>mz*%6j4FX0}5Tsyq%efl;GCa?@ky$T`~wLArZc z(NoX|z!akCOz`ZHlH>QhY2Gw%pk+IJ7b4AN|BA6I-5boPc|~Qy0eLA#fhr+V^SQCj z8Vkr@cog+2e}*HrKI^k?dQ0dA%hR11QI}@91-0FJ8fccB{zjT+ZQBI(md+7OPHRXG zEw9*`%r_S8=|W~vSFx=tz@(TMf<{n0@{Yxlz7yQ0Zy&Y1KeDY#o$(n~3O7?voiyr1 z8|HmwF&MsD%FP@fAP)SBGz~BCRBq7yjV69nF9jau(Cb-^8qNUdDlP-)&0ZAYAs1v| zrYJ65^)IY*C}Qm3hxFv1{sF)x>cEx&-R0u|;E{`W8HpV3r62!l$PD{&({HyV={Zi< zyetB5!}l>qZHk2>5k9^&d=p-@W?K)zQ`T$9zdxwkg*eLJB;!>Np>ah^EKigf+}{aJ zy%heqvq@tfZrU>&qvj(ukI;pSSL#@a8G(tK0I-f%svb_l?xLk}rW<8>6;U~Up5Ia? zurm9eo96Olbm(IgE-g-g(cKO-Z1p}#)}R9xzO%8^{P+F-wL*KSP$CDdBfSdx{eF^b zXO=2(wPO_tm22>DS%*Z)W)*SHNP-oP+K*5HA^MGI@<^zhIWH47*i&(Fy#B8f2Dsv$5WAC-&&v|ADe z#5HOAJ_+4pm!!GuL{r`Xkvy1cH2ttO=+je#KCwYXb&sM{Bw1R>1p=cgsHoGT#A6^q zycUu|e9u;pFqd?q;pxpHFv&wsSd@L?L%L(G1e%z^6R88x*bm70YLez8E{VE7Vv@T( z|Bg+THL4?daee1JIrqlCj-`veo z)Cgbm)*iFztqIJH^TL7s*FD~Uj{~=Era#r|l++X+w1{Q(4*+p1*mcB3iEn%`53oUn zF_-Q$?odav+{>Ge!?}v;S}ct@m^=SLpyBq^T4Ft2P+)O2B%*KMps@9(Cv4_H1coyS zyvup6EzwJ;8wVU5uE}dnj{t25O>>&Cr__94M%0RM0jOF$$(_rqUIA7sWBXPt7vcXw zpkXyh*-e)Ts5>%GS${VFnYcG0roQo?(>=V-Z8I2HZ|4eerh=T zE)H745d9IX=CU)LOCvRFB|x#+DD^1Rfo7Y5jMZ21f4qy;j@;+XJT~lIo)<$1EDT3uzxVFYg;chUkvv>Ory2k3i z>@qE)@b{8UuAjEED){QLK_0C--Jhbo70X;KcZ%WTEO@IORq+tLhHa9gA=^GbUCQ`o zmvSj^_TrInRtx~$=IGmq9nZQ`j()EwE>d6XvuCEs(dZmB3aDCLTZr8+591Y^xUA}K zp8#l@dx4s*J=y6?@RXlEvtBN8+g@wpxKN={TZheg*Ew9q z>WuCfJIz+gBBAA8wgc@mX)Qz4DmFenT^+67k>WVz zRxDO=Z6SJ)ZpPADYIGH3&AK$_G1;R$(=DT8TgR9$a((gEs$ARaz*bxF+^*wKRhX1U zw!KcCu2aK{f>c=(kyKu@tBt?1B!E1_h8?YV-dfB98ya@4rls?DzN)NT4;Oc7tNeOF zALn_%gigsIV;50$(2SD^{z6)Fw(=`8&;*B4{iPV-pLX-kQHhIGw|>4?bwMHvm`GBN z^E=rrK3O8#>49>XlK$jDxpJ$uJeG5S2&Fe-gBiufRd^Kkj?oC7O)6a$T3e-v1uN3)jcBoskT4O(px;M3_l(@5m1(yJ%cpv2ZkU)bL`b zed??D5w+_aE2*N1!1VZ+;8sBi8kHP3_42(bN3zn{#@9-jb#4p zzpgE_pyLRRigQ2ttMaYjM(-|qQ z{yAMbO*i6JYLs~3No8>O8Up#`^<0EAYWze)7MC3gWq zvobb-&G*kNR>3;U?ghcoE(-k5CBeA*ZbXdn&y*DWb=pHh*#D258K^`hQadZh4*}jV$GZZ=e%} zcK?d&T?3a;gl$d(!*j}A@H#+atmAdt`q7=vsnNjYyQCj5_~ZVe%%Oedl2RO50ESl% ze58Pux^+sW|-Lr{Quh{$d(MpM_SE8!$+76vB| zHXIHzQ1VVSth_gbfKILjnJikFRW^{oJN9^*(dZ}u)x)*dZH0kqGYX^JXM>d=pZd75 z5o`Zr%EReoWVX{kR|$(7aLvX3h)VwYL=%yl8zC$=OM~{p%X9g80Ql#Rl+OUD8!qX; z*rwzltuxz+6}9+cP9hzfU=C0H!q@Oxb|ZOVCaqt0Xd|b_;zE3YUe=R9&;vI6-)nfI z$*h5feabW+R0?1Kat2qd#;WS6Fj5b-W>;<3UFx4Inu7u8TUWXB&U7dxlSnXk?bB46 zyfMIhV4J$*%I?EE!z;L9O2sZIr6w3ASaX;?aA+C!4KKX&0L+iHrDt_CxHJ+_BK-`j zM!7C?mdk%C7gRu5jJSy5c`|`cj zX){9u!^?dGCjuwv}UAtu~lF2WsF+`3mH)*Vm&p^;wLge>Qzuq^Ok zdZ5iIhHZ(Pj0;W1U9ZBqmw?4!`qvB+aa(*2@pCHa-Zg~q9PYu^4L|iYJFo!PyEO;4 z=2Tj=%|#$j@^0`zEP;p}UQm)Al6hET7_Kbp{4~`}HE;&0#~9#hT5p-tVE3y!*3fu8 zrW&Y?BUI;i${ue&PfypE#8~F3X#}O;!-8BkNgJQOu2vru%Vy3iG&Ub)pkx|Yd&!HKf#o^jz~nEl=-*&N3#Aexz`nyuj0+y!97QP z690bBEj_LRrJFeIE#4SjY-#|cw^aaYX|U%I6+N0=ul@Vhv!7o9FgwL=?i_Ke23O-J zIVbRW4?!8Jfu8g%ID}$TFVygF^X_AVErkc(9jFrJk9i1nNlUR;7f!B8MO9g`Vjq76^ zm6wOcwInd&j8>U2TB_n;u2P4hH5|~fe_kyr4oELNKL@`RBV>Mcq0qNeHx(oZ;v{=pBrsJ%$ahz znewg)xy^0?JLJUuQ1(@UO2<-*nLjTiY1d+_AFcjE%8VOoL1c!z<>HHY6e9uqJLb|% z*cf*AHY<(j&TuX#mpTr|9+X?ann$qn0o2{Yaq&=Lz%q`WaWi8FC8bPnRCgBRO{Dxi z;zG<;WvnodIQfyf+bL!hWVPt9;h2_F*SC{$K@I9Uyj*;vD}9Iz@o`$^DrhMzG2H4g z47Ul-E-XKv2Y}gN{1mfk4VDbjr=Q`=thU$MSDwd=M5vxg<3{Ym`psLR{@mG(9e&y1 zGpOmg?HyM-ybtM|tj-+(Hsw;hB`Q6+K+lW{WlW0na`+)SBpl&oK?T!85$T2%OPR$TxZJ%Ro z&{A~SJeq7r?)0YmC)N@BHSL@kU@m4EQeZzr*&5$Qzzk?)@i8e%-M=6~LSFB0_kjNG zZjK^gXi)sRiw9(HSkFIG*k&h(|Gu{&acpK8ZqRbW#2R6gkJ3hhHzw|~EF?Hi@GxM= zogZ9j&^p>?%eZUKGS#4}&7!O#Fc9b>iJwXYu=tD3VwpTBs?1ba@1q zREMka*BoFpHUWKW;$Ij(W_UMmu$H2 zPIfjOmaI;VXwT;T+Ra^CF{B){}X=!D>s_eQnmL{_0OQO~#()Y%q`< zuUgo^%5~5{$<1{z!B<$GlI&v~|H`JZcI^ddnh3%{GCZdJ)r1e>I^qS#;Y4_wE$Q?d zfvgwVDc9$qJ_uXm3vZdK&#DkF#zowk)c zSAi$gcnyePrh#p1HCwbQh0;qA4sKFUw4IGPF}%2=lLT3r3#_+`qHezlz}pMKJ=s+C z??CNm%t)Il%I9~)FMbmg1r%c_m|It1OHhC4m@hA*IrMMr7qO78&myzZQR($BL6^#3 z7PKC^aMK5>qwN&Q0~bolE~sROTjCrkH7k{RoHowCjscP7y0-Emmnyr_7p@zAuzjkV z9ND`1v(B?q@DtAq1)+)pfF3*B+V^6IP?fq78_Q<12IDb&*hf|#QsEYWXwb4US8ig& zk>a(sJZ_ZubQFQH@=e=BT#K$vwOu)SYstt32)!S5;Ne@}uT^k=WaWn9;I>`gQl7!z zApxGt(-1XrmT;kzWI(*mA)J2`yg_`I3y8smh;o;e;1S1d)`5!t@l_Pu3kRy0%l>t5 zNt#SyI@OFO2LV_tXh-k6Qxi|3K1A#cUO;{%-;c7 zIBNd&$0j+&P{#;AD3Xe?RTcXelNgED18DaV`3WZ8F)L~1 zQf5MC+=#~u4!pAMwME#=_eO8{9*S) z;t{*n)okqz;`O^PBkkgyaA5Oh)a}05t100Izd16!5|F1__vOwb#$7Zo#S0-8e*5@V znW$kjxI$%mh2WLVBeY2RMnTt#87_48 zv_V~`S$A!pU@|lBCE0PBhRHQlwnlaKOnR^MJ!q`KyLP|*z%o08J0)SdzdrJjMcIF8 z;&Y`QZN^2MFtzv4MRq%U{CthkGpv+1wSA#c7{$hmPm5VYF2-rkDE0i7xxHPhI*qM< znbFF?Q=IYx;@dtkB4)w)D@mrQ(m?+lgcWwnbbGfRpu$>Q7PQa)*+g}i4#kJ4Q6;$Z ztijikU}-q;h~FrN(_{2nkPR@91L3n0Xv@*F+_*oNb)mmc{9H`W_Jjj0TefSH+a& z6>vcC@{^AK_)sgC%u*L|9)F*F=<>>rUe?>q6Qrv#^E`;BwHKrQHen7SysBVIC|CK; zMn6%O&WW8zE2H55@CY)3tmlyFpLoY9oyVlLY|D```+kj$Gwx?rRt4o2{`fdXx>jok zwgcYSUcwRmzC|+rd=Qr{9w_Vhyvn$+6IN_9;cxe~0^hhtlGr!ofn9tGC=}xN?cIJL zdNWJ!Q`eULn50FIWIe7vn`3II|r zlJstAM+36{)zrY4jWk66@h$(vaZD&Y{r@QY z#wbyOCC$EV+qP|+w{6?DZQQnP+qP}nw%vPY=Iq;@eLK5v>YS>dajL$Itc=Kv_`Z#@ z#7nYDx~Ku!_j?KmI1?kLYuhUkn3Htk8%vBJ$y@+UQ;uWTm6);(%^LBkW55l*1&oTW zFR*-8dpw50z*W;S5sdaJA@EE?r(i>}?bRg_D+?M06?zqroFV8Ta^BFhB$%dT8&Wqh z0?;MQK^i&qp7?K|$d)PzwDG9{-g6k>4->}z`av;paFPS{=CUmA;AeS3lw5q?7F@2u zU~s(LNFF&eT`8$}#R2QgM*voXARg}Dw@urTP6vBmK?-{d5wwlbe2#c#TVxK@ja3zZ zm0~{ ze@B36RQ30Y+OoOvdb1)f-00G~s7Yfdgbuswwkw(BeqOK+luAq*3DaE6Qf12Im>0iz zryEfs2Bg-T40Bef*t}38Ix9=mYBuzDK1(97@Yu>HSPr=RYCP8Fw4lRt(9peUJv_E;PO;Mo4~7dx6h-A6CY+B?-51Dm`=_`W9?0B5hG@ha1kho7_pfb} z?i*9AL5(BoiU?*H3LSOgdrxMu@?bfZGbu9gbrcdkdkRBNXAHTg&HcS8Q4n;gY!E;I03BcefPX<3*HPcv z&dT^dv57_{OxSGD!;8GUNBpW6pC?vXaP6R~C$FcPy^H`TE{tQQ#{y)6DrglhfWug-)w1gJ=)L=@v_Lo4>{7Zh%TSBANQfY8stBq_MW&-Tw!es#* zVJBaP&(e1a@8AHb?m^&>HGH$Rgwiy&ET0*?t#G|XT{6lp7i?(7Ctr_PvbpSzy{r+; z&!tC{;FOqY$&RMUf2q5FC4^tI$q1+=XH-f)= z$AsByK^TAFpYLE-UUZLf6SDFkIQ8Swm)^U}sQ%rbv{0`?njmK_cq2P^Y9E>aR9Qp|$G zHyKgxWzz!J^hjOG3cZ%;7nn%oN_fFW%TEh22Qwe*qwTE$aXyQ?@EyCDWcpGFfAe;& zF3SI^vHfSUWs?6VTdk?Bt*MpqzYz%hS3=8DkN^OP`2W9p-T%#&khH#~v6Q)^ zlOwH@o6|oeoTt>~9SPYGeO_wh_7*Wzp|>x$geaZYD4`AM(4cvHFP;_>QxS6AQq#oK zo5~V@KAc+$_4Rt6Nv4;qNjm6>oLky^uD>;~@p@)*3Jh5%BVWUvYu*C&+D9LxFi2Vc z)Gw8b7pb?HX#HuODwgb1(JBW0M*H2sZfI_zmKVGQoxfWoM8eC zM%4?IrexeK* zi*JDF@e@kQfose{Kbe>SNEositPxsnBad-G4~6mygZU7l6i>W4V(1GGS4-9&;ItiS z&wuw%0WSGXoy1mFvh;79C2!qEG-Zy$rvV5g^3!x9LQpv}(9DJHO&yb}&|?nd&>9$p zO^GAOOwv&Pko3okNM_Ua62u@1Mnm+SI0|Q}0}e7Dgy`X*{0>L%$1rX)3ru8tt=WHe zop1@;japjwNUZBs#A-wm;yR@A&lT~^GGAiOo&b)fV300)h9aLyOoa+Q9m=Ad;I?3! z1trj83S&N!1gQ>+JD*OI;wbDVrDzSA@;MRlUB%d0kda#c)!Mxa)rYwSx=c;tL#1aZ z^#r6yG3ovY0F}N_gvh;I!Wv`s>;*B51c2=L6B4M$sPAj*%U*OlduJ8UaJ^DfsVRX9 zXq0Li9=SXvK@S4A<@I_SgSSTCT5oPqDCQ!ROEj>d^DDHw zs2#6FRD{M}#E$H^Vg5R`^mc)2!_ke=9W1MQL59^mnwfPYhOG|4;Y_0lPy^ znTjL!t4RLDdOJx)&UJkS9Eh}B7n4t(J|b*HN1+662@RLR3kvuK$1S35C;{>yMG>S& zvgX3aVTpc%t=Qd&+ynN+jLF0IR4ORY=CtTTvCGTMF#ZVB@ENMBCMv+d447S2te)9Q zANGIw=D<1W<()(g6CfF3kqiz4VF8pxy^<6syr0qGZPZ2R?RJ3n{VZl{@|it(v8l<% z&+D-M`pNiWE4-wugJW-BT4fDqwE(aSNQ*N#^GGy-5E*nmP{tC{JsMD^aLv{~_&s73 z-e%9kn>hu#R_>N+mq*QzG(aH5n1D51=ahu@*ONcLbCD>xHPLJNo$U>-m3+q zY$ZB>Yv~c!x%CD9f(KMi?>kfl+e6wVHVG@g&hnyK-!pnti@0n$h(uxYJ7eRIK+nZl z4+*FZkJ6JCxuQB3?iTQYIbQ47A8eDFBGhZJsV(eh5zi`QTV`JOA+wgfspJnsJcq9JiMGwLti04*hif71tUhHGbQOoF@ z+KSaf>)+yr{%sj(5QV7H3zr#(O&GwKq5G_cDT&doV=a%s6(PpntXCd=#=hu}tE@*N z)$G{PYzc*~;)WS8Y+=UVv!%l3y6#POX`8aeeJmGnC4H~;3oy}E<(~`l{`YsXbjSy? zFg;~_nNnPV0?wLmmnP7m@9$@uSUu_+IGfLamq0n&M)e>QKN(xTQ>&qmxDXMPdXa&o z5{*V&(I z;3YGU5D2=?EL$~Rzp7iZB>Yif{aB)*!OGh~A?k>yyRsW=cnd1|WV#h0bME=sew!f- z1J~dXc6X802bSt^3ByXSX4{Y?@n}pkZc0J`4`N`CTbHHCg z!Y)}`(_PrDA8R?G$|uR;O1L$7cgJ?}K%L@J=!NR7rRsOFzy7;`mWW*A;+chHRWrj> zI2^G9GJv7udC%FiV1R5D+YqIvL3V-yTA2RDTG?WQV@Ef^nWFc#XtH7&Gt|sH)g+cZ zuJ&oue(}5^{;sG0(elv~ug`l3-Z-*y)lYXv)4M40TR-%&Z->O02mcxF`q z&^0t%dgQhh7Qu`_z(RMd9CsA(hdu!IO<$4o{HT_*^qOS^&sfzRgwu0cTVB1!M>*>` zxjHiZLj&&|JJjQO^F=$?Lu!S4U5Cf+$I-9DwKUP6^5np&NWDu_3y24+h*-u{?&=X! z?I2=pqgBxUWdV1VwUa^AB-K>G|DkS;zK*BE1q1-l2MPc{`>%$w3L*l+(jv6hM*oOBla!@xH(BAkE>xj+ zg^p#?a6=4vV9ob%M3k{Q4R0Kgy1cf z0s-=3S?oA$nZj6HjhI-3OaaqkmBd4^(~!dC11&}%SuSAEM4B^Ki-4+I)OHIO&h+8I zU`zDjM1Uj-XSB8#X4m)AxDJQc_9Fm>t*{(Uo=7D?j*&}t=<@(CT>n|qZG;wuD+B~m z2g7UV_1C8ukB|q!zYhglHV^#rqk^K{x^!afMivPUln@9`n&*U&Z}n^pekvEKo@vHn z;_D}c$|VO69+l7&O?vDlIL?e7Pggk_=6EBL;fuMH(dr(?hN>@G`z#HArUkLB0w@&F zFp?7sgxbqUpu%U<;Xgh^*fImOEDIjL(;Js9l~EvB%6ga;`0f; zQ(b;1$)>2^SlmI{1c2qtMYV@mmz(J-EJT;VZ2_d)~)Fw35%yf(f z&wGqi96VSEJDQ$CX-ylMv!i}MV8Gw7dMy3)DvjEKHL}Rip>%+2`Dkuk62iPQeCc@qIc{jy>PtQ0i-a{=W0OVd2Moe%XJ7YV}vn_XRtCq!hOAh}mz}SIHsZEf1t* zXh+ShR|3Z@IF<)vDq4NKMCa-a6=nU6_DK$-vvp=ZZ|BMkLWlH`G33N({aiGSp<8@t zp`fR{g*iogZ!R*r&!`Z+$qKT9L=?NovK2Ph~-tm&X%~h5D2h)XIra)FJu5uTlXi4l0 zisS}DAG}n@%r)+(PaJiDv5yJa$eB!N^=~bv0HGK|X{d5B+}?Jo%EaQ$-n-^nhCQlF z)Ama)!+E5-z&*5o{2cstrFW!0e4|b;i*3J?0M`ZW)c71A zX-_8R;iA{Z zuu=q|N>^zmb#*6!u7+1wKdtto-+1OvmS`T?an4&$b$hc{6-M_nF`O z1B^go$Wic$@De-8f(Z09%tsnLg5#)*jRQ=Pjg$)nOEYAA{uDFPh%e%MIyx3x3bo#F zS}UK6w0^T(Ly{SF`KQz+A=UjNTY_VXh^GD-WI!XEgp4-@PmBz?J>Rqj59IfJQR^A2 zhIsUHQkQ{&rGH{d*MX6QZ~ZvIWNBJyadK{P1cGaAnpw4TPsBryjxP)E|B+w^yc<&S zaEM>}QlA9M=NSP(3oV5o8A=jmm_T^_2crM%@s$56qDHocj{lXzhpiG{y8IoYKYwqg z|CYgjUe{1286W`}kc0OA60_CH&$@v_QE~MNQVTL#1*~KF$ELQAiZI zi;e0_McbpSll&@X6o6bNVK)whWJYw2qj(rA2H#(4(=3q~$MBTmC2S9I_j1+)l~bop z!(!UTX`Go`x7;~J5-fkDd@`NF`=2iN&j8WR%p@I90e zi4^anCUEMg=@PAdEgpqqm_$4D(K3aUer-B1RD_eF<*s7IqLG(QS z?P~XI_tfdShg~=`K;79q-riWL`6)W{mRiV=IDCqix4c-Qs$oiVd*pmDkw=~C7B%#W zu6dthpT1Z3VwpK$zUw!-oN5^TgG48J(jYG^TfI-5Nz-}Z`GcmURMt z#EUbsaz`$VE=`vyvdx^nHR6sN)pbVwg&DIa=7V*7>x3DWHu*409b%C^NS-23UK!H6P^}aLX<;B?BRoaOz3a7v>va5 z8`Hz}0C)P(9x+o;2}EEDcrR`sOKSsp@iI6!#0`<~gaKjiMrQ#>*h8dPGJUI4vcL+| z4W;0>zd)f*V&tBAP$gjLW{LYDgR>vZh#!$%o+}I;JnS5iWX%JZ5$+x}U4|&pA(a^# z(ZEz}0pf8LbpnFk!(PdDFIFZVT#wVcHk^;{;|$+Rbi3GJO8hFl!1qDfWFRC=-fLfj}?xOwTth&{2d(V&WG+5t}gboU)-m; zI~-Wg?SaKBTwL63+~--|RvrKYTwHjBu?gGew&1$3GZ~A{ZAGp=msu_!p*g!V)1liE zwy#Xi?weTI`mQ4<-WpBYA|-s6I6B!*@7qJhKl@&@Pj+5nU445JC9dl{7QbL;YgWEC zd9XYJWwR2HTwB3UJ}1;$Vhn3TFT76yi?iU!v@fGYJr^%r;X>J|A1>g-z{Rtf5oUMu zJy!#F_)}=1%NKsyDD=R#__X?6Z|AwrGhKN5(Z7}!{Uta%FI{C3T=B%xco%=&tz)%b*T zs(OX%nNuvsGpxr8?vwr$;sgE-mJi}dQ&SUM0`=CMv;E<@6CM?-ay!(?B^2?G3KC@M zKnk6J&j1;|Nj>%WV|u_5>;Nd>wa3byH@Et3dk>sg1M`EZetrt)XkjeK05kAdihm=} zTS|Omc=ZABAj9bJ<2IBS^Uor{L&@fPk^(l0EfO^P}0)D<%0D>d*Cv%2wd|ARI7J-pD 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%0AyjqqA8Rm;|MBWW&Bdviz< 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

L#rwBtZCXA`ErV-zJ)y`?Ca`O% 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

4-SGy}j^6Si(%tW01` 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�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℞jRzwey!cD9Xq{ zVpeOnHZhq{jXetl2avj{6$T;4dKN?Ry)nId^UR&p%K!aq$K$j@W}a2| zW6wJzv$+;n-9%z`J6P56oe*=0LUw_3Z`rJW!J~WBwVMXC{{}O=wcTGj9ict^=8dO$9#q z2lMc_1^RklnsAjHau-a}W%Gtp5Pj~b@r_n`SHP3^NnKItEhRMgVrm3RiwIDOYn?l&#(=toEIkb%+ovaHwOePr8hjVOIVXqB#dQLK5{ zPW!hhH?K&Bp>-rz-&+Qqpi?Z5sM`$Fa&dq)iWRUe*gk-a;**PA8AIKi_ik{MOC>1`ESKIQ0Ks;z`W8 ze3s)rDMPX5__{kRTiD*)&b0$_FPz~yTzUDos2qB9B%|y; z8r94&u+?2R1*Hf;?SwDD#Rkq(0izY@0Obcr?dXQ7E8-4RXGTE&(^N9qK>C#($p&kK z4yna}%>%}6v(iVJ%fONuqYRc|VuTsPO-n5M^JCO%5_U2tNHtM8AWnxzl64VSIl*hS)x$iE;qyxnJzS%_4e zYXcOkvB&~lAY~#ae(HYS88~s3R#^ks>^uiBHA=4m4O<@$%T0aS4ynH;9gwyN>GX*6 zw8+cfP=K-Ft0`eL9M}dFVtiJyc4oB~s+OS3avoQp-Znru8!+rs(+r_G!(=q%Fd-EX zb`Ay~m-~K&6rfKF8Trkba2sQ}p_?tRYSk!W03MBys^AP}%3LVdsCzRlAd0~e4a6E8 z(29YtkB++eu9M>ABW56!(+OznB`4bw%j22#1;6|`*Mr8rtphW&gO5+*BMQ|-H>Cqps^(({3_HD}Ty0Twj6~tI0o3TX z?7DJxO+=X)1`)7wyf3$WOO|4o`4Czp;>mgqW9mDBL5n*3LDq~iZlk*D&#rE?38=@! z=tU3Xw^Im)`1_lnW={;`(l_v^nJnS}+82P|>}Uv@W>DstcIL$b%&Nfey*5p2phr}% zXyg>y9fY0%445qH%$@;81#+cg4b#YkbVzX^{i1s!=vngDu9(&No=`!>tAPD@S`#ED z3+A%9CDanZk(EBWOaW98a_?XE@YooFKbNrNwscV7;%0ZE48dV1SOCK*2~f!!aocRO z{>;BzA8|fhN51~<{N#MObRqRgO>|%X4E7^!K)sj($yM~*BXML6REiIb&-5B;1WjP#A(D*ABzz148 zD+$)W6T!a>ySP;V?Zb*xV*iV(V>u?yc0!2oS;#B_spy0nKEkRSO$Ta8k}G z`I$Vqb{mR|rPhyO6O#%gE}8(-3AQPkflTAe97KIf-AJ%%E#=$=>g(>F97vfv@w@${ z3Dm4GO)Gr2yiv44?)5{!@aOdQ6(A1|?ku==ziRp5prc!-Vwc$jd{5O?$uIIBL#%eh zy#c##NMzTSJ36)W+~nmxcYI&ueLDWY>4bdWhHqOe-aPy8$`hQ*&IVYf2jV-8HvHz# zT-q{q^II4$IlE%X78fzF#;)JJ6|AyTr#JYX;Mx!gl*3;dQQPpTrhtu5S$N5Is@2DsW5CXo{Q zM<-MYqKojTe3^<=^{ja<+clm_Z5niG(hKEGu;6Xxy4&R3riP=HHc*q-KmJn+RWa2W zo2p;kAvk9{z0}}o1_%sTr}Q& z_ywx;L?0Vor1$c&-G^u;ztQyS5qNzC|J7 z1PUPzW7KF(-X=pVOlF&Cen%gm|5!+fsgWkARvOu1Jc@%tLRLr?=0+Lt_h6@=m5KF2 zNBrcE1$urq{dLskMKGD{A^rFX+zAkYAA~vsk5hT0odL@r_Xu{Qu{y9BE9f6)qClz$ zBt(m9VqU7XoKzF+!SX-T!g^fK+6}|Q#Hha*0dBnsyBQkDOzg)GvC5=G$fin4AuA?W z6KcI%MKX!PV&o*Ifu^>&*g&;Gv(Q`1rQSL!%C#L zAyz-#4HwMIoRztC>(wj@qXG&{hLinAseRfd>GSA>7~vMo8%;9#8i~Lf zHwbgX8ke1(OYRsaoS8aBdve*a34r-MQrAq8Fqg% zq_tezGK?7hHc2eqI0GtbFTiIn=h@%E&|(0|_Sn=TPf|e=a|X3E8h(tzL;solq(}$} zMh`a23@CFaOua`4zupLZd%2&E9rm?&0?)5Ht=DqC%chNN^7e~E2ngN zcOFj^3)~XA#vgJ~>JhJpRJW{Wxe{mttj4b3K2|j_>UZH8$L`QcB*jbzEWk~BLz;sC z=V4@yq%bf?)oGAGm$7$X5hAUJjjlHlZr0op#T-El;UvJ^bh>>Qj5RGgcnw}~s4zU? zoCaU8*nB$1z(L$*PK_4XXIi_r1@e}t^8`<;nk}2}%zr~=@=j^6C3naMn$)AkDsEg& zRA5MId5OLWR(F#}si`DAeK8e9&R~c0#4aVkqMrch4n;M!MiU;KNWzS5 zU>G3c4zM^+78HelLem~{8&Ljdj$DEx9DqiW+i~bo6vG%q=;cSXmqhs?QA^y;J9}gy z+l}N}vCHAEYWVxmfRF8`AV)x-O0cbs<_rP(;x$lgABsTKbqFlXjt?g0qUx<(@?+Fh|-NhVA{`>h{gsMDt&wWn5$9 zSr7qMnFJ^}(9t#Y)N1v%rBC%s6Ov-HTaDn{h(l}W3$#9+v_Hakp){O+)ApZZ+tz5* z+8kN__PP&tXIdJ+$*0rzKv1c?cF!oYu+ETX*4^@dhbEtVisAOc^m{VfjjZ7E>$;Vu z1$rTaOaa#RNf0&1#yC*@LmaGcfYRw}G;t=~^3M0<9sgFO#V_N(?m=kZ>KD8=v-)64 z^J5w5kJfl9N9yd zbTx(mTG#+E+@nY|8FK~333nk5qxUr2!Pse#vaLfoG-i-Q^cBePgQM7Xp`Li^ zz1?(-ZbuPeF?Cw|2Nr_pc9GkcAa$A?YMBhL;PZ+e{q5T$%o#}aIM&SH*JAS@!wQc<0rUs%m?|26`U7c)c zP*R&~QW!WBNWcrcha23yS}Wn#PAFM!4%l^#&8w@fvS@`ag~<^J2YlL60ent{T!JyVm50h_F+QG;)6V4KPOQlY6rMYBObgYIG7YO{+Zt~+X<5OhYvsc1zqxF+ zgRX}-Dy?D1CE3MzMIGOS7a}arhphTp)p9XihC>_yuHz{=y;}c`eh3CBp9~NNjnA3D zG|mso`_*h9sjL;6O(g|$4XcEi>Fj43BRhG`IdOBSV7{-)-3s`_Zv3?t0QA`bT4H!6HF}G|*Nu>P-?jHt^!bevyWV znjuMZ>IMr=&UOowi7&9_Hyrrwq}Z0Xo3ePSUX*z1pee)i3WblSXAu0L*Y48@g0ue` z?-NlIn>mGYJygr}O(~JGyK>t?O*G_ny53Y7o4G#5+gXH8d?_tzu|;noZMq+;cwOR{ zUfL%Qs={-KoiB5y(hqG``N>6)=0)DeWi8$CbzJqAZWj>p*#D>}ot6fbhq!Nx* zKMu$+^lH{XZ|bvOt$-m{6z)^W2~cKA9hN@w6+!v~CiI}!Zx4SS6CXO4T9!EI<+!h^ zyT?S7>g^4|jyqPAC^fu5D~24zoF+KM0qj$divN>KBbs<*>6pZLgwlZ7-#ld`GjTQt zXXa!!#yyarmPOk-e(YO-q}-L2d5`zkJXAI+kR61*QAy9c4FN!q*^?hBf&DLW($vtmPY6~ zTvHA>lA*;}T1J@kGa?dM9x_L4-JX8=fyVqFyobRq$*QgN(ig}W~?yzQr00lWooz5j{Hq7+CEF-c#9G` z!U!EAiK0V~{8W%3wgSR3HU6Lwy=SC(6KCk{2eS1Ql)kH$dL}hbFjBj zY)XMWMCzS}NgafP|Bdab&^U2Il(B07GRCFl-eiC~zq<>z05oHaH}Wg`O``z=ejymkS5B@8gbyG{#y-&Fis#4^*mQyuV1T16nmgDaO}kZX zghphpuplI`v^ADu?K$~HgofC4Cd`J|R?`~EK_uO`HWOCgv7>ix=Z5%b?kITpWR3spub5LR9fu>69Lq}|LS<{1_TKMZsV@AbhSvVG&GiYoat9qvBx3xZIQlrFk z&Sn91&Cxaa$N;o2w24uYgUlwesHSEdMw}`=(BgKmt2p(vVo6S59x;qwp@K6tclV zRF`yl;Iv!;FciC-2Obfe#y)-!RIvdzPZs`6lI_XFsp3$poL?_H0iuwA6GBD@ zchC||&#v5Lk*9Oh0S9}3RH40rqK?4Yfk1fb3Sp$I`}@2<#zl|lOM1LVbO4n_0U44@ zp-=*g?v_(AlZ+K72}Zd5v^8FRG1iyav7p82cF`mdHRIqx(QYt$l59ZA zrtq5U>=psQB5>CIZ|NTDC}iS796!k+1_X4B87k&&<^jU^n1Ld@br8&9B=oX*JB=~p zphI9kv7b0>Ns({?FcgfJ{~4|)^e8j24pA7NHJuo6OK4Qx?@{_2L8%U!Lnhij8P5Q?oNni^$vKTt> z5g=KCmdcKm0xD8za|)=2gEHi@0>#B{E)Bq-C(9DJV{3`Sb8i`tg{pqx_a9QkWK+1K zo-^)S4){n!|2R7u;uCCeG|XAFB2Y$^)9PC|^?apr|3ftZh2j7+(mYjT+QdwQ5sj&B zvTDW87p$g-4b8vk@vTDU9!g)wB|6#a0c-QfB?8ip`0H%^sI;|WagMWK`M~+e&gJok z!YQ~;Og>k~9@O}n%8w0IpazkAWDx3xDuVhFrG)`X+H&UkM3g8=hh8W^yUJ<+xmd_m zq`hJmf_Aib8 zYrHv4*O5_*Z<({vEDktSs)n*cYDX-?tR+z!bvU+nQnJ`OXZM?f`8TM`&S9-&0V}~V zesPllt0*S1);$UvKn-=uqEj63hUwbPdtP4^Uw*DCMb{_(82KPL;;#UM9QMTf-Yw+_uAJN1V7k}Z9vcL5W z-%0}YDW^G=Eaqrb8A&fXHMM?F=6{RQit9*S;l(ix4k?mAEO^op#f>}kTSKDm>emj9 zp($=;I(KC|Er%$WKi-RicYoq$f^Ql za&vewjAKJnaiEzO87MUZ=Nl0_>V=QeS3XG_T}gwpD2kgwK0?@)9L8P?s7H?u7123>IJ0ct{-wR zeNx*v^%iyW+x%EY9%R)i6KQJML`L#3UzHa_KD7jmp6lVV=OvqP{RiU*BGUc^*2jc)mg2jLSq?M274IE z(i4Q#wNX@ik$NB8R)othX-F%i#|+ju&6t^{E)T9ezHlp2$c4$<>{6Iihf=PDj7p3N zAa}uxQ*A3OKDF0Z@{%~K>1994BytVMU*>(hJfGY4)6NPO9SoM_g)>vk!U%*)9<6Ou zo90zkcPYr>u)Sx{Q~_qED4Y*wuW0T;Zrbfr_rR-Up)e#~376Zd@MoKY-F&^~zz1Tk z?#QnOegaCQm695#u4qM?z!{aQ$Tbkt8b#k&rI+d4D*JjLOXLS=2F_WvN`4|f7XZ|? z5ysj6yM<~~EJf3NB}LV4HOq+)sv0HF0J2rn!yiU=Cz7P0^7bHN2eWh&23Px$L6{C6 zCg3(_hAZLMhR6K2RsjF(dn4kE~1((CY!dGvx8%I>CS1OZshSFyG5N$y#tqm>k6W9r{d2A^ zRjmCTikCl^Ny&Tf4NPYlZzJQRkvV_gFiSE#T|(h^EFFWn_PekQJ9{W{F6}wTod9lx zKr~KcT;*>g)A;Uh1L8)-kmQ;3w)LgUl=EcMw2ncGYrqPA_A~g8-M-hPoA6ylWp=9Yp2T(UKw7Ov!|0aCD^k=!=rWAhEo*2P5$cJnVPPh5s;CXIXy zmp!7hl*hw{niV=(oDDN~Ez;XEV4&>7$ju<}GwBbuU`s%}ljCdCw+EErHjdAjLI|4E z3bkY@fR@Ui87k=E65>b3iF9Mf&ZqE~#-ny<#k2%=JH0m}j!UaE??J@}`25KR?D|Lz zASn-IsgL1a(Ds0hG-o;NY<=^#w(*HbnYJSf3hz;{vvv4kFylvj+lOJ1@%ScTN+CJg z&E6tes=1)c@{}GLjY=i*V_^sp(P`E36sdhjaSmWvC>6LsDD7*+M5SlJ!vSv1V80hj zQA$v{rD;4L7t-xv4smqEkkXs25eOM>W7#OT5$I{OcMgXHI{2-Zx~ENrSGoyn?(MJY zN+bxoG$Ewz7NUvR0F~nv%#V4XY18aDi2ea;IJp^9mjozn_J&|oQ<`~DtYS?KR_o|1 z5G^3yWR{|gF~#J922u(JA=cxVfw*j*U~fT~qs>v}#jgf8Z@!C#1iogvq(C~+K{Nl9 z^2B%F2yX?+!O_{mKo{62=OAbvdzhk_&!oKX+2Fn7imZ(sC@7&b2ohN5Rq`iK z$+|H|j_-sQd(Wf=k2n$Jgntx5F$)%4Zkuw^am;V^K*~OQ0nPS7f&A2DT3ktIu#m5( z<^;q3F;@l0s9{c<|6Ffc^Qs5e+0b9(9*ULk^Ej%2SG6Tb;@CZzUqv-+9!7UuJlqgxeZ)1jiXe@^U8-lGbPm~u6 zKx1?JAl3~r9T6#3yat34MMbH&R1XG5o)o%rY`Zq5icO+eFKrVh@SA;%Oo2Q=sa647Tz7orwr`2O6qP*+oQ~^J?BkR=7ADT6AK-CeLWl?-?$^s_I!i-umq$U7Xm_PpK#H* zhk?Rw%;!=!XzXZ-WpZUttt*`{M!~bLH;6iA4k|rbb9?jp(sz8e{tMA~ffhL$LgR#; zJx!j#n~lbSt2oAEd7mg*R3wajqh9aK{dUd9{bGhX1aQ4l72OH5`sizPiV z&sT=xzGB&`k*FWyq#hvM_4|B1mA-XfP#TUor($?k8Ctu#2|4~C!aE-3#RV92(Tqn! z&(s;dd@_2X1iK&DvlR_+==Sk*aF3}o*E{{Axt``bf7~5Jl72iY%@iFzPzD|`PU}5!zKK2H1dYzgvvzISGg4?lxEa4SAa&S8fb-c z3fo!fSxh?Ej2B2i8tDc^;26(FF5MKp46N;|2BMWWMO>(*X1#u&+vgW+6i;fCxF|h> zbY7B2b^OJXD*A;ng}x_di9~-wQjTBpfQb8i(b8lYZl#nvD9YAPzRXgj8w8gnB!-H1_TyoFIe_|sn2Tqdu>($joT?NwfE zbalj|@*(HvQ7*-+GRl0S;zZ#h%Sl`LG?L>8{})_a9RXQHsz0p4R8F-thzlr)^#wCP zj`p+l<*IFtzF?_*cB;^uvPLe;Q9z$}j`kg2OmO<7KN>e=&$R7i$E$r-x-{e1v|kxI zSO9Mkp(5f@O4U|Azc_+LR$Q z%KQ9S05n)6!bsM)TtnCcd?&g@1--UYec5R*oaI$dG61Byd$;;l6<>~p)kifz>`9;lpH>IkXsXUeVQ@hNRX3+abkZr zf`4$eh|<@i4ilSy;3qT&5n^dum=td^7 z3(IW@AM=f@{fUEPhkI0aHDG6b@_F<->&=cO5t5YJn7I09&@9N4Rqo%xQhZe)Fo7Zw z@c~j>`?rt%VVq|U9WTt^!smVU8urIn+0X+%KR@{~AA7># zi6$>*)~6-kSiUl>XPKu^UKB@(GR0uMqgVAb)NK3yNou$3m9}mppd2(2v=w^Guu@TT zojAca<4_B^d>o9j6>=`RcQTN5-Qv+OVFlQ>w#JLG`ABwvV6$DkAx?+2#Vx|5A~GIE zk}~-*xxtOp@B1k_xV(fM&9-SJSA9TJynfjei(m!Tn-?a znLR395p}H+4`=VqmB{RI8oS%Ry#a$$44)P2MJY=Qy`!}i1HG=IutE*^sF>Z;&+uK` zOP5hlE*8v4)M(JUw6RArUk6A505R0t6lMmPy3`k$Zjt9@W?y>7-|vLxQL-G#*yy!0 zGGymrmFAe~WYBFV>Q1=^jwWWFy#{mqDc$qsQ~=f4akAlmiHM^CPerPA_0{Xl*Km&% z&pnyahx3f&*A-M7s<;B8c<-QH3zI#=4xD0~BVPt&OZ8j-qS!sSIr%QW(E966(h+L8 zpKrvsS7Y*nYFksYg|qr>qS#f5Ew+;+ML85vZ^gmldq6Vq>DUBy2ic+*={;EMs`lqp zY!EvtxJ>_wf(x|<6%Luo-j?*%kGUM(x6MrpFL8XYJ@uBfW8&Dv0^5dv=5fS*?(YU5 ziT*}6hi+g*5slC41dFc%#f5So|84j^36vgs8h3;eeof-`u3$y8&?)q3VoVfR$yWOY znfRz_fXNB>v+H4gHh>2(w>D7&nc-}c=rO17k-ytc)|n!x z^(?4ZoYm&7GRavZbBdxR$t4>knnZ<>wKI~_tZVFy0W3gk2mQORqKCMFdLW{J76o z5Au)^M5s9oEZsB{iyD7sH0ejATA>P6R4)(JNhw?YVGaK19^1<=1ABOx>S0>2Y{>|d zW^FAKi!VI?tIjz2nL#H?yA@KXixqJ^`|P9J=B&LPh(a0;hdE`|kEaqZCyjtRw3;3A z1@Y`gzYD}h#S^+^)12XmsGzFS2~Uy4`>z+0!XQ%oVHp37jJ<$N^Ugt3GiNR0Or8 zZ$9~!Wn1bZKOe?Zpa+%rtO@PJ?J*RkOku|sb{d%?;4_9?cNy~mvV5RkU{9v)FGr_U zN)zAv0P*es7}D_@K4-~y?ZAB=I+HRpzK;YH+!8=?&EJcqix~KfD0BBKO%SXTF!S$0 z{yWys`eKkL`fB5T8ULB?dv>3^3h~cai^9&yldGE|3%*hFwur@y7hEaf&*wdJKiab_ zNAfQ$_vzqjw%tz#4gw^<^5mA!)-8>usJzU(f4~!0rcSn`A`Yu7PIfYA3|tL!I+Pic zo!T=iDh`Q1g|y2g0R4$lyYW zuuO&as!7cz+Prb{&u(wt+kNPz*~FMf%O^(f##D=zBS@3<5$ui za&|>}7*Htp2+9eUDo;uCQW9&JpV7D6Z2|7jWGGUknag`0Daeu+_9y%vQr__nEPLcx z^`2<5?udP>|Nt&W!}$+d4xDc^@nj|J$`ecR-LLs&j_uK(i*DR6#IX_#41VTk^%|$GK$me%ZN%u!*~04qAf|P&|`{ zVjXsV^T1jmLC*-X#IXE0^b}{FRfy>5PXI;B^W7P3$6BbBK&5Xi;kC7loJVj+lMPNu zw19y8)^?~l5l91s~Xp*DCY6zj&OqQ^@IEMJ43$NiNw zt_zs3pF!*@zta^xxYKk%T#s-V$dRF8;xwT7oA$^I^{Tp%34QwqN359$qqD=Xf7F8744^Pw9KjWd=Z#%6@K$1GaO5s>Fl~5L=D+5iz z^5mWWp0%;LwwJ*)J^3rdBkD8fadn(mjcLgwb76bIJqx*t2U%ULq8Z%cyzo1(+JCvWeWQv-8O*O1jb#wdk8OF2dMLQj@Wfr%+=9 z)A7Sl6^@mAkBEK()3lDEvKa6qw_{?NIAzLuRnJ*#Pjpt^g1SCGNB%?fM*to2rAo(dq^PDN4hoZF_pK?LO8WP0iGDL5TV~Q5MKR_C z)3i*0rhFMWG-?Lhhq3-d&_@s521oh;vO>)aoLp->IS1uy#Kq7tf>FbC$n%0Mmc>=t ztRl+pk>XCph{ajQiL#=C53?dvE?~ z9FtJ+p*B+N^f;W0u3OMlGw7kMv_lTf^a6KekK@CP;MZ*_QEyTK`zlCKi)F{5MnH&x z6 zU2=pOzu)Sb&!4;6D7`bvcVS*r0cQ1deMKnLc+JJn@6^-3E@u9Bf>RwT^yOPDz=}R@My6 z;TtSec${aGUN~)|)qCJ&Pzq%UrcgF*nt%dZieS81k-|Eqs?Hw^dhRfL39pn?)>Ze8 zV=GL*m6dtPuBmK>rdjV6L7zmiHH|uVw5qQ8Y{1pAG8ex{^#Nb1K2neu9SW#1E~LHg zH9B?N+8nSSX|1~i+op4+M-xY6$)+QOK&JZ_VCMOX7vWw`tEk0-5)&xACv(dvHdb|( zUC-d;55MhD%Gh)1nzbGO$U9(GEVUbQ+}gRgS!FdRK*Fmz_?`5eySGEp_wKC3+`MWu zNUWR>|AJ)@BD?MFZ4W)S@SKU2Zzfx30~VO$>{HbOMy!O$Pn=fl?>Hyr2AT zVJu@79=>MLFSYqawy`l>k<0TizvLNwUVl+LbI5;5R};hdNQR&nwsj#8;Zo=75V(lT zNRny#)m<>?b}{u~O$i^#L)Pp?7<|`31yI1ikmd?Sv_P~Nb|O30qMlQ6o9*dH%Z1U(Em4+NLDaykn>RT?It%F~CZsXSwBEv%&VAOYd=a69<$uTx(u4Xv11XneZvU1fUK{ub)EhyTNJ@&ZhBtCv z$Z#g&ONhf6Cel`7O*J^FYSBF1n!)C!+4{n5j_rC3eQO}K}g%-aXC2!*7usjMb~ zEuS0wbFm>@HIZRdhCetIEqLm4SJhQguo7H%Bj~sIH-`tdeUL=}x*Y zp=!VURw2A}1OUkvf@wruUA?u}5?+ffjBTBRVjGjoAe+vtKn(T~U4E zqTtzd1P9i;Xp@se5t}RUpCK#JldsH%J5w)2sF*npeo>g|)bLQa1r{VS)ht3Zct8rR z$%cxFn769{$(o}RdihUlOS;jVn^C7|<=JlZAx0yvNzXcfri9wU?uGat|B;BNMBE{O z(rsy=SQiFKs5vw)*lW_T--XJb-=&H~!V{(`nMorOMsVF+obbVSBV$82ZNgM204QCj zWCj{2mC_M*@n}s$qK8l`7c=D@!Sh3$*s*cI=SXjfRB-_oc^@&m$FJmS@Ttu0_4nzP zPDlp1=1I%o%l5E_=NFKc5krRRgrSl%2h<5IRn`{@+{kPHzd~}p_ZV>o7`ASSJ}_np zwrEsmn)lIz90K7y=(l2qh<@z1z3iA!@=IJKB^rt=12WCZYtFPzTnm6Cao_mAeCD}f z)^cnd{3o&5g-0?fGXQ$V#12Cg6FMsuI5Y%$Bb@WLkp{d<-&}1>0?Z_HDA>jG`%rZk z#c&}5JS2oX&^8PSEL}i7C&*-88tZY6lxCF`JZbE8Q+#P`hyyY81IL!$IJX{DaMpANC+!3eh=5P{OHB;)t|4%RZZxVO!PGac02|XR~1;7xZ|PPQg}x zp!tN905fv`3NW&>2k4)KdUHfsnsO4Wui}fZ<2!yTiP34@5v0xn2gvKBf0iIy6qT1t zfm|(v>h0|)%gT2p5%TVDwN9sQU_%4)ccEv-s<(>Y?*Dy-Lzj}Y?IgfXD9^Nni}??G zQ|Fqfpv88dFlk(PHlxMLR@Y2aJoaN;yhSPcEqeLaT?X(k)|nUm!sDKU$c&P#*h2z< zC;Jl{%6CUnBxunK-t%eMr3ShK6w*gw5O^wp2D61w9I?Vo#T_7lxAT&a8N>UYXaPc} zqC|zl{mzh%=u`n1Z{jN|cu;sUN6XM@=##2>RsxaE5hnFxkA(OZ^O{7{+oL|B(tZ)= z5kf{Rbb{n$4XK<7Miz?ZA?2lX$86oY=)H;F&D9K}me3ZX88y7!{CB^|@$h;s1?;e_ ztd;1p=e(}Ku~3i5#n>8NM0c^Dji!igR6mLqAj>Z`%YPIKxqWhKsodLqa7r2}nI}oA zS0O=f_OCK_ajaE zw+WV+D>g(~yuMygLOdSusMVE{^z4jyKAbqOG%+&w5t#RZgV&Q8RN&Yt50=vM=Dn3( zH+S5EHjX1~*$!-Vli(#}V=>;*fOY)r>uTvfeKctjc%73bC{9HgRn^y%R$3*$)bR;b zSN{+LsN_Y-$*z^qg~CvZmQ}(jXF(Mj7GU4kS^=njI&BK-fvsPfaG|;L)6j%#RI*dh zOm{AkI>WaBN3>E#sPE8fzSTv;!l=2vcfk#O?J?NKz-R^qitU%#;1bg#(j3tEr7wm| zWbF~H$~HEYq@3tMHVtR9{V|kC=3ZH}k-sf8rE<9mkNr|S-;t$wzXwF|@NN^K{dOCO zhJg(u{PcXn`Hx*dycdGtBpOv7pHpcNI<;?W?@H3Ayx^LWg3>Y`>Ed9L>l)v&WyOsSN~Gn1>r;aU2e;R~nyeqplGyjjv})!zD1bq& zd657xv-5IWc|7X?_Ed&NtqbF{99t$B1IqXl0j@zl{-HQ20Gk%Jyh^MmvxC9RL5z== z?An%(3-8Q)zjd74Me(l?u5km+KY4v7uV&Jp`f)6jNC8wJ>6#$m0G#8rjrw&v1nQ%L z`J6PQ3;C^Ji~UxUXGgxPZsq@8>v6i-^1TbM;fo@Lcsg+x11A_KHIp-5evbp3+_6lj|0+>NWqf1>v zTb1}k42+)e0X6e(d19t&%2cNfWb z?v=P^qJq70Zyy-eyUT#9S74w2UUygdB271Ly&5t(;HiPrXK`+qmprCrU5}deyFGIU zr1oB|Tf*^VDZYi1X|8i~#W;)RJw)cbIeY*uJ%^-~Iet*ooAVcSB}s{Hi~+O~wB)Lr zkiQ&vs_z>IJfMjt(FbT9DkoH7o*BCuu{Y$#XUcSNuiF#IX1i|UlWFAG7S@uFi`BBE zT4vN3nH>#Z8ik@5;W7PLwrag!1~<7AM^JYZbU}EmC1c|=Uq%DTm(GjUP>d~($WArk zXwUs*C}hF|V`}nKl0s*(-Az=TCPj@MU0ExEc;IGCYKkcO&08JztqXx)G9vbNFt%FW<9_ zxr(UZttTRyV+srfw?+7!?w5|J>IZPsNUO9B0xQ{-72iKa$hpjv~WjwMT z@2@l1f`U#wE(hQn7EooI zS=IZ^r9P{xo2&lKkjuK93l>dOm9jZ*+3;oV%%b75Oi9gid{m8Ku4h-po&fqE9;iS!Tu|MC;ycQg84hyVb9>;M2<|9|7g%+kix;Xi@mf8!G^+Ftfs z5{ZBMd4*!Y!%9Tbu4w6+>q#^y5v>u*BzY8L6S6=7MA~R;C>6w%{AApFKb4hPCQqi^ zO>IDj<3HuKwVy6MoxB+R6x+OFyE9|~ZQ|m7cLN?6yYE2L{TFRuz!;x=4sI|B;s2pl zI#y-19S%Jl5#1|%4}$>L{UJUy{m=w(ZwbWhrYE4T&k$D(o1?t#Z;7zMh=2IE$c2rt zy7o7mYzyZBxRC1+7FVPZ4u zt!=1^eHn;43Q5wF5Vxy4#7>y>A_T@~dxs$u6}p`TO?#094az033iyPtBK0lEh#sx@ zXMyG+hUAFzZ~3-%R6Mz|!@yqD;k2+K<8HfST=$6@w>0s`gA}7B_=cnq{Ou74BKt;F z1my(OTMUQUZt%n*n{-yME zGSJl<8;718>;QfGv*vlz4UD1i`t?ix3)hcR+dO?5{UbI^Y^P{2WyUr+bf>3bRUF{OHOZA=xa^gu<4V=7pfQ$YYHi9B# zr{Ycl#OO_U^tw5aP0a5W)8gpwSNB1jjOhCA6U)F^vptjV1Y(j)YNlAE!jdU>y5qpYsV0KmWpq|m4)sGP2Q!Dm|4zYD9F5a|j@_PCo-Yf{V*dxM|0?_j{A#D8m z`|xUc^{=l@miC%k8u~^euDq&#Pk)@A+zgZFw;vfcqS%O9?SqM8Q%wvtqE4o@^oU!{ z)>a>nU_RKi_=Q`UHo4fl<2)=6)}|N0yYxu1gU3!|^vcP`gzR5=pN0QfRugOQ0V7lk zH@hLzuk#Bm40ajafC9-M92$N6d&is?h~%sFU-g_}&U$^xezr*1FID6juh7zZEry{9 z@LQ~tl5kAlk`#B&Dl6TSVou95PaAdq00JsW$SBSVCFYr#`@9!xXwkY>b7lLGO@{C2 zxzp07;(MBG7jDNu1;pjz z9112AoFG@^1dVRO&Am%mCSF*J1UC&Bci0CYg2o4TuV*@i|-96rUdtY>QZ-07uL)`5c1lbX{gdU^Bcv9Xr&oR{*!# zdRJ$2)=DvypktL?TYUF^rM~U>Q;YIDb5V9MjPu`=sK2QLAug>UCFO6 zuUkwY!*mJhpzfZaqOg|Fc!Ljvp5!LJrdMVj`xM{Wc^@<=dAex|_e&Kg&wzSSWzRlD zO>d8&1pR*KbvU9Jxk^}?w8wu|BPa)4^@GGvW;zCKLpWTzEKnV??HF292O=4SQ|&sf z{)xaQfLw6hUh12U=)W&@%|&=GJIbW3(Q>dEDlj$t&|a$tUie~dOquG5$4)zTON5)? z4|udPICXEneWL3Gm+`)woSf*Awc&FA#!y+8QmJ&)(3>dViu3AdKQ%Gg^-)T(S5Nl# zejlYfZtU$VN<M~VhrxSx<~^3;$7t}AYq018>wP^WIsN4ifG!JMt)ydB;G7g=5t&wtepfT@LU*phlkN-6!9rOCJsgX2;%OETFq|Jg(D zx}HVx2#TUm*m)*yl69lI5gooL8Are3aEb^cGGv|Kj5DlYo1x9c+R*@o#Lgyc@?C3v?@$*3qM%ASvXq0;SImWaKUgL{B*9joD$H~`NkD67m2}l>RG#U2=kG( zXB4K@0SU||?O8ra>jb&ri_U@#1(IImZ&7!BE}0JogB@aAveV6DFxAUqglO9krjxxH zRk)TbmFMKPi%cxdVuwDb?jcMy8MNEK8kMG@SI-sz;j^C7EXj(jpe z@}o|oh&$ZHVK(s?h*OfxVKM+s5kM+Slh_KI4VAeEa>2ezH|e4nLRl71PPuKO=+NAh z;Oqj^FHE4e*29}{Vt3Fgt72x$#b1+aVa3fDnZYyGY~3b~Wm}ZR$eU04hUT zbIQ*sNg82}?PquoW~Yk24h}6jyvkKE2%x7=@L3O?mqgh$nAC^kV@X$=BvJ|shrvj) z#|Qc0&|FAy$`N3%n@O2LR#Hs20)c=Z0l!Gs1-ud6eipl^#hVGW*vU*WsR(J=9Th9C zfGj$se|qBN0~%Wyz+)(LiD3hN=7}eht@+{0fS%ommUX5OUlm6qyQXw|m^qt@wGR`J ze#8v!n?CmX3p>|YRX>(x%c7sN1&5Q~WmO=NyC^H@L->W&y7j>0XcCd+MZ}l<#N&Oa zjjsa8{lIJE5BfB2k^7K2&VJbQfjL=zgTC|(Dws@w17wwt2G|bxb|DSFAgcGg{C6F} zTOKf@2{<#C%G|>8vSPS<2H&~k)Ws%2s~7NyA@hhoS-$YGd#={yG;w=ULNN$KCPY;SXVkQ`(?Aua@*Y-X{byx`>}rP|7fdPR&t8!8 zApR%|6`Kn7|LHVt-BTXd)E3IgkpotoYP0}v6CKi-Q5a~isgF&f6c5$z=Vn_~`efqY z6fihh^0wOxj!)MF2*^9v6fA`tNZ|#m8T%Hc9>8_hpOQfMJSc}_qMAJTsUZh7GHC4j=Pb}*1M2PoaZO)3a^jMhD%U9Mt9+Vd7qq{>B5h1@Y9lP9+(sq)+ zH(h!zi=(P-i$UreG_`!VKOv37$e(S}E^md0DeRK-h4H&oo3^Xe6oXqo_aeFK0K?Thd<6c8aT&7&&3~Ti9KR)AV zX!5yFn472Vf!W9)7w&scjfRVht7Uu+#J`3i{?LY}#G?6?M0J~QYKq-_niHeojqj+` zE~<3|$EE6*kuu2{+Ptb$;*_U~)AWBU2Tuz0oKCbevb7Q^KB{U>h>+NA^cfFn{N zt0({3o`yl!3UPWV^b{Tl8b1h&J^943OALt<*FzEYrsjJJ_t#SP*Ll07A1Snl)HG zmthb1_U+j1gydF9ct&Q{``p1VB*?eEnY&)ZsXTYvliGIsX9L3#ELHK?F5vOz9y2W( z4aBzImJrX4XA}2d!PS2Jx6izky-)d85d~a0Y`typ8t1k$HLax#L?Ekn%2VBn$G!n_I!Rh~YmA{m6Y_(N5cC1$8)aut+wy#8paCd1v$nljE!}JkOUwTE(OY_Y zEa@CymGkg+)2qDG>-jVi>zQlpB2f%--sN%sP<%-gUN{pxQ9wL_UjXtOlS?v3L^r|P zvz=s@Qc0&K2rea9Se~Jz!-xxDdL7p8br!P zgW)9taD$sY7FCe$L3GEeB@&)8AnM=pEn*3u3N%Y)Y^R~uKPPv=Cj9FsVMHx~erFL> z1yokmz@#jNt3Lp;2cc7zdiS>v#}jF#!B6lAZc=WDJstm#Dk>T}l~AO3T2mPRA60ZC zY(QCNOsz?-M?!BPua5i(A1v)h>gAUFeO(Rx=qisa=ndcWa>(6%BTrhz&Ka^V)--9L zD{I4@QG_9^htiq1*sf9M z0YE5blnI0p#~Wul|HOK`px}yU-8(rXSV|IXk#p z=cNul!%YwNs{?!H&58bEU;07wbsn96xc_l|kbmjgPZZ!c=J{fn#0wdp3&?fzpPyYm zuD5bpPh8I%!`SN6a)3x@d&V;#(Jg=C#Z1?QHA7d%%gWcod*V3njhrur_H&t;C3`N? zfo-Xe;Atb<)xtdhCX-;e!$FJI@mQP4l2 zPv-R3t$Oz$N>+^d{r>-mqOdc#=>HK#PdXnrI)tjKz|<<;K864u(q8-FmjdeH6YdU! za6x>j3 zXH0TL8;|%_0zFobWbTVurt^285~A=tW@+VaP4a{U1)Y-GBnldFFrC;0>}9(Q!+If8 zVMG!D+Osc-J7VdBwg*NXVJYL#x1rx^z8uh{36cBUUtwtOOV|VWp?x9ydo6R!vIXB5 z*z^4*{pYW{AUX7(pgo|=Cu3l-$t;SwrD`uf-+L_tg9k;*{tq@=rKLs+bb!#z&OXuy z+HcXHT7KJrVOoLQKA3a(tYbMp_YNq5-Z?$GCyGl?A18v|EjQE}Rr^Q;4(BR{jwybW z-MVdqGX^?@y&uR=(~l(&*xs)xA!hImpId*vZXrDP3iL@)6EbOeO+^P72zfxTPq7))R==2j=$P3||OMzxUs`x|KaR zUA(7LAX(WWbA^3OclsqBBO}83Lv-66-z>q#?Wl;uNkvr7`*~aB%1O+KQg* zaliS}-spTx3WsV^k^`NBxqi8Fv|@V67mU(svjGea1A)s8Wc7lJ)GQ`<4#C_~E9RxT9yZ|&1ayDwrXcBLwcaabP%br(rZghaQ3eTp=NAMrY*o!dq=Y=4nxcWi zmC=GI2xl;5X7RfC3NB<3jCvy{`4fKWgnVKX5`l|W;Sn*_d>}2Oy)HZus?R|70(+30 zSgrE8))#^kz=t%ZLC<0q%BJ|r5bGdGL`!J{-T8DhIa|=7M}ns>2DLmdi3Aze3lr`A zPMUfh2hf|}&nC|*I04w{K<^|l=nq+ATDUoGjJrpQZ*JMTL3Y3dTd%#tJAqU%sb9ql zSH#q(uirF}=F+8+*Q}#30!F>cpGK0YoYnU=No3&@DjG@KfFWQw5e*wua(-uM3kknE zW~{(LtpcdaotR(@yUCZ*W>}_AuNX~-X6FbHzZ&KaFiNdiezUfj)psTNK|2{6J5x2k z+SZ-qDL%DL*?oXHRi%BTE%vfKApJ*?7MJGGoa5%=J~b?vJGLp4Ljuiv_!UzV_CM|^ zgEyVQ!dc))h*c6;z!8-Km6}7!adM8 zg+@5_?!fA40lWc;U@EoLK!OO5vb=14rqsdunIUBnzrA69lx!el@x&B0^Cj}ZU7{*A zYLL|agiR6;dDl*HhW{S5eN35$_9T;gL@^%BzM+!cFB?ApNy8mJ-VyXn>_b*?_T95m z3t*dGM%@I(aE$ayIWJ28yfNf8g`HN)Py)v$B5YVF(idO}JQLIoG5IKg0B`~!t&_Wf zyPjxq)UE!zRtA9}C#QjpBz{ZcHIn?*%&k}rh51D!gMAFFkfS z=jZu?Wk7539NXaWzyFE@Mt z&Q5}seHm+!U1cP+ITg--vKh_98QcenxY_8lMaVmcsV*rGXdQPPBwiT6Sw;})b;mUk$Zlr|&w$~d<-GnQ?}9BTZM_wRKeF5l1$2fV@L;gnRQ$PcPp?JQ zp2W~5-&WbB5!CXBY!5Fm!*r*L@+_QhMGo#1J9zh%nOS@AkXTPYUmw8<2hah)f5P0A z;pV@rWZEatT$pVH5xHz6hKr;A%It;)S0=OvAnAw@48ppqZuUTD`lKg2m!#dw{ zy>GF3&zjxt6TrCG_rLo$sF2`cyWR330nNM@Lf?bhd7#yjLP4C(-;@jeue`1>GhS+d zTTkTqzwZ-^jk_}y;T64QD;G<`^A=+2P}oTzX?d~vgc-oWE?W(P*MB&cPv`{L5|4x= z@rk0!wa!VPtbjA&VD51Q_HS|q#W;|?yW3*U117gH~=V z*FAPN7Aw5O7%EmJiyfaDo+>sel69A6JJ2pkmP+3;yLG0&4>6ioq+)=TGH<_ zy;@V1i{rlcnuR(m>qva!Qg7DxS)6*#T8vedGyh#dNTyN}@m;y4d{b_Db?LS=*H&b? z^F6m%WhtuSslumJrw4cKTl!PSG9Jc0hK$rA=6Ve$ivO83Agv=aiocQO^Y2=wto`q= zLj>TuVG3}>#_+Hjs;G6Nz)6O8*>i=J>$!3w%#(ieZ9O?y@W#ugNoXn4dwpf<+PSX? z5wWGWF{hy8`qdMf7_~kD5x2#4%a!AKlZ?!gA)6L{2WLXwigF82GeX&1U2XfVIh_K< zaxaG#J_cu^zJ%1qV=0kDsHUXrsGx!x>(a(!%ZMozss+t+?MQ*%uwb{eb*;fghM)Pl z%G&i(H37aww`B&d$MR7C8h~IKc)iK7S#LxE$dqo=DBmQ%MJUw=FX#lAs%eF7SfOV9 zd7~w!Lf}ZXgg$0#f#u%~nX{kGwjGH5R%l_|@2ou_C-&5j$66^tIO?n07biEp@H~yI zUkyXkQP~qua7l!U-*e)pB zB9H$TLB*KM4QkWt{K400HTvW9^#Rtco!sJxrPBZNU0^Ke2bDzRjHf%og&N|omG>x6 zZH8&}(4)^kVl8Btu=O+6#OOM4rBwP+8&^X3_pAY{fV3G!`?ec489v1r8u}(i-TF*o zQbIhwkiZ)t=vBH$q=rn^b=o z;KsH=p1+#>OVJfQeG+Od_yym z4VA8sceF48H_0J>tT+~Y6g-?UjO{E`e1(JA|!hXf&9GATX8NGji@U*KQ!Ge zefD^uHz8BAGb$`FJshYa>cmGk1H~FWvS1Q}&KVc*fPfdtGU&N*U{sy24pD6+s{|A* zIgf$IsD2{HzDbh>)PlCeNW(UQ3V=-`hC;W37!mbl{@c-SBa~qc+KLt$si?@ru#4vd zX`p7MLK>HNE+DukbBrolIa9xnBbGrtV;0nl^QeSM8fY%E(`6gB0O3DYNPmfgQdJFd z3KT6+cI&K?|_AprL}Qdp2MywGL}mcpEFVOd`tt_`|z1p@g4a;YX?Uy_=JE*lPVrXNyjx zexS5jmX}h)(a1x*)*|m-g8jOP4Bu+MV_O2DBMMf*=g%8?8wx&UQ5VJ82$70@(toI= z;8+-%LX+^$MPRInQrs#S-t^I){1QF)tdkOa?FDl7F+_glm!&WVUraH)2m>MpSKB~v zIzh&pH=N!MG9F1gaDe5Hy#27zS;fGiW6_LXV_k$UCt>-3Z!NC5wd{QR}AmChx zEJX=sVO+==)&33+c}ON^^CFwY_q(icLtP6HNBsCT6k(Adp1twtgYR7iHk|c0%;wSR};WOaJiYS<0(BcK|QFD`4un^iDG4JGA zhj0Sj)=l;?lHMNwyZ{A^d1fhnCbWFfLsnrtfGkoS0<*)(p@;bY63r4w#r5ZU1+hVA zmQyow25`ot9Ax-ALylJm@t$sNKn4-v(7(Uz?!n_7-q-GWqoi(Hfm&@dDq3R?g5Yqy z-*97QT$>zDrtGeZ?h=?sCC-OlNPhsCVuRgGYHWH__q+FibpJIw@ru+ncEdAZqswYi zVdj;ISp^6(7TRVK;L1eCTI{0yiH|^Z*r*SRfRBYRR6vZ9PNs2#Z0Z5hsg3IN zuG(=Ww>e#Bo8A~>kk13hIb)Q`1cv`A_46&pb4MP%9J3i*cyN-}sfFyg+2gbXZIxd`&`FLz=|DK->0YAt9@&3>3~ z5JM(2U=CyKav(-NX&>xbWoa`nd+IPxg*eJNeSRK8^O&#OfRkASh2@|7iGF_f@p$2L zaA}#X@q#TRd9S!Rr-BGPVGs}!mi*w~P0T#f^6_Erzrt9pdx!Xja5oasOM|kUP|*8{ z2|442@p#-`2*JI(DMz2rN0Ve%{G+)CtYEA4na8fQ_qH_KGk#91h1m-bezl)wo}VU={{n|a zv_R%%4{mJlalO2zYF|i#Y`-d-teyrt3}b6@TWr&unMn~(z6QS=xBh|`IwgGo%Clj; zu@BfB7xK%QM<38GSh)D~ncZX4Ah<1OVpq^db3~(-(W9ajC`b+>Z#0W9&(0%4c&PH$ zJX&KPA0wlsL)vnHSSFgo61}&No%!B_xX+NL%oIxDbZVMV1pJ`b?r!Pb-1u6ID3rac75|AY7D zrLaJZ$R2E~f{=j^8X-`rg0Y!GfH{c`kc$Z5?nl1C!NTWF@Jq8p54}(ogU;;Kjinxm z1}N}F|NTm~!SGeS3}(?(dysGs5;wPE$bKP*P(5pQ(8@kUTJ7#$YfTUs*zOr#W?JhL z>Kkk&dm95@KY0k$0pavxa&$C^?oihl-Yo6hY;`oQN1VJCHIY>I*ejmTgi-W&bQkYu zFNpGiOg|y7X#L!OScgwGmGB~GpiKfhi$&Q*(`Y38quTw^iF|^Iz8{3+r{fg_mJniS zCNN)cMst^8yYST@C4*G=%D*qg+;g3g=o})8N`oOD5ndPDm!Rd1XL50UewBCuIkD<@ zPn|#k6yO@*LF0d~asX_Fz~6=@XZ6w|Fz+a8!y2MuJr^aFIPp-rM>jJiDR^%j5(^FT zULj%P7>tky4sO^YHC;*Ngt?9hw(Jf$QHU$*%VN>}j}536vBIj@@OLDVM`r={ga3t& zf&V>^tpjIp#(I{p2b_~Q&WORqTKWS&87+ikesK6QGjLvtFa6asF#_I88dEz{D{EFk zA~FO-#}<(;5U_7|XU=scSP>SE%N0_a5d@I2dQ$dqyjX~$uM9Ze@#LyW?1pxVq#vewTQi3d;&M>@6lsZ}3#(PU zNRh)=^7~=E)v3QKY}e23f{uK*cbRYEaCvSI<$eV%_KB*_1cB@uu9lT@1xz;YOsc*I zl#HDO4LkBBR?KyX(HT!)(Lw7#bB+% zz^t0aPvWewbNH?O=*YFkGrvWjz|=F^*iSal&0D}Kc6P2Q9t!pyIGf@Xz3(}=tRa`C zZCt=Sy;1-YA;qSwC2tBu$AKNl;<|u%#`4L=$gxbFHu}?bs4Cmh820zwk*6;cMGf@( zZ<#B3;;9beT1ObR$DR9@B)141Wlgl*&)taX$;l15r$87DF&C#T*9-u2! zWVjBIM3n5Cif#>xR+DmTb+6Td!bT+szQSg;kT?e142YKjb4VU;JefxpN7aQN6_c^-?tu2rkZCr6MxnL}k%dZI%$2 zR$IhErH?cwFD=4TWSK0O@_BLdOc8MMYy%{0^GxIChV=zbAh7h#l`eRiVwZ0(B?ans zXtthXhrOkGRUeud_I7>I@MSrTf_CI z{~m>t8Rf8^#;rD6p(s@_0{o`NV6LZ57>VG#VDiGR9?#*J8XcbrPn8#nJu-w7-X*wW zUTnuR-+}w3DaNF@a3rA4ISB_{3on*5?jY4tc`+=*{7Puqh))Fd@=JH`a+{AY?KuJD zzlKxvW=jR8?e_prpn7R?MB`$!cBj?ugx$bZS@A_3jWA@F^6P(7H$!zK4cIdX)&L!Q*XzQ_OA~q<0W{rE6nD$6Y)*$6R<-q$uyC%=N%f{S&?6>^ ztV#cN@7J%C07vH;J1(>y1|Gldbbp~m?87fhYCvpH9%&Xq^=bs8=S7J0$T?5Ws zux;yl`xXtvQ4MO6l6db-k}Rj+8V=;CUZqArT$$UK2-ut2&S8BQl4vUlG-Kc%w>WaA zAeOigu;@??b?D_Z>kJu(nuk%o2hXps*$bqE%`0%QP)4+ z+!d+kd0J3ZfgQle;G<-qvhR&D&k=Ki@-tv{S11&Q!`J7KH{9qfFbx;ZK<@TQEFDFVv5!WtlcvP!Z?C7&2>3o}26 zpQn%PvtTIZf6vMSP%?aOEI4L}`+0?lP1bPZEeA=1tQVY>%9^9_}Naa82X^ z&IENMnyzYaElmirbmj)VW%U+0LWc<s$BCuLr2-I~Gs7{8*M<3@6svvPt&tsk4hK-dbVPiFBd~y{dh*)Q+5h~qg4a^L|gul0RM}F(zH^kXq`w%pjX2# zOAqCAfXGXlr9G#q?ufkZOhZ=I$G;;{jrHS=O-!ZFX+84o; zAxA1b8h)5Gf`s7bt9iqer&W|`dizH-@kcYz2ereSdgdtTk{f3mm$`CTZLhrg4Go&s zgkra5s?KuA1zzI7uE}o$@9PxSbOfCYH^;Z(rvP_X8qtZ ziy2{B|CB1z;WOT6)DRzI=O_|_%mY+*XJUrp95#$OfD-S^c1oxAf+>BHnwL_4Y1LH$8g67R`7ls z)PpXi1{=ny;Z7L+nx!SU;0*u+WM@!epJtkz`q>NqAlVFTfRGmFzvM(Q5#WyKr_^44 zl@6x2tg}$(cO<)3oro$9A=*u1%@~3AP+buSmPcBaDroNGx1^`Zj<8|3J}e0c{7WzM zEPG~Jx!IkNmaXZQrWRAbn@Uu$HAq^nd#EXdC%ok|3e6;{kBwr$#heYWo8T8N<&>f3 zVP#r{nczJCN$LlPDDI7ziG;_{c~L4qYn9myT$vdayamgm$C#qsT>PqcI?zyE5Lkxw z6b0Pt^9?)!&$psKryHI?jIqEL0OLb14nuCM z-KPSC2d!8vELLx}*!oTM=}oK422{7R`5k1JX3ODL=dgj9$U+oYu-=Z~+|TT0pd7pW z7@o@OF8z#H+oVotGp+#p>{On(q0cqZ%l$C0!~HqlqN`=#=U~=<6}40|Zhhk6x=Jl5 zyboean7pm4SuYwzS-UX%achQm2I%``GDxSKy8dLXbm)(bhk)s3)ZUkIQ};?(7-xIR zkq32*ysQo76WoP^i0)~(wm~QSB+-Kw+~0$$t&Bu7U7>1#$JNhp9*{iF`t?TRYFjzx z#Fo;#hNxj2kq{x76%|Yh7~7aYfEXqgb`OMETJ+TkiJj45Uc%1R?_4~j0I?*c zH0*A6HUbU~hT5~DhRXAsp-M^n`Eb7W)BlR5PfjFt^N(`T48$c{%BP>PLUt4FVSFe* zIGG7&cHxYU?nQ*@*Cw`szzj;IJT35w30+v2ow`_?eWHyZb0*y_(n6@$=n(@Z`&q5L zAB_&Ii#gQsJx9H^>B)2>7iXZN1`~M5N9Nu!8H(S-9?ZE9upELGzVgkhk2aNXT;eA?DCnvJmWvM=E8QnNvH$5Cau62N4=KQh8t(Qnuq<2Kw5hM@Fux^t zxx~HZLPC3Y#fAtES#mP{BRbxMl6u;%bYk5fyf`ZSXr$C@M!99W)ALD=b=-^l&qNi1 zot&>(T_&)@QA8!Cid$XL$;0V!?jBz$duh(HX_U(qfs2J2Ks zcN7*<{YZle5r^CETWX1Ex{V=#j+)n4vbR?d`W~1ICUdvGUeV{Aw^q@t$1$LN ztX@@d=mI(8LsnevlRH1^-==WpP9Bhj?)R41?p>dCJW6a*)&sNAb+}QAX7KBIt@@dY zw=yGdr!W%Dq|0WdoO^-9djgLVbVAUALs{sOF_z$Khki#(^6Z`)w~~sj(@P$Xlm0LL z@KvTzQgkSj`fqWa`~ENsO-+sW)opks6e_2fAyH zCiPp{7NyqtvwcCXg32jjhEMFI$@>RqQ;8>7M7NJ)YOIdV4#mpZU@9>Of_xj{I@rzVLR(A%L#dthq)u zC5?+@KSvvbPE|$uiRLG=GNhNt^2LGG3S*p#WX*9P_H&+oLdum%qgq`*B@m8PCr_+y z^C960FEb+G)Oe_db zG3V$HP)dKbDHmx7CsDzFv&G@hgL}rMgJMR(qqy38ZzQs|oy&s5+ee%gl(!RjAgizl z`L0gp{>RC`kyW{q{Gm-;`k;Q~&K%&=#Gte{Z9`K5^~N@93k@#2UOL2^ENbwWK23Sm z$jK<$XuD*3yizQF0UhrBO*zG#{kbF+yBS-eXynxbHDT|;msw}wE_78NDpl-Xf9CP3 z*R!J0(Omppg5sA_>siBm=#j`0gp&L%bS<^#nhmlsRR`Nr4=(AFitZ{vp9X>N`mYR< zh&ncte8ue`NS5Id6({_2wvQh}Avoxdu?1IVX}6w&OcJB7rbC~gthgMatm;ER;LUWI1Fu;R-H2c2Tz()>GW@AhkHxaOR=DX@ot=034STb+ zS4MgL55$#o+Ycfd1g`!lG65Q0vz1-ZtE6RRDbG2=K05{zkn72#)lnV!rSfwgcj+Wz zRKOVxAJkC#)rQw<|r`Qr?%Z3ze~Op0xQ|7vfapjr)TOx1&AfJMgpc6T;rJIfC8S0Ttb#XpAO1amhBD(e9=Bw&$? zH<1eY$C1GmuxJB21b5P@op<>@|Cq#5md~_(;Ke!8U9$(V>G1~Ok__nd z;vRN)m)zhSaPT@&nxsh)B-Fc9F*EOW&(nKOSYCi9STAgg>*{F!r%|&%!G1WMVy~xD zpZ$U(N`!R-hOwUs-CWUIs5dfiPgpxoDaSE-1)FR}N$uVP^q2;)ljIOvt2&h|<8UgI z<_s5Q@!t(Ee!Ib9-nu9G#YBk?*)M$hxht(le-U~qQy^w@=g|~#QlrrPWM1_TY|O4l z{EIl-fLf&*R9oJMr@W!cc$vKi6{EvQ1mQLhaps?8Y}1hNRyDxHT>LpAlek z*+qbRs&1%ri}`@0)I{98z}TvrP0(@=tHf+rJWQb)vwOW6XO6vZewnrahf$oC8=XSW2mEyVx9<(e zeWl|$!W~OLfWr3E%GM=X?Z%olA5=dl^yv)0x#1kMLXu|(Z8-$Wyt(lR?rm4BH$C)1 z7tX`}OClFSuo#Eb|8X{>n8N6rWkKipkXBcJ>z5p)KeFS(oOpBu~h44nlG(tc;DOWkmq*g8lF(NnN^((RmJBly2c}irw9zoSs=cVGCa#LH_X!AoQrO*CfA~%~eW`vy;vNhXFV6m3U+-tfPAwXzM5H)*tMIr~ zX>*e=r6VD-7y91L0B=HCzLCdDiU((36x5S3sh;Y|HJjmc5=)mox+buIVs7$A1Os}X zsf?KsoFgEK7$NE#f><_2nKPUIJsSSn@fxm#$LL=@BO?|(cu~fTxz#yM=arUjiA*BG z!|A&-g>C`IVA$aDm6{EFerQ>bi~hd&fAJukqW}m0?RAap>GtHGwWJqj7VowYdBkbH z*Vp771mCxmRqq@9mpAQFxpdTB0&NU52qf8lqON*bL$I%M z#m^z{u_C{28D}MP=z^#hAkkE!$k)kON@sIHrX1+ti%*YM&vcPfA2}C9W5HZS34rwD z6BOD|F)r>#n!Qq>>BMC|VRQVTt#yl7B$b5|LzM$2S-44U z6Z;QaR?Rd`U_m7fa{|R9pG_9iPq4JeO46|(7>r0P?KkVo5P7Ly%v^}LuCw%OUzzl4 z-8F?PIWf*}-hONGcj=yeI86mfJl?o&7Da*ya_*Iu)RY4}CFu!j@>YCOB9T?C;o4Z{ zwku`>b*prn-I>^bQ~kwRJPB|Ajc2W5hZRTtoHKldlUht>yrWL)AEAEabAjb>8thBsGqG(Z4~EaHs<7^U@$XmTfLzCF^O+1c27FX3*uXkS z!KR02{LA53H(On3QcXIu;b>|Gq)VscbQBQ#A>phT{cy>~ljw1=4AtQPOo~j%NiS}} zr5j|9uDPB1F2`y^oGTLA0*A{}R@Ev<)<$>-*cz`PIL?*ur915CP2ft&ju9(*x9jNy z(+Q{&PA7SzqJlJ2!jbCtqJDGk5xFl(vMvuRb&=_FM8kl5C7LaRZWqLhtn^IRyuhLg z+TkV(N#VDDLGd7fGl`enBa?KtPCtdS-tH7DxEP#iJ0ESnj9rxuB;_s;o9Vf)= zq3szo!<2yRgoVBz>S#Eu@9S~IXJKmOolNeNvX|nJ!)JJ?=#u=6Eow!nz=eN{8D7(# z=mRKgKpwvbx$HdA)tO2Osy9|`3DV&@t^*ad4;9auu{LRfPgaC_#2()74ATn!F~ReK zJ0U+-Z?!c%yCDpv)LRSGO}&G2A9kJ1aSP5Y&!`+uxWMU$top4!8KlA@$e}hvO?y?_ zW>uerjFw{&mr=BtCrI~Z8$QUzZ4TMgVR*z~4=?byzfQat*r~(hba7?Ga4S|naAIGo z07qd-;*Vxsebv+oZ$nQ_c>#NNhAINw)6=Ww(iS)rO54)ii@~4oHQ^%i*#X?pS1fIo zCTsE5a>KxN&XW9!Td5X`+-`Iuu4Km{XT)`Eqvy6<9j`-RipShw;C&kmi#=kB+z%H<|BR9T*VXvS z%BHB2SV~K#9PdEm`4xfOLf@rhdde3$l=Rb0dd+cLO}aI96HURO?6N+33g6|{!VnX> zbd(W~AqcH{wXEu@qg8J9jqHaB zyAAWxDQlevKhJBk>=LMAq2v<-)51NUQyVBz4I!LF`_hdoSjqT)cg+1wEP zP`N4&6N3e-h_ElIMyI;LpYJM5aN?*twy%6>EiAtYua^@A1Fj_7I*knUy<4!Y zN0HsK(}g9jXf>Y@ZTnpDJ48vYL4IJf+czUr;wGqF93GCQ_Ac~i|LB@Liw_LQju0%Q7r`&UGJ2vs9sc|pMcfd8j+tVSlEy5oTn zqgF3!s&LX?>$8n&ZMCKJJcfW1er`a#Fk5mo}<@qSd0# zz_S|gr*PC#VWAc`GPVTfaI%MTI1W<=bAUmNT^P)C?=IdmCxN=wFlJJ3ms#vnWtKa# zX|1y2&bx9P0ts`+GtnFP&n1!c?gK*S`$Y(V`EqwizuS`-po9TRfw(L9S0zZh`%xVU zBTOfd+dm~lc`T6D?~y|y1090AyCXRc4*^A>OUw#myB~)w`HKy)5`YOeki^Hwbqq^m zw&`4yaS`J6r<49d==JczcXT_Gf@_N^+ai$Pt_}`Mk-U`^r1cwTN*fONe?qt43&q80 z%nQJ&qpyQTk%T9phr(}>X1k*`1bebuqkqC=c>csIaID$%BcDoHTKydtg^M#c%cnUspu5c#`<$LyWOAjSdlv-Ku(F?%AvalbRPgE|CQmL4cec1XaD$CDDo{k!5aG7 z+&1{z;fkMJHKs8BXO!eqdL|I^=3!MiXTNByxO%ZuQz*r;)?TT0C75ua{vPBln_}9e zo(LaLnSWwzjMpiAl~H!=3#Q1(AUGfuJmieZAQ!9s;8C)GRV_8i*iuW_6DD32!o+&L zub!sSAP~i;xh!6JH9ysS-no`{r^_`}l%}{=TA3%cC6cw6%J@o&KS4G%Ql>hkvAgNA zLh-&baaE+Zmg3aJda6H;e?s{O2{uP1wb!QuU-H$R8`PSh6}s)n9Dqss<4IG|_V z;&{ z`#ScnB1#NM^A?!V+}lx2t~a`x_di?W-|jNh?SGK8qb>jd*8g`it-YP2^Z(rrcYOZ* zu-F#w?|!LKHk$@U*Co8(wl^Za5c(n2V0il-JSA-NSZH2z4brxBuG?)s+xnhlG;h$Y z%Pj6X&Q6v_>#1Wzix$jHnXzteDpda$XXmsf+7@lev~AnAZQHhO+qP}nw(ZQFwr$p_ zdaL_*zhcd{MvsV&p6KuCY7yRldwr`o#kDFC5?^kJ(PUo z>caMygpd-+ZcK2Y}rV2({3V0e3IBv4Hs_JIw)up^GuH`jpY}9^qYx zRP-1^%ki3^3Ys908|lO0s^~ zcy8juchb#|1|32SsAdsW>K3}q{=io~y}7Pq#H<)pc9NI%(Dwy_ht2%AZ(=U1{@K6G zZSDM4cL8Bk@naAt=)IM2hb0{e=4R2YsRSFlE@8Im4bPuW+tqXb24?Zx#(iyUKNv_f ztL3tVAK6{itm9NIHy>OWtSD~uyScAivUZc_x&b=`xT&7Wmh-C>ug~hy|I-a&=D2eY z+W_zGzBC1AuuyEP3bUol+C9`MJ@f!0P7Yx?1=zwd!*(q0C-8Ejd>9;KUUCMJmTtR&;d~Dr| zcFE4h#@6>3Jm~|9)Z~=u;n;KrPJj;N-Y3rQo^F`JQb(oMdFG5y;s|nIX^<@*}8a(3166}=M-GEQqBZ{$uONd9{IF`G(ffKbdzyczay__SK^uj4KF^W*IK;-O*LlhevPulF*ab5EOo*M5J>Q16ZV z$R~EtvK)RMs@NG_KB<%7Z?wWB3~F%r5?M2t)Mdi;%l@aGO-uQXOmvdriiCn^7|Z}R zd*;xUL~LTSEo(AsqvE5SmV=>-9lnkYpgJ1oabZIYl zex0pk5RC)^I?m&wc$>l>a!T-8&&w3l=~4X8M?{fU=Q_xdWfCxm9>gYCC8ac)3!_II z^^*K5lMW6(GK=BnXCPbc#ix$2JTrW5dawa}T6EgciXvNH%wDUcxYf-~ukM?(g0UdF zP_4X`_Qc6{=}bWpD^_p^gKK<8ul&Eb*8oJo61Yail_C>vO_H(yEoh-vVIJP8o?FpG zkB=KgkeRQq1q2$h00P7LEeYTY8r~rhFc~sM{Z~MN_!c)s2cOmFRCEyn zP0YsMqBGLVl(dJURcJLqCDSA5CFWrz`U-n#6*dxtk%(t@lSW6O-k{ea4YxUQ|% z%d-9o0U=m#?d2!^%3H4C9-t|7%TnSgLyG}T2h=gO1sZ|>!Y-LLtJ(5wi?Gu1e_C8) zV@oto6Bas{9)(W!LVi`}`QA9}XAHHs%5p>I$03kc@<)jY+QPfJk=W!jh1py=z+?>Y z6`>+EHQaEfoC_mK*qUJ=QJ6gf&2LEdV$L#!&t#!R(vqa8FCO^l>*rD|NkQ^SNM_IX zRVsnlcrfIfgxGqG^K$tm`}vt^Yn@Kq9K*GB^AoPH3kj&tm5aAI`ReuQtRR1^b!l>h zxXP2s`-a_SxQcjXb6ky`FV<9b&ZK(QbGK&&*J*qrBkY;ce?M%C}|Co3@X{wBQ#d zxdsnBk^g2!QsHW36U$v>5cf1pw^N8U0&GB9O1OUOD|s(hJHO#r^oE=rQ2mS8w;aEc z2m8}1_X%Aw3ztg-5fn6l{tZ65FY{go$#?5krOem6l~v>US|k^FN9eV~fBNPiFU>FB z&t49s|e}EyzK+_M&=vHr*vT0a5=W}v)O&92Ynm%9?uBvvpET2ejUgNKBEByaRgc4(Z$51%Y_kx#L`F66*zyF z+gD|)EGb0#m6is!g|t2e4$4VWJhO_SSM6wg&$|`7`KzzS!tWD!$dhL}HD=B9Olre# zW3T2P-s16b#g^3$4h%gW-|n zzdobMis)oEQWFrdC>t^^CWD`WkAC%>3ahbV$7?kLG2?%=(M2k|Kr>+u1x|e`X#ndW z6nVa#QORK>+Vv4gPLxK(G7@OLVn@Uis5Eqik53)NZSB%J1SWehXL;>C59bH*9vp~i z>WK6~w$Flry>wg2t-gF1Z17cq*VNgvs!4oc$5ytvIVAekHHGjis6Q`Mx_{Vb_1bTG z>|X!%#sTxsaV?B_0ep*Jo)u0m3;pQZz*K+>)4wKJA*uq}^LvGYic0;aEa_~KK!`AQ z#|5-!QQe&Trgj!E=^DWmx*zi{cZXAn)dQmovpJqk=oBDqgPqUc2V=Y6%40K8gIMd( z*-m^nVYe&D5dW#oX2loF#)tX=30}|2Ki7v<1)`CmF>7AAmcR5W`zG0rZ*-l*Nq(JC z3F*ASn2Q7r2`|Fkw6gaH6A`G=5xX}Ac#7&_t4?anq3*WpjvhmaK>w^|vr(CO>4zNf z2!Fzutz{gIrNs+Dh%|7W(Za9t+&rFA-Ofyl(azeP0~7T>8i`=D=O0K0^nrqr8WZVS zqj*4xi-%y(DO_1%q9Y=|43Att;q)baoIGc zX@LS<>~?AG0F0G(%@V-eq7lOIz2ID#Z6sVQ?qB38ZD*yBiu5K+<_3ZsE=XtOu_**e z@oGUoZNDTRF-*m&Hv%#vmVQH!O>AQ?7-d@`y@kbh|J-7PP}KOG&C*4@ru*NtjLq>8 zI|2!RJnRSjVyppZ2J-Q`Aq0jg@32#|aQ;-S-*gY?z9T<*0L=s*L0)};G?w8qntPs% z<>_`S)L?nESFv8lb=R8BV*(nrAkRcc#jw$|(N?k_TCD=*$e8;j?w(h26`4xX-dBnf z(j3Q}5PO)C;XCv7N*k?af# z{>vUl`pLjE_@GRsLyFo%!=oN97mGmDh9vbmIMzBJ$eM!ST5)tdU|j)FPuE@;y&OQcgOP^WOsfFa`AAon=!H)2 z-kFFIW{&Hn@Ql^wdy5wp+ei88vfF=ojE#Ql*g(wG+rY_ zXwew&s3meVVn#>JFva+4u@1ROSk4D7E+N&}5j+83baEUgG}s-zR1)-Vv|-7M31HM7 zX0!{Dty73rHw2Jq#FHO1X5Mxsnn8e$DkK7hSet=lj2zS!4|nD3iYBF?L85dMTEyDH zSW9%<5*-!9iNoh+09!*FeO9xXj6Go|b7qfQXK4k@Y1Pr4`I#IX<8lf3GbqiJ z$Bo-|aJYAg(tUBVPrl(D?J1%6y#z7iN6cvF<}Egks8fj;Ws4 ztwLG40vbi2HRxcGdt3c$u;Hlp3RZi!_*}%ugE^T1=m2XCg^VJK6km(!ky*X9qRq?& zK^*Q;Xq|nDzLRMNzu+jxMK1T%VfJm+Uqf2Bxd9~02}yjq!thA%yUj}XpwoE zjwlCpCy)d9;dC5m;<$Jl*HGyUPW%r?K`Qsu0>s6w>I7E+v%}1~+XkIo72>eyU38~! zVxZ3r|Kfz78g9BIfAQXvbp9N+Z_uDh*UtpCARK}{@@Wg88qX`k2w{QYto3({3y!95 zB7L_7l`d^T?Cc1H9LoEd^aK-`>;bQy(Ww=1;IYE z-aMTk-3CDuFz9v+wB%taaT>Gjt>K1uO(VF+hbH_7rfmuJc2Vc!niWyz##WZh0w{lAq9WBaI%*+!Bu$8WKm1tQFVT-Lp8d(rKss10%#phwON}EmrrZ`P(Cxb*lYw5w%hxVgFCYZ0= z92fh{kT%QB0nf$P0cEn7iKKQ2L{&GMXyX=O0+Cr%+HRb5H0Ik)9}f#C669I;F&dlc#X|5> z?@qdlJH<-&RPBVRFtYCP0Slj|ni|8FD0(00e0DLw9tx;2dfId(RjuNgq9>`FG*npv zq}2gvVwvG#rK_*RqJ2M}ICuEx?AD(N$V>e|@L$RUK$uUP^&-iFpHBA~; z6WJkNTqDj<6Oh{(hXV3ogJOzRt9g0|EdlqnN^wQ~=$ga*xurAEkqL7$-rsBx6pkwJ zkH|ucb^>LW(pzJ-=LY_9Dd+;_3y=b9>%T#M(tw2S^gFcLUDF~Q(|LfIo_f^GkfnOt#URxsSb*MLtbo-$QH|!k< zVQkT{PG}eZ=S-Z^eRh8QOhgBl)X-C%PxGn8z~1beK>1s=(7Zz&$H++oZXAmcNP&;l z9SasK_0b{$J`VI+gd$}pFoi{L%h!I)YU1J~tklGiW~AeV5g?bR)0xQLs?xxe>C`eO zt-Q5%tGL%q3c;|Zi3swoIPE@jm>$z*M^P%?=6Es5woERKU5e_7pfSrQ74!3odFG%4^;-SCTyiu`3y9J;}D>;PTp)9*If(i`Mj*o8a0I_!H80<(0tU}^gLa9G5n|!^i4t?B1O$l5CPSE**Fy8m4zrFk4KttpKQ1}=7g%xiB8ubYzSp` zt^&m))VjGcokA`O-_k|v-E1II&(|;ODfWUD*zN^14 z`{lrz-$act|7iJ|AAX?p`e8U`Ab=eXuG7H93hSsgYIupiC^s&jhB0*XSxqwLoPPn5 z<1J}67kbUQIi=t*y`_-Q0dVot+w4@UauragGyBo?43Oq&%#q~VuVw~`^V?mbJs9R8 zF=DA9w)FEyeAp*q=_6s=!sCryi9!M3qX6_v73toO6oxO|<==@wgLvB}=9)h+y|%e2 zDY}9#J>)WO#2YF}b6RO?@LeB`I}I(xeTsn!9o5aRIjcLH>)LA29%x(ZT+;`##`K?y z?AEk+kz(ue(X$gu?Q;Et#xo_;04-S3U<0BU`+VY-tI{O`~{Y}^|WN;~2wT0`maL zTz1>WKcqepI0m0C9etM6+Lg^rqsu!F54U`A?TbaJ^dB2H+r527Q#W-9wY7v7vN=)^ zDw`w)2v>XVFmZaRgC9Mu_}`v4^K8n$ma^!Zdf|L4yYJ-#3Y^5d+&)Z~2bIW8qn3AW zUH%t3d3jI?xZ;-?=})6NyG6|Ku5wn1@0L*1$AAZ!j^~$?li#5u+}lul5X!nwZO8Pj$l*hG8^{l z0X0=Kyxq@5rCGfh8nrF8NN-b1Mo=*w^}7i7x+x4xV%+p4TaY&?Y7%&n8{(K4UP0B# zHzh79v}2nD&K`~agHqoeipg0_R@Qlr*J!)zqQ_pn(lkN?(mq3QGW_4Uyi0I}F}i<- zFds;rzCsjv|0qW!^!7EFLLKY&gn@HF`AENIcumn%Cl3*kaQR^VnhDFNTZ^#=bH)8S z)l8fht40*05{Q467$Jl8+WGw;WC|a`3GHgs3EQW!h&?#(mlb*^(B&}sjzlg!zh7)tFgwYC7vE}|ZyaFg$MBDoR5oI{VKvw>BMR;j z;v-ur<6Vg{tUgQ-6F@py7;kWLyqj(;hNm$S3S1{NooG-%7z@8oa6q2o59EgRVaqFAY;5Y6=I6qz?lWBF_$h2LP@a}Ek6g~n`+F}WJv7@8vkloEfDJYub#PsNlV@H069z+0_Ic03Hb zY$>((O1dHoXt-23JIf1FmtbX_0Il!-(BHLHAFhU)fI^!?K>HbVLCqu!5@(1wrL~$N zo}`4|`v=o$-g+jmxT)~XR2qh_^6Ge({5zefwy+^NZ%9UQuy>EkI)<}c3ogZ&-yUdU zkScn$(mY`b7n3iP*(|UCJGew5yVV^!vsp|nDmU`;uxQ3JjhGflK+YiHNF>R|#(!+j z5Lp^0LG(eSS&8$KvO+GNXRVAXppOFS^GgSP3A}j#hzTahRK1aU(W!P-{SbeFcf7fh z(!JOnj<`w;W80?`vok++(=|1OY zWk!-fr8kWxiE}=dq05@)8@6|Q-;%e4K|JgT4h_pc@bS0xv5;geW1%oos#R@Jy(98) zu4k-EbS97Xn^#zIKlHNA$Gfm?_s)KG#U185U@;N)j_GtV-u?8A3v6h$_~{kpKTFMv zts%`NWd0HT%-|bpls(ag+T4#=Jg{^U>_o>+jB*1iX3C=Uppr{nF`R9I2 zd7u6p{m(E64*`9z9#CE1U!cTLxZ(bL-z$3U@Bw4D8|9ISs$3-+Qu?Tw9r8PBeczw( z*;*@G@ABOZZVsQ{!}IPxzqj8X@H2nE&yQt#)FmsB=Y?QHI$;{`>_P(N;4`bKTzm9<71K0%Zr5n#^nV|9y1MOP?wKm0o)wF@ zi9AqrcJkKq$N|cJY{?3MR!+@=%%sPVa^@k#K}2LJt{6P1A0EXmMq5_DVsQkvE>}2A zA$WKVDOh};7qY0APujL%eiOz&0~BYZ4{@o3{ujwmq_Iug$kWv=sym@6{2_BkbFl7m zO>iOh-;cL^a?x@m--=(y>>l?zG-DMdF(%A zEQDMKgCO6szUy;Q`k0?;mLbkky)%M+I0gI4hBpTS3#LK=r=50vXpjUO{ICXw> zrp5CFwBthdj6P^5GrPl?3%0q4SBk6HjB>z;q^Vm#1U$DBK2{4yQ%SZ&Ds9fXh6Dvq zY-bv`*s|^4oMZDpZsK+bHwa{o)79$M=LK@NCbJR-Ov4IQUKo6Uo>oaVy2P2i)m1iA z(QQK8y!m@7xlD>v;HkARuvmG)yAje%IHn$nf8`t?hj4S~k~{uq{uCx5EA$?(eg8$3 z08i9u43YDZMbg&AWw~PMDHhydjjhepx-TvH^p;L#M&!Q&H4apgia=WQc#%wt2c3q8 zJ|*3DR&y(U@;0pbwc=_Rig)|v&rp(*%2Rg;qa&Si5Bo*s4D^bbl2l@JM@R~cArl+xn#kml^t=a;%=We}-bk!XeP_uM6%A}~MTF($sV(y8%-eq(G@Bz9hRo*;4j}HT@xum!#kA5<=5E zDsk(pS`r{*a6V@fIlG}z6M?#ZQ&WEWgNuU8pAN6m%~?3ix{5seB&#C zGg$o&8P3CGFs2?sgk{NJ9g_ikQEqX)a~!S$m&T>7B&1S0?q6(O7`uyTrYr=y!JNL(#;^Je@To1r~xB)*~Oneju zZW5%gD!B~)l-uII8e8VvyW$*NHKh)A%2{>Jl*%h;#*dL<)u8EvuzbGI#3BnXr%`}m z%$)JtO=eO3a`H_-FCJ*fL!W;moh|}kov8cSDgdJ zP4uIbTi)5i8;7e5QHV7*^)!w_HA#hYJho@Wz=_>N5#2w- zME1WuyMR%$1ZvuBQa?{u#UMYVdqe>8oexY~GAhs-pS(2E%bn z3y`&!0yn)wP$gVDfi6=>@X)h4%QN{o4)M8%O#`)^f+Mx1UahTbvtm!$<|r@e#@evA zmDP~|!8{MCDOmP1E6tklvEVTCC~ziyTDiO~tQlT}Ns-PtAK-NY*9lyP6B>mgZFJfKpUbWqL}(SaH&zan0t z`ps+~^WFI`?B!kB6FlZE_RyLouV-^Hz%Sg%+GwTYqi*L9N0zil)=VCkwX*v4NFjS` z70WyEt|)JtxR#}3iB-kj$DqdpFO5tqlt|5(t@tB6TZ68)$^56b%+1aY(>aj_#zOP* z^q^7%$){}(>Ymx}|=QN>_Axqp8b$l78Tj#QIMIO@5+m!+i3)XBaA7Au(z!R24#RLUPsLr1TP4 z$7%>P>lKkT&)X@0zr8p7$pTAjx5QheV)WovK`lXY)of4XY^^!Zo(F{F3C z>O0^5nMG{iP(WAAj!tOBU0*c=B`L#ZI-`A?Xq>kThp05Dn%o9}ca+mdm0y-pGIEOArR zjwlKZcHYB#F?rL8^1Ga4-1AWC0W*7Be~oqMI)qYhcDa5*aTL`A2)--6BB;!A?I=nH zRZK}PB2sQ~JXYgQ-foCxCL&Q{#yM;WdANge2Q%$pk#`9{re!8K1gd}5A6+QDiHWJnai@Nd7g?@uOfTnka55P9tG22y zmJx^vo2t>ba(Bgf;9xMtrTQ~l7KwY-;ZSUilDZXItqpuQF&X^(0B{bRKgC^oz8)@h z`AD0>Zx8pi^Gh8Q??b+KN4tj!2QF*{u>S;46W#UTGM6OK;{uioCm}XK6bdV61Y60TO=Xlj|v-Ov~}ms+q>*Z`tq#pqV7h*C;Wg557XF*_IW zWH?s>1qnc)h+dj|sy*sRb;g-8IK7F8Lj{IBu6LM;kaJuimzVSIQM@wU^cnHmVNjgb!Z} z$rI*)5?>%LZQP(?$_?Fs)Fivp^Ab=Q1(y(ab;FWik+CiSCVJax{w{1VYCAlCqRmB`ss2AIUFA2XcK)nhU^EcA zyWK-R>Rqd2O>&Oflw>Tp`I`hgXj1%Qg?#tGr|0(Zk(HLmrzkx^-GL+v*5IZ4)F~Ou zE<7aU6*%x6H!BD7-9Rg_Wr$vg0=-#MEgiXb%}id-9TqF?j4!MwR2xiuKWO3Jz z^>U?N5foy1at^2VQH-de{=}PYLr@9lt1;>CB{OM5 zR0imlosU@mTKnhJW!hs%#&s0(uomsxXQ99~hJ5=~ETE~wgOmyHj9bh2q4&2W&`@G# zQ^u`u4h;HeIwT?Be_PSz$QbdoZexnOb=d5Wy3fvABza#cer&97iM{)^g`IhF%8{8G z`>(8adIhSNyAO3O(cpqQJOU$kvt)*0Z;Kjpt~T(qR4ef}n2Wd?&^R0IiN&GY+&cL< z8Wk3?NeoOXIzy9Cz8x6BOyqpzNdRL%iyHHa*(cQ%!y)Jx#6iL%k$cNE2&K&3WjexX z)g+o@;NITK`}3T6c~<*4FIWcGH?u#`H63SS$x#N1!$t{5rph64G z^{7SDPpeb;Uf!}Zcr0&+y@lL?=mzdhxo)X6r}{THipC8ivk32aD;wDPe%<~3f7kK; zzel&{-xq#y?Kx``mh9mLyandQ=P}&m+&;ahER^Oh@8)`=?-o5+8PPxT0#$h}x4qEU{gxn#r+N9@(Yz;j zoB99mXxc4)&sVP1{@401e$%QgN8%!v+nT-j#&D*SlxQ2;t}69mk`l(abWMSHe%d&2 zn$5ei#_<5$oA=L1=ZCGYl*y>GMo8A$kE5||#1v?|)HLQ#9%>E$|xZQaQ{ zZ_SFS{ppcd`EubJ*))ok;sgVC%_vbw$asa*b@#@fVSU-$sw8tt$|@oR$+nnck%lqs zx6r5(tXsUQC=*LGsy2K~`%}fLl0#dEc#qzZD^O-ZbD(uOlXsut34o)_bESLln7T`Z z&==i_Bw=%^JgNZyLCz!?S@Lm=R!|7Bp<4KSX`oBszp-TAullA`s-4pVuR;nTfPD9k zRBnq3h!9(0%VC;YiJ|ES`EJJ!o68tJh|qJ zNNEMt64;SYfVRR<88e zaJ`eAjqsrOj(Soqrjz{Sk6-g3W#{ZMjRx94TUSdufzZm9t)B`mOiklu!JF;KSIk8O z|FviH6OoiRCcGwL7N}n0`Zr&_9Gs)>Jd_`bOO*D-iL)Vs0v?W`A9OUU1i}+^BN3F# z1K%f#Ntjt^|2-BeZcvqCqBnFiQbNfQd7*7bi=^}+rLgwbJNBO7XoJgw>1N|VO~VKo zbjx%l)s>svlBM>}ocbm&72=fIEkJ60;K(HZG=sKdnLpK;z$ts=2m?&myou%n(++D7 zc8vu-0fbg2_Ih&=vqv#C}N>a zBI|9bARvAUrG9|CRPFeo@wxKGq<*_$06rui;5i2X@w@6tYML4<+*cIuomN}$>y_2Y zh0mSKr!99*&9%-j4Pa~*I{Dc2t&N@SG<&9OXfU1pH=Odo*ne%ISG!zD8;Rw;^UI`< zu)rkHgBe|?WM#1>Up=_~q1MAI3p9NJnR%f(tw+@VS>b;QnA5-q**(allmUPcvg_u>X7#P}Ip^qDtHvatpU zh}%+;j1t}w9htC?9`taV=|mXVP7?|0<~!^ur2YpXEDDF z_?6R2j*z;~4zNw7#UANs{YYKwA(RA{TlE}9fv|fBV zyOB-+_s~`*PTQx&QyzUs=tP|RU6kCfr^LQc?vor$tU0_)?83xulm+mMA}W5Ni4EM= zq>tDcyMZTu5CjBmh)7p6;L10jWvN|9yK0GRB7d!Fe%*ru<2Co--~hySk1fSk$$G&m zTD2{P=7SZbtMl=K^+i<8v9OdU<^AvcBueZ$+8d(-q`Nv@FIzEY({8;v*q3=@_sA+` z9|lzbxf@NJ@M|bR~(<_u{fvfKMmW(eIQ?$ zr5tM}a^c5jUzo4xJB1P!o`In5YoZQ>H9JawKCH9pFY<@N5>^VM;Vn>slI9UMViKp{ zf8%zqPiYF9wOJuXt}oL{&&?eBTqYQa5b60Tdx_SwVX}5xxNhq~zOv}fcO>kxVSFPl zSr}++I$+ER&6cL&k1Mq>C$CK8;2yqh?m+143FZ#TaeoF(vWmtOX)`kNvi1%4{?g7p zjZ*WY<>p4Xwn1O-czLgx;rlGBe%=d7O7Pw=ugwrF4rfmI8n27r^I1d0*E1I%t}+5F z$t>ciAsYC|=IBdbO71`2On-dzr{Jhm$e}TIcejwD@BRKz@{3w}9$Xx{Nht~g#xac< zj5}Up#b5@CyXn;MLTau9sLTM5vr>f^c_SyMzev8T5LJmiK(&@*y!Om1a-affE|GJ@ z9XnoUFa<9w{Ry@7A*RiS76t29D*8qL>aaXRhd2ZWX@@U>c>LjU2Rm(8qYVJc(`5hB^U)ND~N0P>#^Z%o(SGld7wa`w^Za@3?oaNl5X%RN^ChcZjOCu~?^ZD-7 z+3$86%>?8xsA0CNZ;ZhsucawuGUbw(T!1s{{rL}35g(h-hnvZ!Wq zCSEp(P9PCdHv$-k+Q=7i`;xu|I1E$XyK^jBfnU#lF@SzI`lV!-zqYE#nOw zLw8%h^fMp+jV@rsZWv6=JVob0-WvoPcH3u;RSeGfmAh}UewD+5F=+T35GLe#+G#N? zW3gCVt)|*I49&$Fp276B@n`cce@bcRWvJn|b7R6xT5XDYTV&==>v>Pm(S@T2Ck`g` z)p1@vZ=H57+5*8f&@=a8_(sRhZT0FU>Vzi=p5+DpLu}P`ws4^# zq4vK7Kn9%D0|tzxi;07rA3z6=u!8SrBiTrNh?mX)r`K%v-Q@$tvYvMa4_WEN!8(iJ zZZL8A@HEL>D>ZFc9xRZy!N(k?Hyg*mZQ3;uiRs3{43TNKZMF0c0E!95y#M}iGC_i# z?K6c5Pe)JVJYN?)RUi0|8icLx9{G>X)kYcdAe zzS8()*+9yW3^{pj>T}#;mXGxtAAke~aWRdH;ewdQIRHs!1CI@`rH^z&!P*x)@3C!L!Ma!tixwyVwp!h_8<~U1q z4xT4x%y{!f*`sI{s?Par7}DPc!}G#%P^5t!bThUCzn+6rYO&&%neYq6dK@biqod`szV$Biynygd^PgP z9(fUlT$EY(aClS^7pDOdHzYsjI6Y@2a==UmNF$mIDazpV1OX{A7o}J{cAu9F;qHCw zTsJX@0$?ZG8YmrS>`;9U*uOb_#r=;X0vy0_SjpKYLi9os1;EzXS%FXNUK*vUiHozU zMU&rFlTLbU3%o`7Z+@}22AQnU5CPF%r1jf17-ijlMa7a3-q%VAvWfBs0a$>r7HHJ- zAWSX+_%{Xf@f*kIUJBvqthZQ(Gl=H5l7oL`92dNTdqvDaD+49`Hn$!3f*5(uXdIyA zzW@wPYXbr?^Zd~<$q{L5@bo~nCZ&w>shC4>`N4w6{g|5t1rL~5?kKS}(Elv>p5%l> z>-3%=b1762JKMo7>?|<5_7XlTU@u%LG+V1YjiGteM!H?ccnd#P?6%i3^T#-LHpcm$ z`!L3NV}}mBa4Ko8PM>9#3mfa^-jiy*VlLoAa?UUeSeQepiRI*vCKMvZX-6z*T+}?+ z@z+m)F^0@7hoya;$rP%XHtn_&wZt#j!z{d^!s0KXY37ikxAfaA zzv15Icf#%_X|AyeGh$y59Zd ziu@Br2cr+9&ew)Cfy@oXVhmUtj^)YI?q@4-~a91pC$*gYuO_xFPWfr;G9tRs~{ z0LQEd1Ptqd0*$9CMIV6_f;(|VBnS$gVA74z4$z8V3ITYG7Fy_FF$Lf^hJqp}pa>c+ zAz+9`%t$eq)Ku$E>YP1;o2-I&?6#C-YMz9qJ~Z(-BXA02`B2s@S#<;>4WA)@dh;`y zXEQwr+aO~_RaP|^oQdEnbC>|!W5V<8rP7w+-PPS|`y0G|pc91eSpQ>r24k7l7Qnb8F2%yR3y>oqoIEe%O*roas|wwEMX!YijzU40tyj>;tfv` z!z68=F^b3{q>wGi4D_pF*;)V$$ew@|*y23ch#|8QmS%=vQPMt+mHch2=~X*RzK5-M}h@Y6ur^tZ)fl z)qW!|m2Zg}?s|#+g1%X|0)gHJ`>uwfV~Q=z2l20Zus(s>TB6E@YFEq*slsIE$01Rdo=V_$gW^1wKkZYvyy z9W+aP&2Cu0{czBr6oCdc4s6G5Z(fOypuf(6YGhOo79yFNa5t)$nz%mgXiOL?(PT;p zakBAzFJ2Q(eTy3wr+T8R&sO=G8x9@6rlosoyh0p z;DI~39P?v=h4jUNX)!lFkvZ=WYtvg=!1aipgqqeT=Wz2g1=A+!(q8>tyJlKV5cWjc z7eYjxb+=kV0J-PNHCj2BF=nnSYhEXf1R2zOE5hA&q0*#OO5tcHDvB6_Adx_0N-?DJ z-PpSO(m9UDn&Swl8WzP!?X4J_}CFpL$|kV?W+imAL!hWagB0C^zB*Yl&z zPy7h6$QCJ9!dG_t6NFemM7caKLjGxilhl`d`MbOnhW!yQ!6ni!0>v=?3<22mg(Kr% zjogEK9Hqbx%C%|+r}FYK*8=KVV9`G3aVq(t=^*yQLL+D+$HOVYhzP<`psV#Qi|ik} zaWwDci(YG+>cmZry80Iynzy_G1I~yr@a1IiWqH^-Sqwcx2OZ;#ng&k#%v8EeTOB5P zZKmxOB06m(dmW?MZ(!==3;k9o(TaKrkJK z{QGxYvV%%V7#`Zs@1ZuGMR6AROKdH0KmTCP?y*O`MWf>uJ~c3iM5(~d>HI}qsE|J) zi!mfDMKGpcA&0tS|bIf0-mXzhGxYmY$S(%@hpC~ydB^_bN>O^Z7%NFNORzVgm z#;Z^^oeQtH#ONuMUl%;TcmdhNKTyv z{UjrH?rxfw8wAVNG12!$_E!D~$x$6Ppeuv+*tVu4d^r(?)l|X##SMV5H9BZ?@!?Hp zzCb_3Hv(HMDuV=jfiF{9TxEh0Jw&NkMXExpgWA7mCu)kU5j|Cxfxl+7uq_SOSUNp2 z(+QkG1<1eOvdAHkZ4TzSM zI-7_RWUofP_TqQp54fxDLs#S)Jron$FiE2E&;+G#Pl}6`U$)6E%?T>gDXpQMToA}V4!u?jQ+ z1`q&4yBF}Ofw(bijb~Q&M3HYJ+kntr>Y5jEa|6+;RmpxZ z8YMjfj&2{wM`BMAAr!AupTL%WhI23+5UkC&gF*@xkq*Z%JS1Rs{w*gRt#sPwrD}Gc z9Rxsg*9OaUxWT<#y@_TZuTs<*8u|Wm(C{&=x$>WOR=NZiTeHXkUCo~Al^;ohPz(8k zYP?>Xt^~g}99q>9s!W?V*agKLCfY5sC9!PC(}{|qWKOGcW)uN3Ac$B8NJ||?^$Qyt z0jsi#4$smg)*W_7qwFuikt?2#w4-uUk*SMHHBdljkU}B)+g+#_fxZwlEugd;VITXryI-oJRFTT`AEW{?QGAGH*%{O zZW^ua=wQ1$ylb&G?BOC~9}x#uyq1Aq`7{#6GYAwyu|63M>XOvLtjyPBDZF=Zg|7nRSLu|aS!;V+Tcpl&(<_PFs4m6Ez>iU zWPiHg&9_oIM*90a@#=DJb${KytV{uC7-#4Wclx6a|Bhh~0(juC-|Z`_V97|o*YVYd z*uwfOQ&F-HDL8w&3QDs0;rb$lX(H2;8_zkUq4v?jovMkxxBP+x0_%A0U-Q_n;OY6< zH5uh)ag-w<{esPyC_!1_=H+>34MX7@rM*{hdtu1af6=D z60c;eWI;iQV&p!W=Sp%!40V&Cn%(_1Dmq5gyy1_8d>M{TTn$q@0g@kLa4;5cQ%<7Ml6CVl+YdEA(#Ma- zEkX1!h^D(##CitB6w0rzEc9n%F687ZDxKdk>gArNXi3)^#X`KF4~Wa5`aq~gh-Qi%g=>Yt-s86RkFk~`CD zQHD_^%ExXp);4$!^oyMJaV_zUAp?e7`a<~ve}<{mdQ08dlyT1lrP1tf502X6@n}T9 zQw{+TKlskywl)6oIM6?1sHz?GRjL?e!iAlrE9*xSCV-(LaFU?a;*1Skz>0TTT8#cZy+PS6zTlY<7ZzbuEmG9g0S=}gt2^$55saD|!m1=` zGA>$E@SAH$hW!OzyG}6@SmX#RmXir2%jvCCP*$hANBQA*v+7KcnfqN2yV5zx>c5=d z6AWPTqXwALci1LTA5==~$OZ^lc2?4m2dNgb-9J&C$+a7@Dpu=LMsf=w!j;+qq=;dt zq31LCss0tuLA$xGYnFj=7&7Tf#joAeB~^9~5rm69`=*4=aS!*qCss|mjXe7HPN8>) zV(7wh!JA7zKWX)qFzX7i4of1!FH@me{Hm-s@MoF$`yP6VYbz<tjg9FI8EW(QYw2f4g2%Z!I6UHv9B(@ZHqoT8B_YHPw5 zSzveT-CG6g_b<4MwT8bCQyw)L?jDh(d2R%yVm>TUJv!CmAQ_9)<2ud(OZcbb)n*xQ z+Moy{%7Jn01}$4;EBee_V7*bwwi)&Z6aJTGt!+KLN*t(o=wE22otuRWiG&l=Fqq>R z+08DQJ<}fU_bVV?ECswmvPv$;VY=|^doOx~r3eN7z@)e^ni0S3DjcVZ50!Lz*G8+g z-g?UKry!aHAIQW_?`1Cz2S5Vw0ODPxeXc4Uqi!0hCl#`@v35z_!^ji1kwM#7vrc3lPmvd`^tq4q(fteY$y9>^c3p zr@a|)G(c|8E`{J;ktz_S1AoAuuqHDdGja(HvW5vFfM|+cku^P{St{RLm$4&EZPIuQ z#NR+hcG=yw*Y8GlK4c&19NJz0SJ2}P)C1F;FZa_gF*!CkG6AI>J+=fY8ax>|i}^01 zIt@cC&QE-C2bL5tqeBG%fTGwR0&fGcNc;m2pL$zXzn~m?E|dqCGLW`{wLZW_gvA?= z{_yJASZqDv_lGZiLH7@&X+u!dB6;1lbA>2d+br_H_smjyBVZmjPAPe#WF32qCUP6 z0~+>2;f!&%ow{1?$(X=08%hp?qa%4!wOWG(dyPXPwE2F%vsOi$;`JPgMNs)uo8L|5 zg!+GHF@Z85k5bDab1Vbkx4jEQHebGGZ8-dY9ul^+ckhS4v*`sdf9B}_J&joSZ4yRF zt9ko|b`@U~*-h(+(&)#IzsFef;R^9ejtXKACAVlD4rl4wzW*Pe)3>UQH5dX2hyV!) zi1&YwOmj7Jaiw=O{-4~mQcYvU0|}(Bd_!iL6~`fgXukDxIgd0$E%z;{$4-ds|>l&PWp~U zW*av61i`v!Mt@<*H1&4wVpk^6?&&mjj$>p_ibH?@EmXm~M@g+Pot&N|VMKick|oxx zf_>@i116p}RJIb)j-oR>wi3b8mm-T`b3$sg2-?&ceY^h>e)1pK2&?h7#16Qi4@ zFH(r-z@e=A$;SEbTqCIwrNcL?nc``rEo7!DBr+RQ!a7M(R738iikwj26mx4T5n&nI zN-{L#>tHd{C;N_=-I$SJIm%{)Lz(BOOI;_y0`o1r5i^9EHvbjVsr9T(Ii5qf;{($n zt3jDI%SW>&?cru(Lm6;K(4BbW3 z1lXcG>DCqp$7(;w&5PBkI5HSVVIRjit&MFj}}^HV|*UYjQf|u9%@mW3!Vg#s-HLp z0yQJgXPCfwpaY=q=?^!*mM52ACd)NgdJ~p9?B3;gPOSRky06TYa+MgiLsZtnp$LkG zEUnP>Z+71cJZ!NvGW>h%w#vqs^yVK%wg@@=y3;3|o2R}yB!Vq7Y=_%PQo4BE3a!}_ z!^aT=OqA5;FbvZcATG%SO+vawcMq3UgxgKQS6t|L8Z=wp9ElB`Md)M9l`~3r%j3`S}{wOsf6smmk5~YU~aMyFHLxO0CM~Qn@kD==l@K+8%oo+W}gN_vbA-g8#lXYFxiI zS8+5ErcZ+2v?x_x>^Elp?olEXv(Q$&=&k$Xa*``s+3Q}Fu;^HIR-mU9WFHDNs#PB6 zUY|cK^kygZP{rGHFeOu|0L3he((2Xd@TR$n=8+U$%6nYGdTDwtT7_W-GGJC)Zpk~r z=~#<1D|#t@SN3 zcz37KMC$8A;hl=q?_{TdzUSIS|4Jz69*~sL(XT__;mVUo2{m2_f3;mo z(crITBB$cnb3!nZ4E|TD(2qk&2;sF^)!H{ATRjH9v1WLAiI*YM;1-~sH;La>xx>x$0gGy zBXvTw-i`9!c5Ikjw%-txt3IPvIQwNKtt*SMAG#OJg!N z0OI6pkYuo1xqNkl(3?>k&t7pA|FQt5(S$dl;#k)4oN4TqpwG9FS8|6HyyK^!rm%Ep8MJ5wI9K5SC3qzpFqDZa6oBLUx#_BEn7 z$C^hGwKO4WRblBCOq3Q_{^yP4|$BLraz%Q3OnQ5*Vg06*7L}g_P%gDRd&8#HVC85x zBkauygt1DanS~T!X3c)7;DJ59Dhc|e`%p)6x<80VJ)6Bc{e3X%(Vvc9&f%r-4lrdb zxhi@<5A2&4sGdH-@QJeig8ZLY(0EBlJ&%7H_vareneYEYuL7dTeOC)RAWPvgF8!lm2N|tK&GHPPak4gljT5i&d6S3D8$~?lLxtF| zll66+L&)2ln>X07#b@L8W3<=KXy_jyt-W)CB9`>bYheL6<_;xeN0K3ZD*0^q0hR@v_szBGFi~tHL4)!7&FY94bv+bE_
kibsBs$T2Ss_WQk4Zq~4-1j72_Wo5~MDRN;`?4%?{0 zcI~i3cReU0$&-M8oaE7|8oBCLI@>1s4ea9*v8ZsjU!@w-_Rm2lp+$*68v-r452gEy zUETT`ef*r~g;tG^mL1 z;v=XvpQED7E9sbUvsCo=xW&QCD~qGM+G4Hv3J>nmB8gx|@8WR1124R=^kR}YgQs-S zyqVyR+lw;wMjX-QBn_~FE)pD96GWXlBSV--GV5^n_86x0elU6jPl_3YV2_Ylitl5Qyxh#+2t<%m?7QJJkrgNDlx6-AiBvoI0rZx?&fRFQX^CK@CC zSU3?x`dXPhhPB`@RXIc7NOB>QAP;w?#D*(r&37si@a7miSMv!)U5^yX>$k~s0i!P> z_eEC>dfwwpy}90|@xAy_bGW02EB@?%h)5YM^tdN`l7)fKM684u( zUSfj-MG$q2m`MO67{TWuN9F`^0HN_e17Bo(X=IT!-VKm4>vrWS>?u2khBy-r%Be|k z9f4*LpDnu=$>crUQ5#OdoO!vnV|d#;p(e){aGE3{B*aN_AJ61PLIOTG+DI~Y8SGd7 zo0wB!_0^4=H&-9Y#8GlJ_?7cr3o*%ZGGdss$GUj;#+9ePf@GTZGI867Hje*bxBS_Q zv{_Z>nXrqHsxg%DouWt~Tz4t*+v=(kBu6gkuwx?ZPTvkr-^*TK2G`nk#Huz&fGqnY zYT3`WxNTwUM5vDQIm;bduhz2lifZj|;{@6pD<3}|3+zt2FTX=XXc>q`ac zRxd)AZCo0LuN-I|8hT_GZhE2Q?SJJ};L&qpP%O-}>QxfP3{~}j54#&a1Ft{$?ztM8 zJQz^tg7VF`_KanbwEj(3qhW)voqPzFEyu>LDok;3%Q%UHcYzWmS1y%Ws;Sx1b|M#Fwmt7otlKM_`-) zKS^^88#$a~A0Rf6Isx43I-D=rUZJ#eYp@EqC(iED=l6nEi~1hPO}$$!S5GHP%b<|l z`=!%*UL|Fb=L`nE(IHDyYI!@Tfz_R7?;?+QH+3b)ek^8}?(^3CfVN}XhI7kZlS|d! z2{(*!F7!d1uyz;!L=Fd8{FT=J-BSI@OQ!PJk!b8eu5_d-3%N^K0Zd65=jh{i&eulw zts@x40O**nF>Vy%)-NkaS2y+{<0FAJY?GSnfHUkD$tVWX*I~i26MlgD6EWAd^l15~ zPYa{+@<-jZeXEkVD)?T+kTEasDrD-PL1Uf2rcr8-hQpP}Eik`Rbdm9Kk#ptc0IKuT zfJ&X*S3+qMmZ0fhSgh-te&KmDC0o8Xd&XZQ3BV)hdg91(BS3sQ54CSqPH%b_t- z?7z$9364p)chl7nd+cjrTYs&!_n_VaZaC*<=u;JAe?}3UpL#Dz;OF|~B%kZqwlp_o z?;&d+mH-&~*D6*R4Z1xGA&^rCYV!F)+Gt`6fAbXOFQe2;dZK>(EYWsP;aII6FIvL9 zaA_w~;tvPG@U&yViub&@XGh>E(*raYU;v324l4Z6b@~bWKb386-dw2s2ndMuFDMZ6 z|61ApyPRG6*=XWQC!c!wi?==3BsC-s^7Hf3+IpKJwawh$l32cMT?@FuR0iURrIpFB zFfHcq`X8j#drN^Vvbwx5oVemv(UAV1b8vT_wjo=NsO{^W1;QKTrgr)JY-sP?DczJ?C6XSSN!piL}BPs zSifxDZb!r8?oy`|`zvS00_unZe=OsUN({>m-8?BJgK?ab*H(gj53c>l~DU5w_&GNj(3PmFraFDUCJQ2pR^^gLEPpbbd ztFTNu@nr8xOwcW*Ji{E5hH++f!CNR}M5Jt?d#{GIdCA$$H|D=p&+l z96sWYiSm#5nnDLlwGs3MD`KGDAR&^fsIZ3@p|ru3I^`{rew_p1#sfkM;!PB5-K3Pe3XkW^X^2Hk6Dz5c$`>JmWzTdp28P7h3q`V|NMRz z^yj-mj5t43gO3*=Kma0eb==?;zvy0HEQ(j0K^or!SUN%&=I6Ck zUO3CTITyyim-`R`W_P*=_W+lQOGkr%ORR2QF78tGYJq2kSqPt#h+fsFyU)jiiH3Sd z-;a>J9b*T_rQI7Kgt_|jpE*GR)nUZmVbOpNsFTA*rysO20D@-k1!!5XM}*&HyhOJk z*VRqlUc;q>kC2$qeM4MeIN^s6=qvu|LWJ;>!p{;$!|-=N!LY}z%GFD}_lPfi1}Wg&Hj3J!jjp zT#o4H=^uSaUiFlSCtA3(ll6h^`j3Gf^v@h7Ak-k_J^f#VETgy zvBd2N=IWzhGA0eWW!Z(`>u$ezSv44Re)Yp7^m*h1h}aWaix_Wz5w6(PUc3NFuc15W z&0t*CPMuXMD@^5q^+5QdO_XPCBEQ|&^1T)oiDMbDr82lKlbdtByc zV*8ZmZ*+od!OXCub6Rj@XP;X?p1y@u@-+?kA)f#@*r>B%aLW@Q9%;h#SRi_FlPRkF zx1X2qfsWzY>p-wpM*6?5>)@TYuUes>}6={3ovT6OC3Lt@Wzp4y1WH{*1fLV3x zf~7bF3*cEB6BubQ**e0nhg>sAt`?`_JFK@48j9&hDyw+=l@Ih5b3jELv=mFh!2dHl z;TRTgsZ4oZU#}2;j?fa!?C`v2dS93f#Uacpu|#%Tube4avUvs*O7-gzI`n0t+}P0- zB)CY?&_7y=xcO1t=ilRV&O_v7|Mg^ot4pojNo7?Y-goV&yn=_nE#Va<05Lw?2UyCc z{fR0kjh!Dis`We0%k^- z0GTtcY!SMKW+^*4XNzXV-7X9@5$XVP`=$ea5}jpNKXO_HEO{)23Rs>!-!0#`b=>w9 zbnbpM@mSOW>oH*KVzKYCK5w0?i%?uOHQ3ugzPWeD2`I;*-vcdBz}?@I18%F$m;>Gz zGdenD-xq{&OqN0*0^SKZQs$I`SI1GM7Vav{%k4w_>MzuZXqkmZYEuM-ua)niff{okIWtQ z^Hyd!`%ZFf1^u=9&7@8N~AKqJVIUMd##mDoSOiK?9-Kn*DNSF~3FmqV(3yoAJEkJ5ffnv9Jk z&i~@W1c-hOVzY|62F3{E7BA+42TARWq(BqE0V}^kK680oc5Y5_#oe3c$-}G_ZR$T^ zHOk`cAsKfLZ!y((J+Eqp8BYpH1)d{I6qH;7lV7NtC7eLx={57^dgeiEEwvjzg*`yy zU7j>k=Niv*0mbUX@%ed)5E9IJz+Hd4g8g*T*qR&tpqVDe1IgO(lk20wFSBD# zkPLJ89!i+H=jA?JSX$t_1Sy9IGzZ<-vLG^2ZecWE>2f41HUT0Es7l%<=Zbdr`xemx zpp#)y(cdfyf)S{{=~(!)s-5kIqZ-)R@k%S|63{J~0*}SB6?zzUhdP93jrC?M8pa8h zj`*;XN@1xSS>jN_Qp=z}z)sk;D!rW($8jH_{efj=b~v+e3Qb+Rd%}7WpU?n@ZALJu zY@_}2&yN@#jx1R-LPNCYHztwhiknoKLm_3brRP&lx$H4llxe)SIa$#N#^y>$X(#C{=E z{k-^>{Wp*`A9#exe&yC9nl;Dp;G13JN*Gu2W#J#tKk?g!rgyJ2Fi@yE7!Fa6lgePG zB1*ba0-U(&uXnxxJ+-0FGB#$Bzg6|Hj|}!|Vy}{km>d^mlOSj!xBb56Q1VSxOzDdc z2M6C)j&rzpLqFjbF;NOOJ4GC>PC)!MayKN_3FUssyYF69PwKpsp7#BD4B$Xhj@|P^ z?Ct7$#B?u4*`9A#FNhFhUqF@UY+jAJMD7(gfG^?noxZW{NC_JOn-Kxskz8nY~k7AOe7>J z1VhvnsS?CxjDZoVWC@MUM5-76fD;OZ=0!(GBqFW&ZYN=&9YEB+pck}A(R5|LcNZjG z%V=W>%0c1eS;(UzZc16om7^}miM@kF6*1FRFqTWd1Vq$101s>iw5?`-o`Nx>%3weT zLi~m5&=t;V@av-SK9XOBO=$$=Po=hozL4QLgbJJVi6bTxJ-?QEN~dDu7NoP$v2CRc z(IBD-hsJUCeA77|(fqpNGpAI$ph^>B3lHt;N|q4!$OuAAbN-g}R1*~Uz~?TnxP+1l z72fXge0L-8=w%*?XJ#PCsii%_p;{c1BsdA1w=CYdbr=7#Y0$X_w5S$nj!>Z$`R_c%naDChJv_=b4kxocDu$ zuE55od8|;{Js?OFaF-rtGRAHfre-!*?-KwAU?K{ESoQaHDv-gcYo>K87Spcf3P`qX zmH{&Y1xn7N1(n%y3xX8gDd8UYRd5THNt4NNpP7QG5n-)GLK3*20nJKoGkMKT%XHAC zD>H9kQKS@ZkTvVAFxVTW8i&XVpaPIWQ}B-b^UcPS7Nxm{MTIso!Q7W^6preQ6*^SO z^H@saPudstu&0pVf)y93NN?(t!Qt;Zs2Z?9yih9WV)xM0WjS(P*P}cgmxHg6yg=to z6y{bJI!a+-cbqYuePxa2=hfZdBGTDJb!|PPARu_w<(gf=B)M^*a8!=HG8h4zob_5U zCei?c#0v5Na*W=G=7f{wcl3bggZUy~G07Ql!@7D#t;g6Ynwb24TT7UYgb@^A(9=Ql zJ`emj`@%s)VkuBRibjjoexJ(FnWzPO``r@8qC?`LdKNv+4i^F)djd^UqDZwh|r=zZM>0NSnCq5wrsF)Ug;c+dI~u4ueV0S z^3SIoP%hn((k<9o5#9tW)7~?wATVvp`{c;ZE|GKg!%n}Cr9Ux|V5M;8dIIS{jPVTj z@b^*ZY2z6(Dm8AU^900oBFf3Rc+gHGh~f#>Dnu|a)<-XtNQQj^Gl*i8n|8m_-;)aK zi>0~9XK_w%oJg}~8GafjrEa@-P07FnG*2ub0}4a*xj@vMS1zxs8zN@={pfp=ge}hO z5+w)j!JXI!WG|H%<_5~fZQ313mRa`gRLdiaahmvFc99;&3lG0<4x6R8cnF+VjWB?dpg+7e!MP8 zUEB1ib|pBRw8wYu=1>5Pvk~&^nV8FIT@*&&CMFumhMKkb($!%$$>=67=<*EptFLNn zIat9q6f*GL*U~5g@xfXWjneCifzdYsSxv@}(VSWpKmP*JC*ALAhEHcE_|^;I7!`og z4rf(i>4bc&l+Tz+Frg|-T7OqBXk9@D&;9Zxqz5L2pLaH_@`^^GJ5sPr9J`Gi4MB?r6zyyiJWZ+eQ1%gjL|-Hv19ps z?nnXrFQanb2@h=-FU0?pqharOGrV&2JM=_bT!$;5bog-EUF`b}fV2uWd z_Obs45R`n{#TZ+O;Kk9IuD?w-xWx9sTNY?&TJe|@xyJTJqb9TFv7c}RnLqAkF}&Z0 ziwzPHk}(H|)BA7PO2@qC=oqcb=|^yJEyf0Fdl(vykjB)sH7Z|hV%>HUH)F6w0f%bV z3y@s_fPIk97Ryh@gl}#W>-57NZ(nW#tHK{R<%3`5YcllxW{T7iZUE>Fm+`-3;LJ(v z9KV2$*7wkn*>;GSG&z;o%(P4FIJi%7pGWncm0^aELPg!cH%)_c8zv$Fi<_42dC4*f z@2(M~7NM6^#K-OCrWK8FC+(Dh8N%T3(%1NGCLg0cyK8<$b7!nV!)m1pr(Z^x@{1jt z+eVK%LL}#*;F8n*2|67ATx{bAK3y|QgG zE5YhvAiidi`~xN25=0yv9#Js8cWVWe6vRE9Q)r2TnMn6zB*`yjs!DRkHj`lF@Cr!Ht~DV_ zF$~w6(;D*C)7$)Q8@Y$ipBv?@quM-n_N%SKM3p(7*)}h9ewpYeENV-ww5ohlB@<@l z5J-{6Vb=6L#}R8%1lI zB+TE!*FgRrk`+;+lp^(#{pD=YdQ7ExF3eR|Vya9D3RYa%3UPR;={hiU(1B-g)-!Pf z&n;TCsp;>{raoFLZ#v9ua<&1&<>`CuLD z(Yg}VRxE)D@ziGeUvV4;+g`xT{yhL({v76{>a5q2o1Sg0(27SX;3HUv3z`IPvfK3& zNCknt6AnSK*r$*)-l_&2r4-{DhI7oyInW~*azht%Z0>FgP!%a;*l1*5=n|hEDDUk1 z0NE=F)JGLN%A|!%EYa~SvwMK*4WDdF5+`k^Bl@snVZ@WWe{YMT!h5WKRl~FE`4HI+ z=4d;=Zf_SyEZ)qCFs|<$fI9%pR;?vcqrlm#?;m9p7J#kAZ(!99*2XT--r`^UHN z%l#3YpEm>$N6^-j39V%A75s-6NLP!n-S>FFy%9c0jD38Z=^|2k(~eaewveN+UD{PxVsDSgljm;%Iy;HIX%A@ndliN+0Y8A+qhBC z8B~!UmH$&0mhb*fO^5I5Wwug6+HnE|v7Kb)22n*2CE z77t&o8S)cKhAiTxxeUAUtCRlP6=K5`q&OVT%o440eEfYx8KY%5q^36sR$FUoUM?B) zuf-i01kzESMu~kkyRPPR18)S|w3{jkYC*IGq|P(kwHb%wpFJ>jD@W|2 z+@Oser}dB|^w4Nej4t25uf6Km$RTtoHH>Nq!j9TzWcQWWN=2%RN#Z>Od#XVjS1XAY z^PvoRR4WA`3a+vrwu{<#(;y914>Ke@hGp{o!;}cCl=*|kgAHDm6{5uzzBUljID5s& zI{3-OtZ+_R7OBIBwl16rO!F#Zi^z|IeU61L`vvdi<&@<--)9ukH_5?E_nZu^24`Bu zr_WV^+`#%7LX~4kS-#YWDh1MWeJW|R zB`=n4Gi>ztRqD6a>U^75FcR|B*J(b#M(Pcoe3I|mtKQq2Ku+hR{v@=!EoXjVv{Tc> zz1wJ7)u`iQ1{>&S)GSiamd{(J)~HTuh`3wJ@k)JT5GnN(g5cjo^|^>@d0`^L+yJgp zc`%>GEuKd=*s-gsiT-?e0Vco+*L8ghiQc6rnyjKf#@}u)52-wNBgCEGzaxz2bXwK!3|=@5WcSD}lO0A1B++vU1GrNN;1&#%KZE@8&ig#PRymVU;{UZQ zz>D2imUQrf57;gXpKpnMUR+_Mk7~Tx9p(tnBFVv;m}6oyfR;!z%+2u~`x_Xz&*1jw z8x&CuHwy7^KY?*ASBvO(FXm53ombw%qvx5}_(jh=krLkgWL=Y`;bCMTy9e_r={$6| zRPw~mG>;0d*VTUMA}bUA9KKQ$T&87yo(vYA$3yylNqw_9w5e{b$LjXcVk!p5+y-Xm zZZ~W%T>Y(^$K5JySmTBFSUzia@RoTNTWym^c#2$_o$3C_ke*Ux9~IC$jh=c zUU79RCmnE;+XF9H<%(n4Js!%N6e-Xi;jTt)9=MX!ep_!jH6PY=^E>qLeTY-8*ngGT zcz=3nYXkKZE9_M zqOE`8 zaDNlnSqcB!oi{7H6vFsg-r4}va1#{SRD4d zEQ`6dqF-C5ST6Fh^d45d`Nim&Q4eAg;b{i6&fkBE*UZA@GfF$L_qFAqAyBG7iH|d)4^S4pmS( zM7_or=;$7`3@tM+;k* za>9hKTfm8G*msx{T!o)q1EtgQ_Zed>M)r&~jJ>5EG~$a?A)euHj8f+e>XQky6bUbz zx(vM8+F0(rvYuCNIEr0}wOgi-qysOIXp;wzX@{F{$asxR!iq8CP05vYjwe@mMaIS8O%*O^NsZ2cFHjd*J%CESQ)_B$syVmBW-!Qu7OFf}5tV+YlZB(R9@ zSD=*epghwloWz+TDVo$JmnPrN(JAL$jbyT0G-@QhtaNaGFD6PXjUhzyaWtL-I&;+v z9hCOt!}?tc!!SB-jKN}0mO5{nmrQG4uX+tj+2ZOaYH%vQf>511t_&N@IF!Ke5K%Q% zZ{{pb&E7CkB?2LAlL4?~A z7#%ec@r78Y#0q^B@}2PY&$txub?pgQ6D&>rRIn`8i*}Bt#s?WU7z0`uO-zxV5g7qt z3ORTXc--XO{wTCf^c;a^m(-39O2uN#tq@8+UB^+(V~=H}*}OcJiAVYzZ!;FE?EE=9 zbloMv06c{$%b!PJydMDbxOPUVY~tfCdr2zKxI!5KR3iu-q|<f+sv?`bv|Hqs_E8P^md^!x>16mV}$pdVtHyP ztElDA;Lh8b)z2#(*9VYotAlM)^4@Ri1}UVykw$i|Z&`(rX52@){8VQJT>tH9du)`dGKn*RzHENRseF&;6;z_#Fzwc-a% zFisbvV+M7DAR$<&YlWr!^rfc#bka3$)ObH==I@Nn$bxg>cc;a&RHvp=nujhMAD;T- zIt3#~c?`f}mH^8HN3J2?EO#Wqb+Y-ak)zvaIf*|weCw{}tpz-Ybl!`aP98IisoAVI z9YA7YCck%Zt{>L0uZ@+6wa2&yrzo}4lDwx#qcbSekjmtE+wF&0VCe;miyO}X%^7`` zL78D05~C^b9iC5Dlx~_T zSd#F-NS>Qk_^0|o<|K${rEybo>jd{&iWQFNNnn@jjiAk=w2+>uaQW0$w#)o>#vT)& z+aCo!I9&rHI@ML#Uw1)EH;A}~X+$o8f&!ka=Dy5eslksdzBDnjT zH@t<-8m~+$ElJ6P7%yQrp^o7at>=_cgC}kgXPl5(quRtP$k&{KE48E4fuJB!|iJbr#^=FZ)xxo7n>X>%(H+oLoM{COQ z-4Tis6ydG(+>TC9spqZat&uB^%18~}S0Q0;?$B^$qwa2hZ#ALgx>?GZWjsvQH1vCR zJ%+*{J{Qd_AWM4X@(#kRZ?R8-L{sg*vldU$2ZkCk^F;?E7)dcwtFYCv)}Wkb{COqP zke5>t`@^bmA82ixaf&1c5}zCmaM%3<7>x_m++8i6UrYa7=aDTqXL!fpFaEl*B3i(o}hmB5q z0Z?NlziSuSOFF;Sq;PslkbF%OnEh*sY+AMOSC?3T zOItWKF4b7Pn@%vI41Yq(c8jhs&4G*p^FpkDIrVx*LqCa!zLe`pY2{sVtg7lZJFoAu zmEj~P#0^aJl<$ZMea2<8oi_tk${8{VFNS$xL^J$f0B%5$zd@t|KR8BLJZ;vB+Koqw zTK@T3fy+PjVpoppdUMm#4EUF}DiXVfnS-Vg*3N-1S~`=TDP}?k+nAl4Ae0GZx9{ja z9L*?!tDPbOaV_Q*1IFkC?$%%0_m%dHSZB*E>!Uepf(WD}^G%w0opo_s#|nS1n z{U1N}_s)Wkr~Uol;NP z+&xL^09aCgj50n1QVGO8P^%OhOA(#~Yw)x&g>)w3Fhm%TK04v+TlcX?FyODF$TK&Hi} zn_E$4K`K%^f$q2s(gm?iiMj|gNua(2EB@*^Fk&ynMHuNKN(<1T(!VQV|U6cHEUWxZa|e3195Dr;1*gLbORA9LXI5eZ8$#(Y!ArGmom6e|>VijjX(Fds zEyK%bZK3$7txKt_$z%0e(!Wz0Wb(rUrEAU?98RITTxUu?gFiAqD>6N5wkX0I6?sk) zHM-8yB*lpVHUA+P;n}X+P0~B^$JH*gr*i#?!GpR#;E7w{lbDltU}+EX^T(qNb&k>4 zQeCkl-4Bu@YN7fJqgkp6?qD>QjMoxR?!I#S-E9{4(q-dPn?eB_`rZ+Nr)|(qrr`z9 zaGU}Ac``swA?!%EkY{BEYZb*=4ZUEy8C_$7Bh02jNqCUXn7HH5^INi2%YA)5XWuZq znjZgop3m45s?!4eR*!kN(?LNos_|znX z3v;vb_jq$n)g%MF{4we1%uMpqIoC;%=r3LzL)lF#(`N)nC+`M_eUg@v?LEX&jGNoP zr&>kY0pGYEu#LEPJRHcYHlLHA0|u1+%61Ao09QSq4!^OeHo#kyw&V#SkB|9BC~lD{ZC>xkKvaxo6As| z;fU4FQsld)X2v-_3+RT(vYhj95#Qm28IDqVO3zX=&+hCRm~FMWZJFsYcVh6f<*=c? zno$`MAy2S2$8Y9@Rfn#_|9oTZq%SYbOCi6SrJD~=zjPvfJ-BbTAO#rOl@hr3km z2{T~8%#!%I2X!5Owzc9|7sdp7Gp*sCCs^HrBCl?zsL%SvK(LsZxX%;Y=>%QPoQuul zLqgDrmZCHa;|S9`T6Z(tNRtP;wh3Mgb2%{RY(KzNH#mMT z^C^kGfV?4Hq=EuVvIcRd(@3Zic$3~~!p==jCfp+bfKZ|Y1R6^wR9UE^j_U-fRK$Y3qJyI1HDgpRw~PWee+hp z?kFs{=IG}L1g8d3_$mGczdT(3d28MJ%4~?U3=V_&gf`hfP!kXXal3pf5gDeq}re)&>-Z~W358Xx>x!?xdQSKsQ;5|>|ihA_0#OZFkj+>Da|&J1xr z>>}}P3(0b{S)L*C7+RDhM>XHMP#9870A&#!|EIGHvn%LrZSW8|b| z3@4LBVXBvaXe*tZ%Y(-xG6{lQ#!xgBo4fg4IBha?R9F81vA|U6h&+pJKp_|Frbp!U+#3%2r)RI&U4k>IQsTHV9)-g3SgIes-r9mA z(~Qk4GcI+@AFY#-#4SWMfisd62DqMIMZS>+grdXuU-Ev zOo9ta0n&SthCq3)M3bBPY9VhdW`}n1vA*YKV==pmq2CK-2&wC_0sf_}0Xhjrf$43el^GGnzSA4S zogs}!it7FT&hdk6Q_~J_fm$_meJzN__2H2Po#(y1kH4SEpxOD~4aUn;(6X{>i!>$t zqV3eleNiC(Q$y?84I*EV8w$pxlQB zO?ukVe;RA6DVN6Y^`AU2C&fyYiub)LNzvwp52vyiVb@c_d;lA}O|5bpzr`W!fPC&L zj5YTvMmm(DJ+p=|>_$Z^lKX{kDW3$k(e!Dn0=>)^dSvrMlt>R|VO7nYD<}ec~|X)lhJ$v zL&HQ7x8Vfe8u4bZvU zs-jJkz&l^HY%ZFLo-9#zK{?DZ-t=>{Qh%mpWsj^!eoUuCXRc~SDm{N(I6_YXIYi?x zZ+OrqrsU;IcxsPV@aiXc@XJqIztB0#%41Cd{G87tW<*Yl8%`*#^Ey>yNh2>HnGurP zJM@bn2_PLjvm%~bzx)Kx>hR1e@U$&%dgHMPc340xXOarEDkHz8k$0!8fVr5Q04fm; zPoVTQ;pL_}q$_5Q52bWA9Xi6n2|&e84nH$tWXnV#^b4IG%~T@j9n-{{wNkSiN^`U0 zbWqIYx8^QEImp1d&h64bHQjn&a~-x4j>a5Y(SY=}`cYBcRlwnmhW+A&(tlG^m$LOV z!zNyW!zHv59wNHfBqf5v8v^&@g))CX3Kwbh7J#2*-dKWSZot`WBAFvG z!Y0XMvI?X1aXfw{SWwW;U6i@7V1J7-DSV7sYado&N!=^_+1Y}h$Bc|xS|-&0w|C=4 zr)Hg>9eZc6Y+%e|D$f+-{)}0vB21;qc}J^-^#wcH&S)K!g@Yp#+OqWh6_20osx3?q zoAIwZdeU_#N|r!DhFYdJI5?&w{7z&VcCq=Ep?u@AVpe$J%VQd^P@!qNFtr`*BVFFX zs1FWNDr$RwaD5}NNH-sbjqN|d5?NyowpQb4JU0a!w70}SR1Q8x<-Xs9&>xd-kE=5A zkv9?B!H87oPm}o9-;Q3Dg z{}=kE!i@oKl;cQ>e%yvrx6X#Po$vAhur>WcP}!%Ux+?OD`j=xqt*i9mYGTX2tW&dO z3;jmViaS z+3w1=RbqC?W$th*S zFQP`saFHtAK#Zd^77}87CWLr!AFzoh4e*H($w)Br{4uvrOgVby6oxn71x@?Alc3*e z6*OHCPF;8yMc~$DlA(Lguxe47VAUU|Wc){9l*2fIa~fX5;5o|AqK=8-HG}EQ;P{ng zI!;cloaEFmUrJYY8$FmnKg>u@jU}Xc;N3uw__@K_l5y4qplwFLY2&5F=Ds(*zV*-x z-RQ>)y4zf>yO&;fMEXKs^lU*#FBf-Y^aq|HRSm-kigku-m1-18=YL55hcmvOn8lDBigEE$v(+qa1$ONZG~>`xuu< zlRtP<(-HLrN|-|F5syimk&JT!Qk>KpJ^RHij%ewUMG#_4bKLc#rh|6dXB!#flCKF3 z<0nXm%#55*(36LJKhe8Diy2oAO2S3Tkj;f$;(SeVIX3?IN45FJ%7)!G|G`%7UG?&f zBNgB!|E1sl@sAA#Bw_BDb{$&3qOT~%j7xT>x1e#Owf7Q`O(HaNVQv?X4Ta5oR?KtP zsz;YaG>d?B!zwg}kd_hTyG=?!;D|wb+NP(b8ED)hRJ=XXg)C>QsxDNc*r?{imz=V~ zk+?20%w^S>n6Cc#M`2%LfzoCWv_0@U_8WrUHXPhmjuc&W;W8V#+*sh_8ima`mpNJ4 znN^`N-DRG;3@n9m%>4#$o|OMdc-w@uqyMSHJ1V@u0|0qEhp?>252Sf>HlZYQ79e%GaEJ*O5d<;q_@<=^X%HY%@uBSRk{cHOSSQz^``J34@iMBY#@qck%478Q znI{Z)EFHhf=a=x0_Nk>$VZ^M1T#`+nNrFpeG)Z%Fv#OI1z}ZteWZ@Sw^TygmqjVPzlE`u0kdNPR?>dsPP#S=DApC;u1dH0De4)R8;@4y& zW3!YMBxH%(F@I$4AKXj}4G#~>5<<98O-VeHa&(2hE7W_0AvDv7nKqD_&^fnnVNV7$ z+Gd8hPtsQrP?HYn#l~dn&1&9wT7*55_#ff{1#JpybJIDM5b8$HWTj5bjOfJli^*YA zq|AV{5AlL07Mg=TKC$HmWaY_{)sfL8jO2H6G}Z88UXUI4+?)i`T9`_PxT7jrV8_g& zZ#FehcHjD|f`9l9p3IeAr2wjTKNiZxl;0^W>;s9RJiqTm%KXjx56yM&QG z#?47pq2fCT(=snAXttr4AKv<{e*M)G3RTtoFps~FXiFZTt*MeSTIt~w{~+awB-li; z)=6mz<$nDxd~l1z6pG~N`Z>lBY%E#??ybLebvrWA<&n-!NvBCFSS&SQ(6JPGO?T|@ z3xm~E#LH#<4%Q1C?6!8+92O~j4XUbn!j`bYqmo6|Uq+?Qai{EZ)dXY2FRUy}BM+h8 zc>K7&>HK0Z2P%58#O+Ci4-j&oGUsiZyb&`uQlGj+EdG#@RY?1dZ^+IHuUwu*CY}HY_dMn&QdVfR?HSoWNVfTavpn;>+H1FwKnf?MTRP`H}8(J zY&JPFzHL@j;frm_PAJJQGtkWA&*GKw7kgtGl7$1)F;DaxHP&*cu9|Q(Jl|EXQNW?&>lSU$>y35&0N-zt;hr9A#(4RXVDn6GZbr#iPb-}| zHOZW`@5Nn^+bg;jz#Ri1xQ02xjiFd(tN^RO6|Y^yGFf+*A*QeprQ-M zXG*W-H)bHZXc6u_-(#r(V$fAQ{GOmRWZkYi9mwfqI#Vt4E}lzK%v%&U3ks6*73$;a`ltpCa245teo2^;&K}& z0rcZq=nP)1w!!f=tIBRi#;w&Yk||In@;j8$2&G=5X&zHJnYLa)TdKF$6nwhGlO;f-kf)SqLF0BEZ6^5jfE#oXx)PA+6C9p8pmu!8X>!Sqz32~TjyN=mW7^CbZnnhmjpPaut?87%E?M$O!SF7c}C$pZ@o+wh{IwTbq^^3-N zVFv9ym$>sOjJYyTk{I;bJ(Bg9vm2zSIGPF;UpH>>o~CkulJBrDdAwLP!9P1|rp+5P z-cq68)9{Wi`${U!fymE~C_bV26SSEpC^CZ1iaLn%^=lJRtK*_1QV0buO(5{gBx2vT z#Aqxijd^+{gfYE>e;7EQuAo_Bf# zRB}*Y)`v$SD7mL(Tjd*kya|_TJDdywfX6;@Q6my}XS4T|ZvMTpS{n0%sQbX34<_A_GY zyv)@uLzfS7T6UJD-D9K~Ee)1o_V?Fb@SKhLEeP5-)L^$My>d?iOXS0se`N}q{pRaP z=p9DgbLNUv)KOcD$yi(T54Dr)3X{O!*bMM1>p)-lexgi-z1t~o)Aas{CT#k7njO2; z6w?MhvMZa=s5&K*$wajJo+Mvb+x`l~SYgm|wQCKltrb4Y>OS*Bb05J7d^@t38Tgy8 zVTg*E`kLmeFh)g}70eOl(ICk&;0q7=|9|j`7c%|`RynQ+zjxW>*cYGq_EXn={`$!+ zm+RktM@~A)YJrhsNb>6yS-`#AUbP|`>pUK@L?QYH6{01>!KSZEP1|C{>8@B&ZCk3T zp}GVu7^*yz^YN1e%QBAPZ@z+S$`krktyi-kFXx~|Qswy>%HaGo#;Rr^dpAiI*BX{u zoq6i@>YA7?&0l%hRxrqi^9z%i2JHod9FC1cT^tRq2BvZ=hiIjjCIeJ7c3|sjx)m-3 zNfeDIoI#Xxc<3s70P8w@piEkzfpWG{FRP>fF+q?LzyKOhqYHEz1b>9rFWw^Hu6@;0 zcWL>JzjE?0;{B-ptSUXDZJ@s@xtuD$*>iJgMODb_7G^jyR%>t9KJ8| zP}`pxLgn$(Q{0rCA!8u`zCmY?yqbZOue+J@e05p5a-CbvT25Fx>9}Z$e5KpkFVUa6 z2JzOiZO54Z*v}^qDF2&G-&=B#OfRL+pSFG>4~(5PpB4fD9kZon@RvCn_TCl&ey_9*na^}AA~RZ5ff8;|O7JMwQn zHjm~0`IAOglYh;TJpy0;?-tVF?tj*N zKj&bdI^)Z;&Q{+fRMnzcdQ7KN`XK*s+8>@Dp8ZYqNzvWD*o)M>GzZc|K4q|_dzhzr zA(EQ5V$(?q3d?m?$g2Nus=hD}9#u=P&VC5a24`57f@8qoOqSl|YOk;Bt$}(p#iD+S z9WI^3*A{tJg~)C7C(NUSiXEVW#vp-vn5H+mnolJN^)^g4F&qmM?@09}&&e3S5;`j^ z@}h6J$5Q+0E?S4v7wWCkFeiT*y8Xtp8aa1(xKd~c1+y_2ifH2~39NHJ4Yk)84`~0> z$?3kjIhcf3=#t1~&um;*X zx1B2ak*$s(1((B755}HFNL4nuJpz~|H6xVHXIRRIQ&~R(j-DsP4dDO)I>tT%gehL5 zN2d$Dh#AgHFphJ}wX>d;M+qc%7FFSO}-F$ne66z2Fs!e@CQo{Eqn>Et@PZ#K5>8|tMg zRl}tC5Zw=w8SA*cwi+p6ZK`J%fJxhPK+uWv$RrMbjJg~j9 z7@OH$`W)E2UWQHcI}mukZ>@yVbrwAfiN0Nm)bG%XZ(}vIFiQD3u=?FntiA=TzV)%% zyH2O*TrLSrDEls&m60zg8YRTvF~cn$UfgPL_&KdR+XBn6(LElncn$^O2;ek}uVOs< zIIwixVKRMQ$Coo*h$G@$6qsl#VX$j)LYj^lH)4I5-o3+w5c=VUhzKNV;zkddR)A@6 z!I_IT=-(HrxsYH95sCyUH`v{Ms}eW%T_8G)p#AHQPWbuT-R3*WyvsqE5Tu_)W9g4-tDQqd>>@<{!s0o@i?4fp8IM+xsYZwvC-r0;|-JRMS*G#TER1M%5)@!hG{!2w&d1$w#0 z7a;W7Md)=Iq3vpfw(kG1rGE96@(bHb8)Z6^&+L9nM!0pqhX9uh6afmvl}GrkJHl_v zBYgebBmBpatiLMB7^LGcL(dlw?RTd0-<2u$?Q;+C|KTY(Sa}KvrmxlK*4u(}jbi0B zitoBh9rc_XZYU!^x=cknorl;mUSS0`I3-KrYZOv$K{2y8sUC=Lv8};w&8>6ZYCyea z4cKf(O)<>1)!xGu;MBsXO5Clu8`l0Y>NLBh`~^D2h&lDs_8rgWGu;IGhRyQ|FETM> zrp?ka&q0Mq=aVsSF1Hsp86#>V$<-vP*~B<->3YBahb;{A1SOAC>lRKyvSKF`uEqd77o4aovX`B`5*A)SyH~m7>Ba zgqBSWlEf|ryftk!DFC7wTrBXFRK?>6DU!XOt#^- zuWK6qjv5}u$^4!^|7a9*K$91iu9-ZaOg34nQNmnjEFHgPGQSPD*fJ{aI?*jfhEsSL zAF?O_n7lhK%_4DfxKTaR9815dO$zm)j8Pd zN(z?d@|bryMo^od!kqFT!kWQ2Dnkl8HzaA_g?T(u$9R62sE?B{iTndisaABs4I#&> z%5}n#{nuE$F?+s(5omuKCd>*#D_2+P&n4X`$@I!l+^X-E;y zpnQ9j$z97?b#A=}v$c_wMt53Du**goGMXo3hq#}Pa7Q0iC)<5WyZgBc&FJuR*&#B zO)BH~%Jca@HF(bt^sHrwSSj-%~AiM02lp3t6BBJbsc9pgHp{(F&e2$$SO>v^n<1wsfMA zmELtZ^RNzx3blFC=>>y|FehBD@(Er90xkF@fjB{tE2no(h!w#pZOjJD0H_cH2_)gu zNKZsK8l~A-G}ObrVDIctAN!P6J^37GX@aQ0u`i3Msvh?7{`lM=QtrnRn^Qb5?@Xa% z=2e>M%)Dv@rwr_Ml8(Yjq=$ACj!uT^N6NB6J?!MS@eT;xac{HKq#v(!&Nku%uL0c*DifajTNhVS@rYK=az9kRUq74=(rnM(P zn5vQG6~QSinm%-h`Hl;Vr&R4!d!5tKuf|*s?#vEO$XSjGC`2EMMZdq`93}86rhst6b)*P zf8TmNt~vK}n?W-Bgf6eIo2H?6wc>wu+~m~B>hH6bBs#?zmW5{zz zy8`m!*-5|8r*Pz<`-0yVWAtlX!~}Lw)z&j^SH?tp)0&{Bvtfr zbgQ5A*R93GUDIa{Z*UqFvi91P?={3XraUTUPF~-Ne1trtOLo1sHrF9RKo_Js4i7p_ z<y#MsVYEP7fNviTJ?vz3Jre# zvLJ;0nN*xGovBKx)6qpQgWaI2iq>m5nl!!QDJ^4I_prFOm1p30Eb_&5XKXn-RERe4 zJIRf13q`ZF;pJPV{f^|jq`FTz&JW8oepzL4wg3RWHYWS$bUkQEGB=&l9*pw~>S(r! zZUGZ4D5--y#Fy`VnqEz!&9f+F&~%pliVgH?MuqJ2tJNwa3Zxf= zBsMeYK#Lc^T`V0TG&Y0NR(Wh{9@aD} zfG!yHO>6X0`#C|Ewo-#-IT^V;Hcla%wR{%?tvA{Coi+P=w`+fwz=AHQvf=DHAk3&v zThQEUwVC;YSqwPL!rLi7j3(hU$3y_|7@ttFYjhl02W`>s=W&jvA=)1Snyw$=jtN-Ff6bS1ZiQaHCwl|9{ran-!hB@}neg^T zLrfVx#K}_}X-=r6&>`rAvr4%Z+kLZ!#90a(6)Yd7WRZ+yxT4(~y)*LG}sl-%f!$T9fCA6>1!I11_H&~_Du#4HJ%-58o znF{S$Z~JK6E+*W;s#q>NkYvzXEIGMP#_~OT`2xd2*A*l@jnF`3_^@J=yT6?T5nISs z&8F@1y@#n|zW)IoA3$t-3&HKJ(9+*(%&ug3|7bpo?hn(^4Vs#6nlFkhe~a$}_ZaKc zF>;Z>;uN|#y;*QLj{()~1gZo$kGk*$fx%=602MA|<)?Vv)308zB!c+kiJ8L(=$C$ z2sYBBF^+RI!j2m_OAQJT%=vez>?D7os=~j)t}sq-gFMoW2vPYp)?XR5qCpkYpFH?y z8hgdiy}{d|y90N}Z3oJ~(@2#!QjAEvi9ydDH=a6XJZBb%{K)a5ovC`bq*wBQlo=Y} z3}ELpay_U9hP?z73!}$QtgIgajp7NlMfX)bSU5@GLDs)Sz+qs0V5&Na9)vJp33?`L zV2;JZqWhR)V`+irS`UOrpd%KfcZ2t;24!(;6kgh?Xstl36GG#eNcLEoQ4<+U+hrmo zrcL!GX2=_i_1>+o8r#dV@S&IgK(CtRF*jd?_(kg{0`!aT8eIdlNlifg!++oyLrqzf z32kf90o6|v*^>1j&HBvOwN_kbXSAEB^AII`!^*`*@$%cF!a@P)<|19#$z%I?To+UX zarGX2J}u`{u7W5mEQHV_cOU#qPHu6 z3W2rISsC4!^OUYgZ>PZAnY}!Lk0#I?`>=LaU^cr)p6s7A|2&3saTfix)m2APcEz`` zc)fdNIm?x!DaLQ2>?M!XTO3w2ehizkEcjn$eI{nD6RrOPS=MDTF-@_h`V;I-hp?|T z%bK_g=7qY04|BiXEItZQaWJM!r(CwU1yeI!!n;^6JC+({-d9-N+Zr)VA5tDkTPhtG zF!NsfO}8+q-=6A2xe)x<>oi#e4E>S$QNeU(T9oQS3XSQ8u0egQn+{2W0@^K~}Z=DOa z2VGWHg4A%dl(M?4M4R-yA|DWCigR`(Lxtau*aeMAfXJUszdRTI;z0VU|^A}id!k0#Y@{%g}J@exfJkP?s!td6C5H; z9x*0jh0Ab8L0@`+RormE-^frO%M;Q=poj8Ey8Gyr=>H+i2|eq~lvli*yKN;-+Xc>4bK$SydUZ!$anV*9cPYTFLd3JSSb1G#@v(el zHh>C@Dle>7MatP(3Mknd)1&y>OU!u4H=}IKHrK9v z7mV)%Y@7wnB)Ss?>EN*UJ{b0X=${7m?v!e=QfHW6FwGY9r|4t$t4GcG2E&a3#5l!> zd9DV{poG>XWYlFGO~!2-(hr9qgz!1$P-LuLpojH$9+yFMh|DXgI$37L_cK~f>?Ga8 zjOm+9WjtSDp^^-}m+@Z5(HUT;i)QCj2l5#y7-RIt{CeOBY#%^5@Ox;3%-I9M+)bf+ z$yZ4fdy1CH3sh}Ut;X6aKt(jiWyTWg^s)SQ37}W{COUpg=Se(ca3B^22^TDGwl;SQ z&^w;h=(06F8&hkrxIE^q}hDh!~a?Y;3 zhv|rX-<$r911y3Go>+1PXu(}gd9NUf;B5R|3MEPCP?N>zn8e}PG~cxNLaLE_&07@L z%AKX+G*i6&?JQ!J@?Ej#Zsd(mJiOadpqA>w<4yluYQIw|R)r>OsZ7r$P)5;|#*>c7 z=Y6bG6Krm`g){)}Q^X+@iGanhE%K(PWEYe|YwW|*V1$So$wou6y8wb*o?(`Sm?2hs zWH0liVQ(mw>ZTs9-ez-s^Fr6wBx%TshO32Z%sa0Tn#dvEJ@oc$qdvHrZ|uh#80Eta zH1z=KV!oV%guWNNJQ#!;mItNE6Aw{NK?|9q`|Q{3Op&@V?NU4qZwb=o zu8<+Huf#_Xvncp%yAln(&Jlp_n-gnLH^jGZ9c(st&2zF*HCsPz{bI-ATxY`~8;k{( zOmq;VuVVrH=B|EAYyjT`)t-`0JF5Cq0STYi62&D!{orx)^u}I6e0<~1UTM?>#2d5^ zcI7eKW-{a=9B0IMkSuom&D+up=yN9$sI=lZ*kdg5^QfVH?^p_HQ7}B{2H&bOe6*H& zJdYG+x-`Y1KzA*^EvxiO1GAl$2)wXQbI$g0|Mgc7tTpKZe($gjIemp&6RWCN(grjs zTv7#5sl%iw4+!k$8R^Xi*jXe_ex#jTr+11n3*C#RWe5+c zfshN3KT>Y(P;e9`l(z>*2^tX>T?lg*h!xL+{hVx^_9k2B6U3`1+CubT%N$HdGV?kr zg^%9%rM2BHaQ@C>_y@~-D6FJzvCADj4W6;t0fnocD^NZbWv_ti5{>BDFADi;S)##=F*%j;K29g zH4MYJn9r8NSpo%y^QUxPsC&*(KddYTmjj|2-WJq3p&R0b%bfYbw` zP{o8`@K&|6Ixgh9)K^-fyx{dmqp@-V7l>Il7LHNVaz}Dd>Qi{fkvNac2PASR?9RTEz(eP1;-&pGF;kRjzKWX9x%I}u6DQg`aiZ`w>lLU;~R3%IE=3Qni@Lv zgbR!qB2mhur-eaF{uep$`_>7^F5y@t8ZcST*_J3^QW85MVizDIo7=y~B}|z4*p|QC z;>9i#j`SmN8Z|EB;N?I<`=CRxW`!Z7rec8Mxn%{A@WcL(d;O1RgOlUo*Yjw-1H|6_ zeQBEADFP-NWih>eg;E}L z$$q0>~R8l zb|!+EVIivXyPMQ8cW6QzN3auN96ZkuUof1`E3FPM8FmJ0)3?&M}Jj3I>cd$tl%5ibq+Rr$;Zrkwjq0BTNA8#*6nWa1hvqur%nu&H322tq~|-= zWbm827A6akAmH)Qje5b*cEVW0S|igLDMKGQu_$!Z^efol4@d_ySj|G7-okl6QpftkF`Ea z_D9|(+_?AhkKEKYO5+i1#?d62MdjgoepT)js4#tVOOk)-R4GloAZh8by6G#bII&j6 z__9Q9jW9GO%B3vwl!6D5W#I2uFrNToGoL+7B41#%jjY5Y#EPPfub0cxtRTuBFCuZeM?*NMQhYF+0|!)~WEPFClXyg)9@8}EJ7O|FV2y1un@z$i zh7?}nxx<$zbd;Q9wj1ONzQ7UoP;}wFNxK@|llbFOs7;TxD8gRWbG|6-(wF?X7O$^f zu>|=TWs*!v4){DVlK1BebE#@}I-QnnM?OglDA&>->WF{D-XCX}Ti+7-*k&ri9~!1k z8Nh=Uk2+no$Ga9oWSwCeD+D<(&a-Kn+ki==4b4@`1{F8@86S?bbV`TbHDl`>M;G&} zE0_wK!P=cN)&~b8lt~v!rF|1oK}<;vvWszQ9PucJca@XB4pQTf8NFfuSQ}#+aE&^h>iL?;+mTq$sD;v(DknUkC0GMgeG~xv6 zAUw#uR9`FMa-An*v8RDzbD*nh!akV8iH6i0=0QtsUMx|VO&;2y8o?RjG9KylZQ%u1 zdBfRbA>gd}_2O!`3Xz~B61eKN)=s3HhZfw;ZSEGip8b()PmsjZMz^u`?^aW_v3i-g50l1X>F`AfXFF`2N%y=%^NxM&vUvF z*Q>-_+OTk{q712CW^gZ5R7r)EH77?mT3LyzH!DP)yX$b~X>vsdVnP2egR$|yC?ULx zR;M+(XIyQ|&dUYs#*#D4QqK&dKF+io%zQc~Zw2#EJU>0(qf>SXjXdL9m z72Wu4KZP8RC5Tx=9%b;%;BoT#R(A7NWXpXnyV5M18~Yh2LTXHAN|us`%agoD;9$;D^` zx$FoUEBj5CT$n;t=Q~~HlkWKEE><^O50gyN32p9{0DcA9i`>3z9KOF2dzp?Z&`%mi zb+|~k>#WbOMR{0^W3f)s=qIGp*Re52`%06mk@!pFL6Iv58=An{lwKfO&@9o>go^3+-a|_#YHI#c-o;*8=oBHvSGR2B z3NGWx3_bfx4dWyb{XEEllS%+&s_-$-nSLS8x=ovUEvjF0&ieVgSwN`giqTN_vZHFf zroH$FoQXmoV#m9Rb2`~mS=pIqkJ@qlNJ(@Nys<%2{PuOFL0vIi6&bXvJU=gcAJ1RQ zC(cjtYk_JwQGZ?ZAe+&Nnonrv!n}=pIVD<;FW1CaQ~a4pL=Knh#r9)t#lLPEP!zS! z*P{f;VP`>!YPFmESH^PgAgBHJHFk9ct5rBG}ymdoZkx|23I9fvj`_mdHC2n3^ zPF*$F_l3RdPr_~TXco+;!E9t^QTr&!&9X7mkS||ej52X}VFn6KfMFsA+CosXim(y~ znk*BCxr)&E0|quS%Y{{N!{wFpgC<^BR2ywfj1>7ZRKyu+E@F+PcUkpw?t5l%o-K;xrr!iGx$e#Io(5M)7Llxp zjaV#tb^6$`bAjR}G8v6jz7|-4P?p8~LW z=Co)Q_dq?1NikLiwFQQpM;qJ^baRgK(=F$ z(zPxrD4MQ3=+bgL&ooc!n?&(86JxWx0pq;@ga7D`2Vdu|E!rC`9kcVmjyBNN)ADEX z6&%t!uEv&Y!>QFY>YDALXaL#Av7oa!lxw@4njSsGFsR66)>vk>*9S#wewGV`Y)+nO zZHX~<{gZWsIlHRyxiqIMCu7*>18l*#?;OiLlfJ|i*()oFyC=Hi!WoLIr_)*_*lT2 zro2al=BOsoe`TiNnw7E-iz+C81bSILp z?6*y}F%~BkT=EaUsX`9XS1*j$Fq&Kj?Mi;JUXjk_mAeGpJXe(1HtY2HQM2_p;o!*z z)Q4y%#N$uKU}6Z)&sa7bH98O8>UC<6s(k4b)ZjSfDXJ_X+uFj%wewHVy+k6KiZTL$(R zM8~qa^ihROP`Pn_v!`d9VTmAt-f!ACx%QUkyE0i2OtLFj`{UMv)K*WzjhFh@Af|KQ zEx^pli?tF~{QcJ;CCR`R;G{2|1S?`SeU>q9Y;pw01o8Z=gepHqNcI}*EAT!w;PwUD zBgU`-WuF7bRWK8xQc9#L#uYu5n9o8(7sE;f%M_Da5e|Tb-K&Hnbva9EXL~$;983b* z7eZV_K$AeHi~wbjTTGwoWNj9aVy-qnIU5_M3Z+QN7+HVI80yPK`dM_t=-y&?D{l?? z>qp-mKK9;FFOiCCvuC<8d*XGOGuh_XrtdKE1dj_>_ga1jw4m|w>mltM@mo7Q7@Pxp zXJh+u5DJ;q=CpylY>3lwr}OW2K21b~K3?Ia2Unc44)7DKAS^)& zm^U~aU6*Bwof!u8Mr-A}ORAaqMdDc6EGTSNmOIO;nrVLpT(oX6Grk&h=pqUy-M*D- zm>I8e_-`EDgYu5yWo%SG$uvF2F(^Msjkem{cJJr75tcyvUNew(+p$#qsj`R}wru_K zFGa*U@*T}-$176tUx|Kh$ul{&x^h^lPpE#0Q;iXc^JywZO~Zc&jN&j>wA%iLXKPLg_ZuIs z_izJsn-MSn@QnNLA-9J%>{Bz%q7k`;P;CmTc@%zzBLXfN zjJg3v)sZ)+{iBl~`oUrUeQ)nid^NJy8}Q z`9CMulypGH|GmsRU$M4bi_SlMWxJg}ab4F)(kd&gn>AI!9+&J3{{lwW|J@jVvyI{T z#H5uxU!HL}5}^N~>(ME~qHkJUqfDi#t++Y~hEuy+sc;-zrz1BgB#oc-rKjeaU^@g|MMxv+ABt2A=}Aro;?sqFvzyf0^&vxCwH8Cu0a}LVo9UbNXDGR z=d(XuFWp@|(=!@joMg{g&Yl>g?&`Pd>gwvMU!A$>g!?y(tE-WCq^s9Ot_GiE;sN>$ z(~oWjl!lc0&PAK_nK}?0Emzz$1*kqY4RGi)G6iB}ELuVk6*eQ1#co|pGTE^WoBpJj zqRXdjJA1+@0Ew}7i{`P!MpUXXkc%7KRdA1CQnQKrOc$5l->S?%7vK#t zztecxFg(PdR%OtI1_2T{fNeTj%;4o2K4KrSb`ZC(wOx%vS#_f)>X+to$ZDxRSHv3T z*QBvw?uCu#f&RW-M&xg*=4G0`Yw*9BtpB%wKB|HlbEtt#!kMY<-e(O}!KRs-5W0Oo z5;T!Wpd==%KUaFy7$u>`u);2HC`}IB2cK}e^eOmmJy-Wzr)%n#E8E%0aR*sw77S`Y zrrOd8L##@0)8|v_&qOjh0T5ySzu*owK@Mxao48BOlupx+p5Nq%Ud1 z`Ac;AAf2c?unD*+5 zKLH`c2$>XVp_*y%w~dy@ibuDLMYcdR7VVfZfXWv3Tf5Q@aL-@H^V^saKEN3m;Xd9c z@vZiR!->#dQ-$QY!DenIU>*$jdM63YqqIKRZGs{A_LG3Hdh+$~EqI%`pI5cPZ+LGf z49QtilO7lgmFeRKqa6F|=9Xo9*<3J6^|~4@vKvUvsRWd2toilVEpvR zZBA_#)oFE9Z4E}r;2o)LK;xIic*?Za7+p!-3bJWR>K!L%al-Xv@{c*7s0~vv*x%qT zwAekpe)y()a@c#*N2kC1hv9MWMfa$)rtv0*sYZ_AF&)B8(SmIP_`xK2gX7DBsZcjLs8m0UQIi&+~{#4m$iqPq==+pWh|}bRyi| zE|A`Ddf3KW4&buQ_04gabL2 zO70wc**ojJI_q7W9I6}f;Z8|CJcY_@zB=o4PRi=i$yM2G@LLHrefA33&IF#BvzDg| zluPp?)n>c?sAK^I4-dV$!{R|ZOXB&bfS-*lyO+=?Sy}g07OHEnzF=Sq* z`aIkAyS+ViL7)*ld18oZaA9svd~Qdf7yTr@#rZ2NcZ-UoqhUx50yAaidH5)XK;>Di zqv&3|B4fPO9kDvRL|xC6`aR@%2wvzS;dW^uLfI+EzX1qid6+RidG9tpk5-ghAJaJEc%vCgE3aeU-Tcag;;R`D}Zf*>=`T&MOfX7#yd zn+k4a2gDVZMyoJpdywX`y$u%V?j%EIR19=LpLhPLG~KKzh_-@8w3w%j9HisYi9#I% zrd~}|&nkWB>Cibl4&Fzz1Z|OMIwZRU_=~8mMQF36%4(?4EFHzH?}7C~!~ODjF`V9;2nk8N?wbaIZxv$2}=X__S;@DZppdEab6)ds(e z%Dh~vaLC=xap z;=_u?@6*ie!~6NxVv>NIy=S%iG&@QrD-CaOcdagqn%8{nPqDoP#`AzT+P%BxrmMM! zz_kTrVm3FP^=RV7P6*VZO%16B%j%`sz%Q z5K~3K2s3+&Zi|pVd;Nxn@wQ6Y88UcKybI#7>P0q<2T3%tH^Lm8127cAPIDqLErWI3 zpVFG<091i^8I*8ZlXfnes$|5kOp(r01OZ#dC{AGvczj;QW`Jmj=4(7!55O#1N?o2 zubM$LyGDc(^*6c}HQ|F+pbEpu>pM2})&95N>{tJ{*LVKz(%*FTFS+^4^5WvJK4$Qx zW~YA|o*wO=E8X;XW6e2}lu}|;hkb;vdpNZW} z&Hs=3FEFN_q}uYf0RfuNL~_tVm)w?=C?ll?>iP6sA13Y63DhW7SGie4?FGP;mY!j5~TtU+3W9^)Nxyg03Ht|d&kbK(ynNX?Q}>>iJ*B|GQxXFS@!b-2xIP~J zFYs%ECz4%j1&>9|jof87f4$w6&9raL#Wl;-6L($5cEP(lZ>!Lwe*^v_U@1%kv>1~u z5np1tVTPd5G1{P_vRgnL4Q_}^-wgd+O`ho^nMgW^q;}ka>PTW0;-dv=rU%9eJ8{SE9XD~QD=xawz~Le`wkwK5Vqt9 zi2elrB@OeLx?6jyd=D+;>!@|XkD43sl3I8(dZ{krB*DkZZIDZBrQ zkegjwx@|v}>8E8y2`DOSiqB=bXxog16@aruk|_cXXl83M zp}ED8kaETm7YLViNmC>p)%1CQke;Ua2ze^A@)i@ zJ{>H3R`DT0RTbZ6WGGML4r){d4T4-XN|O5~3g}QJ2zfb_#5kMh8Rm2)UWlUX`JRzYX}B{b_10pH6NMz@Nq zrAGNGCKCCz@qth;U8W6oUyb!WVm>#m0WPQ(YC8bmjW&TDH9HkNOtzG69=~xE9z+vyuCpIBks^Dm`zux4i;Z zn40S>m40Xzj|JqPjyLk>8_q%Wc5;T_B|0t?JKVH`_+q#bwBi5WPSE4Ve)A-FF5zFK z@b zUY|XUO}#``mMD*2d6_$oeyusTTjnP}x35O&Wi(^~fY2{LI*S%ia1F4IfkZJpDg)YAw4qTHHaydUix@^30`xKL!QlZVKxFBHj9L z?RtrvJZAYTJzs}WrWbGM-X=G+t5tFBNgu7dtm1kgc)CPm{j}w!n5#d{`cij%3(Ot; zU01l+X5|vEa$l&;3d^o@bp;w^^(9`=tKwQTgpJM0ZuWr}W;C%h`N{T3JPzW7T$@*9 zxfJM-CIwgBxyVEJRbNx3Ka=Y~Z&5=X_i%9IMtHh-2rrP@>)5;&3?ZuFjy^0B8chhr19fxto?EhHz z2(EGC|5a{ZWF8A;KtO@bI{KL9VEXC(!*DQf@3KY;2)6ZF0a)GB&SAclr6e$N1_->| z?;ff8mcRpSwz4rAOo%nJ=A}k>yEZ!>6&bfP!Z~c@#c9w~vT~el&_%E+d{L^pzV13; zwmD_cE3Azq|2PVmq9@C+X5uNYUQY_!!&Qu^~?4A0tEoQ zkaFO(brhx*45~T!wF0cIQj+bx-UE8Ogl|hvMa#7<0#gQaD!6_lv*ryHg@z@st@&|C zggL?@l86{^z+iatBysI$UU8vlTFz-R5Fo(^CF1G#k=Pj)=B5b_i_R^^2OW$tJ@!>r zbw)7(rQ^`AxenUXGe&w6QpN+j^5n@c4o$zV2E!ACB+%h6&J*+_d#2~dC%&petjdqf zVocqKhoq)Zd|GW+YE-M~OKw|lC-R;BqjMSh;>)4#CtofL%Pj=0XS)%~Lj$B?BiN>2 z`i<3P1_~u&U%p_FZG8YwGO*k3OhB-Z6!(xW{N_^qT)`*qgu4`SmyC?TfVV&OF0S63 zIYUJeMW?yZE^dcUXZr12u0#lAE`XdN8~P0_@blz}XH8uGhT-`ZZqG&{dba>Duigiq z`i^bf%NV>HF!K{`2mGzCZv`vv37IvbKC9P!9?YGjMc8`hDD|P*>zkghs)+e?98>?~ zyC#43dBObuM;?9!^TRz)zY5dDr=EXh=h+HIpqhRKa-Y}#f%Sg6X`Y@}(b>x%$HX;h z7ERiJ!e_CSEi-)4bDtV3?{KzHl_nXFnYSLNp6>Vier><))$fH|^k*W;>HD8c%!>2u zzFTs&i%qc)?h*tZ4;9y&<)e*tFr&`fR}1$+mqeiet8~7GAR+8xY!Zn$lf5j_h@NFSGApfD@xb(`7I~$ zZ_pgs*ei^FPG9r|t3wyXu$t;@O?Mg*dPCWtM|aUH#8#O!&7g;or7|e_>mKf2hl> z2mijZ|8KgomkZcj`e3|0o^kRDzLJakyz0X(#8XhJW5k?6P}zJ6X?-&+hd zsTAkN=2q2UJD&O535+ri*+o25kUIUL=GjL>$qo8-Cn($ntBeiRfsQrI41dzdVlRo$ zn!sm?m4Pp&1{IcbstF4is$rX^0u8V};+eaxL}qe*+Xz5PChq`%)3kF-6}RXo&)+dwHg zI_kX%4|=CRhWjUnp;E%TuTDaHD(b_R!=ekHb0*>ZK@CcuP9kNSZUrJQu+zgm5f|ub zqsB3hO^OAvSy9Dt{!xs;p7)*xOSOZ1izT_BL`QTYDB*|!sPz{RRvv7zW%Qjfps~7S27vI!8pz4=7|DQ&0w0?EEy~DIBOvy z?l>CEQq&ujD!x#4F4JTb&j6P-wt#|!WCzJ8#xbUpM+P>^Cjwt#YO$@O3sp6e z@wBsl-Z=}8JLj)^hhg&s6OW%`mYKJuoFiU!pr|7re?{yzSPai5)L*Z%#FXoctI73K zOT4v*U9rvYaJi58FZ}o8Cr=v4oEc>F%@7|FBbJL3`F-cC->IHZ{CTTI>%Hc+a%M|^ z^xWkq-8b8aL8$)S+LE*G&O0Qv_RYPo&5z~Xs_gCR^{D1YjdNL8ilV;VG6&g4c_qJA zEUSJ-HK=kZMv-kZ8=}R12dX-v z7K=8+oW<}Onp0oEvtjVV@sT!dLMAnBCH!GLTH?La8BgbTODu-*hpGB4nU|7t9CfH0 zA#`IS4|w)aw@c_JRLYK{`2Zer2~Mafq6Wq73uVOSp7gM`*t86a#B-P}#^Xq-)|}KA zx}+V~J&sChKClt(^wEFL$#OrVqR5jp;}e0Zj+4_q^&X zc%6Uv5AfgS-}lAuhtfUkIJ$$uVTZ6k!EHPmZ9$F+H5BODFdZ!53@!HQdq~Zq7Uw{Z z(%+r(&Tmk!_Mlf^K9k+jxk_kyw&H9ML2v^&&M_!GrG#PZb@&JI?AZvBg?2&{%6QVU z5Wfi_;Zrt88hM0GnM!LG5}yF{Ct?JW5%7T{2E2O=JA$mJqi6sckfWQU0oeACE5$hWC=aG7WESndB|Nw3cE z+b&g+OP-Z-74XmIGT~OM)Rmo1e?$c&m1}~xI13Gc26)GPE z<9*sl#Ve5=?sC1>N9J&Zo0< z3eJ!*shK*BuaZlYc(KS7*fwsdEz4rt@l3QX_t@tb32cgxQ@Q;9(6W@591N! zwB8MR(|7`@kkoPiW|n}Qai$GbQo%wjCg~set{@#BYyHLz!@FX4Icm5SG%&n~d@*T5 z8qZ9oki+E}jM6OT>f&*=e16L;9BXzz)iN4<&RMgz4>N79z2dV>+$UVZoy+MO-p5zJ zf{WWXkhsqUJa_j7GV=OO&VhWVMJeyxj_Ivzi@9GFgr+#;~waMA&pu{zyhgz$s_{Ku{kDOgcKGwDpOM+u~MQWU7& zD>@~)VuG%XGx!s3hG>nNlF9(D*%_Q(&)d(1C9_4%qMtBLg_s7;RHyEv5u|1d78zoM zdCeK}5Gmhr_D-AMV@r%2xW$e+m4Y zpeat%Op-L2W<@C=TG?o0wKo5`Nasu2Y?L*bivgk*{ia6;jiT5!aP6+JqvirdxbuJc z(12ew+&(#}zqmu2hxI^NsC{}3+XI+uuShIFVsa7+)4(kbZfu#4z8T5;v5ec88V^N# zL2!SP9T2n^%AyA;qKl#dB;rshu8u&YcG|)I1QU3VFt!3Rf#MmEvUtX>}wjCsrwAYo(hRX5#)>ColMNM=*o#x=vmtBd9&vULAGlG5Pq}vuFPi9QJ~f-g$7?fsduTz53rxdh5glsOcHRQ_N{G)%M84 z^TTbf_6e`riGs{5oIs$!|F4Xz3*M!QO!Si_QE8OxrVRhEd zDB;UTlPM7Ol~ay4I!Xsh^g*N;{0CB&P|sSh_ZN^ibBwoDouOVQz73E22jTafvklwU zNRtY)CaU(2nHE7yVLm8Hfzqjd^<@}t$dtPL`PY9{pYy{X{H^#}k#67YfsUwFIkxGa zZNoFn{wz8|>FyVqT7NSCP=e-lTLxlCm6EQ+IOP3|)FMM#&@KF44W6@+l1;=+$b1|^ zio#t%#tfEXr%rlD-IH^^xa;BqDqjbQz&i=7*Ct)WHmRssLAZ?+r>=i~cn}_SUxb|> z&Yzo!x=`bkqo=1Iu*>&+WRmke``6E&!zrltVGGZ4 zm~Fh>C}RHwxvjx43|}je;oH3(XxiPv-7E#N{w-{HC7{W|KXnw}qvGb1JDN5k?C9WW z@LZi;ibEd@GJMGL+%_8Qj{c+i**ZSnIy^kTx!E3%w_)#R*_uo?Ux-PzRNIR4?%;C! zBzXQGs!jE8W2+H7;RD@OE4!2Vn`Ah@`7%#o%&DpFS$i1WVb$}MtEv^9Vb$%`TTLeS ztf{yUYqpowJZToZz}4!0p;z}SqYgjZQ{FOb-70T;_psIlLGeMbkYzTDukmqr7r#d_ z$j2RALcV$Q6OQkvhS6bnc8WJ-o%U=Jf0&1sq9Oz*AAisa8bANMCo{x4#eFGRsV7@| zw=;Oy5mR7D$~Dy@16EHd-g_?nEnUgF{>zc7uKoNo+`HW&i^kM|9D)#5FdM~_rW{rd z9YD0e)ilwlwZBrM&bpJfDJx&7h*>-eb5=rnm7B8?(Ui z>RNinb~zf7eSLu#8R}qDc639$HXOX}9Q-4s>y`J2$9q4N!q1JH2UW+7qrE7;!J={`g5X}efy0ulkfXi(wt*jb{8@Mvpw!z& zqae@j{q|p%2TLCM>2amfWx?|bh0FxdO`He(#tEL`Jm2cvNX8m>o<@dd0#GO5vvz(i z#Z3?Qx7R&|de*Qd)gO3!!-Rj<-}xooYiRG+ri6dMFV9!3sIO7?sjH*(;rC}N)@5vk z`&5l*vvii-rzRZpUIc<5sJzWF&*lI)%G!3$8DAIF9vM$fKb9(@+&bnv4NZOB0m+Gb z4gJhopTW_hpmQs#{W>aRa$$j}#pPH~FnPVT(zW0WUf?3n7L(Pg(tN>hgA}k6=Zei% zB7h#%_v`i_$6>Mu56EBzc8Uh`h2|aW$K`Wo(%s8>037h5Soa0OQ!YwXVZeDiF-K25 z?;gjGX_d3)lN_50KcD33R6@Kx*8s zIawC(-!n_5PRG1y7IWxT5ZIE#7OLAB@Fs9p20k$8W_78Il1ZuX47_Fz(;igS0yD>M zPf2)qxUz1)^jYNZneBuFT>mYdT!2}mwn&{r%xO~}Vym=SE>ONTfQkk;A3CU&FzBQ> zE6eGqa@k@E5;v=HsJi_6N1Tj>9z3Y(Rd?u8pU52oB)e*zo-5qj1(^r5{8Znn1S)2x zGtOw#x2!4!jYj&!91{TPxg>{%M5#dp&|OV}vr7nU8<|4`%5rij36BO}J$Yh#4uE5i zAM0+5ydd!7DBDJ?*mv^cc?u?S)J&u)zykj1+;-zBDCv+a9soC#Is;x?M_iY?4jx;D zTyiV_AT1D=;bZ|22O?obvG>{;dDo8PNdQQ4>K`P;1)5&-7kyHA4Sd^ZpUH{FXpUR**Z_zy&)T}wP=D!j{^3VlCYUK!nrzM-YQW5^rk{gaR?V#^w z9b(S(>tl{tdr5Pa$Ne1s(N#1H9__ia)W-ZN#?xeeZ6CG-zb}a&Drto!Z8m>>h`P7rnbE z1#7pz>_n*SLg{g^itQuwodtDAUU3lAo`O|g>~f2DPpeTWYW}?@?;e&Tfoos#tdg_7 zW;ctgt5Lj~!U3I|MU!C)K1(Yev|_a_1wBJKc~^ZfSV|@5!YV7S-`$Mob@7!GWkkuL zvSMmh7d$_ge|2lGL;_&)0iJ4~Do^7oPweUdXi!F*SsdI(#-Bo)Ow@6ZL2e!hzna8O z%r6UGrK`R}x5@*xK_bWGodv+qo-x zv*Pixs>rA{ITicbmiFp~%Xs(!5fmN-KcQZ1Q}q#$v(ft=2z1<}?c%Z*0iRu|>`{P= zJ+>n)JPYs_=21Y*m34{J)!S;Knq<-2wbnrPf-A8Hnz}f@)*#r>T*4090yrWcIk(CS zk1%j8m2zc^;*n{VEXXv=fsGP}fm1u-y7Zm(7pSxmep8-y-6Q@)$Ch0!ek&*7aMA!M&Qlze>X(z3?b5+UZDbc;|1(P`4+&yf zO7HhWv0Td`{NT`6gPw#@K!d2xd>RhXJ;5gh2m|!L9ty)+1@s&YX$ffG!y(I6VavgA z{IEFC#eb-cxcYQ|5~SR{(B#T|=U1+k;LBchHH6);d^Es?|JoA>+xPdKv9)pp zJrWV08$wS@mCuHuw*n#^4fzv5^z>jpeE<*D>7_7wy33#DZu)8NrS*~Yst3CaNzdW6 zPaUiwREecmIB4&Ir6<*gPds=(E1DjW;UNzb^bi2I1pf(~zsHHQxXAXaZ2D5^_?fZa zO0~Q)@VC+m?X}XcwzpSTCUNdQ5B^(TgDwYvLw2qh)*p)Q_KWJ*0|J#f8+Hl48#jG# zoHDNO11eiVN0y9Vu}I6c=06CT>g`(t#FPhSqQ9T!A*G;79%aafDs@@FqI&!GatRXE z+*4=1q|U@sXR@Tum8Z_tk~%X_omp8OFXEJ10X2QWx(hL-X)T^TyC+PP?L#ik*pPo1 zM5r2AK&4uS4-Dwu2rh*q(f5#exFCV`d5~Oi(a56a19W*Pm<$w5FAu)@>Z|`)2_>Us zhCI)mO#ROcma+D4pp4HBl<|KX5{M|7fcvh)KwZ=X^>K6y#E3^U``fZj{I-RnZl{(C z$fwcwv?*leas}r!%+5iu{^}-t9eCo0#s0MEvMOXuxY57Vc z8rlvVi#cjjd2jolDw(^$q2>s__$ei`+-yHbovZ9c7NEYkIa4hly}C?cdSBNE)6SP-oKCD zz3{a@!%Qzh+We%wUTSYQxUBkj+uv*NwgT>lS@!48mTs*g{KwhF$-O986p(}7@hM=# z9^Q*i)lxs?Lf@}vrJef3ZLxZ9T+kFb(=uyVg-0QKKuKCoYqcm5Fo~c< za3hA2lyFrdO_lr|MXS?%6}yPeK*xU!0zvb^3ic$O~mw9M$i2s^6nq4|Jrj+H?g-iRJS`&sIO# z9l==d$X?0h^6-u<^s}-bZP~Ho14{W5;-VBS5A?YQFQo*4LeGFOhS(deF^T;2zW}9z zQ61EZ2;1W_1PC8ugPhVJ06ir)ghH7hc&jH}m_T)hXc1a9>A)#YMBX-PRME$rA5y}E zPGdc zD0)-F3b;&@_v$pF315h#T>z&+d7|cHT|8%I4q?DC>^ZK*Cg;fS3bx?jREc*b`YF>Q z3a%#7KRT}tcbQpMp=AAw=D<2b807;51VRFiff2;?9nus|KVPc5GK zl&gCcEW@X-?0v59rAQSuZrwGm-PJ+(-V@5o>YBqY#9zA%R`+>+BzgXPy4V(Rn{4Z}yvb@GgTbpcY5_re(qU?s^N-j;sHCu@0G*As$1dVQ#|- zcBghT(BQny86|GMybBs%eE86SRG8{C`|ts?JKw~~EVzk3M8kN1DQ|zf9-simy~$0%Hjv zQ|%b_h6zHnI3Yh6p~VANb#Q~sE|d8znkA#V0OHu)^I4l{k^Vdyyi=NjYQ^0|}Idn_#lupJMgO#XzOpEt?%&1 zPo8Afjr0&gQ&UwY_ye zx_e4buhuF&i`7pD@8UT`yun|`(YyE{olF?yndZ#(m{sMkh9SJVY(1Brt%a(CXtIvs zfP-kHR4mFEOUfWJxa!LAENy)>O_D=Wo{a=x{)h}OTqmWYq5ikrb z7%jXxC~Ezl8a_#u9nnchH932a-4*#}*L2cca(#{Gy11GbrPrtr)WAo{zeIsT4M96%G!(RKpXHYF{?QO9Qp=u_@FsgslK11k?~8>8X9J zM`JGLmcCRRL{R9P{j-zq$t#X1LJng!IGm^3xxte;!*h7ZQ{)a2?;4?Cui%q zdmAdexqanp%57{9cVet39NCXrFsr2Iz*zE_2I-mhXY%wQ>Y{r6WbO`bwQuH zQh#o5zw3#}A>-CQn6P z@At#~7yY9WwS)P>wB~^W6DkVwpe?&gB-J`KMR(sFM<4894&g((Fv>eP9LAe_!7REB zQL(ZFa6>?J1?C+<$wkvSgG|gBfb1!~6E`rNs%qO!M~jU3{c16xW7IhxOd}zjnZ|n| zy39t~+o)-qnSX4`{`BnUmRtn80IZFz5lGc0cO%4J298*ySv-bSIZ_)B94Ov3AM+~F z4$oDVe}-npy;me>P=!mb9Y^vr>~^P}$B)gHedJi3)7wxpF%ze`-*ANJ{%{BhENMTm z+(f;Y^<;G}DH#P^Mz!0{gsZK+PfFusg~Ijeezm-w?w$WYy=z{(vuv>`*pg zqyzZEkc2;!!qEtVFQ(hU7nvGpD{y;2&1`5FMZD2J*+u$>D{{M22}m$*!U8?=Y<;VS z1J~~5_FM6LA#irqoEYDNAU5r2CEF+EE~e?^D2~*Db^Qw8(>CrU!R@ zP3CCdL5_zr9zsae<{QS4K90qvEvi1(#Wc=ee~?b&;i;zHQN+Pds|3Zbq_lIrH9ZZX zr-&IcjTC?J&e<+25H?G`2)-@VEX+??)on-`%S%f}_$a_HSYCOj6%bwH0pQ&Y)!A)? z#iO#0=W$}NDOx_7VGzMB@p_WZ)PYBaj9I*nL6SEh zS}$>5u|BW#K3x9W*pgAIpt^kCMrdJ1&CS{jFXKV9$oRn_F#?(ZVW!yaU8SXE$p>|r z2UwW0B~nuC)=KHCTew6w)fjPyssBwG(UHF=%~yVCG~53!V=*lX9u4EG1grHfPii4Wl`J#kM14fo z#mHea=V@(3==E@TIKZRX+FJ25GGM!(H8mR4ES|z1orO&Zy0advrpg%?5D(I9k1m-{dtg$%2bieka9AN}3^Z(o0dUs=W6puGcu$g7OU!| zI&ZV&azx>UP>Oqo3!07)mxSL5gWy2Pkjt2Pbg1;Ubc}U0!HjG)ijA|I#azjj+li*9 zk0C|U(mP4#{33}Y>A^zDS90|%(#Kzb5_0jG8Z%fNl~Os$uAp@|!&IB<*PCRjWw?@H zGxp^1%_wV`g|9YEs~Y`+r*>*mFP{! zOo}vx^~^3;GD_xmFg{*(IY({1=0N7;;^+tjku!-LLw}{TwxNCshA-Pij@$H38BhH3 zIRg=BnpM|}lHEZYuH;Ks%Q7h#ePrFuwaP-pg4U4M8iW z1uM)8@d07~j7C5wTU=&?S#k+4Cv~TNX2gx!@cBOL4d0Ks6aMKGn7T&AQ5$af3!ZtdqH;{))m`0i6GLiP_5- zq8Yzzr|vA-s=8f!hc-QtL5f8QYAt*P4tBO~9R`M{K|Ht~f`i@G{}(Xu5984*J>J#$ zHz#BN1niqT5q7GNga=^WgLE>VrK1cU@!&3|B|on6C2Co>N(HmlNqdl_8V1g4Q_kUx z4tBn!!@pk=VZ|by3A&)d!y@YBzj{x&D^osE#g4CZB7rSx}F%SZVu3^4b&f zqtMa~SRj1#N^g9+1kcln`CiB02Lw%sZ&diCFWDv`TL(U(wgeKPRwp6Dfi{G|ZP}<_ zuyJAKvUsqVE4@vV;br5=)0@a(0X%&Q1>eMchlUp>dNfiEDb-4?DVcu)^ymXMRI6T@ zn#wf8t*+amYL~H^IDm)+P^AF2*6z-&)DTX=*6bJ)}L`e)UQ-hmma;^5e zo`X#@8))+CPT(>yh?@rE=O7)%uK-f-;K`F0i)1uJyF-?MPLqPe5NCC;CL(=fp!)jS zkbu|5SjTXwd8M~qH8%Gf;P-cNJPoc>wRF9nrUGyOq~7!8(lJWm6`ybT%`kk?J3CUh z#)B{v$mw>-+O|()1)Wdb>`ZBuijLs6DDOp? z_i%Y9O8t#%_kk_1+Bry_x9Yr^qgyVNT0=(!^)bcS2eZYb&}-ZJJcU5~8r?3dqWc{j z#n;i`F4#Zqf`}P{2jC#WH!yT*0=W>qS1SOL81|5oPTFdI);aEd-wBU8ul5gq4Ef2l z-%+H(C2R;9%mZ*?IcwExppvsnIi?=%Du(eaD-wN>RTUzo#yZuLE=%Rg%4@lN`!FO~ zN&B9p(G`t*O4pNOmGUdsZWVVK*V58Pb^H%COQJxleiWz>8{se%3jwS%Yr4cwxjfLhIO+aCc-PoZZ6lW;(_+WxBe}$46*qjo zaABc13=4O1$cZ#2vFR%W-VC`SpBbJWTqbwcEa3Y|@-={PDl1vXG49V;ZE?Dfk z4i_rxy8gbvj>#50znabj(HQ)#wdbN#2ZID3HD_?sA^v>E7phXta4UF@j_QfNiJ_2z z_Xi--GUj+N)wI`g;1Ibxl=+-|ZYtO(7yb3QwKm)B1Er66dJP}f?KG9Wr%obYpKLIK z1iTe!_IRrmZuMx}!rfs*S4QdeHL#`S#6zV;lo+xythTc^(ej6Od}#C+d=RK{O==kpVP-7n0^-% zM7l1kZ0&qmJl|SOMQ(?5Hbiq~d>7n;Xa9`5g|?^tD}0(ULNzg&fU)J9h-^|}r?bfxzQNjVY|g+u1X7`*Lu}asQ(NAKHjm!L@{N`C27c`n(^%U&)&ld`ZA|AB z8pdXGw1}a2z!fmM2iV2HnLUnFCp)$^$>{sTq4=ihlu{kER%`VKJRatN6Pcs(j$OcD zp;83IJU2H)oC#1C#v%2m=0DY+jB$)Cs+YF$YpcBwj>gituU1iP4SY#Z$Ndat>9&xvTFg|rJ>|l7p?FS z#JE%9v};n`p?!9J-rz`88QIPa>3C`BXpX>MSbv+Mg^IzjOPc~8;yrLB-r7p66O(b7 z*2*>1WB^(8@2#TzQv#>i&)TghH-J1$oP!BRL3Oa?Ee^0l7g^!O^o_|4PT!ja&>l<% z+ss{I?YkwOc_57CQLa?ZKaBfs`~1#&l5!Y;`r4&o1d0y~(8BBbc1PfB1;P3b%R{eZ zT&Uxg#>-Lw89XD?#7s>(hZ&rskcA_a+omG9eo3Ten?W2q2veEg&+qzVKeC?XODnuf zrsD08_zAtd!*mkr_)9vJKzojdFu6!tTUFcyS~ z@PUj1v8j~N8+9Lq5BU&HQ9KG^ZDnMpNsxmlJmW$QRmOO}-=?#78yuVpex>v<2zoIX z1)K*@M534sam8^v597@#k1&7d+7tkQ|`Hj-cabjtHaS?EO@m7QVf{lZ@uy6=G*ECh6fa&GE!RS%a z-zb>(1|oP%n1OOhGbLG4Ns+-#7=IYVQ(TzfY7|}5`?&Sz<*Iftph*5D9--r?ecYKu z@J<*~Y*-koc~!F{e%>OTX4BRfjFhUbN(R6ECLW1iom?E~>QpBXbw2$4>+tKp7AhrQ zsn1oV4KZWDT-e0Z>%l;~`$mJCL>>S3HssD#frUj)5E)3qMYS(~QFuqdK#sEhJ&~Rw`5a_3+hnk)C{cD4^ zxX{mqvxs)e4GiQ`$sQ%16~l+&(ij3`i6J%Jj&-hwgFPWY*B!m9ZW=NN1#! zz!5Rkl=ZrAx)BaM95tBDJ?opf8$9CkTds7K%(AO-^XdR~c0T;twi;1(iF3HJ6H%QD=>@8Y`_{v}@h;g&sxtb)UWvV9gSo*x=i z3y-=B1S@>O;ioK<8egYKugJ9|*R+Y9rYiPozL;eBTd%Os>eVLCEJX0LQ`VM-h-U~_ zVIHS&T@)*V0J%*dP0DA#jJg*3vxSBPpm{^vs1jMj7#!f~G`dMfLx@U7g-8b*id}An zhKaQUE50SM(H_N<>-i1c2y`gDR6>l$1-n=27--ZS@HnKaS~S<@4ichlc7UyGTvF&_ z3*`so;slH@8rxp8>FonBS3x9~enOC)(osth$GzO7N=!zVSvmrrK8O&|L|{Hdtc~`V z5_fRLP_qQBqqYjp+v!>7c>nz3tfRzfS50I0sMFSEzHF0)M|SE)ExWd^pcgslWG#@6 z`B1607^ka2qKc!IXkrz~vcB-75*4Td^BQrFwxCB_mr=Bu21q1B@O0yPI{2I69a8smiJrCsO@)fIHb%d{{s`G--g#~;v^Z?`gSbaO1w zHtVX*L;XS@X4AQ08q@29jwS>d!y4rj%FD@Wn}Q|ET-w=45zqQr+f11&4z!9n4Y;Rx=f@* zwSEs$dwZNr@TC(kuA#n#DG6>&2Q5uVe~YyNd;ks`WG5XodmE8v!sb4`oz=Ew3^Gj$ zDH*sfz!yr%D50e2Oq;Q3{X*Eu1gQg;pk~;+I1kTzVgLM4O|YF?p1$Jj)tI90gyS6G zss+z7inm+A_eln?nf>`3!Em!MthuEh;?A!CDjG!0Z2i3Ji6m2hNt}OaM;;De~liqsB3Cs zBw*lqONuKU?Vzn(C^$fWnB1wuOz(e9L)&!TClN1_2)C}ZbMfZERm3R>FJn05(pgjN zt7jjcwW{wu^aH2L2%MwIFb5hR9+zN1+7|S}H)?}-!u=OLH802gS88vDYP%nWXPr~^ z5$;=t;bFOWi_8v~h%-1}#?$ti;0}8UrwgC9svVr2<8D9^sx6D+T?Xu*aO;dliJ41+ zx1$Fm@Hau0ndnlah74l}N}JBp*#^G@X}4~r&J5uaWLAcbL{Qz0r8A&cC1w}1Nl|r+ zK+{om$P0eLu(Lc)dOeCVQfy&xz`|-W;7)fVTd@s4lwr`ND>)qE0AObSBm?3rj1jhJADCck(+>t*_{xqFZ&%#(8gckk;L?b`-mPAF4EE`%vukW z?!@?-)bru`Hszd|(80<2J3WYRlhYYcO#iUqv!&C=6(X1D=U|F1V)T{F2?GoMj&njS z`gRCq8-NSKkgiy4vXIWD#(b-1LZ321EOc|`s-FtoAsO|9<5<25^Arzvg1 zree!+lJYB6NldTVfi~8uD<3?5o7r!RZkgOC!WhiKR{k@j35up^<1jW6WoqGl4g7bm z1vVyOLng(`0xy#hyC7&37rUtRZ*a(@l$iA1fMX@Tp5o)lxcwj-}U>~tzd{d!Z}o;W0A7SfK$gTtt03Tc^YSFIXC?=)2W zU)2|+C;I=m_5e%=>h;;zMy;B*opSLNHY-YHp>=c&IVM?`9z}|ZFe#A}ZgcCoDN#J~ zi_kuWBd}P+^9X7C>^cmE*NEU%q%j4^RJeh{L}hUZTnKZBej|mUiE}V)LY{Yg7G|q6 zTo-4_a2RWwA>M4Yd7HHDMHaVRT0{na1TDC5#TegSQacybfn@Ysu?VxE&)uhSv^1bX zXf}#jtE&hv353guJy^1`Gn-RJYUl{LYKi zPXf;sZU61aHWRsh$S+i6n=uLmboFIA>qLVaks~e(TS6*RRh#K#&lu5Nq8;hjYstzB zo{z4m#+3Qw_OrOpWA=V70hkB}-KC68+v661dSzDX7a&QNcm+JYk4u1kmR{8hz;yx8 zJ^^*S0Qlza^8}F7%z18fqs24?0GScfn=%~Tb{RGUF>_?$5^EGqf#eKzVYv2~QO&SN zc#C0^e^GjRvfGPp=u|s!<74DjxrV#JV-HCP1w^S!*d5kY$0OhCHE&bEE@_{L`hrTF z&Qv#)`CIbPB!5$t1yyeM7!!BLGSqE9g{hE2-po1e0Rt z3imQdlw7!!clOrM_Ni6JtPnxNXF1Fz#K3ZP%E$qtmt<1}CXH3DJ^m0p~|%aR13R#OW-OiOzuqJwOk!huI1y z&%m+`p>$hFS+XnL4f6RBY^H1~oewKuvJ|GFw0uAjr-E0>WY}EaUKcqm;QL3rvJ>0e z6ZN5e?{IjNp{sxw3n^}z+zLPwDxP`<=}$6mD$wd5myDwEm-UG6AH=U%--|K31k?IgaLJocFyp(VVe({` z#B+~op`V~zlT(Xc^)2>RFeb042ts-Xaf_YI7~UZnDt=Grc$M(%xzm(}1fx`I4n4M4 zoz5g<&z@+W>x6MW;m4m`C$vY&qb1j7y>FHjGs!?5Kq}^=i~f1K)UV=wIm1_OC8t7>$=`a%wi zW$xTo<6=y_F24pq$>mB~2_(MMpK^1V1s+p;n_NN06d_dn-gt(XrzyU?87Jgfd^Mu1 zTlkm-_b^x-etj{WxHt*np&xqIr}feOD%kgNbh@HBW3t>CXLUYj3<;hI7P1*Ox^>`? zz{_*-d@mG8KK@MPho|R06_9&e2rx?GtBsPwrpom30xFhSK1fV2Q4^NUUx|*O6F3FC23|PuJ?!W`FTB|(3e$#fL!*&)R|x_1PF+LL$wJM5olnY9!EqjaEJY9cGu97- zl>XguDs+jyuU?ZYSm%P$%o8F=1N=OPAf6bmdq7Dd5xgcM_?SpMdq>w`z5uUsOsQfX z%WPyhIUySF${aQzKLDCNNMMmE9dd8tKrIPIe3(qe(IlPRjR6nUz7dGvqiH%CElfUC zwGm>>F=@)0e(4dMsBgL%Ax2K`KrZNn82KVjA`Ie33s)#oW8~`j!Z4sa8^JdI8#d{$ zUv(b0Wza5q8LW{(35@vw-oz-W-5RIphMPTJNH&@UZvtD{3(O;EJAtxN2UCL?jHkll zxU~oEL+U&yxgI7wd#1x-MIr%dZkkYjBY^x@Q}8kYH)j{c!Sb9jkP#LE=Kn(j8({OX znBVF>W82Z(*0m>Zn8I%n&Bd^PU$PkSf*?u+hG_xwj-uNc)4pEi;Zw`zsx z&FjudaQ?c3JO*+$*gxw8C%yBa|N7$P%cIVr=D_{g^#bjw+x$TwW*x(Qx9w8jWC3Uzj~g+siihi17Ezw zG@K8(Ycfm_E$({u2>%L@RTfkKDC1}r!Xc-LRZ@b|nLQH)F~Rz-7V04Oh+7$X66IE; z<$h^az+e(+A9}}j{8IJNPD#FO!LW?Q<+v?!t5R`q;f-Q4T(%*;HMiD$)^Htwgu4$& zg~^rkY|x%vDt%@G``G;$)K32`F)#9R)3#yb#$CbUp}%2}UhJ3psp2GU1C$cF&rnhw zwWmSc!5B3NtkO9`&u~E%u?t;TSFx62soZ7I-RN?Vl{9P;n|+%zH`+&PW8^s|QT;L* zfr6Cp$EsKGcR~pV) z2Yzyyb=R|XG0-HY*dQcw8OPw$y|}s>ArOuU-~o(^o@bU1o|HTdm#>V=Z$-<#=3BbA8MRb|Y*}n`r%Tq+!`H;x znsZ(NIM%?eB?FulL+&+w#R>gmL;82Qt?8$_*O-)y74CSBDwbNVr?^GXds9o@B0>;4 z7^49jLO=K}qZK;+#JC}nH8LnOC1?g&x&-G3{=r+w#gu%%Bmpg8Ythh!g$r4&(A8Ek zZndRR&1QLp&JaUH0u#(iN(}hNo9AXmI_EH-;bLY(#9DU8G2D4F1Xl+(zEFTy3;iz{ z&1V*8bEzCKeiQ>W#N>F#@w2d_z5Z?xyF)PVXzfv2Z)9~fzMd1%VX-njuB#cWx-g>( z0fGFo#sTq>MOU#BNJ?>Ej7d=|>qUeyuJHOwGlkG=8YLd4z`-{xctTqn z)wxGOcY<<-A<`!Wi)z{W?iHEX3Q8c>p6TGh`Ya zzP6A(pu2JZ_5RtRy7lj$U-ZfIUzPjkA|~&26RXE39{SgFN&{|qO^4E9NG49E(F!oP z{CV1kqJ1T*7N8Hr-K!IHsIi0bahMIyjl@$bN>zJyl6Tb>Y>KUHem64E{qoS%vFerz zyyu9sPcaobyX;h21FI?Uxw+~K?2a33MNM~pI6vDLjfV%XyGLq~I_DRsXmKUotGqkz z!&oJ`CLgmhux_Q^)G%s_jZWBWAu^Ae_CEfJ{Ly>|e18srk@$Dk3h)#BqdOVKAL?t3 zm2+dFYSS@zOL8FmLSxvX3B_JDu29va2($s9abVVpH4%aeLCA|qPN3aH89V0@Rk`}*V(y^*L^cj}!$B?u+9fNe1V-mDB!0z>|O28FTEf8jd30Oxy zV$@i6q@*1(~XC?e*}weoB#+eW>2tWLIOe zk6x#@>X3ocHo^RUDc845^KD>(O7u}=%P+MoWR;|5r#GP5e5pVqwyvkxOYn%dZ>fSN;EcpK!7OGlXS8_ ze4P&L(}sCI0q&XM($DM@P@i^A=3JC9uNU1du53N+SlxXop&WetOYULt?SdMY$P4)K2%f-+&wXa^YE5IT7cZY17JK0hW# zc*n%b(O_;soe^fwlHofdR@NT5Jc;Ig4L;ii0L8=c88Cl=)-*#!`<8?zV>$O)L5l*VJ?!olkB4l=#Y z5{UMV1@a%?irEL3;F$Fkz;wdWZEtt8K4le=5yEt17z6lE5?xQ!y&@T~Im;o(Il`a^ zEyhw4$^0a-SP^3(!!NRJ^R<-{k6nLGM?={Z$WUq$9Y^q7)SZPW*OiSF{e`6HFG{?M zqHV$*$9M~qB;v`FU*wGV0ZX;Nu#MEnb=z?~Z5MDyo4<%&3RAEk*ajPH6JLwmx;b=E zx0}wpnsJaV&}Jlvrqhdnj5b%z#uwS!Nu#9!$MX5TNx~F=Q(|b5-6-)oRKmlQ7QT6p zi1%Jc*-PMNex-Fe&@35U^+BPhwG)4TQwkXG4oB3nCnNp%aNcccI4c0jEWbwLoPnJf zUPW+;a^C^#5Z5^%@@weus~GT;;5jpI*|>vW@*^zk$S>fap!g?0Ss$Ih5Llvm!NtPX zSl6dd+2@}{T9lJ$EVe}WfRZ)z3WoX~yr-*wB|VU&N>#i@_$)d#j5#N32OWNaR>E`~ z&EDY=;h6iPOj0umn^JT*2{<1&B^%{~m)%nSbj+GxPqRegkU6)HfrY~|fee`lkI%rq zc$EUD?rhoVsV&4M2Pi$ODeXEg9HZi4E%$l(%bL%6z4Y+4b%yy4@&q~YSFrU!Pi=ST zQ|Yv{T%F2mQ}FH+`~o*s4YRjIo07eBbt#i_Lr2X3EZzv0HJJ+(5S<*yGLg9+>MN~O z5!I&^DM1-a$BjtnOF>(-@~m0~@uBz%Xu(BBwc-mGcm1qWPX z6Yxrk@L5+v3?Ot7Xy10_oLiB#XTmePaBXC?k zC2hpW0kr7jcS;31i-%T1G~Q0S#{e|6e{v4qCEbIL;*Y}~dYX{^YFlYEwmdQkvbe^W z94137jYjqc-zd8$-ShBOulMSx6WR;|mW)!*ayP;J<=C)e_vHKiqwZll=%)+LFkfOMrRE&Gskc83by*_k<6%5kyFF{+mG)*npKd>WdYimU zo*qZZ3RLgIv5IF8(5!>ljkq-YP)EiJe0|7pjMUS&a5HKI z{!pMs0kHRr%*%Vg^8W4=hF&_=@Z-O4A?`TAgQ_iman=#STh+k>5hu}2-%ft5`YlgB z7xMcy3@ZKrzQOt^p2eg1eKaBGLeDrkD5SvVWMa~cj!eA(>nuLngBCTX^n5Mq2J6v# zyR1m#huMZ^fApg$?f}dhR$=39$uR;AlLquM2Jl%>cIbrx%`s}*DV=4Ma6YfRro`#8 zD2h{n@!sNl`e>-%hth@gD?-F=uy0I;M3+si{N^rSy&Ok7F%6-bcn>eh;$jj@N-ur+ zl#!#$pA%V5^HYSA_Jysj&Jfi8@50CMQli95Z+4id>rH-)!PawRSeK4u5FeTR*olf3 zRZb^%)puY^c1Xg9rNgrK-{q7ZNlG*Zkvd8B{a9OMczGa(tIH6DzRi_w2Y2a$t``kk zC-)XgiGg-0HIV3!XoOB0q=O*L4MRpevJxGoy2f*mUORPEgg^<)Ms->qzYOzBu(IiX zv~=M<_jDKLiRW8(v(|*?*X_?T-*RTZ37)~bQq*s-he^&U5vG=1OPykT82Ge=&;pqCl4io9a}{oCKoPqF$>e4!$U8vWkLH zTuqs>%!r}|Gp)LHhW}VI78o_1*!ia6c;ta|X*lrCH1ZCN%%dQ37hAz&&Ud4GShnz{ z@4A1SyA@qhQO^Z_kXh^5rN($}1<3exTe1$8!{!MMFJCp3$%*S_7Vh;8r zRDEW+HcwvE{1Z7>=Xa*76g~Guf>h_hQ40pggaoy6oy=4F=@*j_wJ>0+h{H0~^f0A= z&c5;bH&^)NO1hhn5S>}SO&uU=X}n`NCm089>$cM^x*=zwX<^rc@LCeo)nja~q;G-7_>NkRN+oL$6h@*0G^eJdxF+T#7=w-tLZ@hkTX+_z-gD)>FWeUtN|SiK)oB3)E^nnS`7_ReMAW3Q~HjyKtGe zuG{P*uae^`IF52t6nP~aknbyVLjL0&??AQKq&jBKA)|QFz(G7R$^O;~>;;qnL8# zUg8t%C>mfSggQdk-%i#MvPMmz(pf+?L!FWdG~TLfss(6d>;J8!;U_Ll!s4{ zYS9Hi1b@+ct+%kg^)=e63T&Rcr_(jOE zw(^`?;!Y_fgCiI|7GyvWpqa2-H!g4rZmgx#@16Ybp=!zO=jT4Re@iFd`2H9&D^0y` z;yvT6n)u?R%1M_})Ms%09dJQGPgnxMNzduc5Fs@PmE2P z5HV1Km|~%ZUoR6 z&{;kLI;WV0nG^IY0zDrPtk-$Uj|ohz@TOp$12m6o{h_aY4|{#elfgMN2*F&($saNn z;f=sSru1vteykzLy=1^BBNKk_Sjg~}laDwZ4NVnAm;mBzV;tbG+tPjXC@-L{dokH* zL3>#rzQNQVukiCOtoD`qbCbzh-P4cl4q{f8TnYsbMM_9%N^)VO4YPW36ZsSaXh%B^ zD7!_5iYA_cw=4{wXbLD?^Y=M0skO?#Fkw$hAl1nzi!SS`toE$BoWloMI=I}XD)FDp2(~mOwMw9S zAef{TJQkm5^cxeZ>on@33oUQBqSd_Bu>z9EV)3lfSDJAS3(l=nTV4?#FTWy6Mc!E( zJ=6_X3=1cEF;OC%mHft%8GF^69O~Le!j9cu=E%E-V;|+slr0;Hb2BxQm=6s$gt;D= zT;a(vow|MCV5AnoNJtb%qN;I5T{7Nb=<$PhHu!H&!LL+F-j^vRMZ`$X7tsv1E;R;k zupl(?t2K%{IiSgw2ODKpJx{02cDvmQo~!yqQYU1w^ElB{M@s~c`q(0Fj%CypK|llm z`=EUqT2{&CKYO|fkvb@fHlMBrD2FfnW+jbChPy5RqKZXU!VQC^F(elZT(>ibaG42Q zOmzny4ior&O(PcH>PR7sF;U9bXmrPk?wMHI9$}u~*UA}iduP((U1Zihnf>K2PEXG| z{eF0Ha@N^Dc#Zkf4j`E?Bh!a3I!C=Xq1rryS;`IuI)OH(Oi()<&GeZ3mQ#|e6T$-0 z{>l)t2k_qubmurv_c1I65ifrIh}}b@To*rT;_vE$O;fgE(_5O)5ReRuSxQaT0|mqk zC6({?PWo#$Jjf6s;CGDAL7N|d`Z?q#2(&;U`J+2R9>eUv+G}|(ZXbhmJXLomaJWb& z??@HE0$fqUoA4OvDV8pN_9Rfo6-y1rL_c2~-s15zP77kpA$`gqBS8{8LHvLWd z2MTgags+cx744g&xcU^oblwE?K*VR8NY%+#!HFfXELisOyqT$An)I1;1)BhtFZW1O zw>1gFS0AV}+9$iBz>d^fEsjjyiP&+zi}Vu=M#m~%8pBke!Au@4RE9lMz=2Tl7rxN>Sh!Y0Ct2aiO5F>sx`PIPcDk!yyd24oyGEf$}62!s#*MvHSTc3UQK>VP>pTJO{rYnhH`20yj z3ze>|iXb>V5iDR}zSY?}0f9&p4*_;0AOWL9Da8n8pE_G^{n>geSif4w`Cfmyo@;9q zp)qV(Te?aeRSt8I}?b9 z1=*sQwePU#7(01yV4Im4X&m#EITDD{=i85ihr?feQ?9+3 zPPTYPtA(!64gM9FY#ytND!|fz0}tWoPC)NZdqv4cU)1G8D*eBc4UK#=q)SBAAy}Qp z>iS^AdJPNRM3iF}uUU9cl}ODC;62PvL*cd1G(}del%=tN7{Re*bl-qXlG3 zL)FKD_WJf*da$E_BFbIGD>uGiQ2>h0mDe&DWaNebRS?ISfv(yCW{acF!vsM0*UVkI zdve}6JJ~-nqmU|l!(jC`P~j8U;$kQmzrqD+!f+!ENnK@}He5)jU(QZ=9c6BMJI__u zTxxZ6iMSHO?VuGr#v+chuv2Dvk*B(d>#X`nl<};*m?zzWtlg}vy{u0qJf-`YbBr{6 z&IzUI*I~RBPv9T0$bVoQeqL%Q5od#Fir483U?(R^Z0gJKfH(<*ImIv8&_4k5 zCq(g?1UBD&2cwvpK9LK|`giO0zQ7q`zB_}G5?%&L5d!K^7kX7%=z12%6J6}b(qeZp zj8&IAbjqdt#6)@1NOWLyyB-&wDFr7@3|#EcwE7v<#y4_Dc3mVFPL;M}ZqnMa&#fBm z4@{eAhQqk}Y&zn%XkHN28OSMkO^{Z@Ac?8|Lz;YFXV^urbm^a z7N7mX)3;z}3*N~M3Rz27Y5nPEjv^o|Bn^Ya0#k?U0Vv8`?UDtmHbvB;MmzX1U7(cY zqyZXcsbS@6;Z)D0@JtY_^(K0sr~#YW<`+~G`Y~ssv;{yMf__~*80dS88~)v)s02UY zQ000;%X}u;JdQ9IjZPn+N{%U1m7_6p#B^XvaMdOHCeWs_>tsL!%sAi&Zb+vY|{_VPH0DQdp$TP>?j;6f6xt^o!RKpa? zs_ss(zP+x5B)p=c^Ve-^TdO^_C9yf)i33(JQC|AtK5dsUW(NUVR$@%TPE+gr(?Rdz z$zuUn2EYzycLGhW z{;(~a9E|MqW{`|-E$UQJT`2YgVz`*EW%{0@dI zJ!J-@Bf;dNCn2OYG$m)4&SCvkz_hiy&kODLOw$sO$Ow0)gT15hhM z+nQH8Q8qBz&!S^dmXn5%ITF;v79rlEYMAe*(rjl@cEcVMq*cT18y!3%rE5(ALBFXc zjp+&P;tZw}qHSpo>Q%oI}tOlw8jgr#AGu!J(p#x@-zAFq3Q3q8E$? zQ>maGt_gb42;Gm-Q*Z(9O??2Va6<(Yjh3fM|1W|%%;zYM<<077Mk-8z)q!e$M7ERTh z1%UdE?pX|jfbfaByL60!CMkOJji!It`9AC%?{}dydo&w6YefUTYq)F{E$q?k+A&t})G-pK zc2jvN=4(nkp>SicJ+KLv7JOWbfX${02U=xk-R|ZO)*3To+PcUfbnRWOX%X$H0|WxM z-qmOd*7;=w5TKHlP3TZ(YADFLIJs9k23Kl_rX(y~_@gexQSF@+nM&3QX7C+J5f7$Kv_=;NDZwles+M+Wl}?Lb(uKztKtmgLCUbQe#z7mB*ke7Y0}3|P-|c8(@9_rxjUc>-rsE7s z^x@TqqgZuwEdYF$R_H=k~7cc7kRoQY?16y0NSZsoHh|RwehKGZ_YX~Nk7ArW)0lxJ z3IiMx$VINU>Y!z+ZQ=*-Mf8&fb$L$fy9wo;V5g#Ittt}oue)r_Kxiu+8x1X}W#q>u zuO6!^S}JOn;Qo(*j=!N_@Hw_O6 zTfWe@zN$~Z^;Io%_;6Q94d;d0w}DMe4!a*BZ?yYMQ33=_by*lKIP*4BG5#qj$Vuar zf^^lTN$u9VcBRlVPsA{7Vg=lkj5o>EoZ&>r5d;Fx^otSfEzFce$k&&5&=U*dqbBES4hl0y9k{WkzUGA-9(Jebj-^bDbWfF5^r z!!!pQTU#<~Y?1&gKj(FdAv+I*gD5v}qKJ#O;~{ zGCkVb866HS9O#N?%!OFC=&w@tIPL_Ue*TlU`ZSa$A%`~EQ?T*~r8-zxdl|k&e?Q?` zxEY@G0iZ+`ZEnD8*f<*W`UH{gVmcE6TmC&Irv&o!6+R+imW+W`G`YW!S`O@8U{8eN z_I&B}!{hw}_+a9IH*|Y_<~?tNCiKebz21ztcyt)(e?HcqV^(19InBf~=QpvHwh0(U zt@1b4j}S#oDku4HONI^V?)#0#?wq zrJHqa9x%vKr(KZrf}_0uMuZySSJxqQB5PyDyQbCh1+HHr5ldhYume!u=h!GS8HX%V;B7&|a<-l$8gd{t_&4On2aDVz9ewz zfyw56(r7yATFi-xI-_c^FR3|U!PVoLpdeW*m-H+Bd@BVHPF?YW>o9s=wz;1Ije(%!IPzr-@GlZ37&%smz8u& zKEq%w^LlcXf*%&69AyfO2evx?$FLEu$AMMNkN4)Fq^ z(Vq)-Zi644NE+}JQP+v=0JeQu6z!}sJ2)CYltw~8+daWCw0^-p?Vw~Eh>rGr$_qx` z5^Q0sqk(>wXFE93Sh9FGo>VwCJ~g_%1F+0+?hkyiFlctNa+ka+e6+(%=7qsy^QJ`E zXPggEO9KQ70000808LfPQX74Srt$*-0I&xD05$*#0B3J+XKZD3Wpi{ba%F5~VRL0I zF)lGNE-)`=Z*OO8Wprh8bT4yqV=rfPWpi|2ZDDC{E@NX=R0RM5f}q1-rBz{T<2Vrg zo?kI!xuY$nS$a^8?s4GQN+NJzI0&w-v;xN}ww!Lc-T!_wO1epVyWEG%2S?G2 z-n{o_tV|{l*{7GzJUlwM`uOoWfVs5~jRxLUm!ru9!lnTq?xEAY?smGSeF_O(o8EQi zesIRNP_{J;y#~`lZ-=hZe&^n_W%mLb+im**o{f71+xc%hI6~Rl+H6c!5=H=Jr{PI= zTjQLr;ioN1X?Js=MxTp!1beWXS7w#1HEf68 zp(s}(W5O=)?T$hRKM1F_&QvZCM9G7_%cs8;$Z<1 zriwEe08gW&h05KrV6oDjs$rWa*EbyiOeG;-6ESZQF_%odHgsYV=IpZp&a|9_C?GFHo=FCzFXl2zLcV12C33*Jz;0QpKrX^0c`KK2vb&TC(r_vlrVN>e z(}YnuuQuj_MT%ssy;FE-QP-sz+qP}nwv!Xvwr$(CZJ*e-d1Bj1r>dU%yT9t2?&{tb z`*K~5HP)PSyc72iVrDo=lE1(43{kArV@N@{LUkZ;wXq*cdYEANpb3X~jM>i>92+GS zh!&Dtvk01UMLQKrkVoq9j_ddkZCv^%h$LB$Lx^#%3{K@-nm7sz9J4(yEy)Yoy$T~? zr1l*R?`ZCBf$$j1&|*EHjyxB=Rv_Q%&U026`jl+kP z=>E$3TiN{TJYP@4idhiF0&DDDCY0oqf88#5I63^$ZP(e8dGjoUQ}2k?!oH312D4`J zwlJ!|le(+DLjb?4my&x~v#k>wn(*d==*7eAR}2XMlV8grz{&-t{F-MBj~~s!32!fW zDbFV})?C61SFHCB;Qy2pfd4Khzq;~YAJzX;Ir(o&LjPY9@;?v!ANu5qI#_%JS5>A~7p3o{^DPe#X+`m<-3=7=~qE~RixeA#6_3|Yu`V2#Ql!keLh z4~}m>5eQmW=tBqOL#~9+e8HrHsxO&WU!556GB1 zx>La~4ELZzmCeZ?;yvOpT#QkJbAr^YZWjPV#Ar?lybG>5QV0eKzstyn zs~Ds>8Uxl)67g2s-ByMqbLNpjCowOr1Y8_OST6?*?W9(?QbykUSvn$-6;LoPn9N=d zdm$a}pGU;AIH`L@3JNv!>cH84{Tfeof?H zO81YMAb>W;cry@iz^jCxS_!fxa&kB0b%TNJKS^NpUhvX{-|p?p5A7VBk1E*ZS3fma zyRit3;0nUy!Br3SxUzC&GO?6rZ>}Y^+3-CF^3ON?3+FhMu(G^QtX~))ihEdsC&}947ZU&j zrdao|)&UMo@0bAi;yfDqOo0l{F?CmCaklaso&2(2Qx4C{yeoENeYh#-XF)YLQckLT zRftv2aktIc#Y zJx*VzCeAwAFzAf_Md)AS+A-Ps>A!r@rn!HE`+O93H7|*9H>ijBlK~Dne-fBv=phl+oS?OD^J$=*8sCn-F7v-N;0%o##s(c}gvAuqNq z@XCOU+%kN5fq42&qxf|=L&k?{-A9;J)X-=aI;FBoP|mMHu-89ex~Xsf*7~?Xl0xuX zfj=AK@!gxuPpBcLs`OCgauYGc`}|hbDR*W*^4N;CFS`lQpCsWrKV59j9un;#w2+j)N%9Cx(i_QGIfc2XVW=Jm%RnKSz!p6} zbYV1u9l)hgWz)ml1P=Z|T_HIB^A`m#zvdpPpJCH zN#+_#@wsk0e^s3*IKd{t2l(TY{IdVJ(MR)UZ+G~nDovAx5G#-wvY;s%E-8(GxES?Ns^fK|ASaYufGL(5<|J&VVFg8< zy47UaLS|mJ#TRO$Cbf&*ToZ*%jW31D0=(7RQ0B;6QSL4Cc&}Vj2dv$miqA9JyiinH z^zTwcIc7^X>E|2|sEFU$^U>fRV8v;uUU9(bNH$XF{p)ooT=M6|F}CM^yj!I!E}Tfq zM~Qv@0Uvuca(2q;g+~^3e6F2Jpi85L$5(d@lUhF{9_Jw2VMbDM-J}+sMn-53PMt-0 z9Vd~Rwnl-fk+6fST~WI``Ma@6jfa>6)-O=6Wpl`dQY&hYd!rvl2ZRM_oWpUCZjB&c zqwX4F`!+L%18{?Iy_ZCf1>v$gsvClZSFEQq&XV#OTmGf=y-vnwU$3p0xoPmNP2PNY z??dkCO;KAo(;E2)nq+P6a(m_6Q3Ako8YdsjKv!oiigq$R=&*Wl9?!$`JKSb=k2w&L zjt4;t{af1NaYj}sM>yzlN^%4s$LY+5x~Uyo*t>2#5$dw@ap^O~WlRC$ys17H>0=&B z1LYT1$t7l*ubiPgD|0K+PV|9rFBDb^N!tQbKKl1Y1YC@iD?#ngctV2k{BQ7^$Cyq7 zzD$zB-^VwY1Rp0gGWM})6q%S<(SE#KA~^vakuqPUjV=kUQQ9Ea70K5de0tY>UF<5U zB=C@$H0s@zhIr##%X`Je%TLa%_?;BC4lTyYV5CTKFO8j{&*qNqcu9!HCAg+$L+?K&ju) zaNX=)osk@%(k=nIOoR#Qmr?Upx42ggYpGTva-+%2mI*v(qVd0fX$Kg`%s67B6$RxG zestZk12oDI#rL^tz^^n)e;+O0`A+8FNT(a`=`|CJ$NVeE=WTjgN#B@ra&wE!JX+kQ zcM3NZ!NVu1v#pTk&cZrh-@Y2+gbt0Ec1}pTV=6IH0kc5e3+O@y43Edm_5moW>Db1w zvl^BYP>CE8qtk00r^nb&R*!b9aU63qOJ9atpc5Y35wWuq<~1egp+G$P=UHnq*NhGuM1b0B=9B2 zgE+$>q!^38?ULkQM<+{*et3%xx;uG^`ACxR=%u=)uA&sxNRZgkKU5dDu={jeP%(}~ zi@gJ6RCZ4IIUTdJt=|`Sp@k(PJ=BtXAd~MDx{tGWn#}Al6GlOELpA?3&3Tb`;&_Ed z_dGe3+z^WRv_&h1yDYyEZ?O1e%YBbrZbhed;*{TMQti=JQloT`ruWrr(;tMH3tgqL z+HX;`A^1CNLS2{0*01MV%NzG5=1a{Xch*^sb*)9dzxL~A@Y?S`4eg#G zoG}h006+*10D$8ED?|H#KEP=W9Zd|ZXzgriO${upT^vnlU2H9!|C^1bv-kKfv)iMt z#&T9$xNE5X_(ojaUuIRa;Ao3KOh4W=;WX9PY;4{})}d^P zCvhN>95)(Ek;GjkO2jgwd)y){jnfh9oCQ*^kwv8e;-F%z8O4C6c_K05AG z8>wyyDlCxv;OH`U>Iy!8qXH#LM?(bGJ4JNeWM09yN-dDkDa9bbf8({QQu}yQ~51Eqd62Eug6Pux0l@ZHgMiWhY-fg z{i`{r>dgi-Zo2AhOuCiayLd)#wBxn}qt4oTTm#-{Ftn-uULzRZNoTDAELZTuT-I(Y z$aDnZ&7hcoCw-6f({)~d#dSi$8*TnJ&YLEqfpGxi*wEt{+8tjDrmIEiZ1Oq?5aB^+m+iz&R{MzA>EUDcxmqErtDmbFiwqQ=BS8*f0N8$GFbj*g z+{eIx;JDYXD^E0bml+2$tzJ{@R$OsvtImHT1Fo1Xj8;h~cn6u+IHUcUW%?ej)>_he ztxhvynejYQd98`o<@LciU}>%yr=R12jx!l;PBLJS(X+!+-8aZLOu!+f}vmLJv?3 zvIVI~(=eM4k{Kcih(5lY6KxD>&NL82DcyZjNt!W0E^0WBA;1O52p3tReziZytUlP` zF20u8!GHA{z{cC1_G_h=r;A8;gCdltg%1Z9S8V4ZTjvSBQ$0(^H&LX!1>dR@kV&>r z9S+7>-&2`t@DNf6qLfx`OhO&Jmi8tY&v3$IZtTEz=M0mO+>&7dN-pp~qFK2R-c_hd zm>+LMDBF-B2kJr+ubxL}(wzQKL_2kN3U`z*4-6}jD!A$J9WmbX$L~t4zShUOVD+IX z8FYLjvlV>(i^Qh6s7Kh{3ir%jv8V-igm08sPi4eId%taS_u1`nyIGUR7yHY7xCk)^C9Au6KPp1^aL6k@ z$J%|}W9NI3S*>=>7r2cXt&cLtS-W;`L8`mtRt9$WEFS6x58vgo){#WH-1#Of*O*L1 z#227uK0<-X}T*r3)lKf10ppE=3E&PVJNV~fJw<`FX`RB#IgrFMN% zx5RG-sjCwa|IU4fXMV>UO{5Tw04zudrWnQY!DPp}D@@B>?eaVIS<2!CD2rU-a@H-% zeOg)`Mz+$w+SnvFzvQR!)=^|t`xhs>=d^>JMD5MlNPSk>g*W># zRx<KZd*%y{2QPRLBUekjq2!O6<03e;#J+1kM%gOB8ixJ#c5OI!OFsZ-&Wlq1m(W zB1sW|wYrDy=^ehtgHpQhR^CR}zvG*=cE{LJ()gQ66-}MhH#0VEvrp3|I@wV{vJ-e4 z=beXD?vCr6+u?p`Wp{p+g2`l29y$6QL!_O8!l;dI)Wzz_X(@F`dEub>pTm4T;$%vE z=N)OQ0(O^1Vo#SGJ?fE*VWlUW)=O`24z;rmR%>07#@?TiO-??cl&4vzhsvq~0=6yH z^0dlS`Dj$NJ8yMR><-PXtz&59(`0c8rLK&FXLb-*zp(SaTMx@<6+Y^3z*79Z*gxk$Z~hmviSCsrhuV1pg)t)}kn>@F3Z+>$ zGsWwb+WmFk_^9vL?Y#4Mc}348qvTi7yNGudvHUtRo2#KN8Xk|N24C;)9=PjOS%%ct z_{OzN1y1?!+|R%1$8}X+a%x$%3!^V`*ZqnmT>3OjTRX*OFefR5i*Eqg>Ep>iwgtbW zyx!dOi#T##ZTe8E7Q-#{Gbe3U*f8Y&JiX6}6ZFo4p{L|)jgA=D2i3LF-dUCQUBjQU z^XFNTJ$I<*M0-u1BXJ<({+F|;q8lf(%a166XrDane?8IB+$GZu^wM z007Ei005N!fA?g1|Ir{(+qB&jL-1MsBcn`^0=zD#l@Bke=wGO|P>53DNJ;IBMBzwE zE93yGdx>H5(_@yJTth|~S?FP3o|D6DcJ1XQ-OJ0XYU*cx8rEj#hc!R7;Zq=)x<0-4 zoZ4MTKwew1&{B)%Jaa-5>0*0c%CyWw#ls7|X`aom3LdSlGPays$ja5;JqAvJRefSj1Tj`)$6565_*hl*^=b9GYUO z<|xtWv8sINXU9jZp0u5lVZyfRY<&SH$4ZI8?AqA^Pji0Q&rxC{Q!0*-l?mm~I8t)N z^b?InV=8JH+u8YMM#SKbn8u9gp4CS1G8F=td-mHPiC*%`*sSI~Z=NapAwk7m z6#GL)d!E+U6)ZRgkjAIYfo^%&jM*&{muaDcg6RHtOdC!{*)2B(H@n6%-M6sj_&oqQ z)j8u(#i_!7VxBFt^E4mE$zB9?0S;)y;ja9u*5lv78Fkco(oB18zFGSoRc(1=RZZtL zul|!U9cqPnW_6D`LT{RbGda1T(4iLu=-d1~Uuu(w&;vz!xOxJ*oIMs<15RBcg&NGm zgtCI~k+H73{J|g-nv^0+k~R%6Bo9V-4?}{`@9ev8edd@w8!D8(_H7O1zWcs^ok9-3A_JEr^DM@r8OfsU_Ka(P2`>2k+V!?e&LC-_OTu|#L zwXPy4yUZ-3gC<5I7ae^bQ~NH84;(m9^AAarRtypPT%)?5B??nOoX7?AuR=otRux02 ziR7qy@iQD$K&F3Y+~ly@JDg>IbZ3aubP|>C$=nj(US1U8rJj!t2To=`PIqCzqMNB; z!D>h1`-8dKoC0@umz!&x-|se3SG$%_Xg%SGwevQ|5AkX#q#3o&R$F$2t7x%2 zdCYV9+Ji4_Q5dn*M6`^Y85f4tGf0IlTQ`;9UQuqVEQMt-+H?S-b^HswjEIlF&?mm1f)JG2~|2t}s%Mk+pupY30*0 z;xk%Ok3p|tds|IZn>WI7gT^ac}y&l~+ z+ujdYZxfbQufu}bGUO>)=k9{*Kj>GDmVt(Hr9nBSE1;S1$G+BSWwdjxSOWFN>gvq~>QF9*!%yxQUAA6rC@|n*u>d62AwvtO3_L-peVJ)&w zSaUj!{pqehs3%(=q-c*l+kgd)s`aL#?`7EFSd~p&UIjIrZIt!9_J({&E-k|*gZ(8< zSkj_ST8D6e;z-QQ2iwsLZoWcC4^ykXY+xBSIoTEjn4TkBiiXXAMN6(nwU3xNa zJ?J%CYblOYEgqdCL5QIp=0{rAnFiUn`7~Bd%M~?VZwZ78LvCLuNZ($vc-ZJ&r7PP7 z;DmiDB-ZPvWV_^gw8hHzi;_3joq$D7g?k(BsHW>yi8VKFyO7O|35ti${-*ARzw4h^ zYE>QFkh7$ed|9F2{r%*~@bpKe~g8Cgx8|c9*xy$gV1fu=f9F^Er@RT(7LWd zx8?8Lq?k5$trV0xgl&Q~hD5ARvUlkJyvsr~FANQS>kF{tza6>%-Mh@lz}d*0*2LY& z#NOG$&enD&oVEa^iLK^CcV=0 z*XHiu258C?Mzh%TW=!V8^p57z^hs3t>(}NQ_zrKZ3YLhG3zo#d5W|U;$R-H}($(?c z3;BE+88&OOq!P=<4+g%VKpH4U)oYRhbt8!F>|AB2xJc`2qjVMDbPz{ZnUHb5Nvg`ua~&5`<(e zj+CUQ#3+_6unXz~f`-I;lk|HMD5I8#b~qF?hhFQxnR>psM-3#}0a9`qlMRRtt;L-< zrIH$?42BGf)9rdj@`XNt@%HosWw}p)*b*7eNgUu~SwMs#BW4dhIf7(1Oa!zHtH z;61Tdo>P}@w-&o@IS&c^_Pi1mS$H!mPl@Y)O`hWlti15B+ow9Po^is1yjL$jVy{>; z7TY|FVi*6KGllDa1;AtSo=n^|%;U4P9E^gm=TFvJuXYaQ9d|4`eQMP-T)g@$tl+lC z8#NZ3y~nbiXV78CZteFqVPdX2@Kl*`{c$aW1(}<;wCcKHzFD|@s%#aS+AFo|G8R}@ zakT|5^Vn&U%wTIdY;QeElIfBd9r%Tq}?r~1i+XabnBvx;%PrN^i&UVy)q{?0ZCpsOvKSK^2yEpgGR|;M-qu zu0&g4M;TijKfwDo`{y3%0S$MpuAp-hH?P3?G|HTV`&cZOK%Tr9i*i z!0C-a`AbVE1ch+s;^~)payJgHxn$sMsL;kyHD=Cgqg8~GIi*)l$2_oF&3jnkT$G21 zCz*v7bNTa!3Gd7W22kPB>+adffL-q1w>hT{-(Jv|pn{cBtd%FKI1cpez6(RLw_nIsBkF zPUP@y7zIr5V|9h}0Q{iHnO<4%TX!II6Qzws%bhE%{^}!0G(-?5e5zO8$1r91DhZkBnMYWz`LQsBvDZ6Osj z)uGE~)U*J`lV8X;=&M%(UQ(|A?!CR*_k!3VIt|2p8=r_vh+F3}F`EZA8TFf&C0}wt znyP2w{N2ToqVR>KAaSl20O=UNSCj%b$|dD-_^;>bjYo#d{X2xJCF1W);ed>b@ED3- z5}mvhd8;E-P%8<988a4hIK{XG-Mp)2M7A9;RSV&?kx{}{VU_+YMlngFaYTFkkZu48j)zX!RazM(rS6y z_H}q-SA?qz5#)yxE#b+(y*K+7Ayg$9Q#_@|9dOw^uI}o;Ik2kWtK)|){d@YjOtxQug77b%g6x=B_Gkz7c3)8P9>7v%!0h zj{?9ofiu83l|<{CVFq{rFNU}jBcPRec1l3GP!g28dDwqqTP{JPXG^xF`F^DF{9tP< z@7}YtDvo^+M7sXHV))C+KfK)(^{r1w-~-RwCVNx!(5odl@_m&GIi7lrZK{p$s^ace zP@oOHxgXsYEoJM)Z{iy>(8~CpBs{h=-D6LVa+7Lt4)V$LrWkY!Pv9cjrsNjMeudiq z*=_HRb7DT^Qy+56_jO9(z07NKnlyTTD!E;-2niZxv?K9_I*?5Xs3Tfrwxf~~5H|#b z8~g_);Y0&y(I2+nqJsHAzOw9=8hLG`@nlofE0Ry;gB(HGd(@^u*xRXmR7ghnWmb5p zPL-iK=GB^5wc;6Ky+|~+5Zw0kU3>UqomM^PhP-^Sxj=h?ZkpY~=jDC3KK7Koh`UOo zJ!;Y9Xu+DI4M{vr*WaS-hQOR-mC$2Dt#f|BI7UbR;8rxMJv=A>##Oqco7bsJXXCMO z&+nQAw{v~j08`_Kp1^B+v>N@`%hbiZRKPzME7)q(?f7rYA)CTy84ctSKPJ#WCx?+3 z;xxwu0YhX`{QB>J=3((O|9_ggrsj>x(ccNp0RjL3x&L2H-G3A(dNge84kVDiXX+>z zJ5e)8ja_f}7>kl{79mq{vL2)x6Xb+OYy(|JVmhz7%~?M->nd&fNV-V~HBdkguPZ%s zE6*J}J}zNo8r&1lwyXVj|9(B!K&J_9nc!6OT(`{3^o=pi4MLIp(cXCozFv$UO;SN+ z%1IWbatyx*ks2nP7K~6D(caA{_8`gAr~0SuvQJ2BN>KcbW+JG0Oe9%mfs+tRCz3cA zIO(B@!V?gJ@?sH)K1@S(i!aWrL58>R31^r48mHRK#Yg9aJq zQ2|AwDiWUVERO6TFWkZ}Ax{^{a;$?RhiY6N?aV@ZGR~}S&Nx%(JY!9;u;Qfvi+;MxJgzflor{e*(F4luQL-LI(wx;>G}rJQS`0 zp^QVoyMZqy69q1n%he=6>n`IF;z&uFT^v18wWU;PDsa$0ci-J6#%Q=)c(qW?2 zU&H2M01B7UWzXAVX<+OgU=rH8-%s%lqGs1=M9K2k<>teDwyq`^|bhu?|EZ2mqj>imK*wV{19|5s&ok-+2Bm-SHPY)xBxnt9&cG2_` z%mEK>ps$UYHrC*@#*IP3{J4f{AfEQR-+`|#h{4eAydB`$HQQ}9Y5eV0ucOCJ_m~03 z%m5^uB~E+FksYvlQebC+t|`~YLyrTRdXcR^Wj7}rz9euK@Z55Na6;vlezBcsc^?)l zhHe`QbK~_-_lh-WYrp7aDxVWpwvd^%fmP3bt;9x$Y1EjdpH!4RbykkSJyjl=#s-HO zXgV~L8x*$T%wEU3)aj2ndNniy*ecq7-H8$3t6C1Rvu|CCHoEq{;oy6-_LOtb z3f*jJkEco+inh-pOHm`~FmU?cZ>g#kGhw9xe52mEql&Id`F1Y!b^*mpyg&CW!zDZ( zh2w4;asiq0cMb@%a;pnv&TVb(Le6>%JTp=>yZkB%#f9u2>;O>QwJ`ykIMWN`j;}zB zccaax*(|EfHxf4)-@92Y79duC`abn}SUwpOUV*4%)RmF%@)b-jpwY^m-@W-h293FF zK1*o&@Rz0v-|S)L@N%eICK2Ic0%mlXCZAq{&9a=e~B1l zEs2`danaZ((_4PPG(S0U=K%WAX8nDJ#G5o#-b7=%fb8mc?S?=nxkK{VQEzt@J#+cpWOH4zB_3)7{eEOG>d#_5#$J;7A`kINs7|}2j;f*)nx{IG z6VmNk^!EDNo7wrNUYT&!-}Zb&m0#gRkp@(IagYV=0hH}-X;0p~dx|vfK!aucd^P=j z8lu9$sb@*d?VzP0w^tAGaWKJFcC_G-5tv)j`rk+?x4w}zCe9_}$jOwe-AK+6RYl(A ztN!_mNe23>5aY2D)Vjq7DBm)1#_8zyx!@|Fpd0XUzm-~BYoM&Bt_=5;U-`48!$Mil z>Mx$fyP~0|fFQOJhC5nU$T{Z)>Pv=@E3Jf>gY+d!R-t&rpO za1^lp^|ns zm!@4D)sqPW;`k!ko|pd5magW`3NlWj&jrw?VUMEdPHQt93r)?7YU(T{4ZVk-qs=;2 zrJ2>~7vrX?Ib5i5U<{NKTr(I#Ijwr`!MqgR)Q{pEkWnD>;Z`wvk4x$I4UoH49c{jBXA_O5Q6 zn0hPrl9GBWKDXB!_KOdd{M<@?En|3I4SRUmRUBd?p4m@EHcrcae@loR^Y#m7M)s|aDJ1D-817ygSQf0K3k`iz2axu>Y9 zX0_W3E8#&`E zm<#=Y|EG5_SKuGB`E71MBLe^k{cn2*J8L_~|63KPMBTG*pQuWp> zej`ud?=#ifncRBS_Xg0iZ58e8q~D)Bne}_pr#PZQ?t5sDQ=^^~&_YEKiZ~D?@wqyV zAW=0*psQp`;S})zNQxOPbq!{kH!sDTcL>Apdp%Yd3V~Uwx zJ3Lkk1CpttzTrfA`lCH5uNoMD6&w*=)iO3|zFIB61|E?Lw4z8E$uhB&>#$A1Qs{@> zhnG&QbR}KzU`|_Jnrd5r+9TVPmnu~>aiQO+knRQzEm$ZBfFzQ;S4rTbk87m?RURRD zM5;~z1)pl($B+p{ns!7?S*nO!9uqDpbDEks29>C&3oTXA>Fo?>+X3I}g}kMK2kf2e zejN?J22guqZmi#x)G->?2DsH(1o+@xpAA^c6);*?7I5)~aWrs0|00w{V+MDb7cuIM zuMPj|&UAnQcj%RhY=8XX&;4x9wKr1_jsb+j-iJZVcMNC?vz06Nxq-Najln$IJFHh@ z#dpxJZPvXXAiQp?9VdoDmWpog#ns4@F4Gfn!AxKee7#8=6}O%rhpMlp&wLEBx2st+ zPpAfSxWhR`3}91kKV2_(;W|sj!L3*nJP0gaa)GE@g?8*@10kb# z!t=IwnY3RcHf1tKmER_Ca+})?MoW+sY#4!t!HRp2;bbLjmvFdkndw+#zgPgTRwzQH zyHo}!chxglE=?DNdv(_I+4W&faiH#6ixa+fC&ZM_^xA~qV2=zB55tUFW*qpRBe!Pk z3hW^wPZlCLWY{=7N@3;Wxbf~pd7hT=of&29_dPSl8Wdl|(A*j;b(N_`7zlj<$HmHE zg1roKCr5jo45HdzUKkyoLrrzFzz({K*P=6-q0J}^wR6Fw;|F`LTUWCaTS=61waUqt z-lcoGJW-kWQAhy|=89;i%o8Cem3QByQ^zDd>zrexZ46&xg(ifPz7`t44bo6?xyy&b zE6xXnQB;Y%Q~~*>*Do4s>r+a3-!B%R|=Qfj!+;4O3WgLxZF9ib@Pjb=K z9AehlBm;%xMCYI}{p=*)0`H$qo1Ov$M6_X;Ug4?3as3qL+X^rB zR^vvou9T}&79W4WPe*w+SnBHfs{FxEfy6IpN}B_ey5GVOPEez<&Ev`XX2JJ zp0xd4X-pcY8N~R$OjR_FLMBzwk)icaWOq0@xw3ZoUNlY$^RZu@1fVd&mr5VWbUByW z<2Y5UNnf9~6!vb`<`tNxF5bYkdlfz zV#hhOiP~F{b6B9kv00G2^03|ed3T~Xn<^lgYMW~_8-E-C0=Ns*@~A1aJ$Y~ZltB?? z6dxOTil99Cq@!$KZpJ*&woz2ly*`|z4L5Ha!o@6pIDf9~Q=h%w_3Y4iv4t%@0olWx z7xs3!)8qJ+fn0sv$9;STGpa*nIpoEJ``Tk!ltO-@jqr}_74S=%fi3a+#GU3@NpCy8 zqlL|`K27s*ZCW%Onots{+B(vv_&1y&u2F&FLoEKJ`*i~KwcTE_tSsT~#5M`Edq0zT z%=s|u1TnMu?Ik=1X|u)s3xJi^;zR89?isv!;P!TP;}T@He;thPB^glglMdeJl6qiZ zsW_|KX&y1ZaE|$3TlQEj_X-Oj0085^tq$S;@3-22JcCPAW$g~x5PClTz$oRn0M{gK zD<{xGjUgE!+mrk$OvE}BO)$?Yr@lT{G?%KMIml-7NFvf1T<9&M!M&#qp zYT4ym|{iEj=tMJ^ZhOL?sj3{71f>XRsePRp?UZkfI1KmcA z`zoV3d~#$4GV-g+G*D2D;CYOI#cPYB;%VK(b>IpG6F(O%T3~%8Xf3W>cr21u$XW{ z^UtBn#7SEvb)wb={y%T(Z4U#2Tp~V z=Y$sCY&JBVzXMIh@BIWUW33}Pk|lvE&l{4b%l%Bh`9(EC>p1}qUHB^YYl&fI6|}XW z>hjv#+`>R+6-668tra-LIhTe#&VOe;?oiBN?Ybss#BmxhO{`d$B4?I4cW**{L^>lh zlY}ycTe2b}W+4(y+4{8uIP`iRTItmRU%eCRxx$%%e(JQG2L(YiG9YFi06YYy(IXy=PLYNm1A2y` zA+zY;vPlt(fGGia@3LhXJb220x41_m1=>R5auR=&jGfo?lbpBfpuX@1pJNd}_IMYB zC&F*;Z-vA8-_9)O(B|aW)@YVpHIy$b<$aPD=CzlPcT4*~ZS};sEvivhK3n6y80P0k zz0=s1w+8R}R(M?OpnI`gO~byun#`BjnYtWN+(Ai~#O2c+!2I6zIabbd!0_b(e_aP8 z7o^iSeXDU(QZSa`D{C_0M!)G-mZjv~{^nlk*ig1&|8Q^Xw3djJ1*1nx{N8B6$AwYWZUyfuX3RwxQOx46aWk?|!FRY!<>Mrs zP-6=^#~=F%J6Vu7N(9-9(2ad22RAwDY$T*veBwl>5UenP?pa@D_K_qROwpK)>|Bf#tmeb<+PkvCd$8y`||KZFafPhy6a-dIr~=} z1}Ko47V-`+>a3B;Kv#41oUCyqhoQBtM(&N|sMRc$cH|DOO?S?|+3f|3{{hstkPVj1~Z(xElaK{C`(FjZF-k&Hww0 z;D0;|{x2c$E1wUy&DO-*n{R6S<)(_uv3p{R7cK5-Jke6zoEB0&-puD_UY=%=@hyeo z)VMWUyBE7%4*-(BG!yb3FR#BY${J(={rU{);0zczIN`qS9^u`~Hbk-T@PE(3qZqW` zYB4|_u4noKPTzX-R~y2&)?)ZNpuJ=3My>~*&P4`l^@)yRqo zv8VwZHe4ycQqoD#8A28}evHLR$cN4(kPM0)vR?$u_?1-9QW4SrK30xYbmGWFTh@k%OlCb6ahc#00vr^8ySvk5z(o7{94#Y< z>rc)MSl0vTegIH_rM%@nV$FE44YO0+E9RfXfnuI>=FUT5FK9gY#2yirydHMT zk8=6cEU`)yAT~e?SX#)GKYZ*A^E7(Sys&?Q*@?VZGuQC_gT(R4ZdE8`c47 z{`jBAjb2am(BI9cBuxocrQ~%vT>g@suVKo7W^!#Nvbmk+{NQ0lXAPvZh0lIT*S3yl zLlLN=g6_v74`ZA8v9`60(A^-67}e~)!sCMR`x}3sK1GG+t-w{D=Oh=#?!wOA!79pP z5~>M(7jr8nZsV6%YA%8z(ezt~8rr*H=fT?FD2MACkJ|& zNyWInzIEnBWN1RhPH5vL=-sA^7V~mL-wer{(<|R#vv(`l`PL!==2sl5 zn7ge2$)4KPpyP4zRSj*6mo&RJJFYf-G5o~(V26A_co#?!e0DB`a}3Sy-f2GCjYpcWI#OPtajY6fW% ztkFQfQD2Tv+7TP@wVj&8J=Ebu(1iXK#h2uU1W4NK4Ah?wZR0QOVBG1-j^~5cy#ZQ* zI!FIR%m9liz+Ns$RXVRa!7CDp#DHyz!5;&SS_a6~(~w$rg4cfLOm4vNUXOODZap2a zA_^pcL-Eu8(uBvKz81-dVwm#_7Jt5JyBzF1pPjmXsc@id5(>I;=$UO%$Kq5A2D3jr zu-+KRV9hYX_+giT6x~CL)1PufI4a)UZLR)<=84Ry;(fS(PcGRZ3~#BcIOSQVtN-jR zqbW}oy%&<|nhx(-5=YZ5$4? z6WIp5m_bO7ie0E}&poiyrY$MMa%x^ypl{VwLEPNS(6d8}2`CmKFm}0`v@PN=LAIy?Pw;=NMB5U2Ruw4;3fj zbb(vV4=Z^$C;kES4lX{EvmO9okr;WJcV_6^+$D$$*@D|J`8;(c8c!MZb$UpYZcsc_ z=;kBf^co@V4d?M?1_^8=M;Uu=R=o6UNr9U{`NZE*}YwpiT-rNQ<|9_nB?w(<;Sl z$2rmi()c()zMIP2xcsrjrvlE?M*WS|6WC+`L+hqRkD0m+Lq zSL1H_l-4_PldijF?_Pj>4DRwiH`>B)Z#d=n6nt z9FJPfPUbYat_j#fk!Jqup^n83VRRBWlnamHA*1YqJN}yl&5@a=`FIPjR&{`icJ6pd zsQizFmul1O_T7ziL2R>}XO7eIfW}4;2(8Qzh)#f2&=cQ19Y7@F{e&ySU(wPo%}G&G zRS#GS#+P_i!5I_hL8z%9=f?S?lDd~Ku{Zu;gl;+doB~}3Vceg_!Vj2_Bvpu!%iZ2r z$vth8GOq#znL(kS(Dt>i>xTpX*y)%JHx4_B70b+bB+HeNAifpjuyenNruzc%3;w=( zTf{K9e&O=NIVA03E6q^`s{aff_l!?WvcWKi$b&L}v#4Xx9Az3$HHD{|=Ig7Yigv81 z*DhAC@Cyfvk|l+Q3Bi);<6FI%{&?eMlZ)F@(GjQcTu$eZg33`zcmLU*{L)P$+#wAm z@Zv2XU#OtFU!KdVpcUgl+ScctabLZgB{}W2B4admdx;!lZYd@UhK_u7_$38b&wse7 z=34TLp`)i3t0hWaeiIdjb!D(5#$ED2RFB)^&w7HOB7Udzvd@s^)sW>BlC^77Dr7xV z<;7iz(Ac=|x&;7A4ymn|<@67k6p(m5V1n`>oWSv>yWJ?VwA)G_*3@fz=hG6Iv$BbZ z{=*01YmOSi2(>7SwYS;>927oJy0G~hP?f|-&=4OcU>yy0>y^xNy%!Q4ZY$*+*iITd zAC#@W-l)m_L_xBarDiHjCes^%CH4%hf;ZTqNOBA+(enKFR92ksl52cfNUU%gw}NN^ z<#}Ma*wtLk^h#C)D}9v&r$uqu|0Ah=Y@{3`FXq*=t6gjj5t)ilk<^)AbSqBHI-lhk zua>jOH@+7k&E;;#6H4eVC0$E0`%#D<{0PAjfiuYPJ-<4j|H`J}M8D_Q%A-r_Y(gqX zRsfe9%V>cp4uL%p8Q|yOVbfJWOaVnMr{>_I02P5nCa4aXHKBil(94L{eq)j{OZ0dj z+l;ST?>tnnr!y~_-M;?@%r<@$VV$>zj6f{@3Nn}>{{9GqU++L=&+RZ2d*r6moi$qn z`Kyz^b($C5+V_YK?bayc^Cqh&^^MNqqi=ex|AP|Zw2R>peJ4LyP2A__>0nK@i-tQ? z)y;YJBDb`{sJeCEiDQ~Gom~h(2g4Box27#x8@$7rqYLB-I;YfgFq=$o31;E*A4Kfg zmn8VFDoWrj_D`)w&_=6PN%g8&iCuVsBF%zbcJS7`I~`jXn-fg_llG>Q+B6>f1U!{q z0)D&nsbSLr(*&EZ2v*r2T!}El7@$#LBL(ch`K&1*N=T#$zP%2>*1N-3%^W+2VCh$t zy$`|c{28hYQn^cV za;KhkjG9Ff>qKOsXdD%3z%EcD;e1azbgTk6T&nk(WR75ZLjzr~&E>v@mYrQ%dE7EP zZBhN=kXD=pEiT8P!`p!~f{B>?ER8}V=@XoN83ZV1F*9Dq*R%AV=+;(gJm-l!ldqBq zrJjc5I<3n)YWLZkQr%oEs(TfH;nw0o^xM8xZ-6<^fsTF_)aQNJky|}abKx7US9?cc zcdWRfgtvz%Zv=UmkoQtwv`iCt{@k-dBPf>i?# zzQxh0PwVXa)cLKXymlj_SE$rSvdDJyb}*3?&{!}qk87iE0dUvqp+Bj`K$liG2@#s@ zy>An-cogHra_ZFk%n599Dz0skjgj(jaJRR&omB)kVGEZ6BLVpDyEESgHy{Nf@OH^9 z_Tc@A;0!+F6<>1odr!F*J0t2J?Vce7F`ULx8cXT5>FZIrofG5^kY@trLz{1u=p0N? z{awqV6)M$=rPbLCWVW%ift}CO1(n-ok47=K5!CG&Hcn0pPOa+EF^eoEohvfBCgyRH zOq?obU-UA4L;N{@zZT4DSVA1o;OMXWM(;VA>UhPrgGTG{3Oq#!gwz?FkYpq-XNb5a z_lVQ2XH<_~oZ3p~r1)(te@KHAx^4zMiICc9^QWI?X4-&zG^xH{D^m?CTURY;9 zUa@2hPYkl)oQO`~bh zTR>C6aO_e)p5o)n8LlJU=MF*utFjZis@YOMTub+G>|J|U>t7O^_k^sC+>!lu!j0vLW?o#k)w|8{RtG3Q{m_-rHA zHFA0JJmMqx=xog(3UizVG4XU$Nqiul=@_*XSRzUM@nLYm-aNhE+s3M8vg!-er`M-K z-4mGkDUQ3R8kZEi!JU>sA2>~`QK=U78;h-GfJNJEy?=TyqX$H7U5LT^9vzq=c7Q7D zj!gmW-N!sQS{fVz_wb0qAQ7Q>ATJL|E$L$b*pII*#5p)Q5f)ZXZCapUGLdMyjJFcHVGng%)=uQ?kF z?K!eJT303nbg?P2Y{RIU&^@H4*Ei+*ha8$oT8;meepp9J2t5VVb1W zii!$J2_K-q?tB=-0n|$Tnv=~SMWG&bM=VW_I;Kw{r7-5Uw$6?Q1%_*$!lYEYs1+h0 z*8Ya#Cn+xUs=`X99VQX`r8|RB*1$ksr4{302cLBq1Ee~fe&qA1PzPu z7M)YN*_%o(OxmMIp~P!TgaR~-k}%c`8G6lE_Qr)WG`$>YP_V)wIH^JnuF8{4?y{e0 z9j;uS7uI~bCLk0XuEX+V=;d(#r}2Q1XDE}Lp+bn^8!vXX5ktZZixT&~(#)w@zqfl& z)b~}ZOw10YIJ0l;m1grzXTSNf1(!SDVT|bT8Yx!lRW*FGxTqlYg*3CTmDQr4$my#` zq=y3bHJ6)bt^^aI-3h+~8;{~XngpC}q#|YsU;yUOneGc@WvJU~E|ue;}=lUSRI;zJC zQ^I!gfS>2Kp=mzzVQ;psg`xKG0aed(B4Pp~29=?d8EQLeZPRHJmJ}_prJ|-|PM+I5 zM4r(iOU%RFf{J*4Or)$hVqDi@Pp}^{?gEkzi1f+qC1bNgGD3A6Sd5jWs?lQQh9Vdm zHSAGfzEl!$?K4^a(5Pj-@QI>c8I7H%Uy|ZQxO2fLIr$?_heG{q64G{}A*_|viIa;F zRsrj#kpY#C)Rlgl9Nc*7`(hxsP&H4)%_3kw`lcp3>j)`*;ek`Ac{Yw#a=|{dhZ^My)TChL>Ryb~;%H)6T zPkBvGS#ud`7{h;mRdi$K(~`?&s>WFUO{RYE@7m5|jVgK$wW$p~^PF+vw;mdTx>_mC z5edSfaKfhAy{H!{^(|mFTsbgrrL2XMwH@I0V1e?6P`JZ?cmN*tuabE?us3@Kr3?;n zN5Dzy$V^9x3f#0fakqwY)BTI67i6a88G~16%#)Kv?0gk<&)2XAlH|RAe zY-PDpCyGdqCOVVso__Ae(OtKNc{jQB9mDLLJe+`0n%L+=nj|O>A!zO>f~+~kRNfG< zkId#~)v#-DQ7x>L(IZ4?7$7LHY<;4RE*A1ZVyC-NsjgDtE?NQBo8mY*Nhde*{XP@< zTFFPgS@V}`?)z{q`nmbH@&Ea^`2Cw>@w@eJS3Km8(CrGos20|qNMaaYgaDY>5^nu1 z?Mcx@yhxL)eB1%qGs#3Ttf_{`6yk9)FI`(+nF&#iaI}tbT;5q+wDMS47ms~Nd|_IZ z8oHh$t2!IfjFOR_GL(Nby#fPlTu3S1xO7l69HLA_M&X2)Zy(LPys>)QVwN;83U zhKh>3HX}D(eIz=sTg6|bBq&MTLL(!RtQiR^-4vrW zia1L!TXuA8X5J*S+Wg-TG%If-y1H5M(CH~fzF3Jb&5YcR+~|;sVQ>78M1#?^5^6l3 zEBfxAQjy*`VYs&2^&?*;Z*o|=Y$Pxm=qMngtxe_>!7~h;E?EyJG|8$CO?hk2e#)CX zX%AyC3a>9YXb$3*LC`yMJbWr^`V-cw6%f-TL+#y)9m#8x zIZ7>IX{pvPr;?ZNM!0oy1-)LM$q3g9P!G}L0rrwHngyFjGZTIIntn@O`cldRe%vgz zX@QMNCC4b2;Z?`-9*X3}xPCD^7|M_l;_Onamrf9h#52(2cA{_YaHPUQoG)(#oD(xd z#D~|y!QpIKMI9WK#*<*EI*OfrNnb z1<1Q4=4iSUYerssAskgyrkBLf_k76CJ?g5aueDAf9>KKQ z`i3(jyN$q^rKGkkbsuPXq5ZTO&D?Q~mQw0ftAvDgDM}F7O1!<6$MWF!Y#x_vLmp?8 z7ufb39UP7tgOfaxVt-(#x+@KoxEdtkKgty%oyrIVp&CVC8 z25>>`cR~GWE-bt>UW**4`*WvlP!Z@0BYDZ!>T+t-+bW7Fj)V>EXPu9RJWEdukAtbm zs3@OF%aBdAzK5GilXd8Vniq=YgM649{-$yIkFB7Tr>kdHahVxxy8%@CailB>>LI4> zVMu67IQ#Dm|0)ZF{dACdOW<~;z*-YOA3Xj;Ik;R_KwDOz_a!oJXa7XXOZ+Y;gCr!o zP?_@~ZemSTuGi6E?buSe#=>^&J#4{Mz z&swIhCaVPV>07Pp>_FQ$h?2!*-E%d9vy!JEM_5rVgk}c8{OJfXEw+a9>YOhu2nf|9 zFfm)73<~d#=_PdrZnK#(*q|GLwD$ z8eN$I0_Z?so}-MdE`GuYhf_$iPf<{n(g-%RY8M9U4Q0cZe&0 z8w^J1^<)Z0>4jwuMU?E&rDY4Ep5YF9BGXp5=03-~IQY?bO6Xur2^!N!Sl-x8^=mZK z-v+%BTh`ntA^Y^kBg$~z)m)_S5_?tEaksX5q#kxeeZ5;-mw2;$nI|>m1wHK9)R9RNc+21Z520Ode$l zyMGdMBgESwG1Z*O8Lig$tKl-rZ4Le-v59eYHTU%t7j%Fn6z+iuneGB=?j3sr_T)kFBENY+F+OI3^G#R$G-v)y?sXl5 zAYFdD5S4thfJ_zNVgf0?Z~j3}ZFkm4(36=`-EV(4wOwDAN-`RGv;BxsvtklPSN=h? zu;L^jN1gb9H#^(JRj?ED??bw&wN`_uAC&cvsMzd+)(O-YZ_A7>K|t5du2% z$N=6~{JZL!w^9{AH`v5GI;B0os|K#%cH!J7{12Ulii`>ss&45a)5@q&Vh~hx0EcP_ z(l}~5!pn3_nzU!Dx*j6cw*#n@eja{0q)3x=ufT6-<&14|B0dUzyx(xLIg(H{go8>TSiBD)ARfoqmnc zV>IPc(&S3MZT&gOo!2;>+fpq9ZLEVEAYGMmWDrdU@8``RZXxJ!DFNc_U{^s5wsZN$ z2M`e_z3GTE6v|f_Gv3z95eo(0w`f>f%TBNrv!b3( z@4tiHjOwMtXSQiWW}}7D-Hy>@V1U5{{l;(jc>@B|0RH%YIlZ8MaabSZ^E@vtxc^c% ziW=s=-g{1q6)JAsYw3*9wBwDwiCv5pi$Y&)5}hhC-eCRmO!A0tG0o9L{3^V1ev%vJ z4+{L=Im#oWCs@Tp6G`vR%QD|f9F&CD}1#K5dhM=Q(U-F``vCR~knCF1Z15s`N^O1l} zudN#ZL-8FT4or`eg1Kv?QpZi4kQ{RoO1Twx!!OUJVyK-l<{C>{{)X7G79w2N?zxwt zQ9d0omj>wcG%zs4(u7MHBcJ}%J!e4tX)7yXixwd`$8FC5Ro<;dJ&<@=E ziN#4>FXpWEIcY;T(Lh6*bs^2{GGp>7EAjw*;*Ej7$|*4QF$invWKh;DFrA=$!0V{Z z{cUe@ii1Oiw8(+NCnqHGXe%O(7haiQ&JK@sDQ|v3%OLlf#7hU2{t3ei#Wd4Q(4Q)) zF$dA>N=u*Wxe1A*^SA`Pl($uu=Na9yY1p5kFR%nhsz@CLqm?hoSfpQ>3XF`%ov$ck1m*jQlQV_2BmYCE0myP-J!Iw+U3*E~^@F}oYG=OHhes%{E6 zd%u{YYM+GT!r>k{`(qmXcu)>9YA24E2YB2OwUx19w|@@WwM$O_WV+J^E9*~&|Nrz#l=wrm=q~>mc=aY z{eWsrq`S>htp-4t!tsplp0>B-x7p|GvB}MLoBM~77Zk@(w?Jp`;GLyAg!ppu1DpNr zv19dC+Yauo67{o$4-HSd6T=uR!=r_Vq5g{>2kTYl&y-bmJZ2b}kXd5D+ATtzrjt)x zixDB8o1;8)TAAGJ!fG0uG@@o}^fQS-Bi+SdfWhThtA}anwp~|hdU_P<@)9&yzI+7? z2e4Vx-i{Z8BHL`vZJeIhn|2F%T%0~D+d=JnXF{2a(Jx~G(j5oj7h|-g`|zl|@!@`r zmZzrG$ox~EJ$ol{LYFjuH}t!1_X+@i)K;JBZ%PDF8MUeO7`(QIG#Tgtc*;F8DU#F)IwClBJ)vqmMckrj3xy>oL06?4xL)&}SGt z^b8*&!(SUnpDD$RAdEhehe>0C;J*(sz(C>p=g=zSVnThE!!mO%Mce?`D+eLSU3aT) zRYi`;5m>WhNEgPqS4lFfj`ZV>dH5?$MTNv;p?Mevms~1?RmN=kmpjxOUFz%H_lJMv z4m1egeZ$gD=w@b|z?Ry~Tj*f7CKf4f5wApl!Rzlrg-r_xT)$S*v zg(eY4S&Wn4w}p#IA<6gGWn-xkAUHjh@wG>~4rkmyc6>e146&Wt`D7b-IoimZuC5k5 zta5SBrLjh_yZ3>}bpM>dBn<$3Y+{gKx$+HICxJ2{3w$Gx-)hy;J`49F`MQpknUeB} z+u*2;jv)Fy0`8xQXL><7cw$Zpq$XdYi|(_ zR@vl7M*xaa8cNeW9RCZ_MZk~(+DuFjtYd7*!%<{7Y9vwEGL>ZG_M8+ql-AC4#SF)` zqK0H17tdwqc6!Bd?)LesR}%}v_xsm$$b~rLj$dsCT&PbYjxlQyQ?;tT$C+%eJBGy@oXHhNa+eY#2AvqX zgGT596g$%~t#reF!jc2!sUeirjmkXQdM-4UP*K!D&cL=j`uUXOk1NOT_&rA;6Z~JzhIqz)x8eJ8+ zZZ5iMo+rUG7q`g0V6!t5=V*vE%&Xb@1*fuX>Y=GTsw(dNlr-(7ZTTM4}O0v(Lu zgeW`T{p2T*<_V@`DSpc+@wy76{sYqx7qJ<&p)gZlM@D_&%*2f&BW-ls-+^|~>+?Br zrcwsB1mt}8^NYGW5x~@Fl>ZsC&5$nfu61)9I7O6vEeBESAk7uIbcsXg!lhwc)EJyd zJ_ol#trTcQAH{vb5kOz2T0Bh6EhVG1P@r_t=qWNNiTG6q@Q`o*4g{XY5|d;ZD+} zQe&#?+KQE?0!}-((P!8|^63N2)$E$#vM4N_0h${B5_aJwRNqsxWGXx5gTEYnS{r_fvR zPKUwxqaeb2&fe*8eE#^iN>BfH`(iQDtdyABgH&-!2$`&{Q%nvv&IuBj)i)+mBuGZC zz$=}YZGl_C(5484t3LvMQ!2WCK_>a!Jseq&dwSacXhJhK)R`y0xqZDHwC!Cl_JX(V z@f|Ou1#(hBit}<~23KQ>;Y^>C`cwb_D%(0}#7z@vTcm$_mS_0_*_*~n20%n;TNDkP zZ`$3djXX>$m$?wZI#(4a4bLE9hAm8j^^wxQ3zEmlv07_JM260nENYO#N9Im{`a*Xq z)s+9QgQnQxxQ$@{22Ba!005-^-)-gkrXKqLi5>f&oaH0xclL*32tTv>j3r8-`hJCP0Wqa zH_DkiHB_JP2WRlWSm+}=T8Y!ihG*9?)h}7o&813~s=HMwW1dtBmZeop+SirU3F)IOB^)oUZdX?u!F$CjhfEc8qgm0b4a4`(~jL0M5Jd74UpqS&}~3CpR# zj7Q_pM|kB~y%^;5R5XjgGG`D3*veY*q9|zW(GA;)9w=Z4ReWHF?y;4`zoLCIN0THU~Yan5i*);Mt=r zS)n3&;GfCBHA<}|p0MgDTDAKXg&uwiB7j!#jFcZL0jA0-QdX`AVwUblQ2ik#!x%d+ zj5dAgA6ZgCyQqd54lR)vWuT>5)I+cqAM3!Zkii6px-rJPK!8JI|HBDQ zin#EZ2oa>olEk+zK4(vWkfEi1lTqsnZ%k(`?mk#M%#2rt4a|iZ5d&UBuQ+SODMVo| zZqv*Gl2O)R%wq!CSUoP(9GdMO^IR;fDE@dN0rrn$TvWhTW@K(Mm>rpJ@sbl>#&r@- z;)#y*>E3!Vp3p{0eBxXl%OyPbmv12pTefBQ+q&ZvISWE_I0vII@RkNInU%KOGagcgD$tS2)>L&ru=s)6edD_u1G%ANez9rzZnU+Dv0WjJnB-7a!EIS{YXxoT&f%YuQ`t&@*~%j>sq(X4Ys%U=2ySCP*&Vvi6WNUGX>#No#o zNy@_?i}VEB5mQLzOeMm!r)ov&!K*!Dui{r9axe855~F9`k@;vFGGA1CfKsv4Dl9@L zIK`D}J@?F|@ay!&Z)4d9H@?1V_ouX+`z)eRFFdQma{W~}$tzzzU2$8GUk;zl-pNqy zll1SbL2^F8LdJeWUw!zJYBS~ro;~+MU{35`GSq4BnqxDfj=%CO=f6M-g@>AVh&J6j z)Uk~^;v5ZW3eejSgPT=md@o7og$A-ayizGBcau6dlB3I(ocosz%GGYLmR%t?r}s5n z;B>r2N#EkGh!+4Q*^ZzT~;0Aal?dzZHa3BBxi2UEmj;Wm+t()QhPB^Gh-*PIJ zK>CMkK5jP$vJ|8BezWW%{|+cgk_iFP5^&?@B7*=46=eaURegVa^KKMKv)SNoYPbT2 zNo{jxYHF0q_v5lx@$H?Ra@ORVztyy_Y<#PDiyU3K?U=n|&-&}<_z+JxQ+e5&aGWv$ zq0~h&E`hqDH1R1|N^E>O#iHIhyB0fJm2}8dA|^R0t)!|1doW|3zqIYSqQvX=D5q-Uljjq>L5l2HDkh`nJ{cu-bRCEn9hUQ)G`6PuFF zNLQK5vN6F zPe7>uPsCGAwK)EuKznh_wPAq8Ccq{%(t4l4M}9)T;uu3sk{Pu$?p?HN9G6PMa&v4; z^;5e-cucmCAjFq35V%q8bS!Nb-BFE+jJPlGJb31WUu~+PYU^yJ7U3;(4JkV;gbK+N zN>$PqFh^@@+AK?;j&+B+X}H{8V*_IwC_f~{PG6tXCOftyF-wpjvJa` z6A+LHsY9`LLeRBWpTAku+a7JT_nG~Ss+~yvmijZG;LIxIarC4A`sUrSi2?#S@CW1? zQ4PWB$07lVH+!($b%F0^P*wvq3kNW^3nms(_<9;Lc5vK95*_>Y}bo+0zXF^&y%f3OC`>(cGr zRbwmuyxPBE(GflMuT!YhtvLssqx~H2fVn`(y;$r?J1n_$``z39`|7r zTP;|-(r6Xvj7N+=&`f=Hi)DYlF zk=kh!A^$7YM-lB;7@R+_uMt0P7yIT_Q`e)0dxnupiy_0NxTd;82=fQ+WJp%$O^^Vn zhY(7QWf4GRfI!`h?TOVuUka~3O|i+ZtW>2s+1hK{Ai(V^B=btG#3tIV9SgATD2Ayq z%__b9PS*#edL={wEvLvWH@;M^rA6A*(P%4Ch_+1BXK(I)9r+dr^6d3>;!s~V`?)_n;*MkqswZH9YhDLlj<(= z&N-fz1zHqA4DH8^CpHULZj!HUjT^TaeEcw-)k_W$iKctt5zsT#baBT=yj4~?| z*M{do`}WudW%F1vrh_bqo9VIX+TYvZx7q%k3%8FB3;uR$qGsJ z6a{XSWsNoFZ$u^2Iz-i;(56xl`Bt0c^_5i|tRX zPQ@Q;knFaY*$Mi+KA!rb_Lr9rb*K!Xb+TJgQvB#*sHaSFsyUhT$>+(PV_X{|kCchr z&i?+PYv)D?H}b=+hWrsx(as_Hi2QO4cvsZ83mtgjeQ{{E?=xs7Kn#ds61`ehQ+`!uKLhe`HL zh6Tf4e8w};Jz}5p7eps+v#L>&F@)L4kC*>_vae{goOpgziZPVo^hRV5N$h#-)mC zeFwx5Mf-;(sD>VQ!1>1huPW=X$hX@C`cGm16?dZlKUDU=5*O4B|9f3mm!VWaN{&CV zQx>(Y%2eMkWuUx861xe7=^dzQL$6ggA-eMOHd~z=a#R~tC#u+ZJ=^X1NPqcLM2hkiE3hk2$I>NeBo>ca{y`iHBz%k3D8p&OJ;I-Jfr?7mTOV5 z82kWba$JPNgGPEBA%;PY82tj1HYUTQVLJ5omm3krqi6~lahk0rVVfBp$fNYBuN^@t z*|ai=3OzJ3pY8_fPWT`)jE7BVii27|qzyeR9K<1ONYW`UVKuuyngdQ6+%+f-%` zu;nCIQ&E_5=kR=dJ)#PKMhKANpLXhUl?18Um;fzYnjsWUBh*1Oc!;q}#mXAbfvvNDp@i>%_ajcTi15H5wdjs$T>U)@ zKCGv^%YefGbMX)+v*JRpqO3FRKa@vf^1PG`{q zwGrG_Ombj_A;zmA0#n|@*WM6D+rCGHt~0z1S8G=tr^#%r^Wy5LDW!#3B(5uRlb_yxqrQl*6 zN}wo}y(ZPaUw4@;o5p5jx`#YZ3%>@Uj}JHLw{@t7faz-NSSlf8_ts6OpW0|>gZ2Ts zeGfza9sS2%IF|j;_z-In`|&GNMxWO+d9R;0Zd-Dci-n4zfPF#Tip>`18RX>{ey>k^ zr9>Z5v{F?FC(JSaXWvOaFf3|Di=4n?9E@+2XoS+f2d}6vi{SWuF=^^57D#_}_uu2? zq;OTT?@I-3tt6UtNKBM1ql(-xP{?v&kf;aNap!71!ZEU{fPLz-bwYgPQTZ&8+N!nz z9>Blm_Vm$z(|77$2!RFNP;45JYxEqxo|Gb1*m2LwY^M6tz=RMggJDw@kyb!FQy;sI zB=e8z<1PpuRKBK+VpoBW&W{~|tUSVDS=A{iP7_luA7!(3H=n+nLR5d~fo!eC$x!?F z{Q$)LxqX3?Dq|QqJWUeq&U;-wPPQ@j32WmRTn%uH=0)L_gzwdSA>ba2a<^8gVQ-wN zs^vnzesIRhvm`hE{sDq_H!*|oIWF*efDGEAs-5wt3Cs-5W2P5#yLo)Qs^t5zq@ z^=5%9X)4tgK;G1vLAiVECrjEuH)FgiROTH2ivTHpfJJ@ww=0O3vn5u1Ey7(hYps|k zyLB`T6U__Sz&=;(?_@9S#( zKW;1zPyB3JTxVXPftoFmbHSe+L!8XmesAo z^P8-Kw>P-GKvVUI^6FMBz4=w%)EvAdr!<4}`-HrmIk~Evb|V9?YXWdn zJCgK`aDK14LELYHYJVYDStJi8huq(44x2O4D~CdSKitw&dl~zSYW@QMSD8RY9T#Bw zm!d<*1ppxVe=8IJ5o%~==z|>4d~xal9G$XhbZrQGrd`V;{aJE*kSbQekK-=0Ai$15T`Ivlfkj9);KwmYn?Ed z6WZJkr2%q!$lyTkUiR5Q{C#jf<_vUC=NIoEM6;bGVu^rhxCj~%?dPWz2`AhjOY{T; z8LTNo9HDW1)MBFE7oDb@QWS9JUGSKzIT{5U>{? zD;T?{rsd#~naye*3x*%t>uoZqO0cd5ldSxQjqgS~%#X7XEG$xORt0%1FOsa~7qeMj zSeRKB1EWA6-kU2+_$zF)&1I%Kc-Q_#%(iE*1~@C=Z@&;W?~hhneKBh}^w<@!;e4R= zjD_xj_>0or#j5#1L$S8+<0>YGg?MP8m4=t~vN9}2T+BiLazK*xm04BU<(gJkAYy^~ zyj^oI=xOTa742D+85sUomLTMK#b8O8V`VyTY)+)gR%c-g&18kgnh*fvupaJBhHy>E zk@m32P>jlvGjEHP)h~`AyG=-|SB)Fvz-808fu|O+a93$RBAl~}rB)|vBg;7)m~CKt z1tzyPqvf-f6av>ak9gB}0LL(4kY5@acM;fWSa6ANwsp>J5Z_U1n4stQlxSR0~3{sdFHUIqS`!nL94wB6yHsp2*XPX8&Kz} zDwI#L5+^q|_6HplwXmch=j3S}Dc@Etd)_9`U>ud~0s_vKeAzm3yK;T{=aEbg{0*i< zPUNo0wDVfLrcn+rllZy#NM6zM{yfDK;?cKmd+U5uZAs>8d+{Z&4JUd^zyN;?>%liE+*tr1D&^eSoOaSgG6f0tP+WAjvXfwkTA&GvGwrlfl=UjZ%kq zkn~sIH1a{fzv#`3pe~kYH+Af2j#x$fGHFCQAX7+9Cn5K|f+&2WGr-b@JB8QQGqG}y zh`c_C-Xw)RXpo94>qog+{V~1?v{JQ-P0s4fG)UbvhdNSu2iV-kguzrHc{MQdjG6nr zsIyNS#M-S0!Xdk={iz>l$-#IrP-nbispQ^P^=c%=F%GkwSj3itE^)h|ik7gob&~%w9G)#*G(}KWhL6iY!rYz}YUck6ZdmD7*oHD1 zwG*edfaf1P^2aCh8np^bkrhaLci7X#^$%mE=EaQ=lVxyXWG2mXKpNt{skhUP%uKa` zleKa+O5@F0&d!exm*y%d$vCs%6fI^SwU%nBN8&pg(Z<;`p)lhJdIcT}5n zB5IZz`bxiT7}e*IvC~6_7tTTyH(4>+1((%vvdK(F`Y+^Q(TDT+5C)Y%YIt3U)=5`h z4QVC$C!8zS`z%w00@jcqiQT1$z`_TCPG^)GjV?F$dB#Ngb`L*C)7W#72t`oOwGVgw zFI6Yb#%%UohAnF7oN2$5v2=;0!I&-#fLe7I&cL__G?KY}LU)|8$@^LB2SS1Bo+53M zhEXR@H5}`gPU_=5LzSLmT>GzmZi%B5U)~eh^c_I-g`L&WNc$~Ye{S=xJGap=wOW&7 zPpWM~@NKY;$ej5L1(;lDuSe}A_e1GcO9We%V`Ng8giVZP`z>vrDWDWfqZVc6$UbOS zBVpDek7rWOKX}5QmwC+nSgXunZRn(;vGPhY5Lljc=KdRP@7SFQ_;mTkx?|f;$LZL1 zI<{@wwr$(CZFX$i=INQUX07=@XI{;-&b#XqRMoX>*Kcd$5H(T=f+9;qH`3}B2AB%Z z%%t04YLHc<)`@6fJex9xn@tO2iKR;B6C{`3fqHSU4$%NVp;?^ryaBNXW3v{g zUD@u-lMDFx4AQr)x~V}c$x+0Z71*}PTikCN0@wp_fRm}nG0h?x3=$o$pGHZKt6hmg^B>qt=d30W@wn0>nv56w5)C`UWG<>tnm zb$1u__29KfdM(E3`82GlCGD!BJPbxSy|T=sPsMt;9UAij5VnTAoKN^%03?3|%}rw| zFOf2%vI(CVbs+6K8?$Sj96lAiBhm0*QPU;rGve_Ko?7r4i+ay*hEIhcExr%q^o5*E z8Denuw!~@=skwJ_svhJ%a>>N9=#_WA1c8-N- zK%r0&U(bl%0yJ*ZNYyKBsC5($K%dKvSvI?*ynUe%c3|+ob3-yke}0>b8>A0?nIDtI zH3?fK$>YUtJ{G~319RJ#Vs~)t6w0Y9y=IladR-$4~gff-P;QpDC}$@(}dfR)nAH&q6mN0;TI}#3x{ykceH_Q zlzZk&c0T1QW?_A}z*EAn@d~k99C-23J2gjltueR2xmFl3mqi5hm0sxFYl1&x8e=^7 z|4TV#_=&MQx`vSY*rX;r`@TQ2q3vAN5`_PTKOtKX&WL46#DFZiVmc1~ESy))YuT8- zhH{*=WT(eT1+)&|FHi^DBwQh<>sEN3QMWR^pasdg*Q_&H?)`!158Iha6Od7x6<@TRmOR`v6=ssaaTU9rCo=f!(GA0mN zQi(9Epy|Euk{chL$wZ*tdUR6QZnno<^^_oD?Dn-6n@+6pmu5SOVdV^eq5P#yJ zr)p#yZv3@NSkUhyweI70*`9P2zW6P*D!cR$$TQAHCKS<@+LubzGgk6*|2SE5FybbD z(H7h05*eA4ZDRu|)25!w-b4RBs6{Z3*k59C>>Y>e{2PR|tC9v#8|GP?W zft&v0`XDsuLtnA&WMhz)O7ow$Nbhe^|%6w1!$H5a&<$g!?)PHEp?w9fd)2xGK$ASyic4{{AmGY~96juBm_Pq7AhFhD+i9^F#R$HLLj_ z7W%*f0HHyRKjZ9Yv4Jqj7<;lk zN^sy*Fb!HQ+=?nvaHwu#p*iXZdaiV_0P4Eizpa4kO z=pVoglEN&x9U2|@d<7cP{dVjb?ilfoa0#oOc}n4hSR0BGAEq#j;P9*RpK`)vV-2X) zvOr@@60s`5v;&|$GoE`V9qvDOO3C1FlEO-=?Eh3PVYDe14`2dm>&3wFrOY;7(1_Xn?>^Qyv__9H;IIETLu0k+ z%A_smV4Hoa5c7O*fJ~_5xOjRjJ7#$w9|sI|`Pw(`GZL7LTrYEbhzuJQ{s-hb{B|^tyS|JqAqX1UaEh0+Tu) z%-pfJdznbQKFkB9D@02yFGmi^R%8@Lg?D%2J*6SDbJyi(rcf_SkIYJ*7VmEf>P)2~ zm;_-eKc7WbGN7B$W;pdGKLY)Rs-_lhuy!R8qd-3bVo2x!kMe#SzANyeMX>7%=E(GZ zw~lzbT`KfGQ~-HQM%K-26g?;ttJjT z1EKEz!7$cOV&ywaYtL*kFv*Pg-4Y>e~v+cdreuL zp0Y{5qLsT(zO7_zHIsQSzQ|M|OQE~2;V`dFAmJcxMB>LD1{)0wdu;48JJWw~a&ZOn z?iwFvc}`f#b3G@lrG1W`?+}2#wroAQESni{>R^kRPKl9?e_lKL@nNcTQiUeX zGaW@>t&uYEaj)e1;>CivXr1%+h#4FHc=5f7zaVtGr=0iJh7P48y^MPUHhb6`LblFd$r4QDWa zdqPhJj0K$%ZsfB2r(wMgieCg>JgTXBbQhp9{LatmgV@e`CD1$>200Wbn$vibGz1dU zV%koFP5l%AG?=A>EC5v92)w7D9>-5TBhWxtj9HAbnu+#ALc^#*aEZh(Bd($%EVOd3 zR^n#EP$mrG4$EPOa(=%pzS*jRIy}LFG?x9>9;XcnWz0)}4hpNzha?vD3z8o!=p8;u z!3hn~7)>|{>dFs?laS;eQ%n$iVeeh9pUFeuB%CL*?sxNiZC-99JVt@o+dwO3B$A%% zgD6`VV>i>y-*nO4hb^o3M&1R{!+R7Z3nTXK50=GRTWJSoyx696fu(UMNs43X-mJ{U zbblkx3gB$6F4=4^;&pmg=4pm8C(*}^&U*MqzkccLv<{QUFkY;f6B2KSEfW4f=@N2e ztc%tTXxeG>*v6V?(nT7F%IOfc+ggwESmy^6Q}^Ob6eHK)*>`1RuIE!rp%3+(B(4u@ zTT63L`#5JKc2(!C>*Byze)RJ`%jD#YHcNMHP#9;@Hx%ozjE8#(QgEco^rP4f2WDdL z(l{AVG#@NrWC3vp_{dDxP5JP-0`%B^3Z}UpjOs!kqqyq=WLV{`=fCwXub1I5&DnF! zTPeB9hSGGgOKfIjqP65oNorh#GQX-2ejk8h$-&jMwddRGi&m67JoAI2LelO&9Bt0E z!#stTPn$e&Ddx(~^c}zC5ydG5Z>u&Cha95VS)2GCZz&x4nn3)jucJg^{cl#hIqmh^?TLfXuSBOX3n;U#4L}0!M${(siV={(2kH_O zbrbS}sB#$Gc`RnoXSUA=2T?Jr#hfNK`S5dgzf6!p@ybL2(MQWr+>PrVsT1 zOBlhp4T`^-VLS}dJtt8S2t>}s@cSOUY$VqFP47?M>e2lmCctodUlI>TgKbBCKD|Xl z%odk|MGJDu8xJ;Qc2)WHG}~hP7wnZyKUH#2oo<$P7l0Jd#SCZ2pkf&C`R%E~`kU?# zKQ0kpr{#!u8S^P+x%7bg{w)0r@k|H+l0txx^tK_lzfmVE$UZg;Uba1|0@yIGox#+x zTJ!2-ON=Q!cGO)apwj$@lBSGe?*o(r<27hp5#)C_+Q=8HJdB*cfT0To$+c`f4W?F*Z}9O!ck>|`(}`xh4=&#dV$yUVoijh`_~{8a)Mv!V}$8_awZ0n*(IG4 zb2)e<7W#kwpvW&!DQE9HQr{3Y6i{33UiT)QJC!N-shWU-g-tiROgG2ENj_=>Q&reW{#>rSwha+vOu-UOX{F- z?Hxd+(al~Q)E*f%t86YW21h9brh`bMIC!!~2y+eBH``CKPHkBm=J$p!PC~4q1AkV> zUE&OChOC1IyaFY0k#xSLZHfZGPZ8h>Tacz`g>)6&6VE^~&X?b{(8J$R)f6`+(yUZs zS(esnSzsl(a#HZDf7RBlq?9IaoT@@0Yq=Y&AK~qe*#qTef zzWbhMr4u71l@Q0dd*0hldkLE!luiw0gf8F%8-Lq5&;K>^(}FV1aBEE?IPgoS?BEeR z-fy$ej~H>MC}ow|&N8&dLaANvDBKqx}J7LT29mDhu` zn1fS9VBOjl-d z9t$^Gb!W)DtYi%YDk>jKQnH*i2ybO|JZAWlWRJH~`$si6hUU?*$rHc@zCb;VHMGTA z$|4o!!`g{*O=7!1^7cbId%u^*iL*tmNjvvGta9Vh48PDcS=ipm_Q1*!+oF=N3xw%q zINRymOYsV~3@(O-XMcQ#Zjt!vuQ5_3SMJ^k(@WA$`&4cbvd;k}MUn5Tx<3U_;vczm8<)EEp&y{XUp1(i-y za}QVzD7OmDZBSq7CR_@lg7!6FT$$PIi|G5LG}dhNwb%6~hz4}~dcX&LKg{K(t^KYA z^X)ahiwnc-HdOH$)HgMBPi{HN6Z7XaUm?{s*FdJk?XgK0vp${uDYN&N`=(BS#nnnfvsF5h7qY@XZ@D~bVbnw)z>u}Wrq86S16U;I5?4G?oO7sv{? zI8W;*y*+4H$Vn%W#ITg&j**~w-DFf{%vaH!Ybn7acs6B& zcmrX!OO21F$6x1=?5L_*6oueb4Aa8d;9sezDhg+cMi!KNiY#k7v`hoDV6Lj3dSwG$^i>|QAxJ>34|Z>csOlual?b5T+v4q z;5vu(Bhr<|X3414?^+zscty4z@8%iW$?;HqsDGRU)!XL zdssC(;f;DPwBFb#Zh8mcN>NKN{S%SVeUcUCh9DZImf&$g7wu*z+UL9JYfDLS-via; zbgxC4vm=d4djE0ZmW1Cenk~GHoA^-3$T7>f7ko!Em0)m>0KLd6vecQ8m6|yedu~F* z;wy3SmZB?%%*R}g788Kcdv4)tQtr;uANMt(i;bESObp4_?Fcgtv^@C-W)H8iJ>c-b zHPJ+`GFA51r~@1@5^bjx3*ns4?IQLD0P~8Dnen!tD3)NP*DZi4jDc5s{0dLaiv*fu zSa%b6B3Py6=x(%9IxfGKRa?xf6RMO)9v8hGCk<*U;1Y3UL!PdO>icEHc$TFk{v@Id z*CE1#8*R2d7&aIt*sONh0xz{efY%b8mJr#ql%RU~%fjLGL3IPq-1V9Pt^>mZL#rIx zc3z<0uQK0pJ78vC>(BeUK$Lo9WerR4ivfl-wf2NboQ@DgB-D*e!=0kT#d!(H+uf*x ziyX3(dtkwmRVHb|RdjYjQRe||--Bl2pHnC%dySvPGvF>gGk1KBqn6UrA&&+vU3t`j z*EjHAoLXfjI2$GGjvP_Cp1&)4m`{A%l*bIpRUhK^nbWPZBr9sY=i0aHe_- z-P(>ZhgMR%c3q486on0TbPvNmS1Xi=Y|`;16hqBa5Sr<voL{meAVh5@{M`6rVpGO@V`j#s`m76YT#l|sAFo4hJhHD3HIsevG+P1Vx z6;uT@tSnQ8uyJQAZnVnn7Ubb+76?mfDjG|;#95orAFAqg)s(HPK6-grg4cnl)~JV= z7-rQ?G5-5H2mKlZ;Ft>x`a0aG3&L%^*Dy^a#Glw2P{*5n&#^T3*v7JrSMl}R-p;)Y zf$y3>>fLD!obXG&HLpRGXwV*PIQ0R`Iwa=@s`bjcd;d=N*t#y74K~h(GnzU0~C%Qt*St}lhCwyP)%5UJIG?*8bq-TEh;nwTd<)HzyTCUCgvV+&h zP}^uYoCmOU*Z+JmHC7ZYL>do1Zf=U;BEhv(P}AtQa zlSVR_b=!8Ej_#e4-Q#0GZ|rP*1ZRir70#yPO-V05c(V?aq(!?;6;klBnNNkycC&|f zeX!gO__g(^iq zb3P{jHZCUEZat(K5K~bEyO($l5+kzAFP%HA0O$~Rs0Ju~R4D%8dOZS&SiTK-#}JBx z%Iz_O+cyK2uBH!_Ts&=|!r_=uj1`iP$A>g;{G6xi_(6|AUT(Z7vFCXsZd?xjBkfuL z`kS(HwlxI@41GB(VOltts`-B+uHR>)Fq2+~zOb_i_K=XRcu zm;?P(@)~%fK@=C8=or4imF;+Mlh|7G5fo4EzBSnplDtJjjPChW-khu_(MtoS4opsT zp}qGON3Z3^+3Fr>+`g)*jwT4hW3TJ%Y&2tVrol@8--7=VL)PNKy`E!ceq}`oUu}?F zxJ5A?<;Dp3_wB1=oU&sq*TWGAP@s!1;b^;(DUZH?fOQCvT)fP9mJ;fD7Mk>Nk0!=D z$3z8kW{t-)w~Qv%56gxQ@|thfi>5x;AAL^Dguqi-@2ibT_Oe~iAM%4aLE!B^%n#K| zcs}b{MT;gz*7M*x^{uMr;q5j;27VMB?*W06PpJ*g|3((oj>GG?JZ}V_6)RI;P(x7O z^E-|i^X`xKzQXO}o?u$|!=O>McV<#~g#q%>AJd zL3ACjn&Q>({w|K5n!E-A8%?Pr`itkA62Ycf?Rv8<1A>4{1DOhPEndCD=!1d4L%=Nr z>+RVlNy6#~+CHJP`Y@15Tc*o(otJ740Mk3;6}?8ra7lu=9Cu8&!=iNplp0QA$;n+Z zGXVYiq@afZeU!Z%2bXiYNyO-j>FkVUA6BXx!1sEYw~97@ncjh zXSFFE6q1COw30N7QRNY>sy3ESX zfcFE&iyI1~=YA^)ga`x>&eWsje|3(CM3Q6zn9T*nt6Pm4WsH>>sbQA@L1ic(2LkK9 zLz*9if`||UAd&Mssy`R{2}8v!dP-oA3gH4nZ#PxKlxYu z5{Lr%+Is|=w4$uV1C1C6DNDv-3RNg!&xwihZKCEF1RBByPWUMS57d`eMB9Fjs1!+7 z{%IrZlI;TWE9}5Zc7s-UFA$57IS11H(EpYo%ex79Ocqwa5)7H+y?5#vdE918T46Xs zuP{*+tqkD^LmHZj@#HKc(B;TuYs?sDY_xkhBM?B&cBqw z9NeTGN%LmK%?il;RVLQ(Y7un=g>tx}_bcvfi&IO6Fez3Sl8TWua0z2*DeL3n{Zl_| z^0-Z;J%Q<*v>(>1qe!NWq!a?5Geilsja*Ddp2SgbptMj75`0z&9}?oqZ?hJv8Hjm@ zP{{fhEX1k^eq@dOpv}hwz-Rl0a0$rOauncZF=!B50I!ONeEpH6`tWN);Dbjlhr_MG z^(O3759Hg%H5D&7K6d9W7v-J*x5>}A4}+&2Cj2)xWH+$2(hi1B;T_7$_XQb>U$V(8uB5tLNZ$v#BFivpE_zyO%u5Oo}qM!UGMP z$9Tpl^R4)9ZEs%tv~?S{J|F}<^g>%)ZJZ!n#oksvw91m;Y}nVi+`B&ysR)3wbUPKz<-r6NXVNrfrJDi4{YwWjYL3|y$dQu6FKBG# zJ;AQ6f7`bonE4C!K6`u^{PH-ijXQfU&Aww}P3p$GV#O1v0l%jZW@*c&pc&!_To zA^)ZCjGPw-ozK6M;K7fD@R?~LX!+D=d7v$0>cz%|)uT^*`n@n}yAZ4F2#<#(`_6H%oxyPfb;_6makM;bE~afRx?EQEE8C z#JlSB@ePorkacu^MQQnlPK17kQnv3&-g;PuhG|lz;L&Dz#fK1s#k5xyT~@>+#G*Ji zTA%Gzgl9f1B!8_FCwaBfeq7boipg_B9Q{2=`J{o<5axZKhy7F`*uk!C`9-VYHJ?*@ zFA#}Xq?!j7CSAw4h1flA1Si|otX)=yz$@+b16d6eVIey2!f$P2ChN*)s8U9sg1--n zR&}|Uzr)M9ls)DlJia+SdJ0mdV9TupAv;~X&fd4RB;gIhS^QcU_6AXpvl{WXQG&YPXsjY zf%Tz#(axNfqXHS%**{gVN}V`=Oe4&_o$_z?p<5K{2V^LeO6MLW4q&2{C`3c)kxQJ7 zfs@~kBfKApEML@RJjw*~DDRXrk{yor#kvzu!Bf`gsQ4#^x&FRVQk{Y(hXjqbfpOsL z6iGh9%yWW|XPCM$3vFA3&5h3tQ0_Mdou8y%2xGQWtAtCMmE;FxAOv@3{!-PGi1UkX zz{syeX)La<2>y%qA^rOphTHKK)+d{OkfKJiN<#(_KwwOrBxfjsUV4ixA&ConYw8@K z$0UEM?U2gEr4^qTv}jL&iO0c9XMWb6bz?G|I+bwDtAt;pa8%)^x!>=nJhPl zN8%R#b}xaxk5GxndkkegduW0LHYbK$=(U`rt3toKmIw;|wq^Y3=JvVrv-+XF*U^Is z%TI~;129Q}DSsO&Rhyz^Dne%Faju>nHwt&C!kHH5v(nPlt)@x%1eT{ zu7jD9bV@1%>rQsk9aB0Q5#%)Wj;};FbbTp({WF49{i><3m)-N6p(K8msc=xaqZ9c3*bn%8+#?w3(+B{B!%EYr7g@#Fr=wz@^6w`%T$ zj?iXa$kDxNLTveHAhg$ zxOZ*Q1dPiF<6}1X**(6ffe$eYjF7n_)n*#hpoAIvaxWrqI4a9!9ylaEyo zd?`8p(Bw1$F7UdXy5g#D>P;-Zy7+OHVkM|oF1pT=ImX=eoFjQOiBsAA3;e2wy-8NR z?g-kh?+TLH7YJq(kk2MlTV^e0mekO&_2AGGB*b^qUm)QIZkUG$t<% zpaZ$Yig)m0?y=G-v{uU^C6&2V&e*SG+}>U3B*}nduQ64&2AZmcD!5BD;z+$G#q2Y0FP3zHBi*9}~ z$H^KI_2Ie>w4Vo+rHXg@M*n|s7E(P=NwjzivokkRT7vGfhm`5IDUhe<-AyXLh- zNHsta8W~TVRJswCJ%}rLeXW$XfZC45N;q>7`*W|e_I2T|v3>%P3NKGTBMuxDz(W$0YTM_=5_t0}+{!2c}OP?+$%h+W# z!c|+3OT1zY;BJdM!vo&0*ysq`KyVsNwu`tio3gH4d0a-Cb`gB~EfV1ZmMsU+N%eZ_nCwV?HJ@^6~2dZ)^-Yy{{0T^D>0ED^}&_v}}v)we##>(90jVExR3FeEiy!^_P2bnrg)2MXAakwnq0*Vu@{M4Bbi9bRS%v zuv^;-uq*sEBFo(P(%;mb&=*$-I2Ck^!f5A?D>)#BCu1m+u}Vo9#a?~|OWYlf3i=VdaCG#@&JDsr#Z=} zACcjNUxVLf=KvM1DQDGlM-?|BSJt}E4AhO7$(dz~toZBy?09Uk6AVZ8=a~QaC~nh$ zK1k)eZ(5*yo3lpiTEB}><$#xgtB(Xq%`hTS0WtgVqLNwGRsJ5NKCp;ZATq9VpVZ#T zH(9ORk4DCZpI%7Pd*!vkXtOohW$L09TsKAc#%B14n_)EKe5S6W0njd1viiKW}&CYfB2Oty*H z$uhz8<2tg*9y%W>mmSaE-ZTv|Ax$!pZ8G@HG8*FaFp&sh=pYDw-{hVGIZZU&hFM*& zpNN)N*W4}yZSuX8%Q0Sl-L3YiJII#2Jv7_p@9mmQlP#m*!JfUZzAIr;R-tT^=h`PS zQ=j)@jDfXQa;0f@a;2AucAVLC+Vp9%XBm2A;@Lu)or~|b|7r0P`zaP``v-c6fCB;& z|G&QA{ZC2vKiu)fs@Ap}tcd?KUHeoSD36m9 zy;3SnN9bT`<$6UL4GP6Fm5wTy?kbvWQ^H2HrDBk5f%FxTf~g4w(*`#`XB{gkz;nks zzfRhYyEf7UtL|B|EUCU4AprcPV)eX2fu@cAK3iu`s5u_(`%hS6$(xR;Yuw?QtHVbSt*xYn}VpeI>n#^wcCUwDIEaJm2GiIJSaQ;78q(W;J%XCH^#K1q~)G z6AjaTEn<#z{I83rBk)+ej)?CooBHrkw)10p`;e_fxzi+RA2ox5z%3`c6&S%@xMDt( zP$jm2%}qAejZW}qMyPbe-O#>TkW>KWt4B+r(UBxN(1FAK zWY~EPwK2(!Lt9kGqy4?AkeMvuLM|ek^`yl3kzr!?Lwd&_F;ty; zd%trT?%=g_(*}kEu$W@-*2uXF^!DaJb4TlUOM*5d)i6f{hP-XVczXL`h!k;Lxk{FM z#5mX*2S0C9^2+f`aL_lWuxdh;bQFJQP7u|3B$i!-5Y?xV*N=Mj8#1TPrm^WC?xM`W zVOWJt9|YjGLC2u@>l-F={f28#caf1BU1Qn;=LO$rKOX9R8g)nP!Xr@Z8Skq8E?Xff zVqc_egAsv1JGaXs@vudAj!=-tpNW%!Z1od1xoY?H`x2$VIpC%YE#kQc1DAWyCTewB zj^qr?P6=9+Pf#BcZc1~&$n*7QiGlSOG%+PZ2d#TR6^rGdy$QFc6xTcWak3wcULOqi>^$+j52a~2HUiwNB?#VC<)z`DGLhL-nR6DEqk{jgi4wC5rWO+VvB@7HgQNPuV3ZWK2_mTE(s= z-;@U_1~=<2rYHK+a$om^ci+6_HLKj??fR(P=By%ScV#+9bxuhY91ZimPAQqkRydYz z{jwuK=-Rwje<=V75?B)55#qeD2EsNJ{ZY*HYmaCGPUjwG@Ss(rg4BGNcl1I-B^oiw zX}$G6aR5cFY}A%B9J2aAMBFWLF?}LaE~S|cv1)S+q?gB+|83tnNiJrq0V}iR*Qf!X zhHS+{BAhS!aZx-*t%VV2tCi@%o7yBr<1@27_Frhyh+RO3W1xby*Y-u#du63y|884r z_-B2kuv}GZb+RXMfh{hV0pNhjpzCU0x2zWwz}XqYU1O|K>2SLo5J}|nNEU=ZPrRGU zGrjk~~l71e%?g$HKn2rV+yCDhc?2#W8HP0g0X9^Q+(MJ>w3rk||`Z zKnG(4)+f6x+M>QO2IaDRuIPvSA>{TE4>H$$D0}2t5@m}Bzy(K&dpz;~M|5~b;ea$@ zuB(tC(cj=eQ1S4$f>zs1=SlZKLlniSwcrq_beJPX7r-_BJ1v*QpuYvvob2*W2Pf@X zG{z4Ku;wg!9soPgZTqArhgwoyP3zc@yc(XX+Nno?pha&Pkg62E&_P3p79<%Vz_`^= zqgD>$#^>Dn`&7;hg$_bxjC?05A|b2ilTNL*B1q)9(?&%IXAy z+285~LIgo8us7btvM_$J_-~A7gg_6X!lf58E`<6!T=NqIPD<(U$7?6C+0Ovws=B*O zpIE^+YO*kiH~h7p!AK?3GMVI<1cWVe^vFzR%~mi?0)#oj0Z}~ACG6ec&o9)bBEahK zpBBxBP@%8xSt(g)D7)qjRma@g(m+In(~?7K_cS^MhUqeb`>p;4ae($Ptrn?Vt53 zLE|gBgk+GDIC68_hzUgkW64Zj1mNc8Pw+fS6PZ z?k&+7iAHz4+J{l(SNG8q=IA;S?{ppzqIMBv5^6iF0r;Y2Wo4 zF8^A>UJRgSPpD+Bj5iz z#TBvWWL_ThhJqz%lhecyktbn`bLCu?q4PF%UVhU)88tmY0tzV@2PX>16XMi(V{PNo zsL~UhV<`&Qz9(O6I=x2BOPPu871fXJeNq=E@VF==!X!6CH~_H^Tno z-@Q|9Uf;;@4qWnUNR7ralm$>tP*B7i*O)|pV_g|_i= z&N(Gq8xx}dk?UWJBiR<`>6(G~dOzB672QcG=mJOZy;%fnp5b`GP(hOSKI;sFS2H|* zyRp~uA<>5}{yETkynGrXK-1&;3X!w`@hLt+X-OPgX=BsLBWd=3%J8YKTDd&}L@i&? zezR-Uim?#dj@-joua5ctms0K!E*6ys1_X2s1q7t@|3fMN&*@)T#`b{qf7Wt^JZF%8 zb=1@0HGHG+7HG-@DM<-On19dkiK2XjQqj1dZLA52rVVr+7Rbi*xw?vy zPUnFbQ=d(j9BZ;A7_Aq?7-Lm&W2QgUK=&x{d(oF709dS}3#H$x5`Wy=j>r#z^CuEO zq}@)jW0i5Agv}BOt*$f zt=N7jD2OoJj%^$)_e7nVv|kGx89|prGmabh!<#lODGp}$2TU{CJ7D}i}} zB$vWV2tjHtO32uIg5_aSek1tvMOp-CGbPsAGyQ)^d#4~#qHasKYL{)>wr$(CZQHhO z+x9No#xC3Dt-s^mh(3MK)9IId%!iB>IoBL>jQP=@FwEv^kAci0Lbi#AbhXsO3XcqN z!va@3HOP_xP0;N#Mg#fI7E(C&xA)_!CkAMPIDFc41}E{7O3T9@I2+8wThPa0ggC8> zYS+^jHS?+wM1~U^<@q0GhG4IjLk$)GxjWR;C;6Ze<6{;?-U5@Fa=70;*H0MKuJ_uH zO&s&4Wy(Fm2r|hOm31Be3j~+Z9mJj@+pf(hMhe;3A0mc~49jEBGfU!zcu#C3cz6+A zHqNs0iGU(l3YZ(4y<#EA0oOC6cqcqp999(y7e^KP5qRiQ2|^qu{4{8N8A_laowjDy z8((iSl|~JL!BGtSI7ZSnvhN@Py9F{D+h5-?nG+ehrQLzL+uC$f3FQqa@Yo;mGmQ5k za4+@2{x-NQ@>L3mAgl4(L0j)?>}};s z_C+oC1azXIKjQ6N9L#je+?^@%y@b83p2qoVgmwluzH&0|QS*|f*Myy56BYH;pC~D2 z#?C=-l|IO*ufidA$`l#h$F!+owaU#Q-2;HEstVB85r(}#3p9+pdysIC;oAEPQq8~s zT9Scuqq3Io59j9bIqXh%8<(BCt{b~OU69Km-xFkZ1{*V91@0`-BGc#jygaT0Or_dWoo5TvX0);Q^o}I6C-I;L^GI3J1?qy3zSt|pA0M8 zxm@!{=7P+r+p;yZStSRW>5;*i`= z_H6rFaokgp8!R9~xm<@*9wY@0fyJyBwEud`)xPaI z+@llC|3Vtrd#EUb000K&59wd2D>!9|BmRaS)154(7H|~|d325_;nXoFFUJMJ$a&Q$ zMGP1k*MUSQpZ-drXsF%>0_xv?sch>B)AZ30fADF)9p0 zX$)Jb4uud81a`$R{eblslzB*27*QM@VEvjNZVwTu`r-gQzVIS za0oR2#M&MKMOYF7BuV912ZLA?szXu-ntM$j$co#yOB4|!4ZoVB+piiHLjXmLkO+Fk z0zc0-e99#Nl+VzoW-%gl#AX`y2;mSDgG>_AL=sCbLmiaL!w>f6^h+5^C7^2s&J;<@ zOV|9)L+BWXd<#>?DeL-;3-(?jwjnJsiSaYWjH)5e;r=E_(5Q<*bJB_Wn{&5@0MLg* zlC-@iaF$+^mbw}WO#?RtXIAI4PE>^|Rzl*943r!&?e>7z+Qcz&*KxljF&!|u`T`M{ zDY>~Ea6C-<>vTq8ym*_^nW^i5<~sGlYR`gAR9p=`FNI$o!5sW(dThO9Triwiw%7xJ zdC%&C!oJWPQroCF`aY2!_GvLx? z>r3p=YR8Et*I3ipmtKTiH7svvb?}-cZ%y5mL2Y*IH!%?UtBvs8ne=~3c{QxfqR?MI zC3+?EbE&w_Ae8y^?j24Qb2@SJ!jPAxl~I5TheJWJe@DvUa0epAMqA&ER4Vv<&$2Ax z8#8@OUT&ZLjJ(K#FxbyVG?TUDh`&JwO{Qb(BB_i8ZcZ< z!@j^}utIN&fW(`U32MdU4iuj_CsAuXdTbFo1z zb0lD-TpIR8(kiW<>d=3_OcEMcJvRs5t=JrqXX~ksz{|_d&dsfT0LH57Pi?F@d5Y}~ z;iJk3L$AOoh2(P1h-7G%lTEZHgPIoK;+9(GZjqiwa*b{#vaZRS0=fnxaMY>^f)^2? zYlyR+Yu_QQkPq^yX^QVnPz8Bmk-}PTg6uM)=dh)>fR?52FgN6dn$3T`fVi?d@(;GW z9q|4&kE%emDkP@5BeWXdU}3aQoU)=g^Ov#Ue)^uLpD|T`VfJl&6o6cB7rO(JeE5{nW7NCh?6{6|lG` z`^B#Q_;u@M6{wBW`E@^AsassftsZ`iRLRva=_VZKq8;9xaE+pqXoTCPMGP=+-)fs}FfOZPTw3R*ZCs@5cG1LeK_=mx?YDvH;Yqoi^4} z0Nc{Ek1`{SND#2Lt8xQMTObTOpM|Ff(oCJk=m9AfvV$$T8Z}AY#Z`sC^AosMx^jnc z&xF7Vw`P$H+c)d=80F<2#14Z7%}4!Yh=-t-y1U|Horap|unA|K+O1;S7IIfEsZ&z=*04?q7&rp31Yca>*PRg`s{Keae2r_i1P^&Oble z6rWgh1h-B1*AD>9@)1NGzU>*NOo{i^WJJ+_x<*tKfe~w!IMW)Xkd1kA=s zccvlj+r26ds{kcbC}y=jVJXaWiJc_#={n8z5wU9Y0Xei@lD2x{I*>igK_?t;r87%4 zFH+zymMuXqV~h;j^h6R*aYwPb|5D!$#b6yWd)iGO?Vx7tHv1t8MIrY@WV4HI{>Sro z5+Vg=h+6WVo>`23qxwFqIR5QKphe&{fagn0oKND`enf5HXbHldb^Z%7=dzb%Sjk?nIQrZ+p{MpSjOsz@2s{)U{81qw%XK?aENqZ~(%h_-5~d>KJzDB3 zVBHE0MQFjneVs8uXU8Q%ZIT$Ha6td3dn#An4iu#EohZ%YH-qAM0nD`jw%>*Z+HZWl zKC_geJ|;+zDmNbZ?nDM&E`!?ZcCcoTFjWokUDQ9~(xVlolMpd#4aVhg860hHPyTl> z?*!x@`(0^+GSY0RG44IU5(ITTDu!0t4h*XZKLFM-$V@Qh+`0Y!A3Ea%oRoEt1pWR9 zD-NggHq}VLArttBVE~aUcws5xfbR(EJYop?Nap4q3HCDTdPAcg0512r{iF^Q`P~NX zTtZrCkeE5XD*j6KJkCP8M$?t-LTQXXz=B2AfLjdD9`C z$ZtT$sUCks2x#|Qm_LCB2^7o#Sb!ier2{mc(uXp^bf>^M5S<*S#=M;fNwC8m$atJs zWtp;%0}XezJcY-*4#}E3=YH_`=Qepmv2%0lXgnD*%w& zb0fnPpnyUCZ~sxOvAy)nlEMk{w{_pVXXc%5w0kv%5B8Ni{UC*8=v6|2%Sg|2IP_@I zKYld`%GKpZ*}9sXifvSJfFi`Fnhmya-;L|1`_4aE16{qGf*_5RiENZ(>%NOh4)g_< zYFHIGKrWJXoB;UYYfAocyvkgd+J8tX&6jX{)Cg-k-$&8M@)Mjl&90E->l+X-=;h3~ z6=&t`{e|%Q=3%DMu_!q(pgaFK=-~7$b5?%CEnuDgX>O=3B;RhGM-2i(>W2p3d!JTc z1@_e3l@}|zo0|juB1Qke$p><5EpSrn=RPeO95h=RIOSm!r4GhHzQ0xu`5+Qj#a|I6 zcjm7(GXDKi0EjJ;E+jrr#br6=U$K!_K!*>qi_4_xGK&fPNJ2qW{pCgl?3qx+LP9tv zIqC?eBpVDCZo8J`-omi4`Bn*=;HR8r2)8wwHfCmKQ`q3u$bu8Uxj41gv^TqJ2BgxZ zKc*UePV-XIwC?t>LfnH@j`MvmS_ zroJ{J3eH14s-OC;j~(iK1Y^a0+|&?danJ_Uc?i!fZt--_NCcq^0%_tR0Qdf_kt0X~ z7#7xgZsEQt8p4b2w~BBE)6W1|IpVyo1V<8wMfl&^2kgmrt>C41&R>7V`j%zByR!q6O`i61Gnwd% ze(6_-E2j0x%L$b%=g#pP5mtt{zZOS7l2cQQUmBg1~CgGPt z2HCscDc>feZ&ycEN~pBGFGyDB@FIx{g+qupkc+x;r$)3ECqc(wZx@fd%zm^P1dYUroK-L zn2KKy)ZVZae?K(M-A}%m;dn6@e1V9N~CYw5r3HuY=X|sQg9=xQ*XS~jy7Gzjhqjj0-s_2k$aW?b?*RI}rAgiT42rHV#6QdM9->3_ zM+XbG&%AUxorcA0WoMbQ$0=|fquBf+k{9QR@{j4?e4dc2Wrt+I-il}qo;s7wm*k9| zEmFx`4!0#-2(Z`6gx~D_^k@SOh2~8W;RIXzx$f0d<5yNJk;tk?JtbcL1RbB#sdm%C zSWPkBH>9VF{TeUNCx_b)IFI-D+tsr?+>rVs`Lh;Cgx^yfOn#jd(x_SWuFPDSYd($Vb-fD zP;DJWFTM6`NVZ@5=4O~57@FVaw!$qyjtA%QJieh-5;0bqi$+=I*Qo@ ztfl*|9U86eAhus zDQ`@#Kq0)>+VAgP`DIu94Oq%wi)(9|mZ94P1m6B=F5JVJTPL>DgcoXB?Nf6-_iMS0 z;x3o#^&jwsyeo{2q1fw95WR@EgK+LDYI2JKzH20#-(yorKZyed%ezHysyf%8ohHSP zt0BD;9?kLOeJ6un?z!9EjZ49EYcRsAQ{O&U7rgrHFsd$UC#ZYr)AF(n$8(;oiEV%} z7;CTtd-yVaL>v<3?G(UVh}3x%<{o)55bZ-;d+#715|)0rfCj;g zJWKSc)`;xYbTe=q0hVRMy*KH;^0N2%H)xTS_7z}GL86-iZPWzr z?wRF4{+A>Q=|-9EQ&lqxDLnzF6q(*l$*1H&nckei9u$saPxZWQ!;4y2b|a!--dp~a z!huQ*7gVv$QWjYFse@sgbijjRz-po8M^5h4=Z?NKmY=F|GCG=0g>wLLs-OCFFU z35`$3e)DGsXfts<QP4f7LjB63q=tXX*jb<Fr~WtZU7lfA^GYZnn*Et^Vz9{`lCH$vzs*^&-^KqFD?12KHZccj8guV) zW_q05c;^cqAf0_ULNqX5RLbd_rhq8`M@OJ%7;O!HH!~SXQG6f#8X`!#@&~Uti@V+c z78gg0wro1}Grw513W6+PhJK^3ee@8`-8~TZhFP+3Z#xzQd#*&%?5ao;Ll8;!y9Dli z9?aMnvk_ut1OC}|yqD!QfkxxoscO1ar}DY+$eU*IPTZX+HpPUZR?q`eV}{Q z4B7xANaa8Um(9o`l(Q!kkQ|PtJZ^qN=Ut{EzYHBJnmr=vC+>b}^cPnS@nyTR{C|RciTdgw`ug=#aBY zW4f>cM6h3mcnbY>OhriPG;K_o$aNBmAPxIH%G!)&_9k^O2z~(PVx%t8JleR3Fr)g@4_ZC#Tv|ryT`W->ASm9(6+vSmSLcu}XPWWwfCoLOs4A`VDhLe1w-J*l)_Y#Ho%k!0pIu$8GhS1vtEHLWKn z36h&DvDME7(0UXV>qmLC?a_9r_%jo=iJt_j@593?cCn&H8UjS#rjdUktY+zJ4@oks zs7{YPaDrg{AhBU768Jt&?&vmkLn4mM)&t=Ajm-C+^=R*%EmVL+X>y#!;d;GslOg`FKEsNG1BE@vl;Y7ow#72lnTq7@N$&4~zt ziYRwSr4dd&b>z&Qg;8^Y2lOq5bbQbr3q8AI2B1T92TMe&PD@J5dXs9Lj(!yCy_FVrd9m3 z2jnqImbt>}$&!1}kHyveTF)6n%o0I=wbmEtIbt z1fW{%{nSi<>MreHMKLC(+SC?IN8kwyajX4h!(F&jvy-~kImEP=2gwk2^^Xkn!;O_z5(9JQHF$R%7)z(CdsDrCzEIWv#e}8e zMKPDhxQvvcRyA^~;V@Na9 z(REGXf%@|ax=h<0h9)}aO=-_@?R-_?NEcv=B_?dKca2V5G6Wmz<~q;k*lYCmyeRHq z3@AjhAu=rgPjWMY7u8MP@ATIb0{}qkf2x~UTl^AR{xjWh`fsEBJ-yAPdNR;cO{hf_>U zv(RD1e4j`3YG?n*C1FJzXH6e2Wl2-uQsAmd%pRCKdnVV$=jUf(R#NU+QKw`DftpOQ znRu$yDU-!-hS%mSYth9hrHT}CMHmgZF`Bd?P)Vf6xnV+Z12}SL)`d%zmi6HjTt|&7 z^B89V7*h_+5ks=^F{8@@r-eCV8l|JxsZ(Bl$rS52v$uHw(%6$>Su!y4C;?Ft2uKq?A{mv%gJpSY}4mLnPRERV7ivI#s@fngDDQ1N+ z@6>D1S0e_AA6J3YK~~TbR!B~RGb7?7AuJJ4G$c)ukwHq7|M4b& zIc*x{F5cBiuNu1Jwa=7nw{BE>#7IQ7WDm4hxy|~xUO#T6UNAK6j+pPdT^-N4X~U6w zm4a>a@R&T;WjtNt2IQL7o5s>%TWq>iC(F`R?P%b^ z(Y#>x+<~f04p6ey!^fQKut+M+zO29*q#Ij33|tZPuS87ab64hCXvZAp{=sDB+I-42#VtI6!eXVN7MXxH`Kh4=&V zvR@8q!bYZPvCQ9PT0PcFrvGoqj8KqHjuyIGgvNBbgtEJS?NMFS0AYA>xoSgW@AB2U zPStLs`3^xg)n?PVc-B>de~nBLvc5|>P?_@plccg)Q#cl9&D1r0laEExLkTZ*Ch6`V+;MRI4+2S=Tm3MK_956E-|J-UnEO%@szHTSo%GWW#A*Fy*7S!w|2Bro?+ z1KXC1#Gd@-V47$6a_0YlvX|Lg;y07!(zg9GMNFoTI&GB-vSlmcMidB}*(UIPDO1cj zlPI1}hqeB7eZ$c(sG{@)kWwBBQ@N1-0q*MC3Z-;Vuz8X1k=&>KlVyO)O#)p8EC zw){?LeuolK8iO_M9_ssP57xWLEuou4nUe+=r;MX5$|t}CUJnZ@#COUiFnVop1bS+3 zCLROWYNkMKNujus&`7h#CgNzMoGyFs05bGmHNJST?+^&~PUO<+>VG4L;)HCOp?Bgp zmz^GuYAQL*cj^S?3KIw_I}ss=;>U|*;*qwIAZz04hxx8QB@?*MfZPfB3 zX|F21NC2T!y@uT?3_dP%QfWgE)eP`^t_IPDq1s-@`&N!7I($nqw2C8 z0ThLI6`BMgrM=O((wO3;-WD)qq5Yu@e_sI`jVk1It2-T@0TpSZ1HUVD@*DPc(3WOC9$dF?)^h9S36<|tz8Hp>H;)V>hJ!{Nt~j zLkdkUD#OercU)6x`@u_sv`d+u%Z(u!L7r$ye_>WE6wf=0BKjmqHN?gmhbq)Ww#DmJhZE{QCk|v8lhjw(B#KrBL+kcO-Vtubi{-uVeoSw`hY?Q~gyCx9AvQ5RTurexFd{N;``x zpe~lmCmSoD%J3?gnq(R)^cHo@sD+5gNpukBWc_$5F-}O1j&o;-L>nk1Q)yOtrzDp| zTI5{VARd%xi;{ek?-f`0N;ZN_JEM|WE7vCoD4Mjn#^f~-fk7=i^q4W>P-)skA_}A+ zaGPG5SGG}CzUgO6r;ST%z>|TL02oCd&uDlbqPk|6C^Ra1ocM^<8w92G5QVeu^mhc& zLEGD(;JposyCgT{+Ne@e75Oa8B*4K)$X1mrdmxq!Gu@FIz%%kQg^JqON=CB;naxW! zXvGi)?#?nM1r<|Qjx|Eco`AIO%qu&5;e*RiMm1EnEALH6rbSY^%7-#|3!^Mx{~2NM zM)uU@b+}tf5gFE;Zm-o(vmZFpR?tw<5>XKAKmJz(O@3QDFep>=vpg(usp*?ea{}5>J zRj48`sze(fI@dx^133DjCqWSOp?v5ZG|!~<*G6Ku6((e#UsRr}9IWxHertDX!Q`fn zS1(5kbK{r%^C-|}+58%wM*x28Y=VHF{$znY=PlqzVmp$p_&^O0dN*{ML${aOE4C1m z_Bn*RXS`}mR`|Zy0x$xO=eb^i z=$g27fy8$sJ?M2edBkWh0rDXS^3#zAY#}fFPp);e0T7t(et0(6V264w%=eeNw&#c3ocZ`$Q<)U@sFTse64ftX#=s$Madp3$~?FD zR5~3NrFq_O>Jh1#aIwsazTfI=jMj}@c(NijhO?854gFGZ9$S9|As=r8zzyLsT?Ds= zGKwOuvBtMr3x*Z%YEEl!ITvdY7$?U^4^z8(M55Nzq!TD=mt>uKTYoAWvvp>AcjkU+ z4y(Loq6qo@p<`k`hN{*~q2OH9_b+U=L72yDC?UAks^)>U@LQbCyX*bQ_~bBM9je3S zTQ?_?xSyru)!9_xuB%_Srqj|VI7n%9uiCIN1>|7oxOLh}mPMrNWNgri?JBj#n0z`EaK1C*%*(Q$k9DZFU6QhEt?fC&nEeH`RoO_gev#Nw>-;o zjt~EkPP-P>+6thHT=>!|%TD}`?c-DRQhCBd4NZ>alWIv zwbL?nxcmvRXd-u8`g4=AM^mIzV615#cKB~On2|IDdd}^WaeGoY!^A{!uRg8-MoCbc zsCx4`bKZHhoKC6iX3EZ8(<)Wo;|&HCDxQUCuv1@9qj8?@`Wc*^wvR= zW?=OX~hB#CXc^*MW@q!a^<2qZC3a238GF0A9W)Lkn}R+MrId&9I6w2 z<(Z*8EKflboei<&tzFX74G&bB#n;LdeBQcZ%?br0f7(=L0dIFD#sOj+UoNPffcjsX za|V8)UQT91uGu>kc`Sz3Og4Z9dF}7KVw7HREDq1Aw>`ivvz6S1$%>T<5k9|;!m3Ut zl&x4iQEpc_nr4@=vX)iLK6xw3Zu5;B%f}t;iR?``(|fU_=lRohxy+(DdK_K#zUT|} zcU@<@iz}nY;TY&!5{5VP2TWf(9|z_IT`f2_R2%~4`ynt36cUX|=x^_Ut}SbfBWKr8 zyiLnOw=S?$V%nzVo`3|+JW8k{&w-cJcg6j9H~l_s{oTLAwfApGx4h%0TI|JWnHYxU+!mP+G`Qjm7bl5(^Sf^95KB%sJO zR(Db%hr~+*(NXX{e6-$fR(XIBJqH>Ry6GTj(_n_C7UfI*nfm{(9qf zNGET-7a;NUr;9DNL%jGpf^j4Mym1pGQ@ngO+;9fZ1Ctrj8_h4tA^s9n_Mvu%q7G*y zZsCNo@%LVQ*#XnSa^+$SEs5jR7i25uXXil&&|le&jveC$oN>v@mG|+D23>960&z=P z@w4N}dM7hq*Ww8H=?BN8V0&OR$>(9P{U!=k84!@uo1{d6Tb_=^ZO20ZQk|do1;r~; zaotXoP)TK1EJoMxu=9lJT@X>1C>j;4e)D%Y)=Wq9tF`4fCdqs!{69D$bO;0 zQ2Q88<8}2pagh`B1IppuRcmdn#Z7puCOWm{J*?Y~F9C+8&R zu_~w&PDYj4F3t#~4OeKTRcl2nmy!a61miXd{uTaJ=x))j)AD4?9cCqUsUMH>8BAKqqY1HmG*i&75kHPOD+e%_y8RKZfp)@yLB7q8-`N1PtJ9eCz-p+`|9 zUY#>_+eD9$Wo5>&kd?(tZx-Z;5#-34$BYjicGj-(w_`!K1 z`Ahjz*__ZVVK<%XE+?f&T6DC0S6TKe#a4$&dhh3ms6 z?6oEwqD{n5T#WA|=p%;2FB5Rv`mysL)&ttmICzdCPZEJ+qx*IjwY^XMa16a6vi6sT z{YQ%`!yDYBJ{woUmg}}vxo#M@T4eaOp6$0pxQa{M+qLhnN<@!H6|4kT<+tJuEH6l^ zx6))xE=m_DOALbybneXdg@29jxYtO$!m~+e8h_#q@2`O74$=di{*n@_3A^w~a#gED zA=PcC<~WkpTC{?b;l=7RN^(8%1V7-XlZdyImIh@AJ?NZk`W;R*)(#G0&KNjA3mPPK zaQ`lhE#+u7VC{pUpRvOL$ts=QU;%jkfUf&21`r!q2hUmPaVjKYP-214_>M#Nco|L8 zj5*E+Mlr@Epl!bq;6q-Cegz&4OvzVKDxM0h`}b-dyGpchf7%YnUMGeyQzH!L$GG|V zYQP$IBia`Gq0wPH4zh8U`A_-yNxoZgH&w}wSr#F{{HOxmoQ=BKFlTXX#^9@T3zk@(T+kRndQ7JWJNNhRlbmfTXwxw z+V*!^E*08@c2&8(;Oe}lD#G*l&8$dnC2^L*2g?)ckyWGh41TiwE#|YdOs8^XN*u|& zys#X=py|ds9ig$4sDY6{+Dn9H_w4ds5|5%K4fn+W09sauq-)kao+@~lSQE$g(dc7s zT^nc{J5XsqZWJm~B%XYQ!;pFklC6sSLU=sJwa%;CD*GVfZEeGy{80ai-jspl^7^H; ze`^5xl-XYgoK=0DhivD#-^*&_lQM6Vv?3*^5%^OJadFF}YTM~IAgh^{c!8zOLYEz^ zkef7lAMr)uG{DD>;6)7K#S9|lRGzYl{x5J6iE~t2R}7%f|B+d_nYd(hXcmfLc~I(uBmm=9RY8Xw38Xik&h5JLJ`_AnU22=_1cbq2fY z2pA&u#Da$dH3eqULz|@><9!0L(@YPTg|1b(Mdyx!Jdps)JsA?`+*)?gFX1)L-0NCc zaTBfVR%B^?$8y&<(RS*F9d~@AI>*;qBmzeasw0$3O_d}wJ0A(6>{EPH8cuPMJtj;f z46$y&3DN8XIu)*X|2;f4h!8y*5^MPTXN_E=j=fNDy@CQmW85LB11Y@hR`=F?zJ;(8 zk*gowF8jc!-7vxav*7^D0ZE6~_{D!D9M>Kh7!W6is|f>Y*o>q-7@;3PjrwoxUj}$C zsMIu2Bfdzad(W@5fZBDUFEf)YKPEXe3`y%4Ifgis2K@8;GvtnGLe^(LI~z-^-8*nD zdL=ilKiNHcOyhovAJ^sUGitx!Q; z0jp-3zDOqHBx+~4qOEAG;b!!C5~8;og1hq@dY?c!!WQ%@7+>d({*nmKg|~ln9=5Zl zBGDkSn^-K3#iMloCydla!HpLiduvLNfgDrtczDB%)?AOLTPL|X%bT)_s0RQgHqlt_ zinWLV`mtDXx<6_ZN&sVTui(nrTWP}LXJWc<@ z)i!Apf|?Ch)okMEvrqd&Y&GZzd0i~R$8cUCdAG>N7eaZ)v158M5upd0pEfrQh+JJh z?LeNEFxjG`(fchmrA=+;yTL}sOE2Ogi<@A7pZK^?<3BVM78E` z9F z*z?MwPBKf?8qpPl%4P9do0L42w{<=$zN+q?`{$d{&8p=wq~%IgqG9o6hh-(^_YWL3 zo|~%smEDC@GL21c*4WNgs=2Nh?`rEME9@KEpQkIkn4`(bJoI2`-`RGr(XCl}m%$Ds z;Qh_DfxErfu6rxMQKjB1;U!1d2l1X#{;hSR6~H~aK+cgQ;caK6 zJD3*A=Qtg@<0PHrIK;>N@AN1nfJ@l3;>`=oKX*)hf%JP{0CMlqb?a_H*p`(xc0|HBR(Z1 zI?1Fld@K}1fmWa9UPTd^Fw}*%kCcHI8BQU9@6T0n#b>JVOMSdXc6=fsiOny96%y0O zcL%VXpB68H#+X`PrSeY@C84l%Yf;Ciq!J3AFD{lRFryr*^SI zBcjKL2mWdO$RrW`FM}0f3ls`tt^bXH+PET;F*VAOq><25dV}IvXkQw(svQ1TT04($ z&!NvI26{rb9OxjN-!SHmQVrB!js$n$n?A!P4q;3%8OfeP>HLOu5_k#{5Qo=@E((+c zDX2Ck=&%0|gH^OzP<p$AG{) zhcJx_1TF5s&>?qi<-)^6cNwxGZoDBWhm#qukxgw7=Na@$IpPr^=9utFWz%7#qA&CckqKX!2eHxa@{$GV3)_=u@;c zv*S>B?ahNb*LLI4E{6;`hNYnpK%wGi{i$CFtLvE0aWL}AVp0$>;aG!6Xds0XJ1-F( zbWr1$Ruv;w{jM2#SQ33R*)z(>ns)|{bRyHkdT>1v$$&L{Fn4wcbS<}CxdmMMPX-rt zdvF7q`MxROqJF5Wxz&p~NQ4lCH}2G*T8cy4F>gOsn2wWH`V+P>c)}J1ukwy(?a1{d z*oRLoMj7u@Yju04Y5OfQPZlfIc?5hfS#>m_H1Sf{OA1~4_2qOuhE)UNy@UcR+UMJ)-)sJdS^LhYh%YbW`F=XFF=w?DDv4p$hC9 zXsU*}5F|xj)^HZZDU#pB5@{9?v&;{A`3ID~K737zH{fE-h##YEfiJ+he$DZ+k|H^k zyJZ^Q=Py)pX=HNv;QiO#0*yq-Q6|czAT6lYDr+>vuK(ge44M`Q6`(>zr#uoZ36SY6 zv*gvzzY)P42#f@F8+Nl|LPdhEs1$(LIvPJrt6V(pS7AXd*XRKAd0tFz%%(?L`gM2A zb#ODUStUwag67T5^S6n_*#IKG%#Bh#DSJ6@QdGI3dlr<5kX@sFkOW}1P#=eGWAlZ; z2sJUxCzVBq3Gf3@6^SzIe$nIYyKJul19rFN%hm&ReS;cZAOE`D7z$57eedcvOB3RX zRB;ggiE;yNVGvNMIR#`T59W}>SmX`LkWk^ai6xBRe*=!%k1}vgk{WLTg}SW~lewAS3Mdg7Fb2oP8_05|9UqygA8g8Lz%)%}#+a&>T0k{epV)4D9w|DTxr@33iK1;^ z?K97Tk9Cf@We&ydJMF!-st9bHtFf#S{Yn_;18fctkN|(jQNj1`{lp|~mT>`FLd5D^ z6)S7psyERv-&r}8*+b>@PI~|8Vwm`cJ+b7hwiNHAp9+fVg3vyu(-Mr;cp`kk)cUGg z(o9vp&fZVe#K%A<1D<-`VH8r_zki<-pOVN`<|UnCMUXQXh?J`qua+!o}3Nz z#jGC#s;yAHVrs&w3Q!K9BKqXPS<8N)!3W+3ZgyX#nfcu3UK4oY0Hj{;yyYgLU7l6k6*(41 z0YM2&j2Hi^N)o5hbZ(jAIT_gWOY?nBuARNJ zg`MsH8)P;z`rm@gI(GYGh(0H3OYX%eTL${fa#hBrBw*5p5&A2vL&BI47+n(Ht7~I; z1oPM5FJ6^4(SS*_85%kk9^#qTwUtW0Rk!NQwF0f?+UVzl z!nvy$6ma|~*f1gdRn?t)R;u*&lQ`zfBlTTDT=rBU75rXEvXI&}Bs=4y0BLuTFfvUd zYsJ@7NP+rCOk+YbHQ|KLd({BP#?erK3W4s683ngy|8(VrUfeDl*$?;;SfKfN$jY&3 z?m>gxfS^L6m<)vZ`_l|gUvSoy2!zCFq zKgLD5CTtIndi^PAY#*}22|GM`^=%{IAG;ptJxS{7{NM*l>gtNyg{UoSiovCI;F>6R zVf6@$vtq*M9Q<`eI-pPyRr#la{VnlV#mtnj8AbYPNkqUGSDBH1xumTodNs6R2Wlf}=Q! z2D#f3i*Nmhub{RGC(+lGmY2W}8Z5l$KQ!}ZYU|4tX3_OB-rs)1mm~Fc8K@OSyryEU z6?rn&L(S?jg_^%a%uLQs!mEq5CF&^Xq{qoS`7mB|`sIWgE7hz=1v~b$i=qcs0k9b8 ztQ6=csqGQjO>?Qmuta0%Q$;2(wAaeqGokI?L{hL$9z!Rfq2#jEkxGk;o^g2=3vPzd z&=Q1?)zz9E`DMBmUodq2v}U@EG13b`99Xw)6P^+0;*3k7WgX5%e`OvlOKVxr%~hEi zvnH)g1vuhAhxOBu)eS3)44`zF*^1Lut_3R#zIpn1s1PbwKD_0RU^Bo3{Bv+}XzVlw0E|Nk+iGO9NWdhHtS}CW6pu&e>qi0D|X(^V(T1_*P z8fvhLPz`xOg!n53JLx)DMK7IlxiSrO8!V57M2ln=p2yxter)?69^AUt6335Q|0!VnHsHPQUx<8+ ze|(~WdS)FhVC!$;%T5pSnE*CSR?R>;Fmm*IeWdoXN^T4aNF*k#6^W#Ba)flR`9e4% zaS8ws{qmU=3C$DVoP5tUdia52J>uBiX4`vumOCM-bJWB7*?G^$HqwztKh2nT(rTU7 z$l4ftanRO6J4wfPBd5NfvHM22Q3t0~6jQ`^Hq8#4mE5PaQ*d{6F2k??T9DImRZDte z+xx=$01f|xXp0r?kV+WumRdMj#XEWe)D44s8rfN?_9l_o!rmxB^ zb;#y=<3rks9-^qQVY?QGbry#7dv;>eX>*i**;nTf8Rt1fvzAqa1tUQ zjNGQi9SKxDW7Y)=7{p-e;)GB+lH}WlDx=LTZYUGBH|gDkYAry1p9Vl=lADaIn_Nh8 z;Gn2IJNQ}$ZM2R1!)Mc~`9&$4<$DH~{Bw(wRbhKsrtRPPAvkEht=y5~ ziKucVt~CMA8ai|cP=8_R{igl#HRI+6;zxTAtX$zogPHK%R~uKzsP^GQG0KJEzn(Pp zb+?h4<4{iV?!-hK-f+$)A2;qP2UJFPK`$CFj>E!zD{*OIZN>N!%}1LZj_!@Ua0y`H z@VV=t%;Fg?1fsaj&3kC&2_K$+9rw`x+Hbr3vX*t&I8W+JHLw(lV_K*0EET7TFODy4 z$o9^ga8i#eOQh1MFQF0hq?FTl}Wn1*l>c5-+kv<^6nyoP`sT0QIig zM7~NKsIf8Jzl7bHwja=yT7ZPksJy?W@K0-d;gm1MB0JY2QKsgUyX6)Q8`4emcz5RIzg6f zp%z|b*IP%&&IF~2hUyo*6x$XO&cP~pga|$#!;=m|n@%T?6x7~Om=V(w&HBz zDQ~iKytsBV;$zd0HH;tnTp!3_B}OS@6x1tZ0K|I`sN!W*>ae#W*q*rwpkelkcMrC9 zK^mP=e*7!w1v|L~L1LeSOBJk8NxpG8#<6o0IdF^9cDl5deGtZ8Lam(B#WeC3^;-6+ zrgG`KkVM^_-7+T|h@4TLT#A@2`*GVR&e#qW1Oh;YK}lNd_I;Y*;MLdcZ}d@;6Le2$ zI-fN7hhCX_kxc?kyxBIGXnbOrpkNoZ0GCVMsCjx3t8Tt5@2(m(Uf#mB4=u&tJ=nd9 zzTQ(Q8{JO38*qR0r@mHozW+6SO`-MX96-UxE_~f^?&f-dcd@Op%-GJHB8JAA=6T*< zX?AFNe>?{vZz`R;`nDFf<~PCB2yF!4T_?uj{YDhYdo52{ocH@h)tiyVazPM#7%;%S zowjVm#nxI_@T8zXN0W|p7>5deLuuX?>M=)X07O zZ9d`uvlhAZ49x!cRmry$0RYJU-%bF2sVe^!)BdleA+@Qkm65RxwUxOIjgyW&9288@HM4*~Z|)>TQF*5Wb@h3ck6_~&;uhMiRG+H2QI(1Zk$|4{M>DDXe(dcAo8 zii9MHLF4i+XId&dNaFik@!RM#kc2S3(c|d^9C3ugq~$>1agUJ>gTuIH!;ulug<+)c zi1=}t`g3|A#LP68feqn#_L6t%g_(4Pfabcd*t&b4=lIZ?dmPDzf*iBIDf5uX8k!M~lM z5xM%JhB6Z2N+z?a672dY)WtF~n z8|j~oT0g=v;a{HZNesomh8l3BW&i?5!_Az>9C7=SGGgB|c0+ zL>Cc1by7rHT~)kdZ4M`yZ&hNe{27wS_CtAh|oIj(-3s=a`DM3A|VXr z?(720&e7kS(KlZ_DTk|6m-2gZ#=4|ZkMPKo^lHa{4tS6p{=DD!^cFRBfJO9?I}~VY z=jKCMPy{H&k|~ooFXSJAg%W^dF~mxv)+_F82p?M0)`IjFLiQF8-JljC$x}G{MxJ@}A-iZJbN%R;cfOtEXmgh2Al(T+&<1Q_X zt6g5vs3t95zypND*Pe%LQ@F!6wPEG(8Hh~oe9vgsTv-LW#7zD+?u~t7QLr; z`euFWT2?b6D1PH&oMkvA0bwD}d$+Kyu0*93QdOC3#qb^p4i~ICWhnnp48oQC9~;Vr z8Pn5%F_k22l^>`gs|?^{rx;v=-gu?u}v!Hj>1U28# zHqptaFLluCS*!z{zc5tV8h;&g7|y8z{N~1d#a$(Q zwOk~afd?2yNF!b?v9BE6Wq|{N$&~`7|&?KZ6IFYE!Ss;zm|X55m@s{!^F18DJquK z$bV44CWL0EP^(g7YKKoZg> zSm4km$+=AT4glV!`n@j6RojV4Pkey-*auunHzcXs5avvYVeSH-Z;L2Dpn!S}m^cqP zZ*z!Vfg+#__4b6Q$Q6SOoIT%oo(Qw)eCX2X;Ns}4kQ^x>1!i3R8tM_|5XBCRv7`0R zOw_R%UyA9qM1fYqc6Xz==Z_6cds;RftWjr6lv_nWP0J4`L^g{aO6`yZ*KL&kVV4kl zY5ql_v0PmfH4ny1S20^8Fw+i%J|9C_H5-#0kPD2$WyT7Fvi=q2S~UxL6J7dbi?jh3 zp0c3Vo~sG%I3GxSl}(}izI(kB&&TCB!w|nrYSz23ObaF*Y7;{wHRO@DxEPLMg@U`R zSBtqILUn0X2IfSf z`qy}0Y=E}EFx{E#bS!#RcHG9oaP)oP{!tEkSma`ta3bXJ6-aE0* zNTRQdG%AU6Z}b4TnL9G8q`=&UC_xT)D^*UEw4GR7=s&1Td&U(lvhb zK@kY`ew{F|-t%8AXiLEM_5(v&cM3FJV0j<7X_29}CxF-o^*;dsgtYy6iCI?RVf2Dz z_zOb}$BxWG*jywVfJ|Ge!%P*L{~)aHXHC_zDs5Yghgw9+^ORc@JaJL*b+CXWKl_zG z%PmUXo&BjAA}YH;N)vmh9|G_HXyf|`KKA0uP8kx6GNPtQe4M&KdOc`(*H&B482fN@ z;Ky8pzZf#;1Gc00a(T>xI?{Rw!@)tPDwQoY&lYiSg+~(<2*hKrfSLMnnEkn#(}kBC zo15}H<{=nIeID;c^M4YUeDJ>a^R8QqjEb$K^U@24%2YT^#0tNVB#X|CMVI%H2a=+_o9>X2)>9_$G>V}gh|nuvVAf)TBd~e3mpBc($?JxwrBMG{E?YpV zrfl){!Zh`_1&+a1RQ@k3Ry9jT)9^S%x_$c+X~E!8Tw4wJzrDf|v-jIab6m4kKPQ#N zI8CtC+GYR8dy)7?VYyB=3ugZs#ef=uEp+mV7E`}gSgfbW>IaJAhFO5E?j_bEMeSWa z1EE)S+*XhbvL;9}OC}KOIa@xILi4_y9v$(a!%9{iC04DI)S7Lpaxn2s()qF7g*zPN zpyWWs0-9d$_?vl&$1?z>0z1ZG?66Vk_F$SPXCVT{?LUdvQxbyh(gx(>-CI&>{HRY= zT&3~0O0BR>?=Do1UompOS8dXX)wKcwDQ)Qh$58^-|YjiwQ1t zG?SZ!f?+x2a;$Cc_Cwp==9budJHz0V=i6n{w~e8SB3vE{BGSekPDPxF4vWU4k5(ng(%HW`5tx&RxM0r!2f%{5cWYEO{9QT#w`ko}lMfNN9F`QT)@JVeq zscbg)fvbcxYUhOQb1f7?^$AcVqybx7Bm4ly^EaKdp*#QJ{EDZ_|B9;Kw8OQ5Xzz!& z_f?d6SE3)QdU!Xl$a)lKQT!DVJ}Ql*OQ`HvXhX6q6)uk^N#z>k1U(O(1YpZu0kj&AkOtdP$9aeL%cU|Gzx^^Y`BDNtN z>oat`*tp+6mB6C67pc9_SvZdcOhppvZHM70ID!ry@eg%PU_8dg^QJP5bi<%ML#4N6 zwz^=cQkJbJ=dO26TtV;>1@ouGwqoOJ1EXxqWRMx?hxzK`TMVZh(MJ-f))sOnfiIaj zu72MGvfoe8OA>A;VK7r1uDwQn*>t)uS(8=B_=sjiBb&M#7WpKQeEj9fWJRf1LA#A4 zdj0+WU)|n{7DF+~pCiX^u-8aCn$r@|R${H!+n+2@L<(+p(c&7e?QDEtAL*}DMfbzB zqEF|~Lh}Q1Zp^BVDkX#UHRxf+*>L#H`Uc*E&Pg`B`uu9K@-+>YPeml$5KF!n%{Mic z98%E$wVzJFJiR;{Xx#NB$K(oyTF=Gcys~{^^p1peCTi*&RR|X9d}1jh|HmU2G#&`E zp$UcC?TG&J#3F+EsMZ`kR_HQq`IJn*%hyTBox2uBK%0EQY>ydxo-^GQo)+oleQisM zdaIrM6tRPUt|b)U#LmfB57{vkJ7-;pJ7-Gw*)iTCKsSh+`X@DtUYGr($?c=DRayq_ zY5W6It-#PxZTj)fN><35AbdRJA)1I@VH7>L-tVgFC;ZhdT19W)bB`J$@Wd0jzYN44`-r?^w@sjT5{Ss{p! zWpnDaiFZC1o^hZ03i9Ij?<8SC5dZA5ZQIg%QiK=?akFG0F)o$wBrwecRHZ^!eF zfUU&iBKA{z>LbQo1khHE;vnJ(3;Cj3YM`4O+CD8@;Ld(wUwV;IzwQ)?RnGx}BKmD9 zr(m|%4?o9`KElI9aS&ozK;k-1Af?DRoNWQ0gYi@lz{5Gn*}~5g3EVF2KH4YbInt?@ zHDt1t6ZEEgqMLdQlXM_+Vlxuycw>{}tA9$+tA*T??|;UwbaixmyLvk%#y>8Q517^D20t!~O0gSCKYRs~w!<}#evONTIP71ch5N_uE^ozCWSuFY6$!wCT z>;y)2?ez4%KREzp-c}3QZru)|IdO&52@Wzqnw5SX1{x0}hHFXmUQ8i|5v}=dB z&)E(f*fS|b$nnqJNNW40Wk;EjaW1~yJ-_!1AST-JzkHA@O{wRt*{)1nHp@D;Y8QK2 zE54_Jb^ie)6Pb^}TC$1oKPX8lkNYsdZMS>*9f5$KRH9eLP%&BI((#J% zPtU%>U|5ELWn+>dY~S6>;zh-=WA2q@<7x8&g5hgBSJ=D{?kTKkt1~r4R_%qpo*x0z znfZtkyuxF+)t0$!Q^23(2l9V3R61~z@yRmS*MjX%WlDijwHZx*%gA44dFNJwXQrxP zbwq3p{W~JPp006|bWDc!tlR|A{BoG5TrpGWbgX?()?lU$v)ISOJ!oxS>M<V?bg%@D>eu#Qd8j;44 zH8@9r{seD8=N;v@mVG;Y*=S=#c0=>xcx~gVo4qB&>>81#VQ6b7-H<=rc)T3K(j+7A z8Lbf9WA@dLPxT4Xf$Las_DvGX7qKd7!bz_7Mc)q4U@l9do#!T(VJb!!qJKG zESo^+MFrYHi+Gm*INXms3x1fF5`FpZO}j<(vpo^jzez)$tSVkIqR+7=jF*mBTd-FX z_uG;`G!LYguSFx%G7@c^6a8@~a~aoPI5BE-k&@GNj&8Ykh%!A=#=s;}FoC)H0nZ4g zrmnY&y7+7lYMjZ*2%8wGayS|+(}Js}O#WA3(H_yUUvcgro@7^#64+2Xjzw;8n`S7Z zDn+|1E*w!6*9`XL@FHbLapS6adSciV%j@pjq>&OD6FZ;(X=bTmL<@Zhu%`z4KYK+e z?f=y)R#0e&CbUP;%&DeFw9d*KB?#CvAQ;}OOQpxZ4H_x&4BpFs%Xu}^ssHs;dTBqG zXre;kBOOgOy17Zz^3{ziTU?iwO7)eYdE;lh=p2P&z8U&3Pq9QA1V4>CBFxEJ-L{^2RQgg8v@|PBi};#CMv*(s5m) zVdo9i@nAh6Nsom6<0z$7ivrU~vl*jJY-l_qNg@x>l887)q+z;!?Z>CnQv@C%Zq(*V zr()l4X|eX~Wopg0n_B4E1&_qm{eFmL3#)Tf=_pv|0}noy&7SUwo33D@rIw_<=BXAqZ4_460u}i7p;(EnpG(54w?Ni&SIt zX~PM*uaUXPPpL4R*s?hWb)m2yc?Z=P+s3UG?h!lu8mVM%0YcAVEI*ttTVD9VBfEr( zRXnMFP$USAfDl*jpO)JPk68Bp1>^C5gs|+I=!D?*_W*6eL;YOd1F8~;ex%|LX8oPF zEJ##fT44p^%#bf?Kmn0#Var^Mu?>KSSXdNm0Q`eMYL#sMPpGs%C}e(O;us~72GfaL zP$x_EQCMCT#$Pdq8|V}%jPrbN-%0V5HJCI^(0*YOhr)fG!Ldt7{=04R72<2+Q)Hn^$ng_bwl8LKcov1Em@GCS9em9w`CCf)O|4@2$kPpemE zbFE}FjUnD{9FL?k|CX?&wfgQS9Q3dLdKkmYJ-ul+8qMM_&c7s0h~s62(@*`Mc1rlbDwPu$X-lfvTd6dxLvsk7P)X| zPfQk~3PXZ8Wg89$49p3=W8W5Ku>gEAF<^jHk{4*eC=Z=NMzux~Flu1%XQkwtet9~Le)ZuQpnkC7BhYh$aQ zY32wI0YaX_0PKGJTXGijoSADROFUb36cGew`M_%e_R^?pleNHumDg*)^kjOA3X?}~ zg4cHOwH$nav`Aqx$*0ts)0(vm02G!ZmQbFY2zj3FYp)OG#@>lVnC(7T2eZmNAoLR~ z>PPWAPXZae0-CWatZ|KQliZldvNU<(=paUV?ewB4o)>MskhKc><48opVd^M!5!kyYi2$KaSn&|$0G(LeRGqyDw% zvRBUMNSyT^k^*1Drnu^B5&u}Gm{Ck2LP?~S=~SH7q+ z*=)F$9?+{f1lAKjS%UOvfH&c+;Ij>$k@-mki$m@sp;;*)cAFWA-?sIgbllxuLwDl{ ziQg6MEqI1e6?(eb+6ROsTS(}`YxcD(ExY58n0yCJ_I=rsE@$($bZM%!_VORY&dyI= zq4$vA>)}1v$MK$v&V6L~uQxfMJpe4)2NVx_L>q8Bj_A6zgauJD$mPcNBde|{MIwo{ zh$DRLTQ=S0BSkha^$%SRI`Be#jXLpXLCz_*6l7VucocSWLWt!lt!i%SDaCyE{+u?1 zmY8WXpzR|n4X{-9lJE8K)k=bWvE0NRlOw@ z-u<&(=Ow-qB>V}0__&M(E}P1jpyk$brv&kXZ7cZg@FgAvZ7vj)cVZc~{AP+{;QY#w z?@1mO%#phJtoB$yx{ZpV4}jGCceg!Z5>Q3B&FroT2uo)7ue9s@kgz|~k?Bw`fg%^r z=H8kfMv5N$>cYtx02uP4VhJG5*Qqi|%H&=xnQ~KRQ4EoLLL_|SCbmUSqfwL`$oYvw z)3DX5^8BlfC5GvKT@cZfLjmrf=uru>*^lu1geb@f4I>51 za+!8PoZ8HIOQ%JX4#lLFB4s7pI-J0n&*wl6pkA5V+H1&l?M#-yvnHrb+kPwnn|c!C zbJjMM$;|hRe)Pox*w`udiYSiUi&HD`wx*4=9X`aXzC@LbQ^Nyurs$2g)2-=nzNR7c zz(ZH7iRO(jLX8_sPuDe_X^h-c>E4(8hWYqAZWFaq#;5pe4kRa-o?n0+`v8|+kE_We8CZ+%E zBmgCxE_Z)&D+0_#K_351XD7huBsLmZp0V)~Eb_P-C0S9&VSfdFI>Z%Ug>dpUFm)m8 zgIi?4zB;?;FfX%H*$n0UI31R+Qaq*Zwz9no!l9t?Cy>gWjGzQ!5$r~VJ5B$6lSpw5 z!3@&;i-cH>#0Q=ZcTO+QI}dl+59ibh=t+kHBWcpzq-um|G;NP_ICh>dU7iQJL0;#v zoBs-bl%o&|m~1}8m_R>97*ATfCnTwox~foZTD9r01fcB0X+g3Q2J)`~8wZF~?J-4s z@$&MDrpUS&$@=-;hbNQ!^yd5iMBU6w?XT|Ie8^$m)QF^drhg|CVilX`A%EB}Zb3Sn zTR2(#Sq5P?&qqEPkDcQCSUtt$YPD+=2qQSAeOvZd9cv1Ph0NR(9ZCjy@qYQXF~ziv z!HD~{kcNpq1XvWZmP@PgESIiua96W3@SvkX{8rB=9&g2uz>6%rUS)`qA8{p^8WNqR z?4HGgU)9hIkK}@%^e=*2YH!`4uB1ff7~@zw?WQ0}N^);<2LT8K9be|2M%Bx#?}wQF zi-7HCkmD!wXP8Zle507jvp298b@cBgBXYNJHFIpx1E-W)h2J*hu{M}9qsqxgiUPPc zDi597^5qvF_u1Z~vpO*}6kHk)D+5cBcvtcPCLFG^0$lVhGi_h*&42@M)ZYO z!4?6RLBWPo|H+RthNqnFo%1YGg_pOaAS)3Won#Wqd{s;fd{DZSiSgm-(qFnn@Xhl% zIKB3VxI*HH-?Uh=-ZtWAUN=2|SI@qno|nFxpwgg-rFfyMd1CHmz^t>ahF*1515=L{ zKjyUFhv|m`^t6*?DE@xykap87xKl;dt#9uIyQ%PxXyqG=S>vCof6d6Z^`+j2_M3^w zB*ieN)nCILRaxzQfw>mvAUVi%bFb{Lf0srOV(-d_Xl_r7_YC|SKDhA}L1@gx$m9Hx zIw9d6Hr#cr{*aI5Q^m5gyj|j=fdWDof?fgm`tQ4~C}R-;K7%+z%m|F>gUpg7lGMB) zrQVA_#%fD7FvRaq_-bYtN3<-eOH)k;WBqG-fRJQ5B}t$gBW|FBQW2-TuSi;_K--eO zg|Ps+!jXTBI8m5HRXDj4dmcLbyzz=xj0OpFlera`26kNn#$e@&Y=x-EnS2X<*WVA% zvstp0W_PBQKG@qr_iATn+IEU;H)sp+`6-SJqd{#jL2RIZfxS1ix(hqP#Y5HOj<^CL ziH9A|cwW3KdN1nQhg_XoeKe zn_s9%f$XM{E^6na0dL$D_bV=Hz^0S{@!iLKw0BdIxdO+SRV;q^QqS6MSbcuo(6hzL zbn^g&>+%Kb$r}5f%5YGUq^tyctwRiT-r|9$<2ZL3dHQGx)~Zwls-6w}M66_wz6MHa zvvj+8SiN4kWg~!)9oUhvs+6sJhF*$mKX171XY3kgKdRjVrtjhN_gues#f={d^@X4#U@(L&0V7Km-@4 z!&XY!RQ+7eaZr2!PbP1d)P9#uJkOF*`3V@E+?tROkvn~rPYgv-icxlfp1f&6gUw`s zOE4>YP!(S?G5ci1cxL}%W;y`q$h(1}p59vl;W6i%o;A3SH?}#S-_^ zxQF~*gZqvnHTps$znDKO^I0~>88*6k8VP1xyI81ZIG%p>PwmY|Jq~s`Xx(!k*`VGV zs>>E6n=bJr3(B2XyA`m;^z>afw5!OJP_@Jiu@{XRHw8$;UvyfD=M>Y6jAhl@??V3E zB5hL{0xl^6&fKMOW07+O{OH_*l%B}Zkf@R89bM}3>min*h5{!U)mzHO@w)5g4-r%B zZ&4#dH%8GeM!6yy4;;NFTX6JcBk^Wr&=P-QS_0?aqKG>u!bS{MugOj4vsC9ZA*-*z zG9J1W%CbgzS7$_Gh^3zM7{166gNf_JLi&xug6&4t=9z>}M6Ex9&Yo)QB6Vd?l(XB0 zX^Uue6@#^yu*3;|02G&VUC@#NIYdb@9yzEBXbVooV4=uCS7& zL@Otcz||(yCX@C_#vIKrh|gt6%fXfneB-XpYZi4_=frZ*<#yl zhMZdNqbh8(%sq#Ejkc-i+$Cz=3~ea?L&yo|cD$nHA9oVeIdYB*|&zLsgJ$rPXuus@}Q``%@f&;JNw!z#PNanU>^m}Mw7 zEv72G%jxAyaFaD`k*K7u?Ir@g`o#aw3z!e_S<_W~0D!2d|Cejr|Gt3v54g-Ux259- zTf)xQU%QNTObYp=`t0=T#zdugBxB3Tl&%6CU5kd|0+O-gV8Ui%W6{*{@8=5}0OD5^ zV@}2c_;6{U=xdQ)fM49YZevaFI>^kG_7I%U_gg9p=hK&FYNJ2v#bvk8G|Y zO)XJS!{f=!K>8X);q;|nBPx7~49Xq5Cg^uJW2kNcCue{!Tc5r5Pye0G+SJQ2oC{Pv zGXMU3yb!Ffju8S(daqpC^e4ONq%#Jfd^{`$k=4gY@2F}5KE&t)k?F|B?K)&SbRR+p zPXp_09w^a_)`t3ho?;9HOxc|<0npOSil0^#G*H;QI}#0qxB~l&=>^FPp{De@Wg0yG zHi(tED3_fTs}zPTG8iqQpG=_0W*p}dw!i0d0+B`r0^s&IX9h4C6sU0yzzH}3Ot(HO z&JlRnE#}MdZBk(w0Hq}FzLXvKkR2Rb07?UB7a!YD?3}I;JUN#_gIe1@W76N#le|7q za`~LNYPuv8y_fN|K7-{l-gcG|(!d?s(L(sZoHau-{JrAwj>5^^5C@(%45_>$qotDk2ky19S(+*P7npA*8L*SUaZ#)W-ZU8dwr?{j zjY*p5JEOU74%U&&dkZi22C0z8Coq+lO$@EHZn#~51BQn{_AI)KDK=iH}l6+y=+ zrqja)WMn#KnHg!En6fL_5fj&6qI<8if4JYFJ2s$ts);K=FR-rEp9u_KE6KW)x7ojD z;I!(qZFDmJBgZb+eZc9qjdTjKg2bGiKdQ4XRS-QZX0E)mKFJUW%1PfF~qd3vL zgl31}(;}JLx#_oFQI{k&m}79zZ7bQQ(|Tfhq=+eVlOe}vZ@Wu4F49(X0(>jLlUDtQ zuvAubdHwu^daHj6aLHip3eV0lI( zJuEJzFHgCPU|ToS5MPs#A5<2a4k1bT)<#uj7%y#4!}N;N#ylb ztr&bex=uauRGvrvx_r8r2%#n-bW$^nDFlHt?7)Ya?QQrNR>zfHHmugwGv==kN-g&6 zPLaFG$4I)gah@3PkmW}0*WqCn@xoSpCfDrDnJrJRHoZmYN>0$X4bJSeWh1EbNDon2 z{eaLvh|7=n6C9Z=JD2#M+1)<1KMg>o(aUh9u-ifLSHhRW7t7o5dIo?zf{b|Z z0)i3oV9QPpEG*GE#*fq8&SBpm_MtzqF;uq_UfZp_jz%BFxI%__HQKMPN8o(x_AP=P z>4+fD$8NM6V)jR;W)L+p!yxQx;*I0leOGVHYF>WUw6P@eo}PymDlD%Gak?kao})1_ zQ16S9eZa%nMF1jMTYGxYoIuaiR->To(43wFB_S7?073J2MTH$}MmRLnZ`<8BQ;>OY zH(#VtBRx&4E8HV6&{7LV7T=BSJ0Yf{o;yQx#IBaMB5>{|ox8r)K*g}DXl;<=GKJvZ zNhl)YKAOTncwnp-00O`^;MXDqXjTZUf5Em;Rsq9ma5P~q5c7)+u|qo@y%Mq7fV)xB z!TDl<6hg=fK<%Xw!czm(S4Ew&#!Tz`aB%$}j-k_d_2NcN%LWk`xc?ZBk(!ZvlPMwy^*?7EZ+8K!paD%oZ5(k0sW@L1LGm>ObjAvJ?1Ba7}#aK^d z0r`XAlW+;p0PlaZMQGH7<2SR>TE)MJBVe^Z6(NFu_>> zXhZX6h+k^1SqQvFo?@2KgK7c3y5KiJn*}$-=yU#w52n48HE;vKY(#S)3{vbNmaavk zkHz7MpbPh*-C^~S;^WH8&j?~<-wNl6&W&U z4$mz%KEQxYpp6|$u$`O^A$S4OELCrH=FT?v6@7oejMR%Hb88Lo!|S}$@mjr3?as#c z1D!2#q;!ORbwrl8@k=&Z7Vmoo4l5z$cFPJB(B%nB8)W`3qV&j6h*~)O&((p=~vqq(WI=~q7b2c45XF25A7 zX!y6$E(x6coS=*TycJV$y&P~jfmnMFxg%VNSMSrfCB!p2+p0FgOCBsnO7K{#+!mp@0OkWt}|R zhU6E-cc6+H(_G16;=*B0367v5=ndHRq$o8}vV*^k6x%q+WHQWTm*WJeNyM*L*e5CK zeanWJK%`TUD~*_=>2vG?^_`PfoC#n zXL>d0CFiLZ1^NMZdGQB*ZI4zL({V)(sWKNF)~i?UThUn>rrqBfNDvhYfsZ5{o# zP2gY=X4lKtK$^^*yuPWC|2mjBi>8{`Ms%W)YOXi-sYd2x&g_OVTj% zjnxRx(Lw4Fh#b0u(r1f?5la>V--+!SyBQeX+Z&#MEoYJf{sgaL$GwO5H2C+r4>%Z~ z-7@`@4I(=j`%TsK!9>Ot=q-gn^Q!`65O5Wz{U||C$Fg9r<43FXTz&8D?G&H$5!ujQ zVaNTLHSVX=^=WoqD-HSGoW?4n9OjWkgPe)fvIFU+PbM;$;7T3BT$JEhVa|Z>7NDe)e*-)^G zVDn@oK6s(+DGl7T!6pfh^Z#|c@kNvQGYed=rHaR?E*WOriZSv5`RVT+s}mj~paMXb zUt;b~XSh_aFIe$+f+zi*$-#P>Zu07LjRS%$jO|WFK3wyn<$yx&@CgFmJ!57|n6Q~vg#OC2OdCYt#X*X~NC;C&NK&8MS|v*yC%Xq!yl&0b*l$$dA08F6 z>GuYeb?6`SnHaOWVbA{a0VHFPzBom~rg~ZR&qA5la+Mc~k)TG)qZ!$bC6k4ng1&U; zgdfks2s2cRW}PDei?s_OhbyyV+DNHtUwElrBW`LAlcO=`oANaq_3z)=iRL;4PSda+ z?L)BbB?g>Q5JBHHu#k+u)nw*sSRky7ZDl;>)UE06nAZ)7IB2|0HQIW%kMomw3*zS` zqcF4osx_VMmK5sx@*kAzd6%1Y>LEbb10X`?F%rh|1jB>tzuh3_!Q`)9e~<8(n+ji_ zo%`=>KLI*H;bn0fxA}ABr`bvB8(m0pcoqjl+^AOFy5HJDgl61@enHVaM)&QZvt_s< z=sEN&Lz|mp%0FlO+fhMFD2^XYE2gskkk5(Y&;B1?0>~b4b%S%+jT=tc4Snq%{N=;W zI(RZGxF#;2l$}ei$>i3VFT9n%pliqb>m6%=*%X zSN#*#+>vVNsmiHl(}E7x@0jFeGxpc>{NM8gY2QZhnm8}RrbYX6DniujdbC3UHWD#H zG*uB=l_m_g#_^8m-xNCY#3?|9+iBk{>aS{C)+_BN)O-BuP^qdn-CuBsZRRady7*2t z{@vcZb8B--@^>`9QVcnzfJY)dw*ygE3Z~w0=i(CGrjJz3ic96_*ODv>5sN06=};`m z306XKjT;NRE~m@_MVFpjh|I$-5{7CYODg6-ZI6*5it;vGhk^rrRmGd7&DpI zt$udvrm?u1PYRb)j3q%8>WG0=9{ouIafO{M{Jw`q5-scAELTRT?FsljRQP8h?QQL3 zvbtM=z)ajZTYRN5H{24HCDJ6~Pun zPiE_+Foe>I&q&pc;o5}(gA#gK?n($3-p)~vB&4nT%&@Au&$RZLP|Km9`y^~|huh>w zM@HvSIT?A<`mWOGIM5rgc4HttNx=c-LBiK0UB(lbS|0lY$M_}SP#;KKh_nCcH?}hc(5X+KaA6TzP2dd2Mq|caz$fcIqfY z@9J|F$}A)r3v0w{ik9sx(OD~hQysUFPCQCQ>9D&jS545lbe>FzEhrA3!pG$g5@J^9 zTj$8S!Sw{*;#`w*#U^J_yU?a&CjELYAD0fpnOMDXEvHV9h=`CNCK~T**ifOV?Qddd zn~UG=y1Vw=7rB{9r$+`}h8I4k`9qS|h*^lGT4Zk7g&7bFMGJ^r_z?1`SCt9~ZDqCC zbYHckvVzCAiWHdO89AeD)q>wV741v78qcg^7Y^--KxKjG^KGxG(6a8O3|NKEVdJ=- z{dR>4REQfNmB83>ZOJeInARcn9IrW8o4{{umgH--u%Ta__?L<|Z(iXl{6yYPSuKP7 z)kT_86Z6n_KI2neB31=D6XxLXVUB)`tpqTfPyt3ug9PcT_*CLDM`!_s(y#{c2E=sc z7fF%i0@}tR^$A8ZweER;x?hV>tOV(8R-N<`F9#7q-7d z(5lpi@-5uRBgmJ(jp4X?EGubbFz5TDFAhcyyj$u)E{#Tob&m=~ZIiQowEPH|WX(!4 zr1xZlnYin+Ii55AHjdbi=k}z|mNurxUibvSpVltG&_fAkQ3Vz1gsyqr>fMsDUyMQQ)Q2`YMY6B7o%#s1ShVx-Ku6mTJ`qOu- zO}SKIMG&&`HPaAg=ATkag=&He&N{*l=+975djkP(S3MyVE42yT~<8c(gLcl_8}J`}P+Rqm0I*YNY}6vhYqls!0!71Twf_T--fx z$N|_>Zvk6=ncr0KFad9sufs4TV~BI{i?|85;JLLw5pd48x7|x*|-f1 z5vO*jl6w#=E=FI&`Ls#T+5)5Y?5c7~{Q$Ek*8l3OSM-vWm}lB9-eHy7q)xe#;f-^p zH@k4%Rda|cR5;we-V{ z4As_i+f!cu9PoFrW}>9_Jf(l>*_L@YP~5!Fq`I)v8wXGJRaI+MjlH8?_|8#09Coi? z?Nm{+=QmvwZH0x|n~!`o@!zS7;aC=ToJLC~p%%DWB`yCG03dnq$OV(juNeboO2llc z$ATgq>2q2P>=}C!6wgyU@9>J^OkzNJOFtv#(2GER>TAl`@84HWu&L>nA^?!*6(|PK zkEXOZ3~~y%b6F^fpuLHW5h6f0r!LBuQAf5~F{@AQ&`F@rd>u$(R=&$CkdF&x2J<&@ z9(ipM{xdM;wkC{m0OfmAZzeu+U`-ZW#B`NbjQ3EkF;q>K zNC8wRF;#6wwYJKEs|sh&QBgoD%!F~*swlFgb+Vyv6g9K_BrCs4{*25p!I8rQ{-==$ z-$w#kn5?=q$t$L)7&Njz)T45mc)n0w-L=yKUwh$DJrDlWqyaWEJBud+1q3bm1jry> zYawR>*Cr{{a*o*SS=rF)EBC5~gd#>Qx5S>L0;&ri6lS(ybOOV{)CfnJa(OntMaE9xsK+5&ZVu5kH7`?Rg4Z0!Nm5Byy{CtRZ!@20 zNME*kyvJd=>^Q;Qn{&M`ilO>wKVKDvq0IKQ8$;c^l=qoo-410;k|TGP41P0j6oqjk zTyD0DM4TWfJ@grMtqhGE&5&wb^(-BfKqgW^Hh)2-2Bk!yhTYj(9Ir0tV^~#1y zb4`cN;-x|GP(@=#_3Gw(Jo!i_PoyW5<9d}@aFI$DkCHQ5oG&JaWlg=IV?zClwEJ;f zllP}I%9gq~-cE911!BWLiZ#~x@y(G5DLGrs98!Vy#b-eRN?D7F;57IWGDt<((F%@r z(pNdeWJ>9XB2A<;Ovh}Ls|ZJLk!$|LNF|T%CbKcF=u4k=!w2qL(XbAG4U@{oW}l`K z35#41TdsKcZeh8aW2xl!X?QIQkJ@%}b0L+!`Z>o6pc?EZbwnuJa=Us=jFMuKf+cBX zyy}}if5wkH9e4SBSPRxemqJPK7Bj_)x*o;vRv#NlY!TxaltfB_BOFk&f7Ot~*jIyr z8o#IRpnO28fg6FI&5IQ}>H>eC?U&_RJ7VO-9^ZjWmb;QKl2ST4jsqB|6A-v7eimTT ze^?@x7i+u6#=Yl8c}Sw{OBD`6eAzO zM~gUJrTe`QV1c?K8QWt5Twep~b)425_*ZOS5A&3lA*&j7^agulw=l9#t%+qO5Djpn4tBMEvMVrw4p(2%M$5KH|-v+k>DeOoj>M?uU%Jj4g4R^ z3i+9yDtD#(VIh%a#+k0RQvpn%WwpQY@*jsg@Q!26e$a5KO=bZ~6@S&3ltA&so*%eAtmv;&&zkty z*-96M$4eF;`r&iycD_L$dpvUuW})-6b3Q#j1nxqxoN+vN=aM`R z=aD07iEWzPxnqj*=rM;(|9bcy~zaV8lg&h)-x!{p&wf#IX&p zhSKb<=cNF@eroqHQ$x7$swIw;9Z2WHt%K-TkD7?eY+Wv({zvtqR4C;{;i;zKl0?Fl z%=K2MJt5@BT6;XOdVhk*7UwkC^cIO+f~TfU^tX?gqt!tQx*)@4ObJwE7XkP8Veg`l z8XC3@ujpMGveR9#A+HeYDq^y%u;yOjl`is0_CBUlbN(knGC5&`!U>^fT0Wql3d#_zI}6~@?|+R};uaOfgdp*?*z$emyD zgh+PS_L{vC2mT7mmf7=T>7}lh&B#A=qTKJy@ff|Fc7(z0i>xH<6qFzy&v{kl(ZcnI zkE^oW6s8m(Q^||B`@yWC?S;$2o8rSd1TWWykQy+)8yPW3jvk3V=r>d#tKoS1dDqDac8J}oM)A{Iru zSWE@)7s{Le9yVVn2^Xk3E<;kb5~ms_wLX8sbL&2sQgw_)>R%?vsvKSQtut_^F0v9K z)qka>DY+rK~DbaID5_!*%+lifEv-u@R)!|KM#-vJN+04YcS z0G0p0o(6jZM+2Mx%FwW|bv3ZIFs89JurXoy&rSbdmqW3NjNJh%eD{T#bav3ez=bpP zW5Y16ae6)EYJyrqBA9w#9L+jG9-L57f{UNej=bdlmi4@llQ=T$+i^GB;NCwvw(8#_ zbaW{EL&~0cuCM8$x`_yUceZ`Jn_sx;_4y1scJZM`9=GHp=p`QuhGCf~JC-;?awAo3 zXKk79Tt4q8sG2BeiEtJvvCZsuq#8?RG2>j4u^4%*x+3}){h`&0if@vA5wvXv!%$MC z;H)T9Uai8Bo$)Sl@>&<0K1>IiR#2Af;!@-eT84X{Ktb>X8`F=0wK+#!HtDU3uA&02$_C~!+oZI~3@@Kp;aEj^4R=d!RawRamYo`ej~NRK z0WhLra317y9COwgJ|%J0o^CJgl*qCvs8$wAE_1p2STeVO4B|l7~ zuUI()>h`fzs((CdDLqOguA!v0762@8-w`Ium62D5py zo5-m8{w6zk0$F|sxcN9sZRDc~SE8iuJ#a0JYik@+^pyKpHR|Lqr~7pEh_l>t)2V^q z|9RcGSn=R^KSVeSLVD;Jvl5mmVest$R!5dmV&joamD&J^4b?kRu#%$*N+BUF5Bdx4 zu%YETR8>(H+wu1KXvjQ*PXXXE3mo^E_ys>LdLnPz&%8E6V6@iax#a_S~b}1l=%!u8;e_hWG*Y(Mf0st4b>6u z_Gje=`PMQH19UQACb^!kI!a;KU`gfar1(NBGCdEYrN*R1>pco=%T@|v-8R(w8z%_G zaE0jRe-U8yDVy_x{!Y)6-ymYu|0~n;e@L>5RdlQ_MB#l_YSFdHpGAgj^67et@ujT1 z1X7&c)Es0e1mam|0*hGQ?IBV>UuLSZhh9?V1iyBzT}@}RoJ?JLa)r!eXR|rDVQ(kp z_Z*CS9S+@oI6&wB-EPZ2=b{G;j-KDz>T!X*P%vqgDmn}jeeUi zob1*Myh6Y?Si0flOx-~?+IwBGA&TphJ?KpY(0P%wLkh1knP55sjm+dq28M6dVP1<7 zN^7nXE#TzWTNs_oN`+u0;3A<}-o4*r^x>ZOk~J)-{!FjJkz10-F&Ln|JPYSX;{9D* z?@wAEtvkyXr5|Xk*;L(`ABZr~NfUKr!$ay1RO{(N6lnezcDUUJ--ng`GaMX8OG%{_ z6Kxy1-)!M@89FQuF2is-gY5ES+hv6g2Dz&_nA|3e<(AR6Q7|ujVHp2LattZLhXihX1Rj#GJX_MOPg|D22zR=VzaZ-R6anW9CjB5Bx5Z z%An#lGvDRRD0}AC^6^vPAN?016?Z0i1=J6)k}huNF+`|-%`k>9-PpZ*5gjOlDJCrr zkpSU_MDoh0Rvrh!1WAmW)21GG8SoVkNlH=#^vW8^v2Or~Kpeqz1}rzg9_!xl49I{l zff6v}J&9skvE)|#<~Xb(c%)ix--_D6PmX)+fR8^Zk|GIK zM7Pfv1>9pY|HrYfqt8~OfZsNd{aclGuc-4c=2T9X|hWlI$~>_2No$oQAi5F zt2SdMYuwbNJ{^ZF2mB!; zmmrHt&mlBNM|5YtsjZjkgQ15_9A4B{ai6DKi!-mVkrEG8^iWXj(GN_!O+$gVR{$DR z-UiTTtKt1pM4MR_=sa(`O6uT32ZWe z2M;ewOQrd65Q;Zk??(@@Z}yXjTN{Pgj$Bz<(6EnGgxp+T#t%CH4YPFtjc_?FFZ+h@ zU1wIIdOCo|%=`2F69dW~?~?3=f>YRHKL_xYQobKTG=S|q537)eK}pXNz8pAt%0S?+ zglHXTLb>Z(TCUzhWTMl9o&PBTZMJ=Vsr{Wmxc?XUjq!iyH`V{M;1vtBQhdPwA9 zX?~gU5)*LpwS2lWJ{zR#{T6*F;Yj(tGjkL4QVyj^Pz0DkvTWZk$5W4w54W-J)XS+IEnGmp)l!~oN<-BK}OKm01lHg zQhMXM6H~v8Q)2U`sLPK0$m8Q)7LBo_g?HxGM>u}fii9_r5W>PGps0XAm#_Gtcl~f6vALf0ap(g1Oj5Srwl3) z!=5B31kk`MhJ(#X@G%N-pinpb=0PB-ggy^ntMc;fmFlm0zn2FL zw@U8}pz#N17h6p!G3b}-kG?VT=#wX4yNi+`GE5vDWZv8FtX7YwZ5o#^h^2j=-1ps< z79zSZH7eS{Qns?i_J%1XZ~@6%s?lR7p@d=FFz053$ISoj6cUY9n2@L-PVL4@>vT zRS0>j*Eubsco$vH`mYT3iXXkN0R^8^EF&8LxID9J5T+5WN8DF`s@QOGjLc^YtJ7KN zjP+K-E+%$rci@k<@Y$dkfwKR#@F{PU-P2!FJsmj0Tmg}m-7LHGyGrHGIc?Ykr}}o{ z)PGo@#u^;p*H?d)|&S*Y2F5@_Bli zj`!+AbNxQg(C|{0d6hBUm884QkOM1#%&znPW!vUDOU#ZFJ6m-0uzcjRwFGog7@RVv zfpKy*1-r^UmyB=xO7>c=z1>;Ah*p=s*7M1d)>Dr4BeLkd$F%;4Z7rAFxIm6B^QI%h zeHm>Zq>5%$G|ZNG_z$oa=jX))VkcainOQ!ze?{nnKi^JN)fI<$o_bPO%*HbqoOpc* zmo(!3U0mHpUKeXT%M<*CwVBN%z4?JCk>pIx*2Ej6{=aG+U5NdblYryh4g~&eoIjD! z1lg6;HVjK0XAdhSGWB?&L zF9Oawl}x4~XIgMdd;_{m-ueltPfLbMGekklms(cr6~RaAgk#u)?fHTC*m*d;PIE2X zXA(iT6wsK}(0^e~Go$R7Sxd*Q#(&^n#4oG~+5rFl)5411eh3qx-^q^`NV9bfq*H@Z zwZLW|AP^_?&LHnUNtX;JPE){Va6hybXaIix5T&OeKDbPvpHNj%o}e zlfr`sPEbY=pIXt*FO~F3eb0@Lqt%}lZX4+B&l=Uf(w+cSgDlo68rafY1rfZXj|2wH zl(tqJ_dkzpgE{c8)nFEYO+#DdkwP9*fgin@B*}8lq!(b(PK9;~kq+{hBG0b;Pg;C@QAwONZW>CJ0zCeA|xik!=Y$PN2{&uhVHDiM)vNo3)PE67`lqLO>Ln zx~Y>hVRj?fyuG`+#c8H*iAdmb3D7WG!k1x{~b7H6Njg2tCokv1lxl>n8Gqg7jbM^lLT5k22hFVKSNGd^0ri z$04^#2=M7=EJ}9+^DuEy_>H;mgA?FS&up^siwDc8E%$^NZ`AYSk?ip4vEF_!1x_*q zzg_)GjYp1!=Vo&W#v*|o9@Nh!95>(B-HAjS8*LZEmqjwt`RgEszc#{$jD9>xuDus~ z_~9#Y)eGDI99Pmaetm<)005+U003hD2i`6Jw_eO&e-9R0!p;*_opiR4rjce+awy5L z3bV*~S0Xu$#M+%{t2>b+xs3FTy;+E-^~B3YEgk?^8aQ4;_F>I(^6DYXoH=s`)>gFW z!;#cH)CpX?pHE`gR(3WXjss%Iijtgjpn}iE@2)Ia(C!$K!(mJL+Qv_lwv)A;$yK+f;D-lEvE@xSC;dm=Rvrh+mJ-eS%Lo=C?npt*C-UueOEM(ohS;VEcDHJWuP^;r0AVZ&om-NVjBb`owH z^e$n5W9+DL7oJ>CqT9Y~kFb<}VSl&xnB_h>!yJvi-2w8De7vFL&`;n*h+wp+z4Fj1 zpt7lfAtY%W{XvFZ2yJrGTcAC7o_+g-O@asU8N|CyECM|NK0FLs!5FBt)_wIEfKIq= zm-hlcU+&kr%VtpTp405!8|>!Tp^ezv1{%#1G(4~DL^t5O>(9rst&2$07l<5J@a~z7 z$$pR8SbfTAUgw&*PSck{^B?bdtCx@cE;3Ftw9?;pEa1nCErHT4H{sF^&Tj5=XE|&@ zdf^vue|}jmvuwa7>?|&3=bln_K2)$_v4fes$U&Uk7jesBkw&)D zCR({n9tVfDPWGEt(3zXEMZ0WPF0-pb&R?@n#Pf%%8~*!EMrrA@Gs4VUsBLGc6MZSw zb_?L*@x~%6tXLz@`Qv&upe)tb5)dI!LMbfJxn7eN&MSKW{M_x90np3`=9e}*3b6kv(WsgH0I@6CQzy4(6m zcPs?vnLy=U7~IYJZCB_aNd-$hwojg}l|E|_K|mUFy>m~&1~11|R#Rs+D=WJgKOX0o z>mStG#ZfREOl)?bknW=PgI}{mllCYp7gtk9ffIFx*bP@$uQlA~+>Q7%!F}_##Q92V zlD0bo1lB1T$0rDVS{~m%exIb{F zPtkZ$CD8I8$yU}c3Ewq4%Dd6>wXj=fE)W^}rq3hZ=b?G8+$+9en5&-fUgUMWgg4Od zWu;wV4t}dUv59xzyhir=d{Kks9O77pa<5IjJJ_*uC40$S!}A;c)p)^xwq)RMC3b`M znzwBzGx`q?P}^A^4wt%U-Dm9rdrrdpz*Q@tGxfV)UTz(?`wM8%VYTeixW~8{ut98E5g%dVq&$6^0C#xYMvBWrc3MC-ts=+}-Iz<>@XzH=$ym77 zJ|)HOcI6amm0-nreR*x3_?yim1#4|Y@_72m_)%Ir#i;y@wtbi~Gpr?U+dSyF5Hv7z zS^XO5Q~~nZ0B8t_$VmMN^*?lWX<^ry)f;noOy_VJe@G~-x4E&qJW>p=t-}lW5<&{z zr42ZU35T2YI)3yMESVj51J-_X-i1GtU{!nXYrgWJl2D5>DiD3}Ft4!t_(BW3@LO7a zZ~@)x;j|v~-8Z?fS}P$YLBLY6=6w z4ExaoC}m;1QZ6k?#hdt_)PB6=Ir3=hgz>nMVd>k(^W&+vzp3ci=~>WEx|XE5Ogb3# zxS)o%qWL-ijksP>t>=fmVb77_%NMOkn7SujSsD?0Uw`;LxnGbn!Q7bZ==4`iFxBmF z6aYk7SpJglRHOs|1EaZ2?H$C~dtZ?47&;|hW65K>6ZXsHwpwRYjUpLa`pZFWPod+0 zIo>2G`~5jyEeIxI8d?CtpZjL92{cDb|9vBRZcn2r0%tXY0C`?cqXbPHoDanT&0>Hr zsbApU$KJe#f<@!D)BQuEt6l;ggp4_LSTjvR7a%t?H6|jG*C44Y?uF$2(5E= z-Vdg0O^tjNlikLXNd{+SouFqts3jw?fF%dqhZ;2!{e`{20{571gE<@g2RtPxReZ!w z(a5v`LiCcVNEd@cvwXY&4Ka_tu|e=)`L|i{n$-NkQFz>bK--AA#cK{I;T1VgAcvj2 zXufn+HEe;0x^5Jmx-E}Fj)jgBL>w~*5R@WuRdr5{Hgo7TP8<*36Uj;&v>1ZqW&H{G zKB`zt8bs~Z2>K|nyZ~P@FV+FSlP~Ie(|mIt2z!A2p{R$&`~_U)2_4)ijp<(@YET5Y z0hn+k!Ec?6BOiGRTNrK~;hWMw95H6sFlcB^)H=V3)~@hXRu|ucefR?%bU+>hKSgg< zJ)=Gy^!TSF3jA3O!QI>~Op5rJda;s8fx9IS@olhL&k9edZ+!e_j6K(|Hp0Ylbq2sd zj*w)O2UcYDy{zQpWTyS@g{%cYiwKs|?V|bbK950G`n#Lvn(b|{hcuoBb?(tTYo2VN z)tOmu{Ub9KV!>#$xgZ0%j*M zgf6F2CCp*1mKYFQgtkP;N{4VIOw|W_d(;tnOt1KEde#X2=sw=2ZXK$4$9Cy5iU;CB zh`!fllH_#T&jrija&<7XiBn0&+np_wtlDQmA?QZRN(`-xqYx?_S{ABi)8=(Z#P^W9 zLL$3;Af`toyPkX?9}&gLX@~yCWnA@?eKzH$nANW+nZ|AIzDbP)&z!3}mX3mYH9a1a zP3+Pf*2-!h8WmydqO}t)gaKePljBMR`eWd)EenpdcjnCxX3WO#oJQ2~9_D)U5{hB& zCPbS>6ob4<-X|1;Iraiq;e1EUxbb!Z6!!y~dfoghMqRQ)(LCJ2^soRkk*AERvoITc z`YxE`)dbv=5W;!F+t|3Ul?&)$DlzZgH%>p6z&h*Q%5tny*mHIe-+ui$5EpfHax7SN zP%!$xrL^zw0E19el*|@lLgH++xz`f}hI6-Y`BB*!3vJhk**l)|Bn1zw+8_si(5&r( zKsUUbFRy~Yl8+H+)(M{r(2Q1<=8^==q*)Ke&OtVvO>nyRK9#GB^;+(rZKclp4VqPV zF#9D(_Q|_!V+;<2I;POnl>D0D76GF6kS=M@o1HPm*lZuQ+k`MIwoj`4)c?u(3hi(# zO8EGUn4O8Tz3ZOPJM{#>$ z5))-gxPLbLHcWsYjBs^v=fX6+r}OrJGxVPiZzbl7Xsnsv0EEAWq>Sf!N+^oxyP*cl z>r1TkDa7KCIi?g28%% zT>z+ign9oB6~#>qn<)Gvu8i6&0@}3YK@VNI&HYNlMdon#OjFU-bu5C!;^MVVOL^eB2M#>Xy&a9d-3Pc>R$gN$%pu~f8yv<_ht zjTUZFNHT97gq%V^Q2ZN5IHeNU2k zAoi6yP*XWIkiRIPKMV0J>+({1XTwTghil=O4?Xw4=4e&W$W#R%D?)Z%5=4W~i56(} zj2({s(OGa4XmfN?Ou2JCedMuJU;4i z58opjl8z~%SAN1ttlMn++wz2SE|Se!bQ__O-TqRlYoEQD^?sLO zHta~qh&&Ha<;s8<79b>y^!J({}1xTem|c2>;PN@SjVUFHrxvsEhR7 zv4i`(G3e{X%yiir`t@A*|E|_r%y3zakM&BJCR{>xLYw5MYej92D5cZRlN?i|%`h`Y z2RZTpRC^rs$_H5!(>3||W$Ucu0UxhwB`(tnyX?yvbTjdb>YBme#ql?Kz zj53f4Gvo|lU>xvTSl;LOJK{5d>d?7$9oLW>+-4o2X|ML{l&SqA1RVV)Gk{a%NGcP9pDD&1piBNUeoC4Tw_z4@eLNT z@Pe&C1>Q6Mem8#R26{m}t1N{UA@?Eac};V%Mvl{1Z#X4-miC9^IPn#%onVwJC+$@s z>(I#N5ML7uz$0>P62IOh-oN2`Cf&d1`LWP9c;52Y(p=dxR8%7eT;UGcsYLiC`rPRjMq_ta;C!4=Bo zLTS2>i*NnY&h~ZUTX57Q*}YVdK6kjDv!u9c{#e#dpgSlDaVd985dpnmTYQt!QeT)O zx656Wbx~H69cI&9(!}_}jc^4_sh@@BTGULEm9=2yzW!QRe-u28$v}eHPTL?@D66+ z2+Sf3)RYbi5li6aE<;1CHPXs3Wee41CN5PVPpxtZmD|I!;&FV$#(^Yws)Hb~_UDAb zY&Pd)`osmmMdo$pHW{Aj?t`pPnSh=xbn^o%{SL6XKMc)ur|A;37)%h-sa8Iq(pbzD z!V;dv)`2PW$>5Wn#W#-=6`}w^(2N%Rj##a0VZ)W>b~qS!UCHwj%2$=MXl~U`Q9S2; z`nN|JqrzUXb-fJ3$+lR>m6P`IXdQX>d~U$pT0>Pk<_Nni;2O{4ST~8|$nN(Ggxi7f zVm%GKQ=DwD<10$=^9&cxAHdW@OV~}JZG?m0Cg8lfOCsQ^zL=pT5Pnh=yhuN|OXX%{ zOfTJsjx~;{;5k@0!EWx35fuB}RPM5RHC+Wi6Poh(VCT+1W2#w>c+;h z`LYe~xqvzcpv=5wM+c!RCP29$X=;gp(8xjM@un~_#!Pb86U;PkS$&CQps_{nQT5G| ziUA}2ZJ-)0Bj2_eISs2KSSdrFv5&*lbj41q?4500(DYmZ9U!_o?^9GUOV5YOW7F{b z-LhlT12idqnr^!1fyx42$-gl%KS6WR1Q<8BkEf&q1+mRsqPmUS($Jb!Ce2yocK7UI z#y9LgZsuu5cjX-D`m1tKBr zmm<;s;-m`$&c`QGSZ<9kb-N0eWZ~<5h#;Z2^F9Zz9$4ZyF91S;)Na9+V^k62IK}}b zf&Qu@qt78&Gc}75p%zYE2z`QC6Izt5r}a0rK!V-2sZ?zPpmYqmk;?OZXSA)=F|4|2A8J zRfzW=bR~!ki*jj0KGcm=7z1pzd0&LOOWM-CbJ`v0lT4(@CmTpKge6ni4cy@cnX0Bu z(yIu*gA-X@#8Wpgb6+m%fj7=7VqnS2m$TLuFlo*-C;hQ?5O>Mmb$6|YkWL}LmDgq9 zFIJ8j46ruH&&M?tlg!-+iihPU&^rD7sFahF9YycL{Hoyq$I3;SSdnQ|W_U&s~)aBkd zWvpM5ayO9AihJh^N$y3crLr?9DHHn1s>A6yva}1RbTG0(-vGuzV|SF92~c0N>~zW--H4(4Q!XyVU4u zh&yMgfxdrD4Wd)P>QNFsL5GKWyQl&qtn8Gl1XQr znMMkH_1P$t<)F$mY_Uy2v@rp?G>RXdfLlRBli78rh<^1I?2M*RjPK^Y$cho?HWQM# zs_&GXuXTUf8t@@hby+O!8ju3v8k2_>ybmrTAE8n&HM*QT{O+uXeAZB__Rqc^l?1rO zFr*Cx>6Ws)y0&@f)kk-u2l8R9v8LKVdRgp2pL6spA^jXY*JC_g&W) zs0%YLBTf*@LoZL1-am3rf2hc-44j7U^D8>FN_Mkiy0=^uuwGP*Lw^A$=c3;S-_%8X z%LBAIWrNpFIo0z34&(u|GT8|sQWJS?IPBZ+Lyi;$8Z&op`7;dxz8D;5Kc#cJULRSe zF?7O@m+!x_W)6?lpd@P^f$A8|-!m`tDTp8!gmMT6=Wl4k-tkJ`EQ}T$Ag%3Jv0&qT zrK5sT5Or?Fh2Th`P>vxbBS42S!NlQzV0?@kK9jn}01UCGPW_np*1RiS1MwT+Fc?a* zxV1AIRi9YVop;%Q$Z$+1j++yBq!Y=rdtZ*+KShYT}JFTPTNYQ~5wXzkf;JEOJI$mD53zXvXMfmD z5RHL634I=LY9A|{Nq{_6{uOQTNV!E)^%sOGs|Bqet2hEr>BqiGS0q52v1gs+Mf{q< z6zDS|ii)_{aF|HeiS>X}vnLDtZ)%OT?#_nJ@P$|Bq)SRaVy1q*2{6#40n=- zD<$j{1@QtbwSJI!f3Hk%`_wDv-QyV@9tIW1#pH@46f0ADgr`y)H&%}>T@t?9evwXh z2_9*DfJIWVH8KgT*{-}c4I+wMIf@(!7Ib|OIrdP0uDd$1_kQ+0A7-YDLr7^DLj&0) zc2}K166Qxd0u#_fKl=noffe5P&B`Sic-;Sjf zR)h#nkr<4vJ=s`KEHsEjHmp-gILGqyvtm9cEE0=lc*Nj~?L6ZFnA<@--Tp!KO4aMUOavMB&c&Omr zD+@oM|2)R}>aH8rX#Cgs4v%X}M}qjKOVPqY7AlJ8%2jRu?S97&X6l2!8BE9ItV@I8 zA)e3Cn#z@IsH!uf4TVM4dAY_V4W{LAXSsO~%-aJwz^@}9H(l2DH@CyU-k^nMLYk;Y zs(JTrfn*jydJ+8lFsd$#R?alk(KHWRlZDfCn{%HThL7gBh&!D=>)$m=sHo=$);k6h zaP;aPnWnH&MoH(c4ScMJ+MHym(vY<Ero_YWkvJLM0ZQD^Oj18rJ=PV z?6UJa#O`8H+7$*hK?E>O-Z7|jb+a;=utpA@sAg^16i;2Qjo;86)p-iGQ%6RVP+cB- zTH@fNvPBRp4Fzr=-ks8_PY@jYQYQ``{-RO*6LB3S>i<0~9m56>xl z)eW8$L1sf!5`An)JsPl`@%4Rb;^x{|VfL2zGqu zq>#ptrZEa0FG?@teC~J-^em;o{g9-8TWWQ~bU*G*jC5~GMF&#f-Zf`Z70hOl zN#?u+-#j;%)CJ-x(6qPSIg5AT8p!&vwXV_5SGiec1|9ICl4Z0Ic$}L{R5d zx)(t8_RBGOD_BB~Qpx?>mDdDIiElVGdBc*I>+GfVxick2vGvwFzxs^`ir$~g@o8}( z2NP@;9l?CSAD;;4j1N_dTFOjTEVGHIbkL8>ipjVH_I13hRtww193*}gZtrezAt}Un zSp&P)%qD@lsf;=`^e;x;Qm=4Z3Kd)QRgGQ8dF4^Lm$MXEfbGkPh;<;=t*T?5qP*r$ z=-MXU)p)1aRK6bI-QV5yR4~-eTS>3qT%pcFeBhtq=4W5pb>JZ61nU_BtMkBa;I=B8FPlq;<6pj3KOYTB1xz<>OEca^_A5C>;N= zbQ1%KHluK3&bWLsg|ihzCbfb-OhWM_9=ajC2==%_q1tWv)CtQM^|geJw<)J#-J+

{8dKD^e^TC!U83|3&x#O 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 z zmC?i|CO)@fJ5PC_WNvI}a0YlZ1B&nPRlXN=39@dBZhraldqrE+jLH`MUlo(Br$c0u z1fU!dO#KvGi;fwS&DCI1i6s(~9G+;HM2VI-RiSJ(=U8>}3Nh_WvP@w3RRUo{tV1V} zvw-Vs09s~x2Vs?FipiqMCM$~@NM=P8G9%(h8!nD^;4gFc1_SET!goFkwM#d0(l+v; zM4iGP_L6BDV_ftod5Hr3p_VUUTAqv?cO-K-Y9M);eTk{Q+1Il~en>s@9ri+$DRNi7 zMlx&wfwxUUiFbR&Y{pV)l#Pm3hCjqv@3R40NVklr)y^iqR~n$fS+z zdR7SP3U2IUN{H6PF>RVWN7OCw|8q%`eyZd2tas3^XUBO%lopQrN-z9OB@d8Jx*KN# zWEEnkap+Yi^YxF#I^GnjiZZ9K%{=&n(RL?dW(6_wl~7N8`9o0tUSSLn$|skI)rp%K z2RvEg5_7qc@P~KKYDNOOp#Kc9vKADo%y{_Y1PhRUFZ0vf(OGff&3)nBxl+w5NBxz$ zr%t9IxpeOB2_-vj&{1+u41P7Ypjv3#acmRs$KsA=jUm=#-taqTI>iGnm^7(bB;oQ) z&~rn_w|~*5Gxhf%pi>$-$(V%BwTV0i1i&LtPRJX^QMVF2raCVw0supEp;)+Vo zYvqA#1b9s*vWa1Yd_ICrQ19|`IMikBGdIF>8E#6acywsX}_TrttZ zOLj39-mIt0v8ZIK!Q6_55tTqRGJ)k!;limZdwcF=QRa$QqO)6|g*4XYDWFyG*~qSH zoHlgPQ}g)~%{!G?UA!QEB{nNEzw`15rTodbpFn%D<|+Nl6Za!;7+M!9R>8Dh=|p>E zS=Wia5J_yyaZSyEltI_gmTj`b)z%#D2Cwaw&tD5y>ntHI6$?wy3-U?ZPm~i2ZYWBK z@LBF5^4UNKJvMn8h!kr^Ml8pj@nwPXD%eD9hW>`7L4N`QePd0hv4QLfi?*xiT2C}n z##6_R!j91(ntFWAv!yOG<++#=#$k#^8KT{gMi9kc_}*OtWgP`=!p6HHpoDj6+J)Ea zz|<@YQdWud&K$?S;B}}I3Sq#T-TQ8Uw-?aHsoKtwF*3xJoU)0y(&5>8uU-ZmuM5AR zyXR}~yJyLC!wUewc(fYASr!0cuuSc!UfK*St$7%=o5=%S5kidl;gS&a)>$U@*Vo_A zo$18(Uj&#C0!&DGnK%rvi}}^n0}RrTu4=;$lv14-l>&4_!7 z7Z?S$&+mGesx`<8eOZls=`X7pr#MRFd@}ZBDJ-JBA&zQA5>X0;jzAKqmEa;p^>G+Q z@}9+OF?MU9%&0vA+~LVdu_mhkPQplG_g%ldEKVb8knO>>cc;NMs_;}9Sejnh2H489Mew1l{#O|*~=6H zSek-G+pn4E)Yg8oG?g2ASSc#4cK7pekU5*)TY)pymk^vW)Pjz0}JtS zgKE;ti9H2aAeBS@qJ$otU2vTc8r#RCBhsWHF19yBglNdA@1Rm>3wMWk@ zbKum1X$upfEXalC&X+IZOYP-9`BWwB-_UMkVc4(2|3sh#wAYzRsy$>zDv^im2>PCWo-noXXpz>ucl$ zgr~=zdzpNpqAVyS^oBLXm4vpA2t?g!+D%+OIKFmASfCac6rh0_`65R%URy-xLBS3S zV5tE1R%`=;!G-C|R4NrdZ#uD?$zZ(<`pD(OZvUvxYqXv^WkkdXdF6bwwwu1W%t$f< z>mD485a9V)FAWnDE1BTRYrRUYlP}EcPvh#7W2#Z~O?vt)*J;xzL`hbaly<45EpvA36O zE8btv^qLHnNG7&6^@twr@_jdbaHovpe8U~yAs&!3pTw6z%M*E{!+Mo&!@SQ55`LHX z1==8w>QTh9y7K|?XZlKU_2mZ@IZ$3@XQzKW?49lRPC*$TAN_5#e|~n>J08lbW@B6G zxx_}YQ|sEaBxFluUw=9HL;`c-+wGEy0 zJ^zB@iW&{q`Fv$DjS6TnQg4-%;Wu;qT}uD--4on&;)aTpQR?>Ow_4G6&?!{?c?`Fq z>c>lAW-S+O{;%h_dcxU?B9&rFGz!fcr0;g8Q(64qN1Jqyj+8hwR;)clZqJrNO9?`m zV%qxmQ%qHBcOKjPW}aTmSn;WWA5E~4<3!`~x5mk_E*syQLVN;&3PiL?jLPqUcG^M5 z@vTA*d%~5Ofa&|>5goeh$%<~XjB6HX|l? zGNkU* zPP6)gPP+q)GbR9MF)9RWIH5WR6sVoJmoNx%mlQ|Qp+>irYOU+&&06OECNfewM6QM%C4IF;1n48&9h+i1H})D}9%n0c7INxcSW~`q3rEn8eBpq! z3C;(-(fRS|*~t*l?;VWxPdjy5;>sx#RqBw+}2^%(!5cOK)pk7#1wfE2kI zF(S?1-|xMkUG3Oyl&9$HY$z8Iq}i8gpTl=4=t{b(jggf!`8{idr7h#E9k!G`l=8Ni zOd>;(Xu40mOI{_P!nkg7?i5Y6g-$nvQDQ{2g8lSpMDq+O6WUerHZyqDCKUt7;91qI zN^{O&SuMoK#RVW&;bzCnpQUpv%V;&tm@l>qs2-z}^?N+CSM1+awOHhas;bnojwlhW z`KZZMf$Yl9RH|WEH)aQ6u7Z;&) zRJawH>^vUO+;#jKlj7lQcIn)Q=s3dgEE#^N)lj!;$4@F8^j3OB&tZ_%Ebqkd^o*lL z)#-`PIDdYXhfgj=C*`RX9$6PbBjdvrFQN5zgZ^~1BRI6dx2aPvK{O?ZsJh?6+6+U2 zD7pe0z(a%RPC%Z~*_A-VwBry@DJo?9JFm|23he=yk>-99JJA>G&(7!b9&`_=XC5}ET% z4NANcgztmu4DHMS(L_XmTxirw%B9;p(a)(@9pfw2uzm>;4Zye<#SXiewF=(dcoQ@( zosjSN!C+tof()ug`ZSSJ)A7LIp@-fjytYLWg)UzxHo~eS>EZ?%XLnD)8EF73-@dec zbfyuW$bWenSpoS>cV~wPo%YOeqT#B{LlHE?CV95lJ4W<4_JsG6)aZYyHW84Y+70A! zfp_s9%k!93-7&|q?(AfVdFi*+oz&TOI;(7_v!-<{NQbul)xJDe4exj62LkJUTb>3tJ%un?$PrPiKU$T1`k<{Mip>`;HBo{R2Mw!FnmA2s}kHH95mFv$n$WRf#fpw-Y<+G}+3e!w(2Q^nm<#BgP zgQX-&;g(2~8L!fb#1y2$$mn$0`~YdKYj5C#Gn?8OX|2++pJZi&s4m~Xqqez+vjsa` z5S9Vnq z>DhSg5y<4o9<*5AXYTNVGD}2`vUj$;}TwbF0J&b($HrNyo zYH#eu4zE3VMHXhErH!=u9j!7cwZas)Zy)gTEMy37yhZmqVyzFJhyGz|{Nh30Lg>Ve zIbmQ=FMn7=oG|HoIL9k`rVq4@Frnjq6ubiECmy*_8<>0HPA+q0>j+BTw5DG*Y4Ozz zD$z>J0a$8=c;fvQT8h!qaAne9Ev$GIrPXaPBLbVlH0kD+$ajs)Z^R{Y>+}cwd^okP z20)B2uZ@cDmnTp6Cu`hP$7+)03Gw3XN(>x^qTJOw(=P!C2H%gb855b_4#WrJEh%bJ zU~YY%-0ja)0yh^ZWWl-N%@cWo)1o~YGBzpMup_hIUDz^4pCMdu3gS4A9Cx_Jg?-szaAh1bH!%8&gRRN#{HV0URE6Kh&*h;Ee$GXyOFc1t2!U zR>30Pi*xiQDp1y(k>`%0BSU#5DL86m-(yq`o@UK2IYBoTH9VRJ_6T_LwE(O)#Uo{V zqGruQuaHr!gOz`I6Y#!zSxbPkOGQaN3cU)+|xgplY zd6KmvGRqU@fLc=*LL>`NmMeVM&b*U}xAGAH5gLCTg}ybmM-%9qYb=Tv{|xZO5T765 zV?#yg`x~iJN1>NPe|YVCcX<+`HhZE#X7fOd;?SrgShuNNMSVc2VWdvJa5OZjR%_AW zq;|WqBT8;p@xaoTgSA`>&ZX>Fk?(WtFWGorDeX+ks?jHWo(Fu~=_mPSa4$OV4Y<--3zJ2qif$ny0SR#F(A@w285moi??p(TIX^W;D#Org?Dc!4!1u z1>p{6ZLBscDkN~?0P=6azLZAlAx4{7w<&X5&K;Av&kG2BQqyL$q|Ns-nzwL+I{hwd zLGSEj=QcFcbv)GBEIs?PEn}TfMPPO$puAA{q^3gilqxfb6Gtw*$wRaWoTahBupXi}(gkduPSql@%DgU-!1mR8 zDmt4*nBCdDB9tqONxW?EeCNu6#h6+*6rsjqG9mbtV%=ifc;KV&b^qDTco6hpD=6tp>5U8Z*u38c44RLjDO9}>AY(D44(Q;!0 z>i`o4HIVtSLrN!@%wPlb^xWIJo?HsiZY0u8-KuzBQxZ0nk%@*}&%l~ag zse>|-Ryv*(mGQ1}+{p@c=p8%-X=7N;+zp+nTrN21;Nc8aOs0mXc!^*TOVEcXgQ%}D zS5Jg}6S{9wN6A~mn{wjkwmXThebS&rC4R$7zw-nj(vRi(T|W{I$!OCur?$pf)o$N7qJLYIH`4K@r~_V=mkbej-`y=dGqOnX9e8tBc(v2 z(&Yd^M!BwqcTyAY>M1sEyic25(@WN-dwX4{Xy$Z5+G;vFga3?Fpkdx~0;a?c zxS0>V;i!K+-0X}F&rUv#ddI(v)}EMcxFvr%C6_GO z6a;>84nkWe3KH{=Rsomwnhe84De6Rr-PgXjGOoWeo9Q0z*FU}a`OQzSx3@Ms?KIyz zg?#U{))s7VqqN1%!WK7M>Fv*_=sz^zN$@dOG);+|m=TPCi9L31zzW4NdxffQiB9bY z^5V&->C|q9r(17r7u^kW4Sn;lCoPt>w*u43ncR6=8FEVmFnk2!| z`Z>t!X!xr(hWN@TOn_f$WS zX4Kp%Gww}d3d4kDm|-GI7l`_nZ}`OCR?BQKZLmXRKeM|fHPUJMNpXaCKAP}gG~HMs zcU!Wh#K1kowhldC4p)57edb{Ck!od6KtE_qW4~I8g4)K0wbyR7D64-Buc#mqFm))u z$)?{=LyX{A)!=2+=2I}aXznXu^=c-*CHv)KyqBGq8tn30Nl$SbhRJV{M*fiQE1&uh zKyvn5pj(%l`j+q3?o;$5PJgTII5~%<=Pm9M+)*c&n4H}FOsB16`ZD!m+1yp!F|_}Z zWnoQZCnDnJ9t@5$#zGNOcP-r128_b8L$`&9Ab^4{j^<04Do^|a$1dn)%#P&wi9V*J z)O1&~vR#{xSa24uW0SUvLbqD~Yi9eVZiz%h=bIeoxOo4CE|`G2%-vEuMXOY94*d~G zY#6ZESOFS~+EckQN14L{c3`7-+xI;@G)_Jl(&Ui{CRY4VRF3VmajRf!hpQ-uS#aVe z5;T>v@fW%cq;`LQUlyt+N9iIQW#G^eQL>X-^QAGJ&nlP}C!&uuF$}_shvnEvWt9E1 z7&9XSBk|!+-Cn44XQ9%Y3zgoI>uZ@$ zn+ir8ilhD_m!mQKuPD_A%qI3dCgH=K&wRN6{nYzaZtwE3+0rV*lVSI$7DWh^9Icll zAx0;17Dn&lcB6OSZ*5?(E1Aq}00< z2*bPT!Te&zciugz6=~`vN_>UgL(f=@gRXD?5-$QxeYBO|N1bH4C`~gyeIMmu`z9aT zpa1QUEfD`d5!s~--a9<*?U1~)jV2AVXynKfkxH~_X{_fkP0f?qcSB+U(_3Y=MG}rz z-bF&5@O3OG=A~9!^`2=c<7{y(HadSC8r#M5*B^sKJ`USYfJ7y0nUX1Sf-5>LLcX7E z$|uT`0E#!JTwlsi1~EN!ZrN0h)4lFrdmhKJSpJ0*`j-EoGLESTHu5hr2F+*sb>L8r zLn6^3^wVzUoy2-iY^&Id{cC&tHKq_PR1WCo*^B7G)fHwmzqiKW^dVjw$UB%3I0bz= z6TXI7eR&(>6FrPCWX5U~?!fC2d&1a_sLueu3(HtMDU_oC7rfCLWhI%M4jyMq z`8LP0C_ot0++_AmGry?BX-2TVh@p+A&m@sfX zw!DT0csbfg%B)Xe$XCNJ!#ir6e(oFf5iz#fM!UBl5xod3`Tp z=yI~T`z-DRsUko0>e-eWntFJpF+wiWSRrD3FLeus3;DJcpw^4cTl*ff6F8^_>0nGloV$+9sH8rr!`Bq*qmBa(oEv9q`FKuoG4%LmYOQHd`whWn3M`Dy zWzt;uK9Jd76&{S$zU6+f!xI@%izYfiJ#hSNQYuxCj+Xab43Hb!^|g(6Djauo$F)Zj z$FEa}pMJ+xd`RJVVOa4AR09Qa@pn44=79sla_HQ^bL(c7@b(-H@mxo4yYR{9n0l(3 zJf(Y7fN-WFpQMNHefN_yojQSbO8+xusfqOl2Y*=@;%xi3po6~J52$Hy-8FSo$TOxQ zl?PD4f(YZ#a559DY&K(3Rv6vaNZ;uZ`E=rq)ygDEnc+4?=y{^Y^g1n zS&F8hQ(e1b$Go6f2R;>V6&ZgJ;ERZ#V(zNkRMQ7}q37}(1{Jx_x4j@|bbhB88h1k9 zz4Ts6g$*BJ&d3#Td6CR0DqPn&N}3^tlOFR+3Czm~-o`s$CV*QYi+}0|sb49B`NU%x zmlN()sv`Lv;Af%c*lKJK_>iTM?+kAxjF&jYU^m`blhL&|9%(}cHQWk#dNL0KXJVgR zR$=L*$jN1K32n*MSfm<#)vR_aG1wWZ6%43A!lJcN^8RAp$%R2LIN37m|7ezXBzjmo zg2*Ql0;&3)fPH$D?^pzEH>ikzRp&(@6X}MY3!g9S@XoefdE7|u48-<`u1I;4fLNE_ zD2QW|^Q+3#wBMpjhM!eBiND%mi9a>vl2*`jD`WBfCnG!Q8G1=rfw=K>xI=d)vKbh^@3U^#{wl>kZLP^AUMN->|9#fS~jzg zmdwVGm}fOj=vUF_rVU;o-RJ1Ap0Bz}lYW}3rZZkWOLgQNYB8nFh5GSXnyWdTR|dbZ z=Sur+3Fs@!;aSpK)iQZj>$Ku>ah9@YsoZz}S)Kd1-ZbLec|6YTe4IN=;M^{kz{h0H zEK?y>@@KAACab`!P*BT^`JXK1D-g&(UFuf@K6B4gvFNH6^$WFdAwz=)mFhXJC?W$% zv(SP^EYeKAi-c9WN~nB66rKHEJ#gGeek$0wf|>_UfV1-yY^LR<>cK^2kKd*m3O=Yy ziuXAZTGc*sf|9#6C1~@~fRL1KLxuf|2>llg@k0IO9>7n?Gx{6#H-6JZ>qSHDZq>vK zyqn|&XR3OEmyNt2$G-CS*7QideE#S`I#K+d{xGrJE{U33skeru=+SGuLhvhD1Q)ij z5?4WC3oGyx6vBV>D!#ab)$YdAHt}@OwQNW#2vjX5qlA+v#U?MG=FhWS-enZ>RzR6f zNcy+50r^takBuVC8o`lF-Qn=8|NeZ4x0jv|dIuxvUI5+qfv&esjrckyx2U8W)-;l? zd~ZIB<1^%Kb~E3eutAG^nm)TE)h+F(XT5`$4Pl4lH98n}NdbYF76ks_@`}^ZJYWhF z+CvKQ)F)+Ly}-rywKWey=N7ZpoLRVuN&8E;4xmq2KVj7u+<0GYee+6QgJxTSGexFj zX-rNC>hhLz2u&zVu`6yc{U=^_#R&%OFeWaSG70?>mxX*(O1lp3&C6%X1tb2@-Wz{FmsgVN7gGEpfW+WA@~&VE!W-=X*+J^M?{D zHcwcgYBI~`NQQ7CiPg5hZurUxOG+MN>>7ZmksM%2loBU zZwQTd7$g%RsNBvH@d&EC46+^vip!KG;wHGlXYdEN@(?MpLqi~3(D3iS5Vs3KUE>o_-{6?L>h!dpcDcZsOhTH0J_p~KeorKm^UDX!r_-aYT zn~xYttw9e**lm{T;s|m1cQeJ;BnkLyGs)IPwRKDlA80Ayv{`dU#BF7Ff9-ZMF2wGn zzHg?!Z}A$=%nJE;OW&iX@H`-4Pv|VcUt7D$0ScuaKWVgiXs+`-VRw>WHpZh00k}y3ZW4g216VW6Q%LwKXR0cC#U%Z5Pdmp7Nr}mJMLi>FUxhfOplmlv1Wf+j zR^n1BYWQoLS3WrsS0Zy#>N0Y-tmGxXZb!=~DT?~{1w}IXH3@ks87-4irQ70NfVqqD z>!#&Gvr;J*YQ9K<(mRSVEPK2g5sAObp#YWJyeWW7RaizIQi&+8UiKjek2Yf$7OunE z^~AJ_aVZ^+N~6`C7R`5l%+-1aKh(7NARP!E302|sl0BJ5Gk&vgRQ&klsDC`vw|J9) zx6MdJH^cH-&PGv*KeqE@!fFXgqH`AM6BcD1yhztB(66Jzle16VVY{xI zIM}zTt}~X?h~Hv+v0NZ>dR;q(!G|yM1)&Uk4J)@WOt0o9NBFjJROgFBMk34jwJPz< z#DWzFk47P-Do#vu>cEOeX9UusG@yX39s>YisU!+C+Xk9!X-Q;NN49p&Y6QAweLbBZ z1N%#|Cu#9>XD}U;B+`*Ybt7&mR94exx-bVK9v{+;O?3ZOZg5* zQNP<0on~2`MW&R6W)zLvoqD{?0fmDqq|$t%Nz-OMvlby;)DW*5;!XY(qbZxVN)xX= z!<)xCMH;ARDoT=tR+*bKQLbiADiY`%{a$XIByQEyi?XP5DX%K9 zl}KJhW+dqCH0W*JvPm}cXgSiJ;Z<~7sb^d8?DewpR=_G2z6LD?+??)iZ?1mQE97lk zXYWeYsUbpoMf2hE(_thVG!aHpk)9UQN@IN;d(JpRwpp2U)eO-tpCi&BIw=sH%5y9f z!bBozDv83Fut?D3Z(E6P+v?k5vXf)V#q2^+r{7!jdt0Bc(?1JLHGeAS(;zleAT}2V zv6TX`wK$0F6o~ER&9qo}VwqV+5#~&G>+7rrm2^Cr1@|8=s^fqM{EpLIVw&SyE$r|uX!3Vhd1Qe!eCyE6 zzDYCt_V-<5!3!+dq9Sj;$2JgNBS#zQmT!;f2AVzb+wY>D0MJOn(>8hex+(F!NFL>w zPt3S_iw!1(|6IhOS9+OxqKL>E%?(Zw_r+zV#08@0D=7I*8bFd$;yV|=NW%LjB%8$d z*s>X51i&>PXNoud^gTm9y^G;hQ_q^%lUEoIfmfdL<5P&TI2-gVb$eZT23My4kZe4YLn;#x_kKfX656D{Zfz4c`N7;Z@1%{vvgoQ^w~} z*W?$QrOlal*d>_XG4kg;*;tpeZ)V7==P>fqyI67G^9nw(Xa0(}&Be=CiJfyf4qem_ z;=fHX8aq-cX7))Eckg`)MlD}^tq?o24$R`L#I6Kqqq2Nrbkiy~jePGPbC~M# z5pNUbh8G=tQQ(UgQ8Iw`b5iQ^Tj#k!x9{!2!xeI3*(pK}nwON}kR6~|mGvNRj8}>+ zt-qL=i_H|KEs*qBAT6J>iIXi$I(>OXt~jCCpdy}D#)(pWuF;kpUy)wVGNM!0<(Z7K z&9#(IUEU>U-j$Ug>6i?wT1g#bJICR8I`DKQyuiBO8P4xX# zKAJOwkuqyX9?Bydig%(LsyRmyKndxpgg{_%3`~RmqeLwe2QT8Imy?N4DL4}-%sRjQ zUeb6caU{vOUn)-#U04%5+CZ=hwn~Ngfjk;xA7~UnenGin=I5Cnm2FlE=Mj2p#v* zygu&LYu66S#YZQR8ArbR=+u&|PP~q}YOY?x5HEYc*zb*)+rXX+G2C`-KL8v4P55QWcm}*G{L1RsAd1BZZ8#>4n=ho<_jx^Ro~3Qhg_IP$jl>^nH({YDiFsgUuRqzpQ0d@ z>r{ymnj$(zDLB*{N3w^x%DHRjR4PM?FONB@b>VMuj0}}f4RVJCWKviT=0fFeMTT2r zJbtnm4qxuywA()uCh}XSRf3PD$=493Ky zYaDcCEM&qi-nra~{)$naKV=cw}+<_f$xpCTLj4!&jW-~gV zqmLGJbnWa&SJ%!?KN!p}0(A>>=8_!!t?`yBPD&8pOXj#UUZO^ER=6I;?G(+_QJ3Px z(0N$OlOFQiH~U5K+&TAG%GAb8^E!TP6-7cx*CQH|)0?W$#f(arD^|g?fKxh9er-L# zSRa3_B~wUH4k%OA1?)c^mt1%nD&d_c_*+mjUzoe{4pmBR!9GRZyI8+|#q}0RebsI~ zqJE`%m1{)2JSyy0Ikc;FZ;{@w)WZq17VP6Il}#bh%komI6^+|;#s=vS%o)0JLHvun z3U5bJGeTeH7q^zynl(^@;}Ep`4lLogC^|5*<&>SUg9#HAf_MZ)b!2V}pXF{hwx9~b zG?P)_iN4XW*0q3qP~?v_>W-$gZbmoCn_AMhj~u-_JG|>luofA-=+Ya66GO)qXuPN; zSoPV{sYf0fi#}dd*3w)v1@6xCrxO6d+`_wR_~`w|?f@k1VDuTpt$+OCsrh)fI3t;l zpMwP$nQW{c>4i0uVpvSyWk74{?+?&2)!3M?XiRKeUeO#qy{0*;u4+uWWC`_CC_Lqg zNV})UJi-cW%wsPsHZzk2p1{)78(7%bl;bghWSJqD8GU87E6nRpz@?1&R+&+G7F-dt z^6jf?>{`?iN-=CjwonD06)374w*3LhiW0dzMqz0jH|wkfzgMKT^8381$)scTBvwff?#O&)VDXr)^t3dQZzJYZU|&PFbY^nX2rrFWlHLR069OdOmHA^ z5#y;B*rU)J&1AgH=%2Rl?V8KDGVa7s=5p?1*yiZc_iobV%)mU?E&xGq6R#cj(s7;e zAqO|}>jccWNTQ5ux$WKb6FS!Rol2_vDx-dkOzQZ0hD2Y!RUI95@vaGsdbzXn-T`64 zU%SyA%sCf9v*|OJ*P4qP>wYw!&M=@nhW7Q7b$<>IC7IH*ec>oQ5#5q5TFq8d150RN zmyM`!3={M7;-e_RejGuHVVp_~sV`6%Be=|;=?uWjf*7&w{kYcJM)?cDAI;DwzQH6GJd z#Je(Z5yK2{kzX1;>uPW(F;`C$&GhBNdIc7z;A)IkFEZRtx4jti&2(hcTs6KWaoniX zDXVD#KDNyiA9s&mU}DRGEmIWTczDgIbLBdh&e#H;11OcV=n{7VF%eeaal$wW&zt+= z*aAQlMgNbvV~4vU^f>_26Y{=ov=sraHO0qJT-?!JroQFS?WzhG-!X`-z`T!;^$XNk;`2{d@HOJ;zeHl&8mqml^C>UA`k~|vyx+$J z@Wk>psNGI=FHUEFHcp*ZE6&y>^Cbu2!1sgMyBG> zY#T}OE@dDpvcNKvaAbr0#Hhu31gMTaalS|(_JhdC}t+WwN#I+zCytku%(_q+}MsMZEmgSn}AOCJi9$ABeK zX*Y{98^POjtV_%XgXtsh1*Iqeb&nWzQry>3eoO9`D>u$;NgU;bnrQk#XWa>JJf8dV zvX*SqGX2R#;7#Ws>?Db}g2Ovm>6+>rYdSUcPiQ@khAy0Y-*H8qBBY$isgHY8ZV*qb@( zI#`%6&M6aztiZ^CW(N%Le}T7`T0Z6-ZgTa{v?AincL6e))OqmWhSoh^)i$Q$fC^q(t7Q>lb0X>!UFAF%x1h7}D$Y_pmjBdIXosN(j6)29h1LyM6toGW(c7sX1kQz)tNn6v! zsxhxtIRh>&Us!lUyou~1%fGTSWS0`sX>K>fW|=zQWOZIJ3&jR=p5k@Ag>)(T!;I=w zOp#O*57d&v-1F%bfk6zS#e#9fW&vzef>7EC1%M-Xh5eH$uE*2ymG5M0N_$7%8yBsw zEIx7tYCl?b&;$rpGy_5Np0fG2#lg|362iw2s9WmQ#tW7-9;8c2BCKp+nz*wbg2?$w z=jKfU1FMn$Kk5FbO}gdMMzVslVg>1n|*e7Dc#)V{}iFbo6jOuZ~vi=>t!Np`g5%M3xennlyZWvIhAxS5A!i22-1q_X5!Q`YDR8%k3V#X+0Mqj6aRA2e&ELW}ex@RW#YOj;F3p}WA z0K7|>58KW5C5lMrGBK2}NQX*n(r+wXWvo%fwyd(vkhd?_8m5yB1|rcPVxL~5hL3BZddGl~K597@RkHUr)#iIuoo4{dA(nq9QIM3{ZFshK}zOQ#4=d1!&0f}x%S`k*jS0Kal3H1Bq|Ew{Z{=5L@$jI$>2OGu7qrowh4&IdNTwUSZ zZ^;G7)VaFGMOmCJQ67kL(~e-9sdj8|1Bx%fl89vSYY3fbzNtO}@btBRu76FYBh0Tm*V+Qw2CHrwt<%OCB%y)3G zDC1$IiBW{~zYA3iFg}3^tHVi4 z%3=~)nfZpQnO-oISwb|Qycf#Rtkw%gIO*<4j-M!L2P_Q7z8Bx0o4!6bb$71pzx18C zIR*rM-QlCq^MIxRS%d>2!q~6(?MdRA4eT2RabZuryQUER@I{~yfhIAwKyYw@79Igb5EC*eRjdMqB`_=*DA7!r z9s7KY3-_-r|1|W2$N))QwlcyCF=w5Tx)Jl)()1qpSP*qO8Q9XqEUsM|`v!xP)Ij0AoO$zw)a!QWusAXh40|O+o#} zD*h~C<-hOby`SaQoOO76PQId~IC@!pa3POpXInHeU}q;F%4@B5XLAcQN#$z9AxzFa zu~XH|6^N<|#gIg#!~EJRe0wp<=pS0_B!(%f-Jl_yQ1f#;G>;cv2?GZx@v>cQTx`@Pd)|Kxa(eseY)_UReA7e=23`=eiaXU~3wZ;oq=-r3p7+327* z*cUZ6nkfYztPDcu#^w#)+Or?+X zm_Q8_sgaLoC!aMvf?uLFTFwE7emHT?r#k#pVg?@kv@<)f3j;y9IhQNskyl2V7{I-%rRn$p)L zly;B*mPRmov^XZowtp(%i=o{-#>Dt2JHQEP@6UY^rpbLHo6O6=s?R==R{X|u+`kyi zckGD-B5IH4*gLdBYbq~AuCU3&yE`(z1l9a^^^l?>j`7-M02r_G4-O*Y*^kEA{a}i@ z#DdA|)Do~v+c8wxR8iGD@c1sZBw;6R5~4DeQ(URbQfs?;xNH79Is||rB+U#8oR_&6 zg?NZ8h5{WsND;4X7iBxNL7hxrQ&IWp)j`y&i6E=OV&6*|W@*6e!)6qUW95vziA5}q ziOZ3x!srZHw@?%oYpa+Ud2$(li%;O4TE5H}-SvIzL0qBJZX}xukSZ3U!PuMGlSAvP zovd|6(TN}@T+x?b>(7&bq>z=288tE`r+AJ}0%`_yWH6<b; zoE7NJe`A4GI%tJ5z4~T4|9|K_qVeRMzBCG*MMkf@vjPyIn>}&g^3NKsxzl}Y_g#9P zyhQZoLEY$4TiwL;IN|>@hjJD1LgxJ`gG%eG6;4UfA_tAI^v(y~FrnQlB6<@i42B+G z$|BuO^!^s+2hV?t?^-kc< z6VTd+MItPTbz+&6=eSR#5tyo8Oej<}k%`#P=E3#o!Ww@~WWttU;h7JFtW_c;#xPLm=S7mqsgvu~r(QUAC% z8o>bX*3>USH_AlUgC`2T-#_Tp^bb@dSplPPotxPdk84c=Q(M1cg))2|){gy^6uNkqK>T1L3b*c}OZ8 zF>-)lz)!5#CA2MswiQ9su|>%17w~Tk|0XHyPp$A;Tsok-@KU85Av*l%*u-iMEE zmZXhWVnd)nq!4+7i2TH?14M+52(VK0;PWB;{Q&C)_;!JfEa8@=~CDTDP{O~L;GAZh^TpP9oo)zz;-Ot8(K>Opl|d{vTfpW z|9}5-6g379;OqbXg&SR8r&=4-e3tE7+2+?Z;t-8mqRMONr1hUvPstwHfF9ZC!{`5n ze}930M*spoum2^1`S#A0j5pqqG6h`6Dc2iqDZ=}t{uFzA8B--` zMC_}3rcP#|b7M{EZ9P5ta=V2A2l+o)V5Ixk;3tBI#_$m|A>P*TvuuzazY}LzJbvTz zS9(S0!Ydt66#~l9#RRM-YKWAenR{oa!FAKAe4^@2L(+CxEV@G$9jK#nJ|;dWa+90(xvl{ zgy$w>bpcp!bZbrPwQan0?!xl<+iP~UX3O6MSMA8F8zIRn5>bQt@JGUoz%@8UhN9Yd z{huCj1S>7&n^hMg@0-3xe*ooCo4K;_C_%1|zC*pSE4WO1=@^z#Hk=o{X zgx2C3ZxR_f(#hw@>;DjbBxvqbpn20k^Y*`k3@q8tn-yr@%A>icm;W$Q6Xa}FAZNQ| zAZHYD;&#t3wR_w-Z=|0-(9=v^SS&p$FN#E+P^~N$M1uA<8AYh^cw6JKS~BM8-_K5X z9p}-?b_dQE5$WwOU);{Gzy1n;HsRkk{Cf@meu95*;NQ>iuie65SgXc-lFi6Aw({EHCSv#tP7FvF3KX>rAMksF@%RG<2)35n&$X4YJJAHumfPr3JlCLo zreGEjBp_5Hk5U({LSn(%ZP`yzV-@w10p)$}3P!LR8 z!f7KQzyp45;bSB=XL?Me2q6d9IShtRs#o(289dWK#ta`zF&i=&cm)OxYcW=QvNWQa z5h}AEHH$eEYaoENq)vq=WWS-VG{XMk8r5jE2ENB(hNJfD)r}=Q4v0ecnAo`67>~#J z#~)uuVTb9QFKFH8^iW(Nk@SVu10C@WPp2EBJdJr>WUaTNAP-rM-sdEzApkQUmVje0 z)z?VuqOU4>8wyNB2K%RTh@-DV;3y8jRFy2b{JbCZZf&>T!R~~QxlgsDIL9IE#H| z2$l`vG7w8}BMsmw#WiPY26RHt*QRD+UE;1e2=1-p%>z;UF+20tL@=LWx>U4|z!S(K6cq+x4w1k_2u6mx${TXIVaVUk{jrEmM;9>$@E#o|pNI9^Hb(mCi z;z&b{V`u5?uH|~}!wphlyYm}5o9AGBYi!oZ_M?z}ITo3P2}RcX>xlCaMbY?O75LkH zrUw9QH(xgd{E9+!yDF@rY=}|iHdZdUKB@*qax@U;@-I-u>TIFbS_9PNy4Wn0eOdP9 zW&vJ{EOboby$ zgXKeL&nykv(OXxY3@+)12;_5jjdq`&yRg#Hsn4gq)xdy-QA9kQYaVlcdgw9Rx2B?n znexR2jk%DV#uH9%j}0rnse|1rZ+!ztAfEYFBbJ6Mfxr=)i-8=D(T&%9Wc-8YUBRHF z;BSjYZ45x)-p5eqm+z=Y*HV-f4dWJfsK)fd@r)=hHI`ef2J%OY5V&^5Lb>TG3+3}T zX;>Zi@La-ArGpvDy|7+11pKNnoOcA4=7W}0qaeAYC1)roC+a`{)DW%v*X=cN8>F7( zkb6{2?opE5qaMauZR&yI{HRmP0WMc`<%ULmhm*-cX`$%rAW4}VxeEBOn2KSNieXGe zA<9E0tuo5^JB4vxR@4v0eE*Q-`v+oPTj%?SihTbdyR0e^?||={X(~4Js3_+9ha}%W z3}Y$^QC^Vm?+W;ye`GU0nt04dtN2(;)LCLKW6!=(K+EcodJ;|vK{<$JL9!l25!^|ci&4l+-8OqV|t;~tR zWDBWQA6U@ zk3t&ri!v>e=aSxz<^HjKEe|I)^XAl(3ZqCBO3tq*M#9SH+moCDP)Vs|#)3SfCr>Er zY-;Au%qSfhRuzo`BkqMGpgJ{G2S6530qwf{XDe175ZS5~M~Fexq9c}tvKEy}2wQwS zGb1$>HCGBkEU!xq!Q4?NyF~Gz%K6Ywus{fSL5~Y}8&(~}WL#0eDqw6+D8V@l`nPY% zCxD&+JIY;#AmqZM$aQuaK}s)sF|jyI>a@R$%tWoizLF8&ud~PBl508gNIie97gYO! zar)O_e&Kub5R)6oJIRQuOAl}EqOBvquqo$z_}KeLyN(Ny`wWf^c$T_o$eKuuznmhn}9zXvUrDKC;?E4vf0uhS~)H!PvF@H_$uw!9VkDh#^Bd}PA9)KwGGX0wh zmgWk(6hBSf?#*D;8+!iUo{Zm%8+$JN>mY(abn8$6_}(5CY09rME_>!Xx3Fs7c@`%~ zi|%AYkCQ!hF0f5|`XH_??6r7vk-S+ATyNvRz&qa<%AMuPJ0+N9u*$}StrAhR!ZaRb z=t#QRbq2|FU$_+s=7bl}Ih^MaQ{KL7i_4)AROv2xIjK%Do&{uX@QN!uA-F; zoL@hG`#aq|-#fD(lEBIPBv)r(XQrp8r>Cc9rauZWWD?^};9>c}vy!ck2-d%nWcm55|GkqkJ8cwFVUo|t5pulcX;)RdN zy;-6L*c$z96q6}xwa-$LRGxG`1xHB?(cUd5wJ1eSkocfNa2d+ zJBm&F z>1<-@B1SS?ZE*4+Hen)$2jt~L41%B2+vqbq3cNl4_dYdcy~+H->Ih5uY~h#zxRUM- zxlJ)U5oKirw=aeSM<59>BDzSH1?rPfg}5~l19>k_2RsWewLMLO<2aeIrHPb(jeNi- z;X3@xDGBkP2@i~zD24~`8UzMZCmw_06CmWNJ!v3Tg@D^+wVsFA0WbDjPLh-6JC48X%lRMgZLZY@sX?eh!UF>*&G3T5pc zZnfisg@{vDIB;>-D?+DTn>Tf`JBxB;f0)-?ci#^-Wfix(N1wP{!22k?!E3z~4-aD3 z;JHd5heff(J{J(Gh-h@&nB@|{G)hELNy`e0xkktJninihuC{n7lJ6l0U%qnXN*>GV zVfkq17e+#=Br=u17>&uf#_c{Z<{+Ei@raOlhdCGK&2RSigJB$AC20n#BbYh+%3^S@WJovGKMcd<3LfRw;c(ul&>*@Q zPw&?+(&2rT+EgKvG1W~8g!esmilmDOZ!<` z>@~v4ju{+^QGPCHVV^grjYIo-h3|78N3gej&_(t@)`|y z^(f#!*fFDjkm85_HXR|k*)13m5NjQ(>J+o{s4rcJk z&VJbsr-SSLQ8>%Y32{)x%+t^mwr}!_(w6?W%4xrpm6;tDmbAviIBo69MPspTXnj#> z^SQ%zsSKqeE4w+-@mfNaV^d;=t*R8FUlp)>ZCZi&>1Z?O^7Ls--mw2#Z*#4&3hFavp2T}wN;Ap+9b8w`prxV2 zIkw_4Hwi*>Q-prQ$J_Qc=aLJi3VotzWNb7c1nD(TRj5fzQ$BVW+ zzl*FPOxxqIFi?zea(W#n;pAR_?uA4~@?n@Y@RMb<^;|>hv(W>M!h9|HJ{JIZq zt;8hyt|tazYQxAbPF2EJzlweES1f}>%-J{`L@O)uSMf~F@U&L4?l3r=go966z-7f6 zAOE>b(PQ7iQ9T;G6fiIKKaitN|E1rTQJn8L(e!;1qkrKMTO7^R_1(d20?VP#V~%6^ zX!d!UvOTH~wz>U5I!mUx;4`^lC<6;N97l$s(t%MuQ-?Q1i5kl0w;jrP@2uizR3=a} za!tcNM}5OV@#RxGBC3}U#PTPaAC-Q!;%L7|? z={9WBhhwKUjvdn*=}lLIKQEGRdfG_yU2fGza%;o94(I%haiH6c#gL`M#U`vg2G48b z{M;n0%1TUOxc3%E8{h%z2E05XFKVOy!Xo$K@#)@@*4V-6``5=^0c*p{BR|$g`bU%A zC*8d>>I3+Bqj=fnVlw7rj$_-XMh|7mRblZf>#Z74=6-(zRS$40ph+%6sR0%>R42b|2N;dK zgN4B^{nhpn3M&~-7g!&_PeuA7EHTT&R z>Bbdt@IWLY7w{MyD;8xjcZ^KM31#cltS+Xw$fzL4gBl-NugkiWq`ZpKXL$gz`=HfOU;+X?Oti{Hy4v{-|vzVKT4-5p|tQY}heTq(w zfch3;T5R1`UufPP_CrL

&k)#*nNYJxJrYOX__K_ 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 diff --git a/cppbuild/googletest-release-1.12.1.zip b/cppbuild/googletest-release-1.12.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..2eb158e76041f30a3c12a7264af16000cdce65d9 GIT binary patch literal 1081236 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%0AZqA34YUClF$j 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

aP&%S&js%4*AEl1`F0Ww|nQVQN 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 z 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

    qH+f~o$;pW{e9MoD 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

    qGhIl>6Sut+Zra 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≠S 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

    %l{)rihaaG0Z!6$2oVbJWK+oIyd2#Xj++#s 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⪙g8}>o_Eh9(!k5 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

    SwY5tZV^nLW4ARwMF@LjJ5EAq#f9T`%Th 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

    + * This field can contain a list of ordered pairs in the form: + * ((<schema id> | '*') ':' <schema id>)(',' ((<schema id> | '*') ':' <schema id>))*. + * E.g. 123:5,*:6 which means transform schema with id = 123 to version 5, all others to version 6. + */ + public static final String SCHEMA_TRANSFORM_VERSION = "sbe.schema.transform.version"; + /** * Main entry point for the SBE Tool. * @@ -201,7 +220,10 @@ public static void main(final String[] args) throws Exception validateAgainstSchema(fileName, xsdFilename); } - ir = new IrGenerator().generate(parseSchema(fileName), System.getProperty(TARGET_NAMESPACE)); + final MessageSchema schema = parseSchema(fileName); + final SchemaTransformer transformer = new SchemaTransformerFactory( + System.getProperty(SCHEMA_TRANSFORM_VERSION)); + ir = new IrGenerator().generate(transformer.transform(schema), System.getProperty(TARGET_NAMESPACE)); } else if (fileName.endsWith(".sbeir")) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java new file mode 100644 index 0000000000..6f4e655fe7 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.xml; + +import java.util.Map; + +class IdKeyedSchemaTransformer implements SchemaTransformer +{ + private final Map transformerBySchemaId; + private final SchemaTransformer defaultTransformer; + + IdKeyedSchemaTransformer( + final Map transformerBySchemaId, + final SchemaTransformer defaultTransformer) + { + this.transformerBySchemaId = transformerBySchemaId; + this.defaultTransformer = defaultTransformer; + } + + public MessageSchema transform(final MessageSchema originalSchema) + { + return lookupTransformer(originalSchema.id()).transform(originalSchema); + } + + SchemaTransformer lookupTransformer(final int schemaId) + { + return transformerBySchemaId.getOrDefault(schemaId, defaultTransformer); + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index b62495f537..38a168f1c0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -15,8 +15,8 @@ */ package uk.co.real_logic.sbe.xml; -import org.w3c.dom.Node; import org.agrona.Verify; +import org.w3c.dom.Node; import java.nio.ByteOrder; import java.util.*; @@ -62,6 +62,28 @@ public class MessageSchema ((CompositeType)typeByNameMap.get(this.headerType)).checkForWellFormedMessageHeader(schemaNode); } + MessageSchema( + final String packageName, + final String description, + final int id, + final int version, + final String semanticVersion, + final ByteOrder byteOrder, + final String headerType, + final Map typeByNameMap, + final Map messageByIdMap) + { + this.packageName = packageName; + this.description = description; + this.id = id; + this.version = version; + this.semanticVersion = semanticVersion; + this.byteOrder = byteOrder; + this.headerType = headerType; + this.typeByNameMap = typeByNameMap; + this.messageByIdMap = messageByIdMap; + } + /** * The Schema headerType for message headers. This should be a {@link CompositeType}. * @@ -154,6 +176,16 @@ public Collection messages() return messageByIdMap.values(); } + /** + * Get the {@link Collection} of {@link Type}s for this Schema. + * + * @return the {@link Collection} of {@link Type}s for this Schema. + */ + public Collection types() + { + return typeByNameMap.values(); + } + /** * Return the byte order specified by the messageSchema * diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java new file mode 100644 index 0000000000..58eb9ee5eb --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.xml; + +/** + * An abstraction that allows for general transformations of the IR. + */ +public interface SchemaTransformer +{ + /** + * Does an identity transform of the incoming schema. + */ + SchemaTransformer IDENTITY_TRANSFORMER = originalSchema -> originalSchema; + + /** + * Return a new MessageSchema that has been transformed from the original. + * + * @param originalSchema to be transformed + * @return resulting transformed schema. + */ + MessageSchema transform(final MessageSchema originalSchema); +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java new file mode 100644 index 0000000000..f158c5f75f --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java @@ -0,0 +1,88 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.xml; + +import java.util.HashMap; +import java.util.Map; + +/** + * Entry point for schema transformations, will check all incoming configuration/properties and create the appropriate + * transformers as required. + */ +public class SchemaTransformerFactory implements SchemaTransformer +{ + private final SchemaTransformer transformer; + + public SchemaTransformerFactory(final String schemaTransformConfig) + { + transformer = parse(schemaTransformConfig); + } + + /** + * {@inheritDoc} + */ + public MessageSchema transform(final MessageSchema originalSchema) + { + return transformer.transform(originalSchema); + } + + static SchemaTransformer parse(final String configuration) + { + if (null == configuration || configuration.isEmpty()) + { + return IDENTITY_TRANSFORMER; + } + + final String[] split = configuration.split(","); + if (0 == split.length) + { + return IDENTITY_TRANSFORMER; + } + + final HashMap transformerBySchemaId = new HashMap<>(); + parseComponents(split, transformerBySchemaId); + + SchemaTransformer defaultTransformer = transformerBySchemaId.remove(-1); + defaultTransformer = null != defaultTransformer ? defaultTransformer : IDENTITY_TRANSFORMER; + + return transformerBySchemaId.isEmpty() ? + defaultTransformer : new IdKeyedSchemaTransformer(transformerBySchemaId, defaultTransformer); + } + + private static void parseComponents( + final String[] configuration, + final Map transformerBySchemaId) + { + for (String field : configuration) + { + final String[] fieldParts = field.split(":"); + + if (2 != fieldParts.length) + { + throw new IllegalArgumentException("version transformation property part '" + field + "' is invalid"); + } + + final int schemaId = "*".equals(fieldParts[0]) ? -1 : Integer.parseInt(fieldParts[0].trim()); + final int sinceVersion = Integer.parseInt(fieldParts[1].trim()); + transformerBySchemaId.put(schemaId, new SinceVersionSchemaTransformer(sinceVersion)); + } + } + + SchemaTransformer delegate() + { + return transformer; + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java new file mode 100644 index 0000000000..92012a86e1 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java @@ -0,0 +1,70 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.xml; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +class SinceVersionSchemaTransformer implements SchemaTransformer +{ + private final int sinceVersion; + + public SinceVersionSchemaTransformer(final int sinceVersion) + { + this.sinceVersion = sinceVersion; + } + + public MessageSchema transform(final MessageSchema originalSchema) + { + final Collection types = originalSchema.types(); + final Map newTypes = new HashMap<>(); + + for (Type type : types) + { + if (type.sinceVersion() <= this.sinceVersion) + { + newTypes.put(type.name(), type); + } + } + + final Collection messages = originalSchema.messages(); + final Map newMessages = new HashMap<>(); + for (Message message : messages) + { + if (message.sinceVersion() <= this.sinceVersion) + { + newMessages.put((long)message.id(), message); + } + } + + return new MessageSchema( + originalSchema.packageName(), + originalSchema.description(), + originalSchema.id(), + sinceVersion, + originalSchema.semanticVersion(), + originalSchema.byteOrder(), + originalSchema.messageHeader().name(), + newTypes, + newMessages); + } + + int sinceVersion() + { + return sinceVersion; + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java new file mode 100644 index 0000000000..7a9a64c489 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.*; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static uk.co.real_logic.sbe.SbeTool.JAVA_DEFAULT_DECODING_BUFFER_TYPE; +import static uk.co.real_logic.sbe.SbeTool.JAVA_DEFAULT_ENCODING_BUFFER_TYPE; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +public class SinceVersionTransformedSchemaJavaGenerationTest +{ + @ParameterizedTest + @CsvSource({ "0,4", "4,5", "5,6" }) + void shouldGenerateCodeForOlderVersion(final int versionIncluded, final int versionExcluded) throws Exception + { + final MessageSchema schema = parse( + Tests.getLocalResource("since-version-filter-schema.xml"), ParserOptions.DEFAULT); + final SchemaTransformer transformer = new SchemaTransformerFactory("*:" + versionIncluded); + final MessageSchema transformedSchema = transformer.transform(schema); + final Ir ir = new IrGenerator().generate(transformedSchema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName("test"); + + final JavaGenerator javaGenerator = new JavaGenerator( + ir, + JAVA_DEFAULT_ENCODING_BUFFER_TYPE, + JAVA_DEFAULT_DECODING_BUFFER_TYPE, + false, + false, + false, + outputManager); + + javaGenerator.generate(); + + final Map sources = outputManager.getSources(); + assertTrue(containsCodeWithSinceVersion(sources, versionIncluded)); + assertTrue(doesNotContainsCodeWithSinceVersion(sources, versionExcluded)); + } + + private static boolean containsCodeWithSinceVersion(final Map sources, final int version) + { + final String nameFragment = "Since" + version; + return sources.keySet().stream().anyMatch(s -> s.contains(nameFragment)); + } + + private boolean doesNotContainsCodeWithSinceVersion(final Map sources, final int version) + { + final String nameFragment = "Since" + version; + return sources.keySet().stream().noneMatch(s -> s.contains(nameFragment)); + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java new file mode 100644 index 0000000000..13f8da4bca --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.xml; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class SchemaTransformerFactoryTest +{ + @Test + void shouldAcceptNullAsTransformConfiguration() + { + final SchemaTransformerFactory schemaTransformerFactory = new SchemaTransformerFactory(null); + assertSame(SchemaTransformer.IDENTITY_TRANSFORMER, schemaTransformerFactory.delegate()); + } + + @Test + void shouldAcceptEmptyStringAsTransformConfiguration() + { + final SchemaTransformerFactory schemaTransformerFactory = new SchemaTransformerFactory(""); + assertSame(SchemaTransformer.IDENTITY_TRANSFORMER, schemaTransformerFactory.delegate()); + } + + @Test + void shouldAllSchemasAsOnlyInput() + { + final SchemaTransformerFactory schemaTransformerFactory = new SchemaTransformerFactory("*:5"); + final SchemaTransformer delegate = schemaTransformerFactory.delegate(); + assertInstanceOf(SinceVersionSchemaTransformer.class, delegate); + + SinceVersionSchemaTransformer transformer = (SinceVersionSchemaTransformer)delegate; + assertEquals(5, transformer.sinceVersion()); + } + + @Test + void shouldHandleMultiSchemaTransformation() + { + final SchemaTransformerFactory schemaTransformerFactory = new SchemaTransformerFactory("1:20,4:32,*:5"); + final SchemaTransformer delegate = schemaTransformerFactory.delegate(); + assertInstanceOf(IdKeyedSchemaTransformer.class, delegate); + + IdKeyedSchemaTransformer transformer = (IdKeyedSchemaTransformer)delegate; + final SinceVersionSchemaTransformer schemaTransformer1 = + (SinceVersionSchemaTransformer)transformer.lookupTransformer(1); + assertEquals(20, schemaTransformer1.sinceVersion()); + final SinceVersionSchemaTransformer schemaTransformer4 = + (SinceVersionSchemaTransformer)transformer.lookupTransformer(4); + assertEquals(32, schemaTransformer4.sinceVersion()); + final SinceVersionSchemaTransformer schemaTransformerDefault = + (SinceVersionSchemaTransformer)transformer.lookupTransformer(89732465); + assertEquals(5, schemaTransformerDefault.sinceVersion()); + } +} \ No newline at end of file diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java new file mode 100644 index 0000000000..59dc2ce8ad --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java @@ -0,0 +1,132 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.xml; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import uk.co.real_logic.sbe.Tests; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import static org.junit.jupiter.api.Assertions.*; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +public class SinceVersionSchemaTransformerTest +{ + @ParameterizedTest + @ValueSource(ints = { 0, 4, 5 }) + void shouldFilterAllVersionedFields(final int filteringVersion) throws Exception + { + final MessageSchema schema = parse( + Tests.getLocalResource("since-version-filter-schema.xml"), ParserOptions.DEFAULT); + + final SinceVersionSchemaTransformer sinceVersionSchemaTransformer = new SinceVersionSchemaTransformer( + filteringVersion); + final MessageSchema transformedSchema = sinceVersionSchemaTransformer.transform(schema); + + assertEquals(filteringVersion, transformedSchema.version()); + assertTypeSinceVersionLessOrEqualTo(filteringVersion, schema, transformedSchema); + assertMessageSinceVersionLessOrEqualTo(filteringVersion, schema, transformedSchema); + } + + private static void assertMessageSinceVersionLessOrEqualTo( + final int filteringVersion, + final MessageSchema originalSchema, + final MessageSchema transformedSchema) + { + final ArrayList transformedMessagesCopy = new ArrayList<>(transformedSchema.messages()); + + final Collection types = originalSchema.messages(); + for (Message message : types) + { + if (message.sinceVersion() <= filteringVersion) + { + assertNotNull( + findAndRemove(transformedMessagesCopy, message), + "Message (" + message.name() + ") should be retained"); + } + else + { + assertNull( + findAndRemove(transformedMessagesCopy, message), + "Message (" + message.name() + ") should be removed"); + } + } + + assertTrue(transformedMessagesCopy.isEmpty(), "Messages should have been removed: " + transformedMessagesCopy); + } + + private static void assertTypeSinceVersionLessOrEqualTo( + final int filteringVersion, + final MessageSchema originalSchema, + final MessageSchema transformedSchema) + { + final ArrayList transformedTypesCopy = new ArrayList<>(transformedSchema.types()); + + final Collection types = originalSchema.types(); + for (Type type : types) + { + if (type.sinceVersion() <= filteringVersion) + { + assertNotNull( + findAndRemove(transformedTypesCopy, type), + "Type (" + type.name() + ") should be retained"); + } + else + { + assertNull( + findAndRemove(transformedTypesCopy, type), + "Type (" + type.name() + ") should be removed"); + } + } + + assertTrue(transformedTypesCopy.isEmpty(), "Types should have been removed: " + transformedTypesCopy); + } + + private static Type findAndRemove(final ArrayList transformedTypesCopy, final Type type) + { + Type result = null; + for (final Iterator it = transformedTypesCopy.iterator(); it.hasNext();) + { + final Type transformedType = it.next(); + if (type.name().equals(transformedType.name())) + { + result = transformedType; + it.remove(); + } + } + + return result; + } + + private static Message findAndRemove(final ArrayList transformedMessagesCopy, final Message message) + { + Message result = null; + for (final Iterator it = transformedMessagesCopy.iterator(); it.hasNext();) + { + final Message transformedMessage = it.next(); + if (message.id() == transformedMessage.id()) + { + result = transformedMessage; + it.remove(); + } + } + + return result; + } +} diff --git a/sbe-tool/src/test/resources/since-version-filter-schema.xml b/sbe-tool/src/test/resources/since-version-filter-schema.xml new file mode 100644 index 0000000000..730a166e0c --- /dev/null +++ b/sbe-tool/src/test/resources/since-version-filter-schema.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A + + + + A + + + + A + + + + A + B + C + + + + 0 + + + + 0 + + + + 0 + + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f3baca4155c004975275d047218e8d78f6d1daec Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Thu, 15 Sep 2022 15:33:02 +1200 Subject: [PATCH 128/805] [Java] Include removing fields from messages/groups when transforming to generate older versions. --- .../java/uk/co/real_logic/sbe/SbeTool.java | 3 +- .../java/uk/co/real_logic/sbe/xml/Field.java | 21 ++++ .../uk/co/real_logic/sbe/xml/Message.java | 14 +++ .../real_logic/sbe/xml/SchemaTransformer.java | 2 +- .../sbe/xml/SchemaTransformerFactory.java | 9 +- .../xml/SinceVersionSchemaTransformer.java | 44 +++++++-- .../sbe/xml/SchemaTransformerFactoryTest.java | 4 +- .../SinceVersionSchemaTransformerTest.java | 97 ++++++++++++------- 8 files changed, 145 insertions(+), 49 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index cacf53a187..fa0d1450aa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -190,7 +190,8 @@ public class SbeTool * to generate older versions of a schema to do version compatibility testing. *

    * This field can contain a list of ordered pairs in the form: - * ((<schema id> | '*') ':' <schema id>)(',' ((<schema id> | '*') ':' <schema id>))*. + * ((<schema id> | '*') ':' <schema id>)(',' ((<schema id> | '*') ':' <schema id>))* + * . * E.g. 123:5,*:6 which means transform schema with id = 123 to version 5, all others to version 6. */ public static final String SCHEMA_TRANSFORM_VERSION = "sbe.schema.transform.version"; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java index 2bead68c2a..9170bbcdc5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java @@ -88,6 +88,27 @@ public class Field this.timeUnit = timeUnit; } + Field(final Field field, final List groupFieldList) + { + this( + field.name, + field.description, + field.id, + field.type, + field.offset, + field.semanticType, + field.presence, + field.valueRef, + field.blockLength, + field.dimensionType, + field.variableLength, + field.sinceVersion, + field.deprecated, + field.epoch, + field.timeUnit); + this.groupFieldList = groupFieldList; + } + /** * Validate the node is correct for the type. * diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java index cdb1715179..93586bbd67 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java @@ -83,6 +83,20 @@ public Message(final Node messageNode, final Map typeByNameMap) th validateBlockLength(messageNode, blockLength, computedBlockLength); } + Message(final Message message, final List newFieldList) + { + id = message.id; + name = message.name; + description = message.description; + blockLength = message.blockLength; + sinceVersion = message.sinceVersion; + deprecated = message.deprecated; + semanticType = message.semanticType; + typeByNameMap = message.typeByNameMap; + fieldList = newFieldList; + computedBlockLength = computeMessageRootBlockLength(newFieldList); + } + /** * Return the template schemaId of the message * diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java index 58eb9ee5eb..ea2e99b713 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java @@ -31,5 +31,5 @@ public interface SchemaTransformer * @param originalSchema to be transformed * @return resulting transformed schema. */ - MessageSchema transform(final MessageSchema originalSchema); + MessageSchema transform(MessageSchema originalSchema); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java index f158c5f75f..6c08d3706e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java @@ -26,6 +26,13 @@ public class SchemaTransformerFactory implements SchemaTransformer { private final SchemaTransformer transformer; + /** + * Construct the SchemaTransformerFactory with the specified configuration for filtering the messages and types by + * version. + * + * @param schemaTransformConfig configuration for the sinceVersion transformation + * @see uk.co.real_logic.sbe.SbeTool#SCHEMA_TRANSFORM_VERSION + */ public SchemaTransformerFactory(final String schemaTransformConfig) { transformer = parse(schemaTransformConfig); @@ -66,7 +73,7 @@ private static void parseComponents( final String[] configuration, final Map transformerBySchemaId) { - for (String field : configuration) + for (final String field : configuration) { final String[] fieldParts = field.split(":"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java index 92012a86e1..7b4f97d0cb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java @@ -15,25 +15,26 @@ */ package uk.co.real_logic.sbe.xml; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; +import java.util.*; class SinceVersionSchemaTransformer implements SchemaTransformer { private final int sinceVersion; - public SinceVersionSchemaTransformer(final int sinceVersion) + SinceVersionSchemaTransformer(final int sinceVersion) { this.sinceVersion = sinceVersion; } + /** + * {@inheritDoc} + */ public MessageSchema transform(final MessageSchema originalSchema) { final Collection types = originalSchema.types(); final Map newTypes = new HashMap<>(); - for (Type type : types) + for (final Type type : types) { if (type.sinceVersion() <= this.sinceVersion) { @@ -43,11 +44,14 @@ public MessageSchema transform(final MessageSchema originalSchema) final Collection messages = originalSchema.messages(); final Map newMessages = new HashMap<>(); - for (Message message : messages) + for (final Message message : messages) { - if (message.sinceVersion() <= this.sinceVersion) + final List newFields = removeFields(message.fields(), sinceVersion); + final Message newMessage = new Message(message, newFields); + + if (newMessage.sinceVersion() <= this.sinceVersion) { - newMessages.put((long)message.id(), message); + newMessages.put((long)newMessage.id(), newMessage); } } @@ -63,6 +67,30 @@ public MessageSchema transform(final MessageSchema originalSchema) newMessages); } + private List removeFields(final List fields, final int sinceVersion) + { + final ArrayList newFields = new ArrayList<>(); + for (final Field field : fields) + { + if (field.sinceVersion() > sinceVersion) + { + continue; + } + + Field newField = field; + List groupFields = field.groupFields(); + if (null != groupFields && !groupFields.isEmpty()) + { + groupFields = removeFields(groupFields, sinceVersion); + newField = new Field(field, groupFields); + } + + newFields.add(newField); + } + + return newFields; + } + int sinceVersion() { return sinceVersion; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java index 13f8da4bca..98d86e69d9 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java @@ -42,7 +42,7 @@ void shouldAllSchemasAsOnlyInput() final SchemaTransformer delegate = schemaTransformerFactory.delegate(); assertInstanceOf(SinceVersionSchemaTransformer.class, delegate); - SinceVersionSchemaTransformer transformer = (SinceVersionSchemaTransformer)delegate; + final SinceVersionSchemaTransformer transformer = (SinceVersionSchemaTransformer)delegate; assertEquals(5, transformer.sinceVersion()); } @@ -53,7 +53,7 @@ void shouldHandleMultiSchemaTransformation() final SchemaTransformer delegate = schemaTransformerFactory.delegate(); assertInstanceOf(IdKeyedSchemaTransformer.class, delegate); - IdKeyedSchemaTransformer transformer = (IdKeyedSchemaTransformer)delegate; + final IdKeyedSchemaTransformer transformer = (IdKeyedSchemaTransformer)delegate; final SinceVersionSchemaTransformer schemaTransformer1 = (SinceVersionSchemaTransformer)transformer.lookupTransformer(1); assertEquals(20, schemaTransformer1.sinceVersion()); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java index 59dc2ce8ad..eb2f9ad815 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java @@ -19,10 +19,9 @@ import org.junit.jupiter.params.provider.ValueSource; import uk.co.real_logic.sbe.Tests; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; +import java.util.*; +import static java.util.Comparator.comparing; import static org.junit.jupiter.api.Assertions.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -51,26 +50,65 @@ private static void assertMessageSinceVersionLessOrEqualTo( { final ArrayList transformedMessagesCopy = new ArrayList<>(transformedSchema.messages()); - final Collection types = originalSchema.messages(); - for (Message message : types) + final Collection messages = originalSchema.messages(); + for (final Message originalMessage : messages) { - if (message.sinceVersion() <= filteringVersion) + + if (originalMessage.sinceVersion() <= filteringVersion) { - assertNotNull( - findAndRemove(transformedMessagesCopy, message), - "Message (" + message.name() + ") should be retained"); + final Message transformedMessage = findAndRemove( + transformedMessagesCopy, originalMessage, comparing(Message::id)); + assertNotNull(transformedMessage, "Message (" + originalMessage.name() + ") should be retained"); + + assertFieldsSinceVersionLessOrEqualTo( + filteringVersion, originalMessage.fields(), transformedMessage.fields()); } else { assertNull( - findAndRemove(transformedMessagesCopy, message), - "Message (" + message.name() + ") should be removed"); + findAndRemove(transformedMessagesCopy, originalMessage, comparing(Message::id)), + "Message (" + originalMessage.name() + ") should be removed"); } } assertTrue(transformedMessagesCopy.isEmpty(), "Messages should have been removed: " + transformedMessagesCopy); } + private static void assertFieldsSinceVersionLessOrEqualTo( + final int filteringVersion, + final List originalFields, + final List transformedFields) + { + assertFalse(null == originalFields ^ null == transformedFields); + if (null == originalFields) + { + return; + } + + final ArrayList transformedFieldsCopy = new ArrayList<>(transformedFields); + + for (final Field originalField : originalFields) + { + if (originalField.sinceVersion() <= filteringVersion) + { + final Field transformedField = findAndRemove( + transformedFieldsCopy, originalField, comparing(Field::name)); + assertNotNull(transformedField, "Field (" + originalField.name() + ") should be retained"); + + assertFieldsSinceVersionLessOrEqualTo( + filteringVersion, originalField.groupFields(), transformedField.groupFields()); + } + else + { + assertNull( + findAndRemove(transformedFieldsCopy, originalField, comparing(Field::name)), + "Field (" + originalField.name() + ") should be removed"); + } + } + + assertTrue(transformedFieldsCopy.isEmpty(), "Fields should have been removed: " + transformedFields); + } + private static void assertTypeSinceVersionLessOrEqualTo( final int filteringVersion, final MessageSchema originalSchema, @@ -79,18 +117,18 @@ private static void assertTypeSinceVersionLessOrEqualTo( final ArrayList transformedTypesCopy = new ArrayList<>(transformedSchema.types()); final Collection types = originalSchema.types(); - for (Type type : types) + for (final Type type : types) { if (type.sinceVersion() <= filteringVersion) { assertNotNull( - findAndRemove(transformedTypesCopy, type), + findAndRemove(transformedTypesCopy, type, comparing(Type::name)), "Type (" + type.name() + ") should be retained"); } else { assertNull( - findAndRemove(transformedTypesCopy, type), + findAndRemove(transformedTypesCopy, type, comparing(Type::name)), "Type (" + type.name() + ") should be removed"); } } @@ -98,31 +136,18 @@ private static void assertTypeSinceVersionLessOrEqualTo( assertTrue(transformedTypesCopy.isEmpty(), "Types should have been removed: " + transformedTypesCopy); } - private static Type findAndRemove(final ArrayList transformedTypesCopy, final Type type) - { - Type result = null; - for (final Iterator it = transformedTypesCopy.iterator(); it.hasNext();) - { - final Type transformedType = it.next(); - if (type.name().equals(transformedType.name())) - { - result = transformedType; - it.remove(); - } - } - - return result; - } - - private static Message findAndRemove(final ArrayList transformedMessagesCopy, final Message message) + private static T findAndRemove( + final ArrayList transformedTsCopy, + final T original, + final Comparator comparator) { - Message result = null; - for (final Iterator it = transformedMessagesCopy.iterator(); it.hasNext();) + T result = null; + for (final Iterator it = transformedTsCopy.iterator(); it.hasNext();) { - final Message transformedMessage = it.next(); - if (message.id() == transformedMessage.id()) + final T transformedT = it.next(); + if (0 == comparator.compare(original, transformedT)) { - result = transformedMessage; + result = transformedT; it.remove(); } } From d088c5b666fb5a023558271df271e0223cee30ff Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 21 Sep 2022 15:49:04 +0100 Subject: [PATCH 129/805] [Java] Upgrade to JUnit 5.9.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 582bed2752..2e864a76b5 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.8.0' -def junitVersion = '5.9.0' +def junitVersion = '5.9.1' def jmhVersion = '1.35' def agronaVersion = '1.17.1' def agronaVersionRange = '[1.17.1,2.0[' // allow any release >= 1.17.1 and < 2.0.0 From 742cd8a1fa1f0b5f6d29d4606f021719c2d8930a Mon Sep 17 00:00:00 2001 From: ratcash Date: Tue, 27 Sep 2022 10:49:46 +0200 Subject: [PATCH 130/805] Adding support for the package attribute on the types element. (#904) * Adding support for the package attribute on the types element. * checkstyle. * Revert accidental delete. * Change parameter order for Token. Add Javadoc. * Code style fixes. * Make QualifiedYieldTest use the new constructor. * Revert changes to test files (using custom version of StringWriterOutputManager). Should be replaced with a new version of Agrona. * Use agrone 1.17.1 * Remove @Override * make checkstyle happy. * Correct inherit directive. --- .../java/uk/co/real_logic/sbe/SbeTool.java | 8 ++ .../generation/TargetCodeGeneratorLoader.java | 5 +- .../sbe/generation/java/JavaGenerator.java | 83 +++++++++++++++++-- .../generation/java/JavaOutputManager.java | 81 ++++++++++++++++++ .../java/uk/co/real_logic/sbe/ir/Token.java | 31 +++++++ .../real_logic/sbe/xml/EncodedDataType.java | 27 +++++- .../uk/co/real_logic/sbe/xml/IrGenerator.java | 7 +- .../java/uk/co/real_logic/sbe/xml/Type.java | 38 ++++++++- .../real_logic/sbe/xml/XmlSchemaParser.java | 12 +++ .../generation/java/JavaGeneratorTest.java | 64 ++++++++++++++ .../java/JavaOutputManagerTest.java | 80 ++++++++++++++++++ .../generation/java/QualifiedYieldTest.java | 2 +- .../explicit-package-test-schema.xml | 45 ++++++++++ 13 files changed, 469 insertions(+), 14 deletions(-) create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java create mode 100644 sbe-tool/src/test/resources/explicit-package-test-schema.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index fa0d1450aa..2f2e53970b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -68,6 +68,8 @@ *

  1. sbe.keyword.append.token: Token to be appended to keywords.
  2. *
  3. sbe.decode.unknown.enum.values: Support unknown decoded enum values. Defaults to false.
  4. *
  5. sbe.xinclude.aware: Is XInclude supported for the schema. Defaults to false.
  6. + *
  7. sbe.type.package.override: Is a package attribute for types element supported (only for JAVA). Defaults to + * false.
  8. * */ public class SbeTool @@ -117,6 +119,12 @@ public class SbeTool */ public static final String XINCLUDE_AWARE = "sbe.xinclude.aware"; + /** + * Boolean system property to control the support of package names in {@code } elements. + * Part of SBE v2-rc2. Defaults to false. + */ + public static final String TYPE_PACKAGE_OVERRIDE = "sbe.type.package.override"; + /** * Target language for generated code. */ diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 07065da1ac..6f1e68f08c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -15,7 +15,7 @@ */ package uk.co.real_logic.sbe.generation; -import org.agrona.generation.PackageOutputManager; +import uk.co.real_logic.sbe.generation.java.JavaOutputManager; import uk.co.real_logic.sbe.generation.c.CGenerator; import uk.co.real_logic.sbe.generation.c.COutputManager; import uk.co.real_logic.sbe.generation.cpp.CppGenerator; @@ -52,7 +52,8 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) "true".equals(System.getProperty(JAVA_GROUP_ORDER_ANNOTATION)), "true".equals(System.getProperty(JAVA_GENERATE_INTERFACES)), "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)), - new PackageOutputManager(outputDir, ir.applicableNamespace())); + "true".equals(System.getProperty(TYPE_PACKAGE_OVERRIDE)), + new JavaOutputManager(outputDir, ir.applicableNamespace())); } }, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 21ca6f5a15..f8fa753d7f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -19,7 +19,7 @@ import org.agrona.MutableDirectBuffer; import org.agrona.Strings; import org.agrona.Verify; -import org.agrona.generation.OutputManager; +import org.agrona.generation.DynamicPackageOutputManager; import org.agrona.sbe.*; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.generation.CodeGenerator; @@ -30,7 +30,9 @@ import java.io.Writer; import java.util.ArrayList; import java.util.Formatter; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Function; import static uk.co.real_logic.sbe.SbeTool.JAVA_INTERFACE_PACKAGE; @@ -60,7 +62,7 @@ enum CodecType private static final String INDENT = " "; private final Ir ir; - private final OutputManager outputManager; + private final DynamicPackageOutputManager outputManager; private final String fqMutableBuffer; private final String mutableBuffer; private final String fqReadOnlyBuffer; @@ -68,6 +70,32 @@ enum CodecType private final boolean shouldGenerateGroupOrderAnnotation; private final boolean shouldGenerateInterfaces; private final boolean shouldDecodeUnknownEnumValues; + private final boolean shouldSupportTypePackages; + private final Set typePackages = new HashSet<>(); + + /** + * Create a new Java language {@link CodeGenerator}. Generator support for types in their own package is disabled. + * + * @param ir for the messages and types. + * @param mutableBuffer implementation used for mutating underlying buffers. + * @param readOnlyBuffer implementation used for reading underlying buffers. + * @param shouldGenerateGroupOrderAnnotation in the codecs. + * @param shouldGenerateInterfaces for common methods. + * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. + * @param outputManager for generating the codecs to. + */ + public JavaGenerator( + final Ir ir, + final String mutableBuffer, + final String readOnlyBuffer, + final boolean shouldGenerateGroupOrderAnnotation, + final boolean shouldGenerateInterfaces, + final boolean shouldDecodeUnknownEnumValues, + final DynamicPackageOutputManager outputManager) + { + this(ir, mutableBuffer, readOnlyBuffer, shouldGenerateGroupOrderAnnotation, shouldGenerateInterfaces, + shouldDecodeUnknownEnumValues, false, outputManager); + } /** * Create a new Java language {@link CodeGenerator}. @@ -78,6 +106,7 @@ enum CodecType * @param shouldGenerateGroupOrderAnnotation in the codecs. * @param shouldGenerateInterfaces for common methods. * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. + * @param shouldSupportTypePackages generator support for types in their own package * @param outputManager for generating the codecs to. */ public JavaGenerator( @@ -87,12 +116,14 @@ public JavaGenerator( final boolean shouldGenerateGroupOrderAnnotation, final boolean shouldGenerateInterfaces, final boolean shouldDecodeUnknownEnumValues, - final OutputManager outputManager) + final boolean shouldSupportTypePackages, + final DynamicPackageOutputManager outputManager) { Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); this.ir = ir; + this.shouldSupportTypePackages = shouldSupportTypePackages; this.outputManager = outputManager; this.mutableBuffer = validateBufferImplementation(mutableBuffer, MutableDirectBuffer.class); @@ -144,11 +175,30 @@ public void generateTypeStubs() throws IOException } } + /** + * Register the the type's explicit package - if it's set and should be supported. + * + * @param token the 0-th token of the type + * @param ir the intermediate representation + * @return the overriden package name of the type if set and supported, or {@link Ir#applicableNamespace() } + */ + private String registerTypePackage(final Token token, final Ir ir) + { + if (shouldSupportTypePackages && token.packageName() != null) + { + typePackages.add(token.packageName()); + outputManager.setPackageName(token.packageName()); + return token.packageName(); + } + return ir.applicableNamespace(); + } + /** * {@inheritDoc} */ public void generate() throws IOException { + typePackages.clear(); generatePackageInfo(); generateTypeStubs(); generateMessageHeaderStub(); @@ -1188,6 +1238,7 @@ private void generateBitSet(final List tokens) throws IOException final List choiceList = tokens.subList(1, tokens.size() - 1); final String implementsString = implementsInterface(Flyweight.class.getSimpleName()); + registerTypePackage(token, ir); try (Writer out = outputManager.createOutput(decoderName)) { final Encoding encoding = token.encoding(); @@ -1208,6 +1259,7 @@ private void generateBitSet(final List tokens) throws IOException out.append("}\n"); } + registerTypePackage(token, ir); try (Writer out = outputManager.createOutput(encoderName)) { generateFixedFlyweightHeader(out, token, encoderName, implementsString, mutableBuffer, fqMutableBuffer); @@ -1225,7 +1277,8 @@ private void generateFixedFlyweightHeader( final String buffer, final String fqBuffer) throws IOException { - out.append(generateFileHeader(ir.applicableNamespace(), fqBuffer)); + final String packageName = registerTypePackage(token, ir); + out.append(generateFileHeader(packageName, fqBuffer)); out.append(generateDeclaration(typeName, implementsString, token)); out.append(generateFixedFlyweightCode(typeName, token.encodedLength(), buffer)); } @@ -1238,7 +1291,8 @@ private void generateCompositeFlyweightHeader( final String fqBuffer, final String implementsString) throws IOException { - out.append(generateFileHeader(ir.applicableNamespace(), fqBuffer)); + final String packageName = registerTypePackage(token, ir); + out.append(generateFileHeader(packageName, fqBuffer)); out.append(generateDeclaration(typeName, implementsString, token)); out.append(generateFixedFlyweightCode(typeName, token.encodedLength(), buffer)); } @@ -1250,9 +1304,10 @@ private void generateEnum(final List tokens) throws IOException final Encoding encoding = enumToken.encoding(); final String nullVal = encoding.applicableNullValue().toString(); + final String packageName = registerTypePackage(enumToken, ir); try (Writer out = outputManager.createOutput(enumName)) { - out.append(generateEnumFileHeader(ir.applicableNamespace())); + out.append(generateEnumFileHeader(packageName)); out.append(generateEnumDeclaration(enumName, enumToken)); final List valuesList = tokens.subList(1, tokens.size() - 1); @@ -1272,6 +1327,7 @@ private void generateComposite(final List tokens) throws IOException final String decoderName = decoderName(compositeName); final String encoderName = encoderName(compositeName); + registerTypePackage(token, ir); try (Writer out = outputManager.createOutput(decoderName)) { final String implementsString = implementsInterface(CompositeDecoderFlyweight.class.getSimpleName()); @@ -1320,6 +1376,7 @@ private void generateComposite(final List tokens) throws IOException out.append("}\n"); } + registerTypePackage(token, ir); try (Writer out = outputManager.createOutput(encoderName)) { final String implementsString = implementsInterface(CompositeEncoderFlyweight.class.getSimpleName()); @@ -1572,13 +1629,22 @@ private CharSequence generateFileHeader(final String packageName, final String f private CharSequence generateMainHeader( final String packageName, final CodecType codecType, final boolean hasVarData) { + final StringBuffer packageImports = new StringBuffer(); + for (final String typePackage : typePackages) + { + packageImports.append("import "); + packageImports.append(typePackage); + packageImports.append(".*;\n"); + } + if (fqMutableBuffer.equals(fqReadOnlyBuffer)) { return "/* Generated SBE (Simple Binary Encoding) message codec. */\n" + "package " + packageName + ";\n\n" + "import " + fqMutableBuffer + ";\n" + - interfaceImportLine(); + interfaceImportLine() + + packageImports.toString(); } else { @@ -1590,7 +1656,8 @@ private CharSequence generateMainHeader( "package " + packageName + ";\n\n" + (hasMutableBuffer ? "import " + fqMutableBuffer + ";\n" : "") + (hasReadOnlyBuffer ? "import " + fqReadOnlyBuffer + ";\n" : "") + - interfaceImportLine(); + interfaceImportLine() + + packageImports.toString(); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java new file mode 100644 index 0000000000..9dcd568c1f --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import java.io.FilterWriter; +import java.io.IOException; +import java.io.Writer; +import org.agrona.collections.Object2NullableObjectHashMap; +import org.agrona.collections.Object2ObjectHashMap; +import org.agrona.generation.DynamicPackageOutputManager; +import org.agrona.generation.PackageOutputManager; + +/** + * Implementation of {@link DynamicPackageOutputManager} for Java. + */ +public class JavaOutputManager implements DynamicPackageOutputManager +{ + private final String baseDirName; + private final PackageOutputManager basePackageOutputManager; + private PackageOutputManager actingPackageOutputManager; + private final Object2ObjectHashMap outputManagerCache + = new Object2NullableObjectHashMap<>(); + + /** + * Constructor. + * @param baseDirName the target directory + * @param packageName the initial package name + */ + public JavaOutputManager(final String baseDirName, final String packageName) + { + basePackageOutputManager = new PackageOutputManager(baseDirName, packageName); + actingPackageOutputManager = basePackageOutputManager; + this.baseDirName = baseDirName; + } + + /** + * {@inheritDoc} + */ + public void setPackageName(final String packageName) + { + actingPackageOutputManager = outputManagerCache.get(packageName); + if (actingPackageOutputManager == null) + { + actingPackageOutputManager = new PackageOutputManager(baseDirName, packageName); + outputManagerCache.put(packageName, actingPackageOutputManager); + } + } + + private void resetPackage() + { + actingPackageOutputManager = basePackageOutputManager; + } + + /** + * {@inheritDoc} + */ + public Writer createOutput(final String name) throws IOException + { + return new FilterWriter(actingPackageOutputManager.createOutput(name)) + { + public void close() throws IOException + { + super.close(); + resetPackage(); + } + }; + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java index d9a09966f2..3fdfb32674 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java @@ -79,6 +79,7 @@ public class Token private final String name; private final String referencedName; private final String description; + private final String packageName; private final int id; private final int version; private final int deprecated; @@ -94,6 +95,8 @@ public class Token * @param name of the token in the message. * @param referencedName of the type when created from a ref in a composite. * @param description of what the token is for. + * @param packageName of the token in the message. Use null, except for BEGIN_MESSAGE tokens for types that + * require an explicit package. * @param id as the identifier in the message declaration. * @param version application within the template. * @param deprecated as of this version. @@ -107,6 +110,7 @@ public Token( final String name, final String referencedName, final String description, + final String packageName, final int id, final int version, final int deprecated, @@ -123,6 +127,7 @@ public Token( this.name = name; this.referencedName = referencedName; this.description = description; + this.packageName = packageName; this.id = id; this.version = version; this.deprecated = deprecated; @@ -152,6 +157,16 @@ public String name() return name; } + /** + * Return the packageName of the token + * + * @return packageName of the token or null, if it was not set explicitly. + */ + public String packageName() + { + return packageName; + } + /** * Get the name of the type when this is from a reference. * @@ -344,6 +359,7 @@ public String toString() ", name='" + name + '\'' + ", referencedName='" + referencedName + '\'' + ", description='" + description + '\'' + + ", packageName='" + packageName + '\'' + ", id=" + id + ", version=" + version + ", deprecated=" + deprecated + @@ -361,6 +377,7 @@ public static class Builder { private Signal signal; private String name; + private String packageName = null; private String referencedName; private String description; private int id = INVALID_ID; @@ -395,6 +412,19 @@ public Builder name(final String name) return this; } + /** + * Package name for the Token. Default is null. Use for BEGIN_MESSAGE tokens for types that require an explicit + * package. + * + * @param packageName for the Token. + * @return this for a fluent API. + */ + public Builder packageName(final String packageName) + { + this.packageName = packageName; + return this; + } + /** * Referenced type name for the Token. * @@ -515,6 +545,7 @@ public Token build() name, referencedName, description, + packageName, id, version, deprecated, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index fc26d9cbdc..064b5358e6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -218,7 +218,32 @@ public EncodedDataType( final int length, final boolean varLen) { - super(name, presence, description, 0, 0, semanticType); + this(name, null, presence, description, semanticType, primitiveType, length, varLen); + } + + /** + * Construct a new EncodedDataType with direct values.Does not handle constant values. + * + * @param name of the type + * @param packageName of the type + * @param presence of the type + * @param description of the type or null + * @param semanticType of the type or null + * @param primitiveType of the EncodedDataType + * @param length of the EncodedDataType + * @param varLen of the EncodedDataType + */ + public EncodedDataType( + final String name, + final String packageName, + final Presence presence, + final String description, + final String semanticType, + final PrimitiveType primitiveType, + final int length, + final boolean varLen) + { + super(name, packageName, presence, description, 0, 0, semanticType); this.primitiveType = primitiveType; this.length = length; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index 6ddf288605..6349ce760b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -213,6 +213,7 @@ private void add(final CompositeType type, final int currOffset, final Field fie final Token.Builder builder = new Token.Builder() .signal(Signal.BEGIN_COMPOSITE) .name(type.name()) + .packageName(type.packageName()) .referencedName(type.referencedName()) .offset(currOffset) .size(type.encodedLength()) @@ -270,6 +271,7 @@ private void add(final EnumType type, final int offset, final Field field) final Token.Builder builder = new Token.Builder() .signal(Signal.BEGIN_ENUM) .name(type.name()) + .packageName(type.packageName()) .referencedName(type.referencedName()) .size(encodingType.size()) .offset(offset) @@ -323,6 +325,7 @@ private void add(final SetType type, final int offset, final Field field) final Token.Builder builder = new Token.Builder() .signal(Signal.BEGIN_SET) .name(type.name()) + .packageName(type.packageName()) .referencedName(type.referencedName()) .size(encodingType.size()) .offset(offset) @@ -372,6 +375,7 @@ private void add(final EncodedDataType type, final int offset, final int sinceVe final Token.Builder tokenBuilder = new Token.Builder() .signal(Signal.ENCODING) .name(type.name()) + .packageName(type.packageName()) .referencedName(type.referencedName()) .size(type.encodedLength()) .description(type.description()) @@ -424,6 +428,7 @@ private void add(final EncodedDataType type, final int offset, final Field field final Token.Builder tokenBuilder = new Token.Builder() .signal(Signal.ENCODING) .name(type.name()) + .packageName(type.packageName()) .referencedName(type.referencedName()) .size(type.encodedLength()) .description(type.description()) @@ -505,4 +510,4 @@ private Encoding.Presence mapPresence(final Presence presence) return encodingPresence; } -} \ No newline at end of file +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java index 8a1e491ff4..dba276f95f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java @@ -19,6 +19,7 @@ import static uk.co.real_logic.sbe.xml.XmlSchemaParser.getAttributeValue; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.getAttributeValueOrNull; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.getTypesPackageAttribute; /** * An SBE type. One of encodedDataType, compositeType, enumType, or setType per the SBE spec. @@ -26,6 +27,7 @@ public abstract class Type { private final String name; + private final String packageName; private final Presence presence; private final String description; private final int deprecated; @@ -54,7 +56,7 @@ public Type(final Node node, final String givenName, final String referencedName } this.referencedName = referencedName; - + packageName = getTypesPackageAttribute(node); presence = Presence.get(getAttributeValue(node, "presence", "required")); description = getAttributeValueOrNull(node, "description"); sinceVersion = Integer.parseInt(getAttributeValue(node, "sinceVersion", "0")); @@ -63,10 +65,32 @@ public Type(final Node node, final String givenName, final String referencedName offsetAttribute = Integer.parseInt(getAttributeValue(node, "offset", "-1")); } + /** + * Construct a new Type from direct values. + * + * @param name of the type + * @param presence of the type + * @param description of the type or null + * @param sinceVersion for the type + * @param deprecated version in which this was deprecated. + * @param semanticType of the type or null + */ + public Type( + final String name, + final Presence presence, + final String description, + final int sinceVersion, + final int deprecated, + final String semanticType) + { + this(name, null, presence, description, sinceVersion, deprecated, semanticType); + } + /** * Construct a new Type from direct values. * * @param name of the type + * @param packageName of the type * @param presence of the type * @param description of the type or null * @param sinceVersion for the type @@ -75,6 +99,7 @@ public Type(final Node node, final String givenName, final String referencedName */ public Type( final String name, + final String packageName, final Presence presence, final String description, final int sinceVersion, @@ -82,6 +107,7 @@ public Type( final String semanticType) { this.name = name; + this.packageName = packageName; this.presence = presence; this.description = description; this.sinceVersion = sinceVersion; @@ -206,4 +232,14 @@ public void offsetAttribute(final int offsetAttribute) { this.offsetAttribute = offsetAttribute; } + + /** + * Return the packageName attribute of the {@link Type} from the schema + * + * @return the packageName attribute value or null, if not explicitely defined by the schema + */ + public String packageName() + { + return packageName; + } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index fbc66f9888..455278d707 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -326,6 +326,18 @@ public static String getAttributeValue(final Node elementNode, final String attr return attrNode.getNodeValue(); } + /** + * To be used with child elements of {@code } elements. Returns the package attribute as + * defined on the parent {@code } element + * + * @param elementNode the node inside the types element + * @return the package name, or null if not defined + */ + public static String getTypesPackageAttribute(final Node elementNode) + { + return getAttributeValue(elementNode.getParentNode(), "package", null); + } + /** * Helper function that hides the null return from {@link org.w3c.dom.NamedNodeMap#getNamedItem(String)}. * diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 6ad49097bd..297fc02ec0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -481,6 +481,70 @@ void shouldMarkDeprecatedClasses() throws Exception assertTrue(decoderClazz.isAnnotationPresent(Deprecated.class)); } + @Test + void shouldCreateTypesInDifferentPackages() throws Exception + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(Tests.getLocalResource("explicit-package-test-schema.xml"), options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + + final JavaGenerator generator = new JavaGenerator(ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, + true, outputManager); + + generator.generate(); + final String encoderFqcn = ir.applicableNamespace() + ".TestMessageEncoder"; + final Class encoderClazz = compile(encoderFqcn); + assertNotNull(encoderClazz); + + final String decoderFqcn = ir.applicableNamespace() + ".TestMessageDecoder"; + final Class decoderClazz = compile(decoderFqcn); + assertNotNull(decoderClazz); + + final Map sources = outputManager.getSources(); + assertNotNull(sources.get("test.message.schema.common.CarEncoder")); + assertNotNull(sources.get("test.message.schema.common.CarDecoder")); + assertNotNull(sources.get("outside.schema.BooleanType")); + assertNotNull(sources.get("outside.schema.DaysEncoder")); + assertNotNull(sources.get("outside.schema.DaysDecoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".MessageHeaderEncoder")); + } + + @Test + void shouldCreateTypesInSamePackageIfSupportDisabled() throws Exception + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(Tests.getLocalResource("explicit-package-test-schema.xml"), options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + + final JavaGenerator generator = new JavaGenerator(ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, + false, outputManager); + + generator.generate(); + final String encoderFqcn = ir.applicableNamespace() + ".TestMessageEncoder"; + final Class encoderClazz = compile(encoderFqcn); + assertNotNull(encoderClazz); + + final String decoderFqcn = ir.applicableNamespace() + ".TestMessageDecoder"; + final Class decoderClazz = compile(decoderFqcn); + assertNotNull(decoderClazz); + + final Map sources = outputManager.getSources(); + assertNotNull(sources.get(ir.applicableNamespace() + ".CarEncoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".CarDecoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".BooleanType")); + assertNotNull(sources.get(ir.applicableNamespace() + ".DaysEncoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".DaysDecoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".MessageHeaderEncoder")); + } + private Class getModelClass(final Object encoder) throws ClassNotFoundException { final String className = "Model"; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java new file mode 100644 index 0000000000..3bbd7e4fb9 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java @@ -0,0 +1,80 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import java.io.File; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; + +public class JavaOutputManagerTest +{ + + private final String tempDirName = System.getProperty("java.io.tmpdir"); + + @Test + void shouldCreateFileWithinPackage() throws Exception + { + final String packageName = "uk.co.real_logic.test"; + final String exampleClassName = "ExampleClassName"; + + final JavaOutputManager cut = new JavaOutputManager(tempDirName, packageName); + final Writer out = cut.createOutput(exampleClassName); + out.close(); + + final String typePackageName = "uk.co.real_logic.common"; + final String typeClassName = "CompositeBigDecimal"; + cut.setPackageName(typePackageName); + final Writer typeOut = cut.createOutput(typeClassName); + typeOut.close(); + + final String typePackageName2 = "uk.co.real_logic.common2"; + final String typeClassName2 = "CompositeBigInteger"; + cut.setPackageName(typePackageName2); + final Writer typeOut2 = cut.createOutput(typeClassName2); + typeOut2.close(); + + final String exampleClassName2 = "ExampleClassName2"; + + final Writer out2 = cut.createOutput(exampleClassName2); + out2.close(); + + assertFileExists(packageName, exampleClassName); + assertFileExists(packageName, exampleClassName2); + assertFileExists(typePackageName, typeClassName); + assertFileExists(typePackageName2, typeClassName2); + } + + private void assertFileExists(final String packageName, final String exampleClassName) throws IOException + { + final String baseDirName = tempDirName.endsWith("" + File.separatorChar) ? tempDirName : tempDirName + + File.separatorChar; + + final String fullyQualifiedFilename = baseDirName + packageName.replace('.', File.separatorChar) + + File.separatorChar + exampleClassName + ".java"; + + final Path path = FileSystems.getDefault().getPath(fullyQualifiedFilename); + final boolean exists = Files.exists(path); + Files.delete(path); + + assertTrue(exists); + } + +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java index 8f895f6a5d..701d50057a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java @@ -54,7 +54,7 @@ void shouldGenerateValidJava() throws Exception final IrGenerator irg = new IrGenerator(); final Ir ir = irg.generate(schema); final JavaGenerator generator = new JavaGenerator( - ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, false, outputManager); outputManager.setPackageName(ir.applicableNamespace()); generator.generateMessageHeaderStub(); diff --git a/sbe-tool/src/test/resources/explicit-package-test-schema.xml b/sbe-tool/src/test/resources/explicit-package-test-schema.xml new file mode 100644 index 0000000000..a0e02791b1 --- /dev/null +++ b/sbe-tool/src/test/resources/explicit-package-test-schema.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + 0 + 1 + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + + + + + + + + + + From a52aef5b3f4ae8871f03060a80ca367a806a09d5 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 27 Sep 2022 10:29:21 +0100 Subject: [PATCH 131/805] [Java] Clean up after merge of PR #904. --- .../java/uk/co/real_logic/sbe/SbeTool.java | 6 +-- .../generation/TargetCodeGeneratorLoader.java | 2 +- .../sbe/generation/java/JavaGenerator.java | 49 ++++++++--------- .../generation/java/JavaOutputManager.java | 22 ++++---- .../java/uk/co/real_logic/sbe/ir/Token.java | 4 +- .../real_logic/sbe/xml/EncodedDataType.java | 34 ++++++------ .../java/uk/co/real_logic/sbe/xml/Type.java | 54 +++++++++---------- .../java/JavaOutputManagerTest.java | 17 +++--- version.txt | 2 +- 9 files changed, 97 insertions(+), 93 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index 2f2e53970b..a0be516bf9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -68,7 +68,7 @@ *
  9. sbe.keyword.append.token: Token to be appended to keywords.
  10. *
  11. sbe.decode.unknown.enum.values: Support unknown decoded enum values. Defaults to false.
  12. *
  13. sbe.xinclude.aware: Is XInclude supported for the schema. Defaults to false.
  14. - *
  15. sbe.type.package.override: Is a package attribute for types element supported (only for JAVA). Defaults to + *
  16. sbe.type.package.override: Is package attribute for types element supported (only for JAVA). Defaults to * false.
  17. * */ @@ -121,9 +121,9 @@ public class SbeTool /** * Boolean system property to control the support of package names in {@code } elements. - * Part of SBE v2-rc2. Defaults to false. + * Part of SBE v2-rc3. Defaults to false. */ - public static final String TYPE_PACKAGE_OVERRIDE = "sbe.type.package.override"; + public static final String TYPES_PACKAGE_OVERRIDE = "sbe.types.package.override"; /** * Target language for generated code. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 6f1e68f08c..2dade346dd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -52,7 +52,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) "true".equals(System.getProperty(JAVA_GROUP_ORDER_ANNOTATION)), "true".equals(System.getProperty(JAVA_GENERATE_INTERFACES)), "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)), - "true".equals(System.getProperty(TYPE_PACKAGE_OVERRIDE)), + "true".equals(System.getProperty(TYPES_PACKAGE_OVERRIDE)), new JavaOutputManager(outputDir, ir.applicableNamespace())); } }, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index f8fa753d7f..f02cfc419d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -70,8 +70,8 @@ enum CodecType private final boolean shouldGenerateGroupOrderAnnotation; private final boolean shouldGenerateInterfaces; private final boolean shouldDecodeUnknownEnumValues; - private final boolean shouldSupportTypePackages; - private final Set typePackages = new HashSet<>(); + private final boolean shouldSupportTypesPackageNames; + private final Set packageNameByTypes = new HashSet<>(); /** * Create a new Java language {@link CodeGenerator}. Generator support for types in their own package is disabled. @@ -106,7 +106,7 @@ public JavaGenerator( * @param shouldGenerateGroupOrderAnnotation in the codecs. * @param shouldGenerateInterfaces for common methods. * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. - * @param shouldSupportTypePackages generator support for types in their own package + * @param shouldSupportTypesPackageNames generator support for types in their own package. * @param outputManager for generating the codecs to. */ public JavaGenerator( @@ -116,14 +116,14 @@ public JavaGenerator( final boolean shouldGenerateGroupOrderAnnotation, final boolean shouldGenerateInterfaces, final boolean shouldDecodeUnknownEnumValues, - final boolean shouldSupportTypePackages, + final boolean shouldSupportTypesPackageNames, final DynamicPackageOutputManager outputManager) { Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); this.ir = ir; - this.shouldSupportTypePackages = shouldSupportTypePackages; + this.shouldSupportTypesPackageNames = shouldSupportTypesPackageNames; this.outputManager = outputManager; this.mutableBuffer = validateBufferImplementation(mutableBuffer, MutableDirectBuffer.class); @@ -176,18 +176,19 @@ public void generateTypeStubs() throws IOException } /** - * Register the the type's explicit package - if it's set and should be supported. + * Register the types explicit package - if it's set and should be supported. * - * @param token the 0-th token of the type - * @param ir the intermediate representation - * @return the overriden package name of the type if set and supported, or {@link Ir#applicableNamespace() } + * @param token the 0-th token of the type. + * @param ir the intermediate representation. + * @return the overridden package name of the type if set and supported, or {@link Ir#applicableNamespace()}. */ - private String registerTypePackage(final Token token, final Ir ir) + private String registerTypesPackageName(final Token token, final Ir ir) { - if (shouldSupportTypePackages && token.packageName() != null) + if (shouldSupportTypesPackageNames && token.packageName() != null) { - typePackages.add(token.packageName()); + packageNameByTypes.add(token.packageName()); outputManager.setPackageName(token.packageName()); + return token.packageName(); } return ir.applicableNamespace(); @@ -198,7 +199,7 @@ private String registerTypePackage(final Token token, final Ir ir) */ public void generate() throws IOException { - typePackages.clear(); + packageNameByTypes.clear(); generatePackageInfo(); generateTypeStubs(); generateMessageHeaderStub(); @@ -1238,7 +1239,7 @@ private void generateBitSet(final List tokens) throws IOException final List choiceList = tokens.subList(1, tokens.size() - 1); final String implementsString = implementsInterface(Flyweight.class.getSimpleName()); - registerTypePackage(token, ir); + registerTypesPackageName(token, ir); try (Writer out = outputManager.createOutput(decoderName)) { final Encoding encoding = token.encoding(); @@ -1259,7 +1260,7 @@ private void generateBitSet(final List tokens) throws IOException out.append("}\n"); } - registerTypePackage(token, ir); + registerTypesPackageName(token, ir); try (Writer out = outputManager.createOutput(encoderName)) { generateFixedFlyweightHeader(out, token, encoderName, implementsString, mutableBuffer, fqMutableBuffer); @@ -1277,7 +1278,7 @@ private void generateFixedFlyweightHeader( final String buffer, final String fqBuffer) throws IOException { - final String packageName = registerTypePackage(token, ir); + final String packageName = registerTypesPackageName(token, ir); out.append(generateFileHeader(packageName, fqBuffer)); out.append(generateDeclaration(typeName, implementsString, token)); out.append(generateFixedFlyweightCode(typeName, token.encodedLength(), buffer)); @@ -1291,7 +1292,7 @@ private void generateCompositeFlyweightHeader( final String fqBuffer, final String implementsString) throws IOException { - final String packageName = registerTypePackage(token, ir); + final String packageName = registerTypesPackageName(token, ir); out.append(generateFileHeader(packageName, fqBuffer)); out.append(generateDeclaration(typeName, implementsString, token)); out.append(generateFixedFlyweightCode(typeName, token.encodedLength(), buffer)); @@ -1304,7 +1305,7 @@ private void generateEnum(final List tokens) throws IOException final Encoding encoding = enumToken.encoding(); final String nullVal = encoding.applicableNullValue().toString(); - final String packageName = registerTypePackage(enumToken, ir); + final String packageName = registerTypesPackageName(enumToken, ir); try (Writer out = outputManager.createOutput(enumName)) { out.append(generateEnumFileHeader(packageName)); @@ -1327,7 +1328,7 @@ private void generateComposite(final List tokens) throws IOException final String decoderName = decoderName(compositeName); final String encoderName = encoderName(compositeName); - registerTypePackage(token, ir); + registerTypesPackageName(token, ir); try (Writer out = outputManager.createOutput(decoderName)) { final String implementsString = implementsInterface(CompositeDecoderFlyweight.class.getSimpleName()); @@ -1376,7 +1377,7 @@ private void generateComposite(final List tokens) throws IOException out.append("}\n"); } - registerTypePackage(token, ir); + registerTypesPackageName(token, ir); try (Writer out = outputManager.createOutput(encoderName)) { final String implementsString = implementsInterface(CompositeEncoderFlyweight.class.getSimpleName()); @@ -1629,8 +1630,8 @@ private CharSequence generateFileHeader(final String packageName, final String f private CharSequence generateMainHeader( final String packageName, final CodecType codecType, final boolean hasVarData) { - final StringBuffer packageImports = new StringBuffer(); - for (final String typePackage : typePackages) + final StringBuilder packageImports = new StringBuilder(); + for (final String typePackage : packageNameByTypes) { packageImports.append("import "); packageImports.append(typePackage); @@ -1644,7 +1645,7 @@ private CharSequence generateMainHeader( "package " + packageName + ";\n\n" + "import " + fqMutableBuffer + ";\n" + interfaceImportLine() + - packageImports.toString(); + packageImports; } else { @@ -1657,7 +1658,7 @@ private CharSequence generateMainHeader( (hasMutableBuffer ? "import " + fqMutableBuffer + ";\n" : "") + (hasReadOnlyBuffer ? "import " + fqReadOnlyBuffer + ";\n" : "") + interfaceImportLine() + - packageImports.toString(); + packageImports; } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java index 9dcd568c1f..9d34d89a81 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java @@ -15,34 +15,36 @@ */ package uk.co.real_logic.sbe.generation.java; -import java.io.FilterWriter; -import java.io.IOException; -import java.io.Writer; import org.agrona.collections.Object2NullableObjectHashMap; import org.agrona.collections.Object2ObjectHashMap; import org.agrona.generation.DynamicPackageOutputManager; import org.agrona.generation.PackageOutputManager; +import java.io.FilterWriter; +import java.io.IOException; +import java.io.Writer; + /** * Implementation of {@link DynamicPackageOutputManager} for Java. */ public class JavaOutputManager implements DynamicPackageOutputManager { private final String baseDirName; - private final PackageOutputManager basePackageOutputManager; + private final PackageOutputManager initialPackageOutputManager; private PackageOutputManager actingPackageOutputManager; - private final Object2ObjectHashMap outputManagerCache + private final Object2ObjectHashMap outputManagerByPackageName = new Object2NullableObjectHashMap<>(); /** * Constructor. + * * @param baseDirName the target directory * @param packageName the initial package name */ public JavaOutputManager(final String baseDirName, final String packageName) { - basePackageOutputManager = new PackageOutputManager(baseDirName, packageName); - actingPackageOutputManager = basePackageOutputManager; + initialPackageOutputManager = new PackageOutputManager(baseDirName, packageName); + actingPackageOutputManager = initialPackageOutputManager; this.baseDirName = baseDirName; } @@ -51,17 +53,17 @@ public JavaOutputManager(final String baseDirName, final String packageName) */ public void setPackageName(final String packageName) { - actingPackageOutputManager = outputManagerCache.get(packageName); + actingPackageOutputManager = outputManagerByPackageName.get(packageName); if (actingPackageOutputManager == null) { actingPackageOutputManager = new PackageOutputManager(baseDirName, packageName); - outputManagerCache.put(packageName, actingPackageOutputManager); + outputManagerByPackageName.put(packageName, actingPackageOutputManager); } } private void resetPackage() { - actingPackageOutputManager = basePackageOutputManager; + actingPackageOutputManager = initialPackageOutputManager; } /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java index 3fdfb32674..7d42b02599 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java @@ -377,7 +377,7 @@ public static class Builder { private Signal signal; private String name; - private String packageName = null; + private String packageName; private String referencedName; private String description; private int id = INVALID_ID; @@ -413,7 +413,7 @@ public Builder name(final String name) } /** - * Package name for the Token. Default is null. Use for BEGIN_MESSAGE tokens for types that require an explicit + * Package name for the Token, default is null. Use for BEGIN_MESSAGE tokens for types that require an explicit * package. * * @param packageName for the Token. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index 064b5358e6..ca81a4edc3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -65,7 +65,7 @@ public EncodedDataType(final Node node) /** * Construct a new encodedDataType from XML Schema. * - * @param node from the XML Schema Parsing + * @param node from the XML Schema Parsing. * @param givenName for this node. * @param referencedName of the type when created from a ref in a composite. */ @@ -201,13 +201,13 @@ private PrimitiveValue lookupValueRef(final Node node) /** * Construct a new EncodedDataType with direct values. Does not handle constant values. * - * @param name of the type - * @param presence of the type - * @param description of the type or null - * @param semanticType of the type or null - * @param primitiveType of the EncodedDataType - * @param length of the EncodedDataType - * @param varLen of the EncodedDataType + * @param name of the type. + * @param presence of the type. + * @param description of the type or null. + * @param semanticType of the type or null. + * @param primitiveType of the EncodedDataType. + * @param length of the EncodedDataType. + * @param varLen of the EncodedDataType. */ public EncodedDataType( final String name, @@ -222,16 +222,16 @@ public EncodedDataType( } /** - * Construct a new EncodedDataType with direct values.Does not handle constant values. + * Construct a new EncodedDataType with direct values. Does not handle constant values. * - * @param name of the type - * @param packageName of the type - * @param presence of the type - * @param description of the type or null - * @param semanticType of the type or null - * @param primitiveType of the EncodedDataType - * @param length of the EncodedDataType - * @param varLen of the EncodedDataType + * @param name of the type. + * @param packageName of the type. + * @param presence of the type. + * @param description of the type or null. + * @param semanticType of the type or null. + * @param primitiveType of the EncodedDataType. + * @param length of the EncodedDataType. + * @param varLen of the EncodedDataType. */ public EncodedDataType( final String name, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java index dba276f95f..67a09d3152 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java @@ -40,7 +40,7 @@ public abstract class Type /** * Construct a new Type from XML Schema. Called by subclasses to mostly set common fields * - * @param node from the XML Schema Parsing + * @param node from the XML Schema Parsing. * @param givenName of this node, if null then the attributed name will be used. * @param referencedName of the type when created from a ref in a composite. */ @@ -68,12 +68,12 @@ public Type(final Node node, final String givenName, final String referencedName /** * Construct a new Type from direct values. * - * @param name of the type - * @param presence of the type - * @param description of the type or null - * @param sinceVersion for the type - * @param deprecated version in which this was deprecated. - * @param semanticType of the type or null + * @param name of the type. + * @param presence of the type. + * @param description of the type or null. + * @param sinceVersion for the type. + * @param deprecated version in which this was deprecated. + * @param semanticType of the type or null. */ public Type( final String name, @@ -89,13 +89,13 @@ public Type( /** * Construct a new Type from direct values. * - * @param name of the type - * @param packageName of the type - * @param presence of the type - * @param description of the type or null + * @param name of the type. + * @param packageName of the type. + * @param presence of the type. + * @param description of the type or null. * @param sinceVersion for the type - * @param deprecated version in which this was deprecated. - * @param semanticType of the type or null + * @param deprecated version in which this wa.s deprecated. + * @param semanticType of the type or null. */ public Type( final String name, @@ -118,9 +118,9 @@ public Type( } /** - * Return the name of the type + * The name of the type. * - * @return name of the Type + * @return name of the Type. */ public String name() { @@ -138,9 +138,9 @@ public String referencedName() } /** - * Return the presence of the type + * The {@link Presence} of the type. * - * @return presence of the Type + * @return {@link Presence} of the type. */ public Presence presence() { @@ -157,9 +157,9 @@ public Presence presence() public abstract int encodedLength(); /** - * The description of the Type (if set) or null + * The description of the Type (if set) or null. * - * @return description set by the type or null + * @return description set by the type or null. */ public String description() { @@ -197,9 +197,9 @@ public int deprecated() } /** - * The semanticType of the Type + * The FIX semanticType of the Type. * - * @return semanticType of the Type if set or null if not set + * @return FIX semanticType of the Type if set or null if not set. */ public String semanticType() { @@ -214,9 +214,9 @@ public String semanticType() public abstract boolean isVariableLength(); /** - * Return the offset attribute of the {@link Type} from the schema + * The offset attribute of the {@link Type} from the schema. * - * @return the offset attribute value or -1 to indicate not set by the schema + * @return the offset attribute value or -1 to indicate not set by the schema. */ public int offsetAttribute() { @@ -224,9 +224,9 @@ public int offsetAttribute() } /** - * Set the offset attribute of the {@link Type} from the schema + * Set the offset attribute of the {@link Type} from the schema. * - * @param offsetAttribute to set + * @param offsetAttribute to set. */ public void offsetAttribute(final int offsetAttribute) { @@ -234,9 +234,9 @@ public void offsetAttribute(final int offsetAttribute) } /** - * Return the packageName attribute of the {@link Type} from the schema + * The packageName attribute of the {@link Type} from the schema. * - * @return the packageName attribute value or null, if not explicitely defined by the schema + * @return the packageName attribute value or null, if not explicitly defined by the schema. */ public String packageName() { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java index 3bbd7e4fb9..97bab7f9ff 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java @@ -15,26 +15,27 @@ */ package uk.co.real_logic.sbe.generation.java; +import org.agrona.SystemUtil; +import org.junit.jupiter.api.Test; + import java.io.File; import java.io.IOException; import java.io.Writer; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; + import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; -public class JavaOutputManagerTest +class JavaOutputManagerTest { - - private final String tempDirName = System.getProperty("java.io.tmpdir"); - @Test void shouldCreateFileWithinPackage() throws Exception { final String packageName = "uk.co.real_logic.test"; final String exampleClassName = "ExampleClassName"; + final String tempDirName = SystemUtil.tmpDirName(); final JavaOutputManager cut = new JavaOutputManager(tempDirName, packageName); final Writer out = cut.createOutput(exampleClassName); out.close(); @@ -64,8 +65,9 @@ void shouldCreateFileWithinPackage() throws Exception private void assertFileExists(final String packageName, final String exampleClassName) throws IOException { - final String baseDirName = tempDirName.endsWith("" + File.separatorChar) ? tempDirName : tempDirName + - File.separatorChar; + final String tempDirName = SystemUtil.tmpDirName(); + final String baseDirName = tempDirName.endsWith("" + File.separatorChar) ? + tempDirName : tempDirName + File.separatorChar; final String fullyQualifiedFilename = baseDirName + packageName.replace('.', File.separatorChar) + File.separatorChar + exampleClassName + ".java"; @@ -76,5 +78,4 @@ private void assertFileExists(final String packageName, final String exampleClas assertTrue(exists); } - } diff --git a/version.txt b/version.txt index 28509b3918..8503140e97 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.26.1-SNAPSHOT +1.27.0-SNAPSHOT From ff5158ea475976a5a0efa0dd48059bfd9c370eaa Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 28 Sep 2022 09:30:53 +0100 Subject: [PATCH 132/805] [Java] Fix lookup of types ancestor for PR #904. --- .../real_logic/sbe/xml/XmlSchemaParser.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index 455278d707..0d55ab1262 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -327,15 +327,26 @@ public static String getAttributeValue(final Node elementNode, final String attr } /** - * To be used with child elements of {@code } elements. Returns the package attribute as - * defined on the parent {@code } element + * To be used with descendant elements of {@code } elements. Returns the package attribute value as + * defined on the ancestor {@code } element. * - * @param elementNode the node inside the types element - * @return the package name, or null if not defined + * @param elementNode the node inside the {@code } element. + * @return the package name, or null if not defined. */ public static String getTypesPackageAttribute(final Node elementNode) { - return getAttributeValue(elementNode.getParentNode(), "package", null); + Node parentNode = elementNode.getParentNode(); + while (null != parentNode) + { + if ("types".equals(parentNode.getLocalName()) || "types".equals(parentNode.getNodeName())) + { + return getAttributeValue(parentNode, "package", null); + } + + parentNode = parentNode.getParentNode(); + } + + return null; } /** From cd883801045eede5120ac8ffae3bffc5793627c2 Mon Sep 17 00:00:00 2001 From: ratcash Date: Wed, 5 Oct 2022 18:22:06 +0200 Subject: [PATCH 133/805] Fix package name support for embedded composites (#915) * enhanced test case. * Bugfix: embedded composites were missing import for required types. * polish * use Collections.emptySet() * chain append statements * renamed method argument additionalPackages -> importedTypesPackages --- .../sbe/generation/java/JavaGenerator.java | 97 ++++++++++++++----- .../explicit-package-test-schema.xml | 18 ++++ 2 files changed, 92 insertions(+), 23 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index f02cfc419d..5977951e69 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.Writer; import java.util.ArrayList; +import java.util.Collections; import java.util.Formatter; import java.util.HashSet; import java.util.List; @@ -60,6 +61,7 @@ enum CodecType private static final String PACKAGE_INFO = "package-info"; private static final String BASE_INDENT = ""; private static final String INDENT = " "; + private static final Set NO_PACKAGES = Collections.emptySet(); private final Ir ir; private final DynamicPackageOutputManager outputManager; @@ -184,11 +186,15 @@ public void generateTypeStubs() throws IOException */ private String registerTypesPackageName(final Token token, final Ir ir) { - if (shouldSupportTypesPackageNames && token.packageName() != null) + + if (!shouldSupportTypesPackageNames) + { + return ir.applicableNamespace(); + } + if (token.packageName() != null) { packageNameByTypes.add(token.packageName()); outputManager.setPackageName(token.packageName()); - return token.packageName(); } return ir.applicableNamespace(); @@ -1243,7 +1249,8 @@ private void generateBitSet(final List tokens) throws IOException try (Writer out = outputManager.createOutput(decoderName)) { final Encoding encoding = token.encoding(); - generateFixedFlyweightHeader(out, token, decoderName, implementsString, readOnlyBuffer, fqReadOnlyBuffer); + generateFixedFlyweightHeader(out, token, decoderName, implementsString, readOnlyBuffer, fqReadOnlyBuffer, + NO_PACKAGES); out.append(generateChoiceIsEmpty(encoding.primitiveType())); new Formatter(out).format( @@ -1263,7 +1270,8 @@ private void generateBitSet(final List tokens) throws IOException registerTypesPackageName(token, ir); try (Writer out = outputManager.createOutput(encoderName)) { - generateFixedFlyweightHeader(out, token, encoderName, implementsString, mutableBuffer, fqMutableBuffer); + generateFixedFlyweightHeader(out, token, encoderName, implementsString, mutableBuffer, fqMutableBuffer, + NO_PACKAGES); generateChoiceClear(out, encoderName, token); generateChoiceEncoders(out, encoderName, choiceList); out.append("}\n"); @@ -1276,10 +1284,11 @@ private void generateFixedFlyweightHeader( final String typeName, final String implementsString, final String buffer, - final String fqBuffer) throws IOException + final String fqBuffer, + final Set importedTypesPackages) throws IOException { final String packageName = registerTypesPackageName(token, ir); - out.append(generateFileHeader(packageName, fqBuffer)); + out.append(generateFileHeader(packageName, importedTypesPackages, fqBuffer)); out.append(generateDeclaration(typeName, implementsString, token)); out.append(generateFixedFlyweightCode(typeName, token.encodedLength(), buffer)); } @@ -1290,10 +1299,11 @@ private void generateCompositeFlyweightHeader( final Writer out, final String buffer, final String fqBuffer, - final String implementsString) throws IOException + final String implementsString, + final Set importedTypesPackages) throws IOException { final String packageName = registerTypesPackageName(token, ir); - out.append(generateFileHeader(packageName, fqBuffer)); + out.append(generateFileHeader(packageName, importedTypesPackages, fqBuffer)); out.append(generateDeclaration(typeName, implementsString, token)); out.append(generateFixedFlyweightCode(typeName, token.encodedLength(), buffer)); } @@ -1329,11 +1339,12 @@ private void generateComposite(final List tokens) throws IOException final String encoderName = encoderName(compositeName); registerTypesPackageName(token, ir); + final Set importedTypesPackages = scanPackagesToImport(tokens); try (Writer out = outputManager.createOutput(decoderName)) { final String implementsString = implementsInterface(CompositeDecoderFlyweight.class.getSimpleName()); generateCompositeFlyweightHeader( - token, decoderName, out, readOnlyBuffer, fqReadOnlyBuffer, implementsString); + token, decoderName, out, readOnlyBuffer, fqReadOnlyBuffer, implementsString, importedTypesPackages); for (int i = 1, end = tokens.size() - 1; i < end;) { @@ -1381,7 +1392,8 @@ private void generateComposite(final List tokens) throws IOException try (Writer out = outputManager.createOutput(encoderName)) { final String implementsString = implementsInterface(CompositeEncoderFlyweight.class.getSimpleName()); - generateCompositeFlyweightHeader(token, encoderName, out, mutableBuffer, fqMutableBuffer, implementsString); + generateCompositeFlyweightHeader(token, encoderName, out, mutableBuffer, fqMutableBuffer, implementsString, + importedTypesPackages); for (int i = 1, end = tokens.size() - 1; i < end;) { @@ -1423,6 +1435,30 @@ private void generateComposite(final List tokens) throws IOException } } + private Set scanPackagesToImport(final List tokens) + { + if (!shouldSupportTypesPackageNames) + { + return NO_PACKAGES; + } + + final Set packagesToImport = new HashSet<>(); + for (int i = 1; i < tokens.size() - 1; i++) + { + final Token typeToken = tokens.get(i); + if (typeToken.signal() == Signal.BEGIN_ENUM || + typeToken.signal() == Signal.BEGIN_SET || + typeToken.signal() == Signal.BEGIN_COMPOSITE) + { + if (typeToken.packageName() != null) + { + packagesToImport.add(typeToken.packageName()); + } + } + } + return packagesToImport; + } + private void generateChoiceClear(final Appendable out, final String bitSetClassName, final Token token) throws IOException { @@ -1608,6 +1644,23 @@ private CharSequence generateEnumLookupMethod(final List tokens, final St return sb; } + private StringBuilder generateImportStatements(final Set packages, final String currentPackage) + { + final StringBuilder importsStatements = new StringBuilder(); + for (final String candidatePackage : packages) + { + if (!candidatePackage.equalsIgnoreCase(currentPackage)) + { + importsStatements.append("import ").append(candidatePackage).append(".*;\n"); + } + } + if (importsStatements.length() > 0) + { + importsStatements.append("\n\n"); + } + return importsStatements; + } + private String interfaceImportLine() { if (!shouldGenerateInterfaces) @@ -1618,25 +1671,23 @@ private String interfaceImportLine() return "import " + JAVA_INTERFACE_PACKAGE + ".*;\n\n"; } - private CharSequence generateFileHeader(final String packageName, final String fqBuffer) + + private CharSequence generateFileHeader(final String packageName, final Set importedTypesPackages, + final String fqBuffer) { - return - "/* Generated SBE (Simple Binary Encoding) message codec. */\n" + + final StringBuilder importStatements = generateImportStatements(importedTypesPackages, packageName); + + return "/* Generated SBE (Simple Binary Encoding) message codec. */\n" + "package " + packageName + ";\n\n" + "import " + fqBuffer + ";\n" + - interfaceImportLine(); + interfaceImportLine() + + importStatements; } private CharSequence generateMainHeader( final String packageName, final CodecType codecType, final boolean hasVarData) { - final StringBuilder packageImports = new StringBuilder(); - for (final String typePackage : packageNameByTypes) - { - packageImports.append("import "); - packageImports.append(typePackage); - packageImports.append(".*;\n"); - } + final StringBuilder importStatements = generateImportStatements(packageNameByTypes, packageName); if (fqMutableBuffer.equals(fqReadOnlyBuffer)) { @@ -1645,7 +1696,7 @@ private CharSequence generateMainHeader( "package " + packageName + ";\n\n" + "import " + fqMutableBuffer + ";\n" + interfaceImportLine() + - packageImports; + importStatements; } else { @@ -1658,7 +1709,7 @@ private CharSequence generateMainHeader( (hasMutableBuffer ? "import " + fqMutableBuffer + ";\n" : "") + (hasReadOnlyBuffer ? "import " + fqReadOnlyBuffer + ";\n" : "") + interfaceImportLine() + - packageImports; + importStatements; } } diff --git a/sbe-tool/src/test/resources/explicit-package-test-schema.xml b/sbe-tool/src/test/resources/explicit-package-test-schema.xml index a0e02791b1..fc3aaf6929 100644 --- a/sbe-tool/src/test/resources/explicit-package-test-schema.xml +++ b/sbe-tool/src/test/resources/explicit-package-test-schema.xml @@ -18,6 +18,13 @@ + + + + + + + @@ -25,6 +32,10 @@ 0 1 + + + + 0 1 @@ -34,6 +45,13 @@ 5 6 + + 1 + 2 + 3 + 4 + 5 + From e46a5e78f889d7f2487d12371fb37ac0d8bfcaf8 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 5 Oct 2022 17:34:35 +0100 Subject: [PATCH 134/805] [Java] Tidy up after merge of PR #915. --- .../sbe/generation/java/JavaGenerator.java | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 5977951e69..9a7cef4b48 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -61,7 +61,7 @@ enum CodecType private static final String PACKAGE_INFO = "package-info"; private static final String BASE_INDENT = ""; private static final String INDENT = " "; - private static final Set NO_PACKAGES = Collections.emptySet(); + private static final Set PACKAGES_EMPTY_SET = Collections.emptySet(); private final Ir ir; private final DynamicPackageOutputManager outputManager; @@ -178,7 +178,7 @@ public void generateTypeStubs() throws IOException } /** - * Register the types explicit package - if it's set and should be supported. + * Register the types explicit package - if set and should be supported. * * @param token the 0-th token of the type. * @param ir the intermediate representation. @@ -186,17 +186,18 @@ public void generateTypeStubs() throws IOException */ private String registerTypesPackageName(final Token token, final Ir ir) { - if (!shouldSupportTypesPackageNames) { return ir.applicableNamespace(); } + if (token.packageName() != null) { packageNameByTypes.add(token.packageName()); outputManager.setPackageName(token.packageName()); return token.packageName(); } + return ir.applicableNamespace(); } @@ -1249,8 +1250,8 @@ private void generateBitSet(final List tokens) throws IOException try (Writer out = outputManager.createOutput(decoderName)) { final Encoding encoding = token.encoding(); - generateFixedFlyweightHeader(out, token, decoderName, implementsString, readOnlyBuffer, fqReadOnlyBuffer, - NO_PACKAGES); + generateFixedFlyweightHeader( + out, token, decoderName, implementsString, readOnlyBuffer, fqReadOnlyBuffer, PACKAGES_EMPTY_SET); out.append(generateChoiceIsEmpty(encoding.primitiveType())); new Formatter(out).format( @@ -1270,8 +1271,8 @@ private void generateBitSet(final List tokens) throws IOException registerTypesPackageName(token, ir); try (Writer out = outputManager.createOutput(encoderName)) { - generateFixedFlyweightHeader(out, token, encoderName, implementsString, mutableBuffer, fqMutableBuffer, - NO_PACKAGES); + generateFixedFlyweightHeader( + out, token, encoderName, implementsString, mutableBuffer, fqMutableBuffer, PACKAGES_EMPTY_SET); generateChoiceClear(out, encoderName, token); generateChoiceEncoders(out, encoderName, choiceList); out.append("}\n"); @@ -1287,8 +1288,7 @@ private void generateFixedFlyweightHeader( final String fqBuffer, final Set importedTypesPackages) throws IOException { - final String packageName = registerTypesPackageName(token, ir); - out.append(generateFileHeader(packageName, importedTypesPackages, fqBuffer)); + out.append(generateFileHeader(registerTypesPackageName(token, ir), importedTypesPackages, fqBuffer)); out.append(generateDeclaration(typeName, implementsString, token)); out.append(generateFixedFlyweightCode(typeName, token.encodedLength(), buffer)); } @@ -1302,8 +1302,7 @@ private void generateCompositeFlyweightHeader( final String implementsString, final Set importedTypesPackages) throws IOException { - final String packageName = registerTypesPackageName(token, ir); - out.append(generateFileHeader(packageName, importedTypesPackages, fqBuffer)); + out.append(generateFileHeader(registerTypesPackageName(token, ir), importedTypesPackages, fqBuffer)); out.append(generateDeclaration(typeName, implementsString, token)); out.append(generateFixedFlyweightCode(typeName, token.encodedLength(), buffer)); } @@ -1314,8 +1313,8 @@ private void generateEnum(final List tokens) throws IOException final String enumName = formatClassName(enumToken.applicableTypeName()); final Encoding encoding = enumToken.encoding(); final String nullVal = encoding.applicableNullValue().toString(); - final String packageName = registerTypesPackageName(enumToken, ir); + try (Writer out = outputManager.createOutput(enumName)) { out.append(generateEnumFileHeader(packageName)); @@ -1340,6 +1339,7 @@ private void generateComposite(final List tokens) throws IOException registerTypesPackageName(token, ir); final Set importedTypesPackages = scanPackagesToImport(tokens); + try (Writer out = outputManager.createOutput(decoderName)) { final String implementsString = implementsInterface(CompositeDecoderFlyweight.class.getSimpleName()); @@ -1392,8 +1392,8 @@ private void generateComposite(final List tokens) throws IOException try (Writer out = outputManager.createOutput(encoderName)) { final String implementsString = implementsInterface(CompositeEncoderFlyweight.class.getSimpleName()); - generateCompositeFlyweightHeader(token, encoderName, out, mutableBuffer, fqMutableBuffer, implementsString, - importedTypesPackages); + generateCompositeFlyweightHeader( + token, encoderName, out, mutableBuffer, fqMutableBuffer, implementsString, importedTypesPackages); for (int i = 1, end = tokens.size() - 1; i < end;) { @@ -1439,11 +1439,12 @@ private Set scanPackagesToImport(final List tokens) { if (!shouldSupportTypesPackageNames) { - return NO_PACKAGES; + return PACKAGES_EMPTY_SET; } final Set packagesToImport = new HashSet<>(); - for (int i = 1; i < tokens.size() - 1; i++) + + for (int i = 1, limit = tokens.size() - 1; i < limit; i++) { final Token typeToken = tokens.get(i); if (typeToken.signal() == Signal.BEGIN_ENUM || @@ -1456,6 +1457,7 @@ private Set scanPackagesToImport(final List tokens) } } } + return packagesToImport; } @@ -1646,19 +1648,22 @@ private CharSequence generateEnumLookupMethod(final List tokens, final St private StringBuilder generateImportStatements(final Set packages, final String currentPackage) { - final StringBuilder importsStatements = new StringBuilder(); + final StringBuilder importStatements = new StringBuilder(); + for (final String candidatePackage : packages) { - if (!candidatePackage.equalsIgnoreCase(currentPackage)) + if (!candidatePackage.equals(currentPackage)) { - importsStatements.append("import ").append(candidatePackage).append(".*;\n"); + importStatements.append("import ").append(candidatePackage).append(".*;\n"); } } - if (importsStatements.length() > 0) + + if (importStatements.length() > 0) { - importsStatements.append("\n\n"); + importStatements.append("\n\n"); } - return importsStatements; + + return importStatements; } private String interfaceImportLine() @@ -3878,13 +3883,6 @@ private String decoderName(final String className) private String implementsInterface(final String interfaceName) { - if (!shouldGenerateInterfaces) - { - return ""; - } - else - { - return " implements " + interfaceName; - } + return shouldGenerateInterfaces ? " implements " + interfaceName : ""; } } From 4fc4462e52fbeb48410625e05197df1175fd9f76 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 6 Oct 2022 09:24:41 +0100 Subject: [PATCH 135/805] [Java] Remove broken works with OpenJDK link. --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 98f247b51d..bc0984add5 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,6 @@ Simple Binary Encoding (SBE) ============================ -
    - - - [![Javadocs](https://www.javadoc.io/badge/uk.co.real-logic/sbe-tool.svg)](https://www.javadoc.io/doc/uk.co.real-logic/sbe-tool) [![GitHub](https://img.shields.io/github/license/real-logic/simple-binary-encoding.svg)](https://github.com/real-logic/simple-binary-encoding/blob/master/LICENSE) From 93dbe85643a11c51cf3d29fff951e7f3b5b478a6 Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Tue, 11 Oct 2022 08:49:06 -0700 Subject: [PATCH 136/805] 1.27.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 8503140e97..5db08bf2dc 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.27.0-SNAPSHOT +1.27.0 From bb199949aab31e9b172950ab7666b980d8a3b947 Mon Sep 17 00:00:00 2001 From: "Todd L. Montgomery" Date: Tue, 11 Oct 2022 08:49:56 -0700 Subject: [PATCH 137/805] post release bump. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 5db08bf2dc..f9aacd1c13 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.27.0 +1.27.1-SNAPSHOT From 100cb64062557a2419268f04a6b8421f81eaf9a9 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 18 Oct 2022 09:26:27 +0100 Subject: [PATCH 138/805] [Java] Upgrade to Version 0.43.0 and Mockito 4.8.1. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 2e864a76b5..2c87d894bd 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ import java.security.MessageDigest plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '7.1.2' apply false - id "com.github.ben-manes.versions" version "0.42.0" + id "com.github.ben-manes.versions" version "0.43.0" } defaultTasks 'clean', 'build' @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.8.0' +def mockitoVersion = '4.8.1' def junitVersion = '5.9.1' def jmhVersion = '1.35' def agronaVersion = '1.17.1' From 4a33a5d6e2c0a7eadda787130d7e12a6f71b65ea Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Thu, 3 Nov 2022 09:01:31 +1300 Subject: [PATCH 139/805] [Java] Correctly print warnings for undersize header fields. --- .../co/real_logic/sbe/xml/MessageSchema.java | 29 +++++++++-- .../real_logic/sbe/xml/XmlSchemaParser.java | 8 ++- .../java/WarningFormattingTest.java | 50 +++++++++++++++++++ .../src/test/resources/npe-small-header.xml | 23 +++++++++ 4 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java create mode 100644 sbe-tool/src/test/resources/npe-small-header.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index 38a168f1c0..f9757a1ed8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -18,10 +18,19 @@ import org.agrona.Verify; import org.w3c.dom.Node; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; import java.nio.ByteOrder; -import java.util.*; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; +import java.util.List; +import java.util.Map; -import static uk.co.real_logic.sbe.xml.XmlSchemaParser.*; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.getAttributeValue; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.getAttributeValueOrNull; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.getByteOrder; /** * Message schema aggregate for schema attributes, messageHeader, and reference for multiple {@link Message} objects. @@ -59,7 +68,8 @@ public class MessageSchema this.headerType = null == headerType ? HEADER_TYPE_DEFAULT : headerType; Verify.present(typeByNameMap, this.headerType, "Message header"); - ((CompositeType)typeByNameMap.get(this.headerType)).checkForWellFormedMessageHeader(schemaNode); + final Node messageHeaderNode = findNode(schemaNode, "types/composite[@name='" + this.headerType + "']"); + ((CompositeType)typeByNameMap.get(this.headerType)).checkForWellFormedMessageHeader(messageHeaderNode); } MessageSchema( @@ -353,4 +363,17 @@ private void reportError( errorHandler.error(sb.toString()); } + + private static Node findNode(final Node contextNode, final String path) + { + try + { + return (Node)XPathFactory.newInstance().newXPath() + .evaluate(path, contextNode, XPathConstants.NODE); + } + catch (final XPathExpressionException e) + { + throw new IllegalArgumentException("Unable to locate node with path=" + path, e); + } + } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index 0d55ab1262..3705fc491e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -363,7 +363,13 @@ public static String getAttributeValueOrNull(final Node elementNode, final Strin return null; } - final Node attrNode = elementNode.getAttributes().getNamedItemNS(null, attrName); + final NamedNodeMap attributes = elementNode.getAttributes(); +// if (null == attributes) +// { +// return null; +// } + + final Node attrNode = attributes.getNamedItemNS(null, attrName); if (null == attrNode) { return null; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java new file mode 100644 index 0000000000..38b0e83d31 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2013-2022 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static uk.co.real_logic.sbe.Tests.getLocalResource; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +public class WarningFormattingTest +{ + @Test + void shouldGenerateCorrectWarning() throws Exception + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final ParserOptions options = new ParserOptions.Builder().errorPrintStream(new PrintStream(out)).build(); + final MessageSchema schema = parse(getLocalResource("npe-small-header.xml"), options); + final IrGenerator irg = new IrGenerator(); + irg.generate(schema); + + final String warnings = out.toString(StandardCharsets.US_ASCII.name()); + assertTrue(warnings.contains( + "WARNING: at \"blockLength\" should be UINT16")); + assertTrue(warnings.contains( + "WARNING: at \"templateId\" should be UINT16")); + assertTrue(warnings.contains( + "WARNING: at \"version\" should be UINT16")); + } +} diff --git a/sbe-tool/src/test/resources/npe-small-header.xml b/sbe-tool/src/test/resources/npe-small-header.xml new file mode 100644 index 0000000000..96ade65735 --- /dev/null +++ b/sbe-tool/src/test/resources/npe-small-header.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file From 224bce368ff5f51dfad5a23bd6605cefe60f0c8e Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Thu, 3 Nov 2022 14:51:26 +1300 Subject: [PATCH 140/805] [Java] Restore belt and braces null check. --- .../java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index 3705fc491e..1ad8ac15f3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -364,10 +364,10 @@ public static String getAttributeValueOrNull(final Node elementNode, final Strin } final NamedNodeMap attributes = elementNode.getAttributes(); -// if (null == attributes) -// { -// return null; -// } + if (null == attributes) + { + return null; + } final Node attrNode = attributes.getNamedItemNS(null, attrName); if (null == attrNode) From 80c130f398e6f79c4ff1b33ee79955e86131d30a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 3 Nov 2022 17:35:39 +0000 Subject: [PATCH 141/805] [Java] Tidy up handling of reporting warnings on non-standard header and replace use of String.format. --- .../co/real_logic/sbe/xml/CompositeType.java | 53 ++++++++----------- .../co/real_logic/sbe/xml/MessageSchema.java | 7 ++- .../real_logic/sbe/xml/XmlSchemaParser.java | 10 ++-- .../java/WarningFormattingTest.java | 16 +++--- .../src/test/resources/npe-small-header.xml | 23 ++++---- 5 files changed, 54 insertions(+), 55 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java index 667da499dc..037c01c8c8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java @@ -195,9 +195,9 @@ else if (!isUnsigned(numInGroupType.primitiveType())) } else if (numInGroupMinValue.longValue() < 0) { - XmlSchemaParser.handleError(node, String.format( - "\"numInGroup\" minValue=%s must be greater than zero " + - "for signed \"numInGroup\" types", numInGroupMinValue)); + XmlSchemaParser.handleError(node, + "\"numInGroup\" minValue=" + numInGroupMinValue + " must be greater than zero " + + "for signed \"numInGroup\" types"); } } else @@ -218,8 +218,8 @@ else if (numInGroupMinValue.longValue() < 0) if (numInGroupMinValue.longValue() > max) { - XmlSchemaParser.handleError(node, String.format( - "\"numInGroup\" minValue=%s greater than maxValue=%d", numInGroupMinValue, max)); + XmlSchemaParser.handleError( + node, "\"numInGroup\" minValue=" + numInGroupMinValue + " greater than maxValue=" + max); } } } @@ -275,22 +275,22 @@ private static void validateGroupMaxValue( final long allowedValue = primitiveType.maxValue().longValue(); if (longValue > allowedValue) { - XmlSchemaParser.handleError(node, String.format( - "maxValue greater than allowed for type: maxValue=%d allowed=%d", longValue, allowedValue)); + XmlSchemaParser.handleError( + node, "maxValue greater than allowed for type: maxValue=" + longValue + " allowed=" + allowedValue); } final long maxInt = INT32.maxValue().longValue(); if (primitiveType == UINT32 && longValue > maxInt) { - XmlSchemaParser.handleError(node, String.format( - "maxValue greater than allowed for type: maxValue=%d allowed=%d", longValue, maxInt)); + XmlSchemaParser.handleError( + node, "maxValue greater than allowed for type: maxValue=" + longValue + " allowed=" + maxInt); } } else if (primitiveType == UINT32) { final long maxInt = INT32.maxValue().longValue(); - XmlSchemaParser.handleError(node, String.format( - "maxValue must be set for varData UINT32 type: max value allowed=%d", maxInt)); + XmlSchemaParser.handleError( + node, "maxValue must be set for varData UINT32 type: max value allowed=" + maxInt); } } @@ -333,33 +333,25 @@ private void validateHeaderField( { if (actualType == null) { - XmlSchemaParser.handleError( - node, - String.format("composite for message header must have \"%s\"", fieldName)); + XmlSchemaParser.handleError(node, "composite for message header must have \"" + fieldName + "\""); } else if (actualType.primitiveType() != expectedType) { - XmlSchemaParser.handleWarning(node, String.format("\"%s\" should be %s", fieldName, expectedType.name())); + XmlSchemaParser.handleWarning(node, "\"" + fieldName + "\" should be " + expectedType.name()); if (shouldGenerateInterfaces) { if (actualType.primitiveType().size() > expectedType.size()) { - XmlSchemaParser.handleError( - node, - String.format("\"%s\" must be less than %s bytes to use %s", - fieldName, - expectedType.size(), - JAVA_GENERATE_INTERFACES)); + final String msg = "\"" + fieldName + "\" must be less than " + expectedType.size() + + " bytes to use " + JAVA_GENERATE_INTERFACES; + XmlSchemaParser.handleError(node, msg); } else { - XmlSchemaParser.handleWarning( - node, - String.format("\"%s\" will be cast to %s to use %s", - fieldName, - expectedType.name(), - JAVA_GENERATE_INTERFACES)); + final String msg = "\"" + fieldName + "\" will be cast to " + expectedType.name() + + " to use " + JAVA_GENERATE_INTERFACES; + XmlSchemaParser.handleWarning(node, msg); } } } @@ -383,8 +375,7 @@ public void checkForValidOffsets(final Node node) if (offsetAttribute < offset) { XmlSchemaParser.handleError( - node, - String.format("composite element \"%s\" has incorrect offset specified", edt.name())); + node, "composite element \"" + edt.name() + "\" has incorrect offset specified"); } offset = offsetAttribute; @@ -434,8 +425,8 @@ private Type processType( { final XPath xPath = XPathFactory.newInstance().newXPath(); final String refTypeName = XmlSchemaParser.getAttributeValue(subTypeNode, "type"); - final Node refTypeNode = (Node)xPath.compile( - "/*[local-name() = 'messageSchema']/types/*[@name='" + refTypeName + "']") + final String expression = "/*[local-name() = 'messageSchema']/types/*[@name='" + refTypeName + "']"; + final Node refTypeNode = (Node)xPath.compile(expression) .evaluate(subTypeNode.getOwnerDocument(), XPathConstants.NODE); if (refTypeNode == null) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index f9757a1ed8..77be002e95 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -52,8 +52,7 @@ public class MessageSchema private final Map typeByNameMap; private final Map messageByIdMap; - MessageSchema( - final Node schemaNode, final Map typeByNameMap, final Map messageByIdMap) + MessageSchema(final Node schemaNode, final Map typeByNameMap, final Map messageByIdMap) { this.packageName = getAttributeValue(schemaNode, "package"); this.description = getAttributeValueOrNull(schemaNode, "description"); @@ -371,9 +370,9 @@ private static Node findNode(final Node contextNode, final String path) return (Node)XPathFactory.newInstance().newXPath() .evaluate(path, contextNode, XPathConstants.NODE); } - catch (final XPathExpressionException e) + catch (final XPathExpressionException ex) { - throw new IllegalArgumentException("Unable to locate node with path=" + path, e); + throw new IllegalArgumentException("Unable to locate node with path=" + path, ex); } } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index 1ad8ac15f3..c2d4312af1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -176,9 +176,10 @@ public static MessageSchema parse(final InputStream in, final ParserOptions opti * @param document for the XML parsing. * @param xPath for XPath expression reuse. * @return {@link java.util.Map} of name {@link java.lang.String} to {@link Type}. - * @throws Exception on parsing error. + * @throws XPathExpressionException on parsing error. */ - public static Map findTypes(final Document document, final XPath xPath) throws Exception + public static Map findTypes(final Document document, final XPath xPath) + throws XPathExpressionException { final Map typeByNameMap = new HashMap<>(); @@ -216,10 +217,11 @@ public static Map findTypes(final Document document, final XPath x * @param xPath for XPath expression reuse. * @param typeByNameMap to use for Type objects. * @return {@link java.util.Map} of schemaId to {@link Message}. - * @throws Exception on parsing error. + * @throws XPathExpressionException on parsing error. */ public static Map findMessages( - final Document document, final XPath xPath, final Map typeByNameMap) throws Exception + final Document document, final XPath xPath, final Map typeByNameMap) + throws XPathExpressionException { final Map messageByIdMap = new HashMap<>(); final ObjectHashSet distinctNames = new ObjectHashSet<>(); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java index 38b0e83d31..def80db067 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java @@ -24,27 +24,31 @@ import java.io.PrintStream; import java.nio.charset.StandardCharsets; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static uk.co.real_logic.sbe.Tests.getLocalResource; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class WarningFormattingTest +class WarningFormattingTest { @Test void shouldGenerateCorrectWarning() throws Exception { final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final ParserOptions options = new ParserOptions.Builder().errorPrintStream(new PrintStream(out)).build(); + final ParserOptions options = new ParserOptions.Builder() + .stopOnError(true) + .errorPrintStream(new PrintStream(out)) + .build(); final MessageSchema schema = parse(getLocalResource("npe-small-header.xml"), options); final IrGenerator irg = new IrGenerator(); irg.generate(schema); final String warnings = out.toString(StandardCharsets.US_ASCII.name()); - assertTrue(warnings.contains( + assertThat(warnings, containsString( "WARNING: at \"blockLength\" should be UINT16")); - assertTrue(warnings.contains( + assertThat(warnings, containsString( "WARNING: at \"templateId\" should be UINT16")); - assertTrue(warnings.contains( + assertThat(warnings, containsString( "WARNING: at \"version\" should be UINT16")); } } diff --git a/sbe-tool/src/test/resources/npe-small-header.xml b/sbe-tool/src/test/resources/npe-small-header.xml index 96ade65735..07a4fb277e 100644 --- a/sbe-tool/src/test/resources/npe-small-header.xml +++ b/sbe-tool/src/test/resources/npe-small-header.xml @@ -7,16 +7,19 @@ description="Message format for XXXXXX" byteOrder="littleEndian"> - - - - - - - - + + + + + + + From afdac25369db273ec9ba3762f1039e0f8936c9b8 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Fri, 4 Nov 2022 09:53:38 +1300 Subject: [PATCH 142/805] [Java] Formatting fixes. --- .../uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index c2d4312af1..8b95df9ff2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -195,16 +195,20 @@ public static Map findTypes(final Document document, final XPath x typeByNameMap.put("float", new EncodedDataType("float", REQUIRED, null, null, FLOAT, 1, false)); typeByNameMap.put("double", new EncodedDataType("double", REQUIRED, null, null, DOUBLE, 1, false)); - forEach((NodeList)xPath.compile(TYPE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), + forEach( + (NodeList)xPath.compile(TYPE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addTypeWithNameCheck(typeByNameMap, new EncodedDataType(node), node)); - forEach((NodeList)xPath.compile(COMPOSITE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), + forEach( + (NodeList)xPath.compile(COMPOSITE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addTypeWithNameCheck(typeByNameMap, new CompositeType(node), node)); - forEach((NodeList)xPath.compile(ENUM_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), + forEach( + (NodeList)xPath.compile(ENUM_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addTypeWithNameCheck(typeByNameMap, new EnumType(node), node)); - forEach((NodeList)xPath.compile(SET_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), + forEach( + (NodeList)xPath.compile(SET_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addTypeWithNameCheck(typeByNameMap, new SetType(node), node)); return typeByNameMap; @@ -226,7 +230,8 @@ public static Map findMessages( final Map messageByIdMap = new HashMap<>(); final ObjectHashSet distinctNames = new ObjectHashSet<>(); - forEach((NodeList)xPath.compile(MESSAGE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), + forEach( + (NodeList)xPath.compile(MESSAGE_XPATH_EXPR).evaluate(document, XPathConstants.NODESET), (node) -> addMessageWithIdCheck(distinctNames, messageByIdMap, new Message(node, typeByNameMap), node)); if (messageByIdMap.isEmpty()) From cb98b5e828161000c73d715ce461eca21adb57f1 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Fri, 4 Nov 2022 10:03:57 +1300 Subject: [PATCH 143/805] [Java] Prevent clashing defines in C/C++ codecs when multiple generated schemas are used. #884. --- .../main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 39e521a360..de8d3519eb 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1131,7 +1131,7 @@ private static CharSequence generateFileHeader(final String structName, final Li " #define SBE_BOUNDS_CHECK_EXPECT(exp,c) (false)\n" + "#elif defined(_MSC_VER)\n" + " #define SBE_BOUNDS_CHECK_EXPECT(exp,c) (exp)\n" + - "#else\n" + + "#elif !defined(SBE_BOUNDS_CHECK_EXPECT)\n" + " #define SBE_BOUNDS_CHECK_EXPECT(exp,c) (__builtin_expect(exp,c))\n" + "#endif\n\n" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 95151c7106..1235fc1cc8 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1126,7 +1126,7 @@ private static CharSequence generateFileHeader( "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (false)\n" + "#elif defined(_MSC_VER)\n" + "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (exp)\n" + - "#else\n" + + "#elif !defined(SBE_BOUNDS_CHECK_EXPECT)\n" + "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (__builtin_expect(exp, c))\n" + "#endif\n\n" + From 953f137527d6f4db870d804e3fc4c28a8cee9857 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Thu, 3 Nov 2022 21:34:09 -1100 Subject: [PATCH 144/805] [Java] Move check for existing SBE_BOUNDS_CHECK_EXPECT define to outer condition to capture all platforms. --- .../co/real_logic/sbe/generation/c/CGenerator.java | 14 ++++++++------ .../sbe/generation/cpp/CppGenerator.java | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index de8d3519eb..f82eec476c 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1127,12 +1127,14 @@ private static CharSequence generateFileHeader(final String structName, final Li " Set __BYTE_ORDER__ manually before including this file.\"\n" + "#endif\n\n" + - "#if defined(SBE_NO_BOUNDS_CHECK)\n" + - " #define SBE_BOUNDS_CHECK_EXPECT(exp,c) (false)\n" + - "#elif defined(_MSC_VER)\n" + - " #define SBE_BOUNDS_CHECK_EXPECT(exp,c) (exp)\n" + - "#elif !defined(SBE_BOUNDS_CHECK_EXPECT)\n" + - " #define SBE_BOUNDS_CHECK_EXPECT(exp,c) (__builtin_expect(exp,c))\n" + + "#if !defined(SBE_BOUNDS_CHECK_EXPECT)\n" + + "# if defined(SBE_NO_BOUNDS_CHECK)\n" + + "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (false)\n" + + "# elif defined(_MSC_VER)\n" + + "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (exp)\n" + + "# else \n" + + "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (__builtin_expect(exp, c))\n" + + "# endif\n\n" + "#endif\n\n" + "#define SBE_NULLVALUE_INT8 INT8_MIN\n" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 1235fc1cc8..81b8da29d7 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1122,12 +1122,14 @@ private static CharSequence generateFileHeader( "Set __BYTE_ORDER__ manually before including this file.\"\n" + "#endif\n\n" + - "#if defined(SBE_NO_BOUNDS_CHECK)\n" + - "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (false)\n" + - "#elif defined(_MSC_VER)\n" + - "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (exp)\n" + - "#elif !defined(SBE_BOUNDS_CHECK_EXPECT)\n" + - "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (__builtin_expect(exp, c))\n" + + "#if !defined(SBE_BOUNDS_CHECK_EXPECT)\n" + + "# if defined(SBE_NO_BOUNDS_CHECK)\n" + + "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (false)\n" + + "# elif defined(_MSC_VER)\n" + + "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (exp)\n" + + "# else \n" + + "# define SBE_BOUNDS_CHECK_EXPECT(exp, c) (__builtin_expect(exp, c))\n" + + "# endif\n\n" + "#endif\n\n" + "#define SBE_NULLVALUE_INT8 (std::numeric_limits::min)()\n" + From fc609e2192bd539f5a5f0bf2d31444c73524dc5b Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 18 Nov 2022 08:47:35 +0000 Subject: [PATCH 145/805] [Java] Upgrade to Version 0.44.0, Mockito 4.9.0, and JMH 1.36. --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 2c87d894bd..a0abfae24d 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ import java.security.MessageDigest plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '7.1.2' apply false - id "com.github.ben-manes.versions" version "0.43.0" + id "com.github.ben-manes.versions" version "0.44.0" } defaultTasks 'clean', 'build' @@ -44,9 +44,9 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.8.1' +def mockitoVersion = '4.9.0' def junitVersion = '5.9.1' -def jmhVersion = '1.35' +def jmhVersion = '1.36' def agronaVersion = '1.17.1' def agronaVersionRange = '[1.17.1,2.0[' // allow any release >= 1.17.1 and < 2.0.0 From 9f679d4f6f2a0156369e2c80a5bcbf20d6df8135 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Wed, 30 Nov 2022 16:12:06 +1300 Subject: [PATCH 146/805] [Gradle] Upgrade to 7.6. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index a0abfae24d..abc3c3974d 100644 --- a/build.gradle +++ b/build.gradle @@ -822,7 +822,7 @@ tasks.named('dependencyUpdates').configure { tasks.findByName('build').dependsOn verifyJavaIrCodecsInSync wrapper { - gradleVersion = '7.5.1' + gradleVersion = '7.6' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8fad3f5a98..f42e62f372 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From c8d39eaa4475e59bfc6be54851b8c81ba41a9584 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 30 Nov 2022 10:23:20 +0100 Subject: [PATCH 147/805] [Gradle] Re-run `./gradlew wrapper` to regenerate scripts. --- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 61574 bytes gradle/wrapper/gradle-wrapper.properties | 1 + gradlew | 12 ++++++++---- gradlew.bat | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644 GIT binary patch delta 36524 zcmZ6yQ*&aJ*i+pKn$=zKxk7ICNNX(G9gnUwow3iT2Ov?s|4Q$^qH|&1~>6K_f6Q@z)!W6o~05E1}7HS1}Bv=ef%?3Rc##Sb1)XzucCDxr#(Nfxotv ze%V_W`66|_=BK{+dN$WOZ#V$@kI(=7e7*Y3BMEum`h#%BJi{7P9=hz5ij2k_KbUm( zhz-iBt4RTzAPma)PhcHhjxYjxR6q^N4p+V6h&tZxbs!p4m8noJ?|i)9ATc@)IUzb~ zw2p)KDi7toTFgE%JA2d_9aWv7{xD{EzTGPb{V6+C=+O-u@I~*@9Q;(P9sE>h-v@&g ztSnY;?gI0q;XWPTrOm!4!5|uwJYJVPNluyu5}^SCc1ns-U#GrGqZ1B#qCcJbqoMAc zF$xB#F!(F?RcUqZtueR`*#i7DQ2CF?hhYV&goK!o`U?+H{F-15he}`xQ!)+H>0!QM z`)D&7s@{0}iVkz$(t{mqBKP?~W4b@KcuDglktFy&<2_z)F8Q~73;QcP`+pO=L}4yjlzNuLzuvnVAO``skBd=rV%VWQTd0x6_%ddY*G(AJt06`GHq zJVxl`G*RiYAeT=`Cf(SUN$kUEju!>SqwEd8RWUIk$|8A& zAvW|Uo<=TWC~u}V?SNFv`Fq9OeF_VpfyXHPIIay@Pu5J6$$pg{;xE9D7CROVYV>5c zv^IYXPo_Z4)bg5h?JSUX!K`q_u{>F%FzrG>*!Db_^7*7(F@f%i34Ps`JBAH6{s=ygSr^CVO)voP`v=SO z7v;4cFM_D>iVl{&X*N7pe4_^YKV%`5J774`5!DC}g;D@50h?VA!;fU1?Hf%%`N8R1 zSg@hZ8%Dq^eYV1!g8;`6vCSJoK+V1Q6N8ImtfE3iXs!s~B>js)sLHB9w$r+6Q>Oh#Ig&awvm%OBLg!7alaf}9Cuf;M4%Ig9 zx4K}IQfPr&u?k8xWp!wI4{CP#GTs#qR0b+G{&+=vL}I{b-Pha43^%8=K3997~* z>A|oxYE%Vo4~DiOih`87u|{8!Ql5|9Y+(ZY2nRP+oLdGErjV&YeVKw>A$JyPPAL+C zA36S!dNVf z;xJ)YR;^VPE1?`h-5>{~gwY2pY8RqhrsiIBmJ}n3G@Zs!!fD6y&KWPq&i8HEm*ZAx`G} zjq2CD5U==ID^we8k?=geue4Y>_+%u3$-TzVS6QMlb4NoS%_V>;E2hQ)+1Q@v(reC5 zLeK*f%%{PNO-mtrBVl|-!WaiKAkZv-?wnOwmZ=Tv57k=4PX=C?=I4V*THRFRE8a_{ zb>5YwDf4o>>$o{XYlLN{PZ^Ff?0FJl4>A9C-q9A$$&44l122Qsc|6Fd6aTam{=JO3 zBFfFe9seUPSUeyXQc*RA>2{WoKIYVltA&@5spdIW;rzOOqoQo`CN;~UNgU{{m9^c1 zTrN|8w_7+Nws4}Z-4eS9WMpF3h<@81a)oK9njh;-TB74vR;u{vE?>6FDG7<%GVXFL zUR9l{z*eEND6pp)+hpNT$VVM^Pw*S;#NrbCmH{dhBm?%6D|k)0C@Z9H>T|kby1^)# zOPmJ8Hq`8waoEK(9}IfP_q4yr(s?ME+T%UV-ikxW!XFb^6w02t30j$n_VSwevg;{9 zx0OXK_uGBFej=gbG>G^pEv^`I8&_a@t9>Nr;#r?XNKquD&Ho|`)qK6C^-7SCdo=S& z)vUi;m5*qIePEIbL=wJ|WCBNY;zCm2F-+@N2i{I^uR9UVZm$o`I|@<&2}w)C`h)vV zW{)yGJ3?GCZNtFe53Kb#uzrC7v-{JygKZUiXDV5mR z5la_vAFOvoh#yn)B`$^ZN*Dxp5Uo~_k8G9skn2)Tb>Kw#Vgxi`bti)^(z--X9F~oR zZ6=^_x@mDT~=h_@GGVcgBtLzssB1|Xy(xc(lUYJ#_ zgwc&ajE%^cCYW7d;xAxi{#LN*1}s>{K79MZrq!tYMpRA{T!#^tgXP=J5FvkbZ@gx~ ztq-E&c$`|KX8GS2a_voZHf=y8C{6~f~`DpC- zjQfrt2OGi-WGx}Y4>vM`8<4frU*!bq*NJ*Tyn0cqk=zpDdYth-PJIfz5>pLF@qnai zzj2FEhuOa-7$JR=U!L{UWWJBA%~SW-6Nh&3;<}iQO)DvOI&VKi1L8rmICePWqoY^F z-dC8X8~1T}=C9m&yb1kZzbKd2;29_Pm*Cs=y{Z06QZDlT7Poci>1@hFa%t0<`1()UTxcQ}e`fAh6K`<5C_SG`dw$IqzwEYNKvIH3VWlhz z_#^(T53W}jeWF#WIhj^U7AdIB~3feC--5iUiiT4Qyu81 z;Xa^8#~M@p%6B`LCKWWTa7I+35BLP=EOa&Gp2pbTWw5HOIjrx;2J(KI$$HT|w8}R-8fbp9sot&LiLs7ILlyZc8 zWbss7=*Ah|X$LEt1O|T?ABkIn-0NN`I8+ipfoBZcW>(WiaASG_khBtKM{hfkm5VBS zy0Q`4*G6HRRa#9G)10Ik3$C3|nQbFzmU-dA`LjKQY8icnx?2OE40%z852{OJH=?mbvwr9 zhlx0RDo^D;p*xKx?yT(`s7wj7BHA~rHF2yxnL<1PcU7FM57;?g^ z&CyPh9W4KvZ;T8w;AuNMn|nQ-xJ~CvVT7gAPAGi7w8udw_LOp+p4eZiI`JEC@Mq9F z#dA2AM_};CnL=y0#tZALdB(P~Rz*KqGqjwec%Fy?K(PGoO0tfskWw-aGhd7$ zTi~x1G>4h5q>ek=tIoT(VBQxrq)&#`_0UHC(j*ZO%%}%C)|EzTWEpvYDqCYXLexR9 zlww1ESB+IiO}=oq)8WZj%cY_FTQcEJ`JdABa=_S;O|kLhX*|5|D>0c{12DoC?K95f ztNxm(sTU6cWWd$tv`5X(=x?yAo)IYQ3G*2+o#|EfXko6erF;M4Pc;G0)pUDY)t`H9 z76Z8V9HqbWA@!`BelAT&ErrGTz7}%M*605PEY@3{gv+`yEhr{=EVp_tU%`b54Pn4a zz8nN7`eNx=*`f1t#^7>7G07IEnbnn&`RWZ}4Cp8W_DFDs-5)GU`bw}uBmOQfKmi2@ z(cWWmvHFTUNInRH!0y_ZtuI9Eh@O3+64wy-_2DF~E@KF3abM`0gC%|kHi@&hP_#B$ zLN{Z?$V_;+h?%2zEC{2ITyWOup*w*K?~vpwB(DX1i6oY+F)??;nyHpzaPLIt6G$4; z6>iAsB+&&NN0;ObWVOL+-^ZwD?nHgY>0k>0I3iA7o)f# zN&aX$lM@r_Iu|nSdPjoF{#QD9M6>|JSNPLxX^T2!jCKjS5mwNaO+SmBfOY z;6ZdwfzhO6Vs|9u81f4e%7*mU%8K>A7QWO0;QcX7W@|NSUVl)_>7VEf#&N6E~ zn9Wv88@Suo9P+M_G2(f+JFf#Q^GV#7QQ`qH#$N1y{A*_t^`5H1=V^u?Ec|EF6W+6B z(@Q8ChIUyq;+I5CmjEa1*v%d5{WHyhcHSjQuwzQq?;^BmfV#okq3v8bp7dBdk z54B+%D3=JWd-2w$)puXxZyZH>-$O-?tbSIlGc{em9xHN!44iaCr}6uZ^FpN7IvNh8 zbp!%4xR9np`>AOEd1e2_y}xW#v@@h3wYc?WiwL6Q>fxPQA81V^J)XtGs|Z&er6w~M z!1Ph~85TMG>R&ixNUnevc(w>fgb%+X#Wds6Yl+wH29aE%;RuDeZz5dEt%#p&2VK1n zKkqgl&*_YwnO%9`0<6MVP=O3{02EcR7PvvZPbL2KMuoRsU|Y%zw38qeOL#!YFp#_~+rtNJVl>lJSh_*B0A6n3XkE5po z9RpE_h=pnmDJFX*n6wmsWJ9GLu2=L8y!_R;;Aa2Jl|)I}Qff&`Fy@iOhop8>Y2{F} zbVk3rNMi$XX(q1JrgcIhC08@d5Zc>wLUL3wYm}hzS^!5d&Mec$Sp^$DUS1lD1>KAt z|Efof3nJ4^k(WKL_t-u8ud4L(t>q#9ECj?v#W~W#2zTt>|MCh&*H8Wh1_I&^2Li&M zq9j0`(zk~P7}dB`+15b*j%VPGr$;@4MBQ5AT>-y?0Fxfr2nC1kM2D(y7qMN+p-0yo zOlND}ImY;a_K$HZCrD=P{byToyC7*@;Y$v6wL!c*DfeH#$QS6|3)pJe68d>R#{zNn zB0r*Es<6^ZWeH`M)Cdoyz`@Z&Fu_^pu8*089j{gbbd!jV@s7`eI5_X5J3|poVGlq` zDo9}G;CsjW!hgN2O9=1|GpE;RpQvrBc+&dF)L>V&>9kd6^YIL?+*WDmcQlvwnq`Lf z&N$gF>3+E*NcJojXXI^}B(B-;@ebpVY}l#EcDWles7s;Ft+KZ@m+6FWaD^oYPBXVw z3sq|aKIDh1x5Ff=tW$(LO|!e&G?Xvh^H!GfiA(emluL!LmD=EV@|u|8S7w6ibUePJ z>{sOC6L27R+b&}e?VH;KvV3a;O3G=gwG}YzrkSTV6(&=;o)EV~2OD(Eh4mu@K0G)i z3#44IZhqN6+Hb2h#3R8YwJW7LesDA9=n)75u#46_ZmSh@6Q-4oHvGxFPY8x;Q+)d@ z*-SDqhVeyPGkoD)iq;z0r*M)IhY5I>gMA@RS&EIYPq}Z{$Q4Jbfd76EVhSF-sR^TO z!=o?>V(^bx!pG$26J~Z>Tvu&Uu+0;>m+pg(fmbu(97^(OHBH4;J8WIfv-f5}VP#VS z$Y$}SHKdphDUHlbdIVW!k$L6T{LY)|H}MT=l$22kIl>|46FK9dt$?3Fjk2RA-~AX7 z1|Xe`n)%h~e-O_qLpoFXJ$%gmocq`v0%hRw1k_6nh|+3pvJDy}m)V|xjL&!Z6?%pU z+m)r2*pWjEl!etAYxdzWb0{mGc;#$>rE%)b z@Rnj78P;$lrzY!XCa0&x+8a^YF*G|Q|C}bGeczz(5m_gq08wJHIH`WqHH?A}!~_3{ zQEvMXmL<*nThl^pL58nbHgQ1n9cYmN{C8J^6AKS%?~>1DCt70Q2Vp0;E@`GF%Tzkc zSUt&LJ=wHI6@#8_%=2s=j^4VBd1-h_)3 zeozYua!|{x(qk#z;tavf28rj_5Oen-cYG%;R6I}Hz$yMXeg^)_$OUUXx1r^qrl!DG zYXkAXKBMrVM-rJwAo<5J{NW1XJhW;Nh*&`nFV-Z;Vd({KSkMxV#cn|bXJ z50GtvFE##sqGhV#lv2s6?^yeBShlhR%XaPIo)iXOue}jwZ;Zq#dgDn8H?74Y+$Z?C z2Y5mCC66>dp%sVMecUzCirWq99Ea(TDwClZxtEB~4N-2JmlH#>Z2jOcaNaw4tn?P->BBGNHxUHez7>C@TZNT5Z zHerlG0a4~06L%>tn!~$s^L5`~{ueLZ5?`$46nHvwKxM0V9VQ(k{A40xDVw{+Qt)RV zQ)T2Df)cp0nv!lUFt3D=i~k!V|7dUjpz?K2ZiynO)$d{2*YT$N^CQ{t=luZ>WcE!> zg25p}If9RTho%G@PZp;5zBwv`n+e9iO=6dx1V^|4Ty%`oE=f7O&QC^s!4MJ+lMG>^ za!mgpz*^SHT+M_zm;{H#E~SaU^Kn*y)nTAF*2@t5mF+l)bte+a+goaA*zXJ4P)H|y z{4OwbJnIPtMp4E~=64gM-Y{#o{x)+8YCg$C7Yy=;9hdyBgRFIY2_L9DL3*B@%$5#m z8P}+)glf*}UPD$C;_yntx}9VPmSSnY9`Thd09nfoR;3`kar*FRfS)`+as*t2l*USWgmaZ!qFubr1DegTGZspyYMgic{inI0dSt+rJR z((jjMrdq^?VSZ8FCO;0NW@>O_b67gDHP%W*^O?J z91NQ7ZFODMSvHj3cvT#6RJUF7x=-BJFQ^6<&mOd15Z&M!?b+3Tg!UcgldD9tOAt5K z3X>MlE-a=sj;K&}sSng48jQ7sp|&u3;@e>V4Cuf(!s@9lZ0Cg^DKWmki%>$<85tOG zU;e{%zHU~KREBUg?FbcseK{lmK-`*S1p9j_4hF=F$y)NB;HsHwuf_A0Zhy395eU7o8^A zi2t7Ch|KVprUn03N0T2XshT!g$HTErcQBBG=TWaHkYtaI2CJY7ajI%yr&9 zVC^zJ3WW03bjwGNx{l}#+D&Ml_uI4PQhV}qZPXOP7ffSv(O;hX{Ff1|HoA~v)V!4y{CdALyi2YPjrRVmRYilRv z5PSkj*Z_8Fa*sCqGN?7YTnkr9=i9X`qcw7nqz#{bj?B7NiV9fWF+%~Rb1X@MuS^Mw zC)d#K{(-9!?xStM2K5x%x~ogWxgIK>s5r_RT1jU_lxdTtIEFWvi4eJSAiGec&HXQ( z5t7!J1b#SL|8s4)u147PWQUq_e33!5Z#f$Ja&az)(Htl`Z0@Ez)0d74BzNHHfH|<-8q*ZMf?%eJzoGS!0S6Y zSU7y^1+;V$Je9F027>1eN#_tz+2t}Y^N zYfi9}J!N^SU1CYoNBDbD39@84xLroY@0f%%c^(5CE+}!b5-Mt3oXe2nBdyicgGIL+rzTTKv`}Pp%fG1f^s?sgNH8=Q}s4Z>0ZCZ8ZYF z4og8nK%OA~zZMJX01uFtrmwhcgg*XbiMP9kfkPYFASbp7*Bk^5ZBzV)dL)JhPwDkM zkgdHeKw)orJcj4^)a^wQC2|->G=OBzuc-SskRrrf+H-E%HQ==Ex}d*504#GbIUXIB zcZs@Oo0i61MG}&0bu%@2N?MMJMRXyTVb8@3wF5eY3G6-1NdT~{{~YFs8f&SNebdaq zKmP>XqCQ@iaamuvY2m%xJ~gdSLSj~DBhB`NCj_c}NbSjB{r(E`_-+6a#vx*|S>-GU zHsw^dxxu`e)q1HbH==rLFap?cebKumnTo=iJQ zJD1#=o>0%Y@&jP?^)Q5bTV!pzrf=FoHq2c_59pq@my{D4AW8VU*7LVp;LF-qESV;L zClRfyQ6CcD$sd84K@e@p_ALH%j(Pz@Em@QFyY`AG&(|!(cG8!oV#ejr`y(LolX}Iu zL$)G)8^y4sUAYCWprzVR?`#OJ%NU)9U^B!OGSj>Ly;<)<(nNh`?z*GvJ|ZBKfZ`0 z=q_yGHWPp~R+J+{{@APVwmp8`=%N!L7AT^l^oaM|JrCFu7J#@frf=z(vGq2>sQ^@u zk=^d#gDf}ME!~9PaLfw44~rsG!)T7h8~dY^VcZQa+ueWPGG$mWXB|H2$$0BT(QAIu|=DJXPQDNes3Q>-|Mh=Ih zy{WR)QmhL5rQbBYPBa+e7)8Vo;_aKrg`}izmN>#ATuSDu!QUFA zsgM|Kv@W(S}Ag^6e8)9pQc@JLj_2ZIkO=8)#ARm#mU=NncWbmd-SbO;ad=y|k`shy3b z*8o0@EJo3b$#zSgmnlT7KAp)U!qI2M`hiC@Gp0)pNGHYMe1$MBNE}Hd{Sv^`wI7>MzNwgVv1ZzL zttmyv!=TKuPH$b>r7$lgP5?vho;#Ks4+zLzaz-1b{p-Fn6dWy1Agg7O2{&VQ5@s3A zAqzC9QokRD59!@ex#k>xy61kq6h~O$lb;lB;Q|chv&wzR+N zgXdIo%?q1Y$TzsdCo+n$^NODN7yd}cAv+rkG|u-(wTp?zUSUxaA-W3dwqikdrokwz) z68)Gn$Nwc1zB$F9`#(af|C3v;|2$bo7fU8f7h^NK6h&@xi2m`)g4mW$?l@5JEc*VV z6d67@Fl2w6mO;MYUl2U>R996gQUX$d>$D>)TNGq*arz}f21yh^uvIM!3u$H{_CH5! zrjt9L^&J8UqEV_lLn&}nc|Q=MDei6t=vL_>X-i8B%f5FDi)|qQ;2V-T!qOi*uqq{U zElET6#2cb>Z_6p_vw44&mN!;T&~ubi&p`XGepCNAfa0-T zC84V@VN^R6%z({m=$%iXrbiggxvMiBpww~ktD&=9-JPK3kPCOGCJNQj8+l9k#!QeS zv3h$Ej>@j<-zBW0Qr`5tNQVRfYK_$3>nWUzf&c*tCpl@aYwa%b;JNeTX10OevcxY7 zqnLgKU-X9G8~&?Dr)`*7GryqhN#;9v`D_c=_xBcD{j-cLop~pSnM?&7HggX6gb++ftBq$idM1|>5t+68sWf{ixREbMkZesmpjJsAFPQ#2+8Uek z$BPbu3cQuNDQq+^M}&ZuSHjxUgxOjF<^%4 z*8lc$CgA<$n=DYg_DsrHB7zYM0Ro|gS8ZnUq$u3GQ+{owv9RdB$wG%d-;R+I>?i?b z+r_mu{IL6WTYftdz?0#pbHkmQP31LvXcMK6;mAP+;q^L@q}v~TD}Ni>f7@QYcbM!T zX5kShHv3X1U=>B!2*si9=AEJCBt~GIH7DL4^+gHj+q}tk0F_?Q-=z{JY%77nkw>$F zG}6ROaL_)3t$jX=ZtFG{Q=LZfNjNb2LK=m9l|7iaB++N|S$vAr1 z_gf3JpIB|?dptfQ{sOZGlhyj~D;T#hjaNh0X5(o&7)87^t@@Hteh{0DOM{tCu$l#& z&NhA&V4VR}nzZP{7i(5bGB17<7bu+RJ1}k}=ffSg%=+213Oy@Aj1vv2U>U>8tRhKM z=*e<21)u6SSb{CC&We%#6X@duqLWGJ>O)Ls`uM98``34g11;D}*7>c3+^c|Os&;t}`(BWMD zfbyr~$j%{6%DZ`kR-}s~p?0#&-5a}b?6tDqwtqY%ep0ypSRIB54G@|0J5E#LkxQk# z_&xE=d(U}q?*Rh7L7f8AM5{qdGpC<&t~9YI!%j2G@nUPoLPSiWHjCVP{JAe?cBjQ zTqI=R{nv5c@|R)8Oi3cTL{&6%XdTgDP4CNYT}q2f5|Xf_hID#;83kd+v0RRyNKYn} zyPahwd=4ncDORLvatBc~KzT+jiiD{tzd3d*T(f7ayS;J&I1X!xaL2~POrw2ST=Pr5 zu*c}fb@)0P6jv))kNl38C7gmnWGmlL@{PWOVYt9se*cS0w#@W=N+dY#V08ci=Zmg9 z+${f#Qfs5)hOPxC;q{(J{Kx4HF)2QMzlVtXz0-O&h2$VxtT;ROvZ13nN{IG>Asv{% zHuDqgZ{R2(X*hkO+!HYHHWvRYrvN9fl-1?x6b)oseZY)@dQ6O>9Y#8*23~%bzN~Nf zpHGMdS-G|%F^v3Gnlsc$s4Wl=ZEu+J6y~*Ih2tpmHfO56JXKjldm$BxDvW6ZH>JrU zdRo}=^466lAq6!qY_@nQ}5ETUEoF;`>7b8W910_Z17!r`D?QNvC z+WF%@IkPi43n4;0Ks`M{x*0-^GK7oCAp?pFK1`~RoMSe@jAlV8vQruCUNyQ_7wk?` zSKe*|!4ar@VSA}!ThlIB*Qa5){pu&HS!a)-{lWL2@o1486ZK_!!}FSZ>vyUPIOX#+ z5d3~J24Op?!f!oNytub~egnkB`}h?eh!QyX6&^LbNuA#9vH#N_7IL|#6kIDhLL=be zEg3Cwmw{A(cm{&T zPg>XIWX24$Mj_#^k2I91C@h;b$8WNVr&MLjEwgAUtSeJ2W0)6Fit}PF!K&1j=*+6g zL{XOUrqhNyPLemIF4C&hThR8fie9^fYg$yl$m!1|YgcPlO>TB-(X{lkN~X}R=GA!Q zou<9ZJV6*}SN_4WRsqzRGI&p$;9DxDFTlyPw6Q9rlo@E3tMN&Wo4eFs{1=RCUij$V z`8)kmh0fhTTiEyvRl90B%q2(Moh$jg7{NeQiy> ze!H{zbG7<3BcK}XE&V_1kFfGA7D^ODxn*@nqlp!{LhYb47zIUlV^m+7kZh^a7L1^D zvI?m^9PECMnnN$0hi^Ur0b-~QgEORanrv|`dd;ek$4rAgEEof3HyvuYoZ)H*;+TgO z8CJY~4YDI^7RD7O)m&2h2K`-4e-I$1zcZ*K>Cd7~sSxEXc{d7-;f z5Ykr56Nkie%=z4_LIA}H>c81e$%ey=2hjqzTxoO0MDe!J&PE@EmX49jQJJg?HNw;B zHRHr)3do7CGDa3lPAZ4LAnpT)spnk8(ZiFz$|F$1m*A@!qCPug>Isp|MPI24i>jp~ z((9EQ9W#Rz)0AYT&ZWOWKBNtdNYYm2QytK$o-_|W5j7Abr&73(MG+Ar4K!Ij=nKu# z;SNkveY?Oc!I|Vta2{rb@c50#p_byn|_tu>Pv}6YDydl|}X#4oZW2 zvq)Y@8iG5@6c3?uu4vdLSBq23P&qUSvtGcu_qgH*?KfaT)@QueLx6apA97FI7sXP=foe zmrEu7;%Z=yTTGUsHsjR(wU54xNPI$hLFZUOwh=uhZ&rLammOQ?w*)}?Ah#%&K~OZc zl#Owj1OCEeXt!ALV7LgJ=MVbCo}<%92WX$wCS~Ins}%5+sb*C{WoOT5*2%sgjya;~ z|A#;k?j~J9qB)Tku1BGX=MrZ}<%Z4}i$OvCHv_3vtH_NZoK zjJljjt(~Yh%aI@gFnM*e*@_*N190p^@w5?SjRMb66N_^3EZ#Yoh<8FM>Yx$+mTbp$ zjQQS7(rs2j^54CJXdkH|$1&$wPOGDvm^@1o1pl9~!5&B+I=U-f_M-M&r3zfp2%TH%Ib3lz-^t)+Z9E+>W1Bt1`B}rZ$hZ3{0n|nZKM9O z$?_1+y}fB2$zEzE$zC#46=0E_4x7-VXY5}<+d!g2+Kg$gvU-Xm-A9DBZz+bZ*zDTx z$Wfb93))oLQf;wKi5JBJ%$yq}m42lacy`bC9PjFg*}pCnqn@dv{k9WiwCC07;6n#e zJ499v3YGQ^WyYY=x*s`q*;@R_ai1NKNA}<6=F8IvJArr{-YbdY#{l1K{(4l$7^7We zo~>}l=+L8IJ`BhgR&b$J3hW!ljy5F`+4NA06g$&4oC-`oGb@e5aw-1dSDL}GOnUuy z)z1W)8W9t(7w%OCn_~#0;^F)xic6It5)3h);vuLAKFS4b)G;Z$n-R&{b6h@yGxGo> zT-cq0W7~n+qN10;1OS+*c>H$(GoKq4hGG% zL&XJG$PDQ6K^BD#s_MsnlGPE+$W^B`&a+Z+4;`*nyKil99^E(wW?t>#V_xYWHLl2} zIV`uiR-__g+<&m#Z*4E|wjKY1R2mCm%k2ayMSDw`Rz_KA!3P$uIbB`dl`3&A zmT@gMT@ZpAxBys8zRtgoH+ebSaVA)maP?G1=G4x^Nw3mV0?qehWL35vMI~p$y0hGL z6@vHf-50P~uoe6yY&*D)Ekmi06LF!Jqz9#7kMvWexYMbAn{}`{3ZBsd6$5jBCujDp z<0N?b*1%T<-_Nxh`lKtla|FFqs7RZMtjHAwZ0Ck&s{x`#^S?36BNQN1JU^0f&TRoC z$}c)LW7)-n$CmAg&n(96AycC4!4_*D(~HvXyLW>HORuI0;ny$f9h{!Ud0=X0x%{l6NH$ z?lttWn}DQL521;-r~Kf$N_YPo)7H>3gI@Ivt}GnR=8W~Nn7_PE_3{sRNn`R~bs`g1 zoTh`7o4H*TRp7VBp=%>&t&Cd*Ny~@;{C)P;62d^dipuJYUV3-Dh<#a&AIxtrmX42( zYEH-8F3|^nY-=yw(?^d!hTojNxr~A!n$Ao+2mq*kZ&>Zm+BDC*sul=~!LUtWiokIB zxc(dNwyk&5o;>WRt)Q-Wj;fvuvJO&DLPe%mt@t!Oq^VsoIN0iTh%fh#`-{Ha?a8gf zj^yA3`=_NEONO0Z?}YVP*dL{T}v|A&cE7$_0G=g;1s*WDQuRcq>cJ?z=8b5&i<)=3ELSW%Kff zs=my9Q%8?aMxZeDq=RBHg*&HnIeQ_}X@oh=f#?C^HSg?1dwLn#wu(o^uANrRZD;H; zYbOec$#wJB(u?w22{gV+zb~pv|Ag!q$N@^|6n+FV5-X=lR$jajjeRh$1tjht$URz1 zhw)(ksAr2;QBXH9T#A$6V4PsR7K)){JQb?79o6&*IwDPZknNqySIa6pwcs)~xN81I zKc-GmzZ$i(8RaU==$Dx{tD@4nph-V*=W{Ln97*VEN^F+u0!F<%$l=K`ikIp#<^Yt} z{rx1gk>;rVccPIo6hD=xPQ$PxVwl6Cl;YI6iLf3!aevhsyXXZovK#TOv0|*T+^ii5 z+YO`u(SO3@ybv-DG)w)E;@+ULoj_+<;mc#iW8{9Y!99vE`HdAK=Utac&Eq1uy!TLgOS-C1E90Am)B{Tiw z$>$Er{s{snLEaO5@u&zqxE@v;p6D&?u@40t{#VNA&7SZael};kGEwnHgD4V5RNM@g z(EL~B=A8&?pPPW-fTja0Oi6SVtI_(3ME!qWLg-uK2afWhBn(C2PAmUyu^2h?Y402i z9P03g5$1#etGdUUo?#skjQ|$*()ybRGMXM`-2?jjThnTcPV==7sg$k{GxYdF+S*zz z%dtBo(R9!7SW6Utq|wFpsKMSAH-x{WB|Cz62A8!p8!kHz1tM=9I=M&xqQG zz17xBW7t?Q?C%@4YC`p*za(>hOrK&ELyDQu{5ACOg9noZS1SGh{-FcLy_W;nf$N`N zGYxdIzy7mL3K@Kw65DmvPH0@&;T{y&jP^AsaYENi}q|A z3}l}5V?z_VvpHf%CkpN@IK`czOuLPY=yBUf8Q3b9$X|kEiYROV$`T8T7ZjFPvKhbK zDYxzz99JRNzsx0f1Y>IrIQq9o+W(TsB(ZtN@4*)DMGr3?4~Jt|37IBI|7oQknQI3X zAWs`45xiCHga9;8+W{|!Yy>tic?%SNq=3EX@z2Mk!P0dKG0NCHNz0*F-a z`7K?6d*D4ri*=>wyQyQt{_t=t95*gB1|tdTg45fR{KmKD|3ZuM$QlkX{-tUkq@3Qd z-6X|jEyZa@tuxB}qrdlJdc0{8``%3M$xl8$9pUzkFa$Ww{Jocp9>;5~oNC8o`3GK& zy7_X8YoQDCO1TU_a%#Q+rC?Rr`r)W8CdpEe=>uMYDx6^46V_1DthgX`6CnF*E+%bY z=GYih(DizXEVFDuQRPQY&dc2p;Pwo7L{I2r3;QV8IEPg1McP{PchEUDf} zbtSAoBMPt?&Q@{fG_3a7gzHl58O7e(h_F6^rKgU=a&(^WpgH3U%`tpj3CMVRA-uol z(hA)(VF{4@`k@PREUQJ_8w6CcMW4Pm06{fw^*>aMH%#ik6lD{{j~nT}Vw=wZ(;Ct& zi1nt}RmOGrVHP++5;Z@eE*lkdw~?>AJL_Yg!~p*adS_s1`_oT1B26S zt&1-4twO45pMl<5B9T;SLH9Q?E>dBXcy@5k-{YQ5K!A`=YMYMlLOYc(+LdC<@@UIZ zxq%vI<;6P)=W4nRb7nxQ9KGzXsOjWs_3V-2*V+r}?dAZA7{7f*>^PxEw|6+WS0wAs zen2zj2cFKIr`~Ai`YU|OR4%DQw8uM=|g2B{;1Ho`mx@??e)rX!p$MSlA70pKVcvZ@|fYLpEV~s7G z>#?88yv{ekJpeJL<-?FY7wf10XpS{B4}jy{uc)7esm&J1)ZYt5LI_{)0BkN8Nc}ep zg%SYD0Cub3?KXLY*-dYntrghE|}%?RY5i3yVcPFlheiJUMLIr=Xp=U-^siywr8MF^JAEwl2uQ$VIfuDFPisd}4W2ZxY$C`2`tBTA~ zG2P62@*~(9gYmO6#Ya<1TG#3rQd0BwVyNP@Ayt7B(h%z<@N>Iz;|2VkT8T3`anW@3 z03^F>TCLS9Y*sY)#=BX5!LYD9Z;z4QSOL2^Zw~0e;OutRfp)Xu83Yz~srLh8rR}fp z=#yHH{&=!mHgDg!b;9K@Ux99VmQ*K2Xn%gV6YWHHw(<_uA&($p}$2U2TIs7y+ zM7X5Yk#^wpDE4kQZmN3&VC{!nno7wD2`bEeAwS;W6>$oUt#~E57Imre?b54{c$`tHdB6GMC`IZWLL(%j20Bh zW@}9_@4EsYT$u1Q3ZPWkvYxUX{6AcsV{;{1w60^@wv!dJW7}rOw!LE8wrwXJr(>&Q z+xFe(e7mP=RLy@dYSfEoS{pC8KXH4kGf zd``z`=z(*mSdLiXj&Y{>&akI{IMzo@tD>a^<(r*Ssf6Nz;ZsaLra9mcD`MN8$2`!w zj#+BZCrV}b_c=qEqt7{oF$>wI5*0B0kP{DNQ5_-V9dZ<9u;vm!(L2I_#p*nprX%tU z!{;Gb7IuVBg7pdB2!{X!ZgHqp5+?drImJ(UE6~P2|C?+`E9th5QSv!}?=L}=tvcFMQuyE`=pek1zbRxBAFdgqqB#0~EkA_CpTe0`e$i(eyMD!C!D0SjSaixQMIl zQ>-Dj?K($9qMGwhRqIt28n$`*FH_6v*JjZRnIMxz-qVe_KzSGY5Ph0$(^e$r-hLD4T4m@eV#69bG7_fQ>o`!yu97p=$)>fb; z&!>)wS*Fj!ag#iKWRWiC735;`@XxXFT)nniSe~^1r0v?bQ6_Fokmx~(-O5D{7$d>R z#Us$PxL8^}t1rpnJ@#E}+O?`@a4wB;n{#!lX6WlOwo}C3TgP%?N=BT*FrxR=JR(g$ zJn3EhTI~xj_mVxhFImqt22JE`CI;B~Pb~*cFE>{uL*2mnfeKb_aYO6sDC{Khp%ba`v>+M4WqY2KK4@w{=P~Tzx42!1yHniJT#~*CHF5|TVC_n_ z&;r3b9d!f0;?+iQ8rT1N>MM-D(HQrU-WWU9=w|>nbeG#luD0;ayPj`4=&7Ik$Z{Z3~ z!oob~d$cMHx9;vjAfJ{XC6R@pzkLW4q1ak{?IimWUVBKithq`vKQD14&60gGKCCale{X}Ft0By269l*P6r zuTm0E33lN!&zezRh=5l@mQP_RAR5sr^}&4j;(eFAj2@K*7>|(4IdGb4yB%g88|TKZ z^M@nOtS|f?{!z}s#}S=w{R0`LbVP{k5xhlw?;F>N1tIByWsnp`Bg)hb4sZR>Y12=3 z!#Anh?EEZFm==f$1I@Zw1Y6-%6aE;!l&t#!4vB-%4AfB{X;!sT(jBKx*-5qZn|89Z zK%Is6JLf#w>eauBET9VUE&>aD*^+~!ilaiM?p&mM&kqY3D1*5QUGBbUOI)=eY1dMv zJ=ybPA_VaWPE1+MDhiYq4$DfAeVIv!IP-*#v53?V-c^a) zG6p$+O#_1{V`nNcS`{^%iBn8Oi4fO$#Q7x-$tp2dRs-etYmui-mt@P{hh?ldJJP!? z`!i88d>h`9rIRd6=^pZVuo5}3zUbAX>~uzA4C%servKlplCW0(Ta+B&Eey1CQ5DDV zf2Mk*YRAVjE>){hi_9poOCsx=BU4gQV)kovP|^v!npW_>^LFUzYHx;MKo!BEj7Xy9Xg-A6>kWs*$)aMAWh^_0Fnx;eR|2;L0ZjLl*+F1Moh4?D&8h6H6jJQ+OxgwJV51#)zSmqvRnQ5 zz~62JXPCCiwK9W;yo9-%7Xka%OtQeVDK5SGr51}$q@i)OE>BHgfOFiV%SZ5E(VC*q zYujoHFnnF^qs^WhZG}uBRIs4{4xGP&Tbtr=RJ?=4?;IaVA9Yzp!}H z9QDT#L{7Y?)r=m^ucWOjUuJh*FSmqL?!<1x{iOcP?l7BCorp91#(gUNGIQf@1)d1lXx(RAI zhm*TFNYgXZn_A}FPfh;WMHE%oCs8d+1emobQCt@YTjxcWoK81LeXY~+9)^+UOmeCk z)#LMg9G1`jWr;WZrrR$Gwve9&X+lKpB~*OkxAEnRpO&^BwsOm&TDeQBlvTv^nuju5 zyB8jH2{_Xtz=1n}8hD4nhhZvyxynbGz%2iKM-8|$N`wX8O-Toi=&@x087+joKHd4@ zsx+@?mPB(R?mMWCIeejm^dhs63ARzdm}jsA(O)QqT|m}QRWm-(Hzh#M1)wVV%1iJL zg(a=;b~-ZkGDk#mk1~G*z!7zGrRGL-8}=VILi|%;0knSAjJX1jZXYa@^cU6K|NAIP zkrpm_?r8?!`$D^>c>@hwX{b1l4f&cY;wwU&Q2vPM9oGB`Uj2&haf>bY84LFfn>4P} zUwt~VVTwui2oj$uGt#`OH>|MYjm8`R#n z{C%^u?$@fW&NV}iCuMF`&DU3gT0TNA(vM@&mV$M7yWD^p3 zN996Z8he29k4NFCg+9PbnZ$<&>5-W0fbtK7!ePTkfP37tvtUFQiW$|1%XoEZO`#0Q z2^XjxY40!DruxCn-p%m|j1RfInIaROco}Cf&3zhkkBHj&Rt=WZ_VkNJdliOb-H{>p z4n>c+XW~q#1M6<*boFS%=vdUE3ndU*iM+EFUvAM1=)%}A49e~^iF9Tr^(nqF(J^n~ z49*I<-WXCZ`1EG0hYOd%nsoM{LT8_q$a&QSBz;#S3YCwj?)0mjn_saa@O3c^sMqwF z!ZcWHQHCT~S|SVe5eVTt=z64&T=nI)wG<+4e2@}Gp9#uWEM+p-{L1PUC zM9N-bN73qWRRpT*YCLuK_D+uRgFcwsV}^odrD$A zI~cJDK#5qb8UPL(A_=P(=)Z0U`Aq`WLGuPhE^-isi?g-0`OZ?4kK^MyAsY+mxqt5G z-B14#h=^(sGv*CF8}cd}Xwl*_z1KEt!uP`_(wPBT8=FmK<+VOOk}fZ4Gj*{W-MSmu zygps+?d@%?tx#Fn|0(KF86C^QEgcz^1&!sUz|u||p8_`(gR(h#GELI8FrjSjfNCc zYJ9BHx9555<@$3ttNMYtIMa?NQe?V&_luijx2?!gBJ8tg}l4R@z5x73q4 zfZVtX0lZOzVV%@yTg!w5oMcYuMfGrD!RFwqChHhY`G22|vNLn!6a7VRi4gD!@Ae2K zT6A|%SwkYp{k$!ki4db&5nZ!Hg{8dj)h57Z<$r$9=s?;uzmx54DcKt)m0_ow(XjO@ z{}vbrW9)Fk2;8-9>tkzX!IEOW7lMb$gf~wwZgu2{whBB$YvW7BQSPQZQDy~)5Wh@8*P!VrB-YNi~zFb27ia7UtoAd`4C|JS~iU%&Qw1UMjN zC(CRqwMFj@{DT5Q%Z!g{RpCq?CpzVQqdKjxHQ1xa=u_EKr1ec5)TH;7hvWIn?hs@&K~48_$RK3+ zdu{2({Eh&7HD%B{)|+9CYaV^V1<$`JDFoj0UB!kwzCp*vlO(9kJe-Iv4aj7J^fJER zTEQS`H@RGhfs9w?M)S`;LliZ`Qvu3g2?r)nr?wT^cRJy(wBCr0MDqtRFHm$E%-!6g zMLRw$2+YPDN~0`{Vm}H&to@Nr&fF{~L0>m}Ghn>Vj81s`EIQnE@l@Jse`#}N0!!DL zkzs?x4I;fLH-LS+=E9Vl88}Td=@l&5&xyb1KaYf^1>c=cC+$#bcr7(`-gQsjD7Tws zxszZy^8Sv(2%nbY|4UVV<}>Y_l1lTjrKy;Y5${ej*V%OT0+D~Ec3-9;X zs?8%af6+X@s}jQO+NREG?W&1rhl(x1!Yfpt@?JLkH~UV_9l*DG6qvuakx_O+bAq=s z({A;t{jPMtJAA3|O@KE~J3M!)@g5`5KHrMBrNC_Vh4B|&pimlm=+i4!K-R<3m20bD zzS$Ki+QfH%hnUo)1S~{GWomug`!{WD(v+ zuvqIy(f7nrv3AgZ=8rf6?es-84@=OK6qbY0wJ-G zL(2?kPhb zZ{|(D3#69jUn8s@S7FY>F%&HMCc-%c24`6k2TkwB}T>7a66k$Rk>2x3dp&D-EP;6vCr%iE>GKFx;(izH3Le$SQsp0A%5 zm-Se9<@jb?{00JSx_;^KuDtmei!?oLZDoJ59(**b_6Y`2ZP$kvK4#2^Lk;B5oCirY zRlPg?{iEPr_J_ES2=O`sJ_qloEFsXBDQ+Z4sZubH45vc)72Y|~@)oVTzXL$U?w#*n zclYx8f%j*|f#eOo&_;}Am3`vA@XpB}-9L>H4kiQkO%r&~{%W@YWSeD_%B5+F67d*j z?Utu*W~cd#8x`Co76I~a0hZ}GzEOX;;hDT#z2m$G4zcHYIefxJIe3HizO!1pDziPE z*|lfM&rHZW`dhSY#7rpieqo!w>m&7!e)!(++5So5!vv0pL0Wxlkw z;_!rN(U5yR9=>CNO_J%S#)QEl@X^i< z$-v~-byW{BRXav4GT1VHt3jrFK9-@DZunt&iHnR->YIe?0!h%8oHlN&$VawG{+?<< zoY3lysffn`42Anr(od87p_%kBvtEl~1Jq51oU>0Cs?E%&n0t{t#)ExsgW$H{YuO*? z(`4X_deFhMU*%36&*Y&?o78sAOZl$&98gl@b9zEa>Ul`Eht&~4&@b1AzPD7{!Ati$ zwXVr7)>u0Sv&p#{4{|Qcx56H> zF?_X1-NV9Zi{jD!EQY!op(nLS=XU(DmJtXhf;wDL&4dvd`O>zAaBzN(?%law3sn1p z_#_Z!M+Gw0@Qk>REY&5+l&ECBG20Y4{6#618u0a_FxP38r-^@-!(PFvJl*UdjdBDn z11S4BYW3AgDE#Gc`TX_x<1XiTCER)+z?$_X z7n&6Ev$hKOggBsrg&CpBUpqPE1~%I*WKQW)@&B^`ZW5)SBHYAX27S#;6vo)8c5BcH z!iREPvmG%-xk%IahqAZVSke7KH%Rm!>V_tpH`>bSS4Y|tT-m!g!=Ni9VbK>Rx}WE8 z1ss1w(!|#dy?b|&w)Q0+&&lInD4O`WjJ{*tN3GHw8{8SD?rdB!ZRgxa1F<=81)1({ z2JvQ>m?i8VI<$}9MmtE)MyKN(H%%Ec)=3jmP)K#QS&7qL0o;%>!jhlVO3 z&jsJtdo5DnGgt&A^6{Y8a8ne9+lmC2B)oq7mWC?KoKbd`r)Uj|vMQx$o%)qPrk?b_ zW1Nh}Mw*Y_&LN|blw(R7 zFqMcuihIjBcSQDyLEoxd@%w52JEp%6+H?S#HPt_I1T@F@jW@935OmoG zE^SH~5V5=!n&E+yvOEFgM<8j%Fift}(j53d3V%1r9NT`}I%2p0$%QVx!#G2{NyO0x+|GF&XFcta601En$nx7I1 zQqAX}hG!*oND@sdrvXZQ=WU5MOE7QtKbgX45%?B?waqj`sNjDd- zUTH|{!iKvo{j~L-X=^?Us9D+2O!SG>$w%in^7zGGy+BMpnFr)#L4Zc0>7HJeEGS(u z(RiPD!>0L<(^-m_3%r!)MMdobk+T+6rOX^H>@PRjP^E3Fvx;U$0pz%a=(m-W6LZ}U zX2QnW7lPQm!-pgsRh$Rxq+tS|LfE_T9hZ*a3%%5EE8!rlmCi9s zC%T&Q39zQ(krY&I&{y3pYWA%5nHIL{j;9dmcaU{*@}l1i1fbF-HD&(6I+spEHr?l5 z6XUR+=CRY)I%wupKQI4-`6@A*Z2p1C5}Q+EOD4Yb@LB`10Ghl=YqM}RO`lWgijdXcY?-_PlpTe z5*pPp$8~kOI0r-}EJwDCeZBX!`~Vja_Xl`%VEZe$l0N#Q`pQFV5Kk9_nkJD}iNtEl z0C^Kr-ATPgZ(oeg!%ExcVXg|I_d=BoM=ZHAT`5PDZJr04Ur3RdN~zCSJui+P?cOm? zZ_4uvSbO6q9^3ohA?X&NT{--uRs)j1^n_QP0Q$3&rxFIzTz7O`nX?jRXhg1DeB#5) z(GfV1DF?0?JQ|Qk@MriD8NQBaWeKv2Q%Q{4hBkh-u_vne>zF%J~@`u;J25*=?$ zdhu8F1#*^Vel)g8@`n!4w}b9O5MZ9mGr6l(IoOWq9%{A1u0kLk75}< z&VTouJCQe<1WILdAsGA2MManwFz@+UBd8q0t~Z?>7i9wlMSc4rIngyRBL7^uYc7hA zBHUFVhg$Uoyx@ss=>vt^E5y7o;$7KRvv{t|CpAnB&qk`W5$c_mfC9N(b79uh8{1b@ z`%f{Lmb-*Z{$${zz}Myib@*kI7yMEizc6;Irq>h1)$KEnLBTf!E}{B15VVoV)p+aT z76}rh#zlkeIT-ez_6b@mR`!5_WT}T{kciOQ8yX_<@OT6_PmxrmJyWnWqxT>-Aho3b*pIl1(z(06k|pbILiK8h1e<%dkjsXB~8Vf{m4 z;ClZn{kzSkl4$w-j^Qx`(3BIce`g>_bgmJy8*cgJ=8Ty6LZs*o(tJ?TUi$1Et5WlE zPm1hE>IZ@-G>o3sf#8sEAr@8W4+aYgQTPkDDhUV$hNQpvpEmwC*qRWQY}4A92_0DZ zmPs>)&dZ8l5)X-zicS159QB4{Zwz=3=NVHv+vF*NB9 z1yz|msvE4PVio9vx4?D z{ZQdbB!aR@k>T3)149tjYac!k9CIDV$2WZDZLI0o-b>X4G9HSuePIX}6fDMrw_{k4w^WTJKctikHje-7u zn7gF^^f9vkrII_IBPZA9zyVn%O~I^a3h^!RY1?E;v_(46klc%M2I=TV%+aGbx1n_|{GwNit$QzspH)ZRKc+9Ky0a-Mj~~W; z9=1QW{@mQWZ0CL4h$4e)g#u@U;Tecj_=E}U`TnGM7>o{0dU4MT*|8>hhQ`?UB!zFB>>~9<{V@O>aC9U~Une3IWIR5R z_5_;sDvxI0ns0l_QeF?}X5QNM`1(*9drDI7dr~8llWtCKyo`HdZv%?+Yo+%2`Fb=5 zKSVr%FvKu>!KA)Y5&sPD zuJbS|=5`k){vruC`iTofuv9tp)kTGFd-$o@dfQ&XgVVImF;1#Xx#`I3vul#F$qWYb z%LOU(SbQDVH4RnT>9}Wa7hO`?yKvd%M<7B)^-9gvI0d9NpIMkS zRT00KAyowFDZ=SlDLo`s`r?978R0T>hJCU9`HXoWFBuyu7Ifhz-OU9hFUQuonGfWr zokmWPK)otgYn@!v?`Dtcubl8K1%*k2j$mrp>~SkW z=^_So$+T1|P2fC#QyVCNlVUHq?y@pBngYPoosbeTuE5F>N&Y)$kL=WDpkyH~cO!1J zMU8RHS*10ceS^H7l>?Ax-ySAEq;fFak>8M}foyYCs-;Rmzg$T;k1$Bi^ZQD=+=cv~ zbPGjC8@KD2%G>R7`kXxj(wO;v?YYy^+8h$cQIphb3NS8{p_AkYO+3 z@r-QEvcg|3shClf+$g=3b_M|nrQ|lu+E$yX&=MQ;_k3cF{6!0wx6Dg;;-oBc9EN>k zD#NH0R)&||qCZOZwIv9erOFWBUabK&8^iW^&#Oat0LxZ=F3cTrBau=&v4cK^>5k@gj#zWtyXj%YL_X!h>bYx@JNuVPpBwJE56w;HXl zZ1;k@d>8+2?a%T+rZv`KSlm|ckXJH62?JJAR z7ldHyEgPiZ7!yX$7!&3vTs-Y7hkx;Id(DrB6cEMyABU(*M((X7YWt-L#i`S$!5}fl zC#oXNEBbfMF4HSLYC0$tY1Q-u&Ykz7^Eumbt#?%(T*Y>yC7L`~p}oAkt~tH*7e4Q& z$EWB(at2C8c9em~sOw`1CvA#}IOF9Z2~%FBmb4G8IYeC!Dm&P!zH#Jna-NO;Qd{(7 zATVoYNg}*h`Jn02H$^WRu1L+psWjwYMr~!BZZ{afjMr|Rh^JQYjck*m8ZE0?)~vqw zSAykMDOKwNT}~IGR-3e435!bEmBPlvKn{**+>sru9y;ynv+RdQX`cNo_%uiQyM~gY zkNXTcZ~J38fc(I+Tg@T>ta#K|CyTKv73iu?Y3>J!+07C?lcTyZWvw|?(w33jJN{5- zynWxvFsqw231<32Aj^xVe zS{qBm^{P2re~|C%4rPHF|F>PqE#D4Gqy(PQqW(YSb36aV+ngr7;Z^rsa`1CFOVGl|5mBdB0*q*?%XBXPjPm^A~cwh}`D~ z?6gO&d^<6m>+l5?;>v6BSph|=1uthK(GEITC3RddQQ6I%I8e=$ZwLj#N5a1>8ivCg zc9PxY9k%zK80_2>^XcdCV4!Dqbplas_v^F62wKZCbfyb7Wbkyg+t5R?jVp_p=87)rAsVG;p?@}0DhfjF2KY=ur_sDRN5Z@ zBoczZ8+*l`4CNsWF7`5M9V-hSSKJz^0xO62%BvUldB37t{XX4Ba8~4nB7(_iRUV7C zZ;UVO848`?$wGFpL>#F1+QXS!7Eecu#h!577tuSg z6^-(>A_N+VK1MVMP=Fhb(cBTDWU#U9m4gz0I*3`Ekeu#d_-kiPg!qv3`67kym=Gc@ z4AmeEJ6{D5GT9l)0Nt?D)UZ!J6$_sfK%VCX&4dy{lH3oNgOFQ2La|}=(_+;?BPZhJ zbklwJ?_h@!#;1t8lY{2DbWMd63lRBe~A zUI018Hx{L;2 zP!4pmu_b}ynHxga0}8?m18nj=$kLnve9s^Ie^-H@{|7@7h%5N$^Is(t_dm!303><- zFJ^N8IbO0tDI&&}NbSz6da0ByoGx4z$_S2h1eJKQLn#puSq70^es*d-_l4(XJ#*_n zK*J}P(truL6NXuaq7uz`1IeN|p&1V&u2eyhN#=m1r|%dhlWusBQB&9Kj?1K#Hhvs^ z-dw2ubqArME!@rtqD~^LMn}(jgSFkP6{lq?QJpdKZ;mfckF6(uBjSn{+8(#`kG@;n zm3xcjQ0qycjaDG+MetaBT!=+z$|gzdx#dMIAswr_Th_kYiKDKk!&_UmUaRf(O6SR6 zzMcwVclitdu{K&Gt?B%0$DH%Ka)m`JL6Z#Jpcu<41@jFbBz1!FpuJbOJ)Z8kHKT}Q z_!}IRR?c>0&Nt&Qj;h!jwPEdQD`+lYT-#aWIWB5Cq~_MoaCWl~Jf%0pW3b z-Ku(nGC90fjj`rXh7Cc(Xf)$}yt?d+VM=r=6)FS@`OQ&6LV5%jY**8LDEo=q2-2;W zXLFz5Yj$C0KPF35%Za62bizyq5V&Un=D1ejqYy`jNUkEZx`7gG{jZU)SoHqE-`bUo zsxgy5URx|pOM9qlM|Bp2^+Otw#8?sx1ynFD)OACtwIT+Y1B}#snwfkd`ZNWUuZ1Dg z3J5J&JYAt6fN_#GTqdGv#wb8&nj)t%)0R_2(EHvf6Pta)r*dD@@=u{net~%WnTTt@ zjak199mId#cZ9@4m$bZo{wloNngnd}jm87j!n|hi9Gq)eq)1}J2NY6a=#-LWMACKc?Fn0eJgkvFVwzHPJSCda^P{jTCuDdIo7gYl<=sY)}+_Q3T%^*<8y46+?f*t zH^<~z8%7i-y{g&sZx`Wx(?%_9eB=1?F3Q=~ZWpcXS2{)%Z9?Cz?VlQHnd}xq*zI2y zC9dbVFHaskv)NGv?a~q}@_}vlro>|<@v`XmF4Xxq2O;^%wnr{e?a?y4zMGVO?J%x^ zqr6{Bq#9Sdib%!nZ>kG=6?f%d7)P_OZ)Dq)iWU>+(HwnZ2ea?AwD@Sgm6u&|?0uVx zHxW#~O1#4B=U!!E>x~yKjHM?d#H@c!rP-Zxm{VDkNw8W`WrERLYXUVKYIYoFqPj*A zFD}v?HkI1j_Hx{o@ika5m+~!ax#-9xYI>XIWkO7@)a8b3_C=V??O4fZ7soW&yvXmK z-Ps1%D+Tf_>unWrYEhe=B?nJ0+0j#f@%V`N7WrAJ=nVTZJE zu||VpNVe*I9}B7xo>6jqrpD3elbe=GMt4c$PzD=N*o1C^{TEqP{ol-`R~MW*V!kQ% zn+%OSPE%}dn?Wye?nKP0-xm5TJ80J_9&2daEWBpADhIPefDBt{al>tbKt)<2snTIu zZ=8K+!iMD>YoHCf*0G)b%;7n6H#1R~!v@As4^5D1lst)5TM3#`b+OnbI8 ze2bnPSnwdjYL}M91Q_*VgiH&E$IwTZ8S_za4*+yAgj5BfnG{is4=6UmO(6JZKUR5SgyC~B8+P%s38NFVIE@Q6rfXPzmilun?o|)VM7f+` zBdcF#M3FbOR$Q@j4_G#;NQenj3gRkK>d0ZD3{BN3G>@?AF2^t#o1j%e<=&-KcS+6# zm6Eq30rjfpO$--s?Bj7Y=s=H~<(V?^04ns*QVD^CIxlO0hb~rThyP*JH%;Os3o-J4%j@DjkQ* zLeNu35%fvejsqOEvSa^M)%+~Sb>V1HspK+y1Fw_zI1{Y*=POV}KhLx<6ibQ~4s47T z9GzXb!%Psmx}s#;glavT22gg7+Otqq7wiTH1hgtBRnI*GQ#>D9U4?Q(U=8Ef&r_)N z0=gyY`$sC*AdM`2lT31sy!%Z?Ys5TOU?=+5bRrov=-JL8B#s+Yvyd!I7ej~T!?yqB z0G*_hL^v2o@bg96In$!D)){V8(7HmoIrS38vkt=Hk`(G)a-;#YyjiDcdB0a)e+l(c zZm;JipJkXo>r!!n|Drb)#WeSzW$q%|2m4c~$7Z)uqb+w8Cuw%9_w^&^?xo*ck_nj3 z@uxkG#F&A0mw=OGT>nKcYT1XP=j~}ze zn><9CpZC;te(7Psr&pm%h}d%@$tGvUmk74-*flv?d+qOAVh6;i))(ag1T^!K6{7w~ue z!|EGUtV7CwfxW&=hxs>+K1hz!@B+U!ly3QxjW>KHQcY2c$WirWOqv|mZz>>sCYc8( zb%Zcz*FDj9+sw}1&G{$)chro>?Mq@q&LmDOu;2mtO(FN?UjNt5^ovxp;t5fo@QHzU z;@Re6YR|x?3ORQ%4G;Mm9#`^!7H|`;Xumbak->7ftC1n_fQOOC(Y%4vPXoHvvjLG> zc8D~=@;n6U(W)GDu&xX|!V_A-YIzVVtZDOu0=ci9mBwRhz zFqbia8@GeR7L*&w&8f2`d^!*4v5n9uA^pY1j~onD8Uz=Xti(&Y5Vt=jP7-gF6G4=5qf>o$TuBF<{bDQW z0b?DoR%bxUoO?s<1AS5!>{}@}*5I}_zrca*l2lfIwAeWp8$3sC3 ztEe~-=&EHrxI++EdY}cv7fZKqiMa;iYSBl>2Oym1mZ4f5e0y;F2GSZMs^!hUS$x*a z2x9lgyVN0Mf+2;s^Orv`y{3ztYA$?w2dJ!1D4*;^h;JGzMmFu3ry}jIu)6VTR`}{ypXCA07t@KT>O#Gs%@vd7>me@^RA7eN=#Q>CzXb-L%&MZzWdOV}12D8!Qm# z!NxL)Cak9k8f)TR!7r3e|{Z$-S|MS9FN8DrR3$qkh}! z<`ucgSNcmAQP!FnVJ+dIMQmR>##46@b&ruT(WY`9yt%YXg3x?K^J#|)6Kj>n_;2)0 zm3y_Qk*;Ud)nT%?iqrJm(>i>`eX-3+%cjK$o3rJfDbTKEad5T1T|O7#9NrqHu~rmt zN#ozS^(SDrA zsv(RB8@C1~R?f8Zekms{TPVD5IM3Z5td7{^#dnE0>oo=gjzot0pc|W2-CS6Sq_xY2 zKMDYyz&m62bzH&UjDIx#Y3dY%4v<=hB-68UFkV`UdO2n=$ z#L&BUcq-2)V8}*ybjF?kFjFJjt1T<@KGe!$-^(q=N1LgKCHaX=4v=|7;o~<0rzSEhRMu+*`oOKW z5?SX<;N?sF@l6-Kc}=7kTvS>_d~#^UkwD#!5W!16`VLA}O#fomaSk+2EKlne)J(XWzpHxYn7?p-1nR=c# zTBjb)7n*)FYNEN|o3!YkmYQ&hI$^e|!bc*!!0>rekNz!DNYZ#$6A^S^LvoH_P$Rlp7@a zv#OyyvAiwaMX5Am9pv?V@u_5A0mA!KU|3&r8 zpROC7?dY#2mr0fJZOR46^c1;}+FVaQ9q~Ysb}-iX@Fj05!hZBw3NZdz=k&|W(w7ht zbW%mADXI^t)}f#^V80V&k3;4+rO}GH9b8#W9#VgsSAjF*maJdH`dPzgJo81_2Xj6B zJ?M*!zA#+fIE5N^f$!-N9dpW~a%ubr zd_d2GxJYsVk4Ts)vAZiCi+n{SDW=MO5zSQ=ui$AD&S~!p9(aku@VF^KE&Dp%D0f|I?$O6l|8FC5g+$-iz8m9mo|L&C8{W5`2ds*u}tmk?Njg-NH$ zuYOT^Z6+X4k3hP4;z6TETdvNR=lR#Nrl9yIl_xy=)8Zrf?T?DGarFi;1Ez}5*}eDF z*k0GJ++IymAM%H#tFlzTmafY98Ox-XcLSY8SwvFPht`ItUu$z4q86N?zTuX>LiAb= zlK=f#yCxc&orpOyjF0y`XPSLU#kcRfrbv8KNQJvbMg)Z051D(nq^I#O+N~k_rE3^b z7d~@V=<*_xEmBf5X;pk)FMi%&)Db#b=!dc5kMQgRc5;-gb;nNfstPyH)^Ix8@L!5{ zlF1VP3$6U7zVU~d<_qiWn#c2qxq?4l>5EY05pwrj9OV5a;9Pd1I5*(JJPX!(wjzNZ ztk+_oHW*koHw&sj%v}q8^&1R8`YYHU@|{TOdBLH70I};=UY@EUkS01XT#dOHO5)we zAg~vu^3FrMVKr&i1H#u2m-wJuqWB1}w_x5H(JExSxDp4Qq{9U}k>OtiWp+5U@H6vL zBilZ%XL1Ifs^Mk%ad$;&xX#5S+!T>@H@Oek$1*TUQ21Cg<@w+eVAbh%`sIUJ;&s28 z&b|j-P)*TP#fmBIGS^y9D=0=;SE@SUw34e=<)|rOh7_X)eQ7I@l7#=2=zL~?Q_zyY-NH*)p__8 zXl=T?l&$Mk;T~zeH{2`IHP5}e<7FBv*>4~b*qco{T4Fe{QmTwndm8vgt**DfC7CYj^x4(3e#4BnUZyCm>k zsypku(lIZ7|KRtdLkDg0(`D|@fP#}ehZPFpUFrPB%_3QBQU4Pv^DH7{W{U;8ceoPy zV~^F5{ZZp<93x z9h#!%4@8_||RJ`FEIb~EFW}a)A)E--&5iii? z%}-rwtJHPYM=>hb??##Q1)hIGlDOZ+-FDeHJ%>og3OCN~H?Z~H=Cn>dYeGTf&^G!HJ;=j{ObHef}gi_Ld zJJ5hmjNqRtez^0*hgfd>{R0Zxyw&rJ0*4)#u8s9yzg-C?d25;-n4+(`D1;FQ>!(sUC3!(_REC? zbP^_^zyPg9hK;2vAV8PR6|A__<*1qLq6$Eq8l4S6miweXq5?a-nHN^HdIY!f_-o@u zp>Y<5g14Q{Vq)T-cj+<(iSIn49(9+qkL2C3?9iuc1&4aE89IqL*f&6a^^zfQ!1XvI zfXQM>34_t9t82$vL;XRil9PbsK+TGPzDy#&S3cjbOdEm~NI6t9>84uAq4u_*#>l9q z>VI>bQwUr-2dEYXydv#&S)X**ktfYGV57CIm05Omhc}Jl(!cnjYr1cFV7GftkGncB z&Hn2ZS{d3RwD9IFW43<+gepDlSxb;sKMd4%92<=IMHrjqXOhMtmgBT~)AzY1_Q_Nj zw@j(JDHekRvv=jqG7SP@l9|N~)7YfFU*pUw<#ReCAH21<$J61cB~wM-4wnZuf?!x8 z&@&FDqPxuKW1#{Qs|nwITE(P<^g=KYP1JZt=8t1#dyQx~P)ChKLSV$ir527yem+}C z&!-)ct4_`<5j}3Z5e_5){UC0`%OIs5&V!TEOyxa5zGJiDegY_wdbk620d=Q*!#?^i z2(l5VjooD9Z%&w*U%NHIDy}RGVS6`mlYp4y-LVW1;yhH5ADCa|jvjb^77b)wd5-wz zEa)Y94>QRui~kZH!G|4I!~88=%0&5G0eO<-nmHrap#K1XR^grjSe|Z|icAjz75nrP zACVIcUvi7-|NNp!+-;Hwr2EQhS0&}q%-04`%he-MLZ%u)DE3(ue zxb}WfOasYLv|TI5YXcSpqy`fNgeG}+nlPF93JI91>1BvY--xvJTv2LSv#U(gM20pcy6m*!qT-REi98kj;igw`RKd( zC~Lj(W4oNOhm!qSdy9MN+v(nUxk~==dUOJzzjMH4O1xV@F(@m5V@h|b4a{J?WriGBkzCCt>v1AD;OO~ud zS+hiL*0B>p#vMeuS<-!EH+B=*GRP8IgoH@h#@K0WF;|rG%kOEr_vJO6f6jBx^PclP zbLRXpXXg8SK7qpH#M2sM(~zwCG;wtNyn?vMWGJEWiqBj0IAtfzk9VBXz_y~AHU6~9 zecjKYtN>+acdRx@uVVO?`NcJ&LhT1VM{@&HtRG3?=|2^Z60B~K*p@boc23}r-TbaD z!>XBP(u5m`S#SH_8J3gct?H5V^cvy_&#begx)Yl6h2xK*oRO@Z_Bk#4%g%EXE^a;b zkdlQ0F~ST`@j9*Ukp#&{yF1LU&!?+q4-voEIiw6U1cY^&#p3_)YP{yLY(Agqbw4*} z8(ZHtUQ70I_%0rD;mz}WmdC+0xKo3QFeYCmLt{d-lfmT;q-hFyBwF=F%k9>_`t!PruazqK8B3CmUW_dDa zB)FO$wiBn55}KS%KJ)C|1^w#z0|)Q6S9)z{ffONO7hcJN5)R|W9vdu zoyY?Fc{jh}d(4(E0)-LvT6x;Xw+t|wZ!NgmE6k&T#;PUpagBt@kH>C#&)1QC7t?o_ zAGL6{))=~`ebD+i!0lx%G|ZSqFsmA;M>fkEdtL1C89?>1IG+_kb(Cs5{gGC1!-(ON zM}(4=p|PQTfWwU^_usPnyyi7ADZw^bJ=~J+bw8SzTDySd=E@>hxg8&3{L`~}(y3Z% zTbEOv62Z1^`_1$_4C`-6(Z~G7_vh=SAG#x|65B2UCPq!?^i5{&D_Tm_eSWw1uIHig zn@TUk&u!KYG7rm4?ApX8yR0$1&ey!0O9w)5rKNLOWZR)+LC!X^mE!XjZypOQMFo== zmvnO_yf}T-26K4YI!MOfmLivK-8F#=<~6fxyZh< zDenbKj-#aen^9$u0nf~#{nX>NLw5e4-uETs@zK<|UKD6Yl2Ed0Icys!G>* z`dZe_AfCIqLx1P1+N6?X{7YMGtt7VEB{zz~#I=XoGkH}LvBRHap207-`iz$gn{&4{ zh&b+cohV1@otped*^G;Fg|p-3hRt5gX+$C`FV>nOxo6+yY`w>cwW2^NMP27@_Lw}y zeaVVqMbe^?%#osXsOgU-hFW-hvZ9_)GLOA;>wpBC`+#W8jq)h_D@5#SkY(|uF!^Be zvpDxpLH;k;0&3`IV|#nk1OM7EvmXh2`2Dis?iDd54f*uw}jI5THWNIpIqj#NNJ0^2-^Wl*XFz;=xU8n9fv&FLCRIMSj7Q{ZWQ@hZc50(s; z3m6Qr;uqSO66T^?IXs83+G)5t6Sk}PG{2s=Wk-sPcMR5+`7w%`ajV|Oy3(43TSu+C zM~-Zmxa(}^%;=3m237SDD%R~xy8}xO5~CNQrV)Ltrk&z;N6jZt9)3}| z@p0saOnkL#elg?UO_@Ig`wP$CW^}0K&8wf#eIy++_>C90jd2LruH+s%w`}ihw92os zil}cNBDANCIN?G$uC+&?1()6!CWQzL*!D=s5W4p6HKG=QYwh{gCf&{3AST zrcNN5Ph~ju9%GXq_H!sthKqWX%||#6QQ)I!eFR95MgKL%q5H-4IkR`d3zHeeKHiFy z(u>-81|;aIADIjbIk)%244uctVlG#1_LwwztihjJ%A5%KqOMyC2rvu|l#eN|91lN5 z=Nt%}c-$Ej=SrDJCxNO7n}28o!M0qw?(~+_vJ6vZYt6Tye z6T%7!VXP5SO7V$#{fL1jMC{}K@z(d_t)^>op*uwbQ*~aco^uJ0YYm$`n&-3CT0M4^ zFXv+7eDBVP03x6O-dE>vRE;nbk$iI7r0?Z}g>Ni#E!lJJj2W&fiz6x=Nh+D04r|@# zfX;@vAkD%`Z1>BilpnVOI0lkfdtaiv2ozv;#fqmZm`>4^9_7-NWrc7gB~{=VO0r|6 zi%rTpc9bR18A3{*7gMjq+3UOVpKWMM)QH+;&%Km}>K;^!mqB|X7TOYb9#>(mT>XWq4gBjFX0woPN(1n^o!XP zq~rFHG`l8OKHGr&=M^G~PMXO+(xsUFhg$FK8?}<)`m7;V2eyLo#pS zkX&aXT3)!$R%e?x&V7=z5>efncx|Ql+l*CJ5z3#j#p$}#Gqc4tP0QJgNXW1p`S}VFsL_g(d*5kcnN{R|e&8PrW zKTs&SOM>;#Ax#=6M1~6G&d35Z&T2GJkrEZ6pOpa)9IJjGsXzsSkdS{BB;hyeOv! zKFJJDEwaGMyunY48gwI|%#ti{pmXrs)Mit$ZQHhO+qP}J;Tzko*tRRSU9oMal2ljs=<)aX`hJabHP3$5o@<>0 z+y`6!4c0*S13}rfE2|m?1cU(-1cWwa-VZZH@dqxz8+{Dp8!E4*e5J^>D2lW|f-j0x zo<(~QnFNO1pI8`Gd=Dh1B^mL?ab$;(Lh-=8JXtcDpd5?J1y(UPr2%wU(aZOC<-9lL zfcxF*)xE2UIN)87z5VfIhVHN5;|_d+;QhP>h}{S&#GHB~#GGp3!G^1MJbr%lo)4`o zc_%nvPRltX1nccyRLGDVhDq}twP!iOEwD#^U`j(>W|X!^l(A2Bq}thVpjupbJb$tJs_GSbRy=NhT>;2vm1Jp_7P7}k!J11JV$6$a@ojwipW`qx8>vXJJ zJ?zdA<96Wd;j-7&y8wUZb`0vX<7W{%()c?7O2Z!-sp^ecl~$6a?0}R|mAP(@jFxjh zIhxOTBZ1C!Nb1X5dw}fW(aiP!kXA5QDScnJ7E8 zW{-~6^Pn2k&Fjj}2Ckjx{MvEXtEAXY>rYahfIyx>Hw5VZ;Rj7GOVwBeZnpy+Dv>P! zGjqds6s?W0{q=I8gany>eP?xNX%WZKX==PuvH9xy+WvMz8S6wDjx)_Zewge9Gq_0k zEAWR=HIJ|Z#=i8{dR{C6TMglt_Hv?R_Lr}FzoWzvzrxeTP*T{hrUn}X4n&;~;bm)n zhjTJA;7Z3(7NN6M_mgz4;=Ac5MkX47SN*K1*q|LqUH{umM_55_r&15}m{Drjev2>) zSD%5XQJ(QP3Kf{R!Uun#|9FREeI%^-Jz|lJy~g+~DJU z@}jhnz%n*4U3{jH#O4aLo;oZ~;-*?!?e`q^m&_*lUsR@Vuugr{mlw7#;AMPBJq!28 zFJVD=aoQsXXU9xeE7pV7LVn#q{p!VZ3%Y7}jE47Oc_kZjN{$2I_Ih`Hid_gb!z77k zLEPp?R;<|(jHShvV>3q;6{-VZbkCCwhse5}9x5_xyKM(xnjv^V-XBsASA(EHumh^r zu4uRPY+C7=BU8QW{OGSZAfm^B!Ait0-jY>*sG>$R-+;7@n-8id2AU2mHkJf0=Ox7L z3wA>N`?)k>o~;OBOg*l9-c&2Ax>sd#(g1YY--PWe-tT@R^ihOGFOUaF!s{7t|8@Ch z_a_pXzZ3hE9!TK$1W#azp-gEOQ-WuU#0`utpn2;A8trA^l6q$YQF51^@s+gh=n(ox zoxo50I#y^dUD+qqZWwdRChW+6_RmN-hX4{Bk=n^oC1Z8WWcqd|_FqA#1Txzjttspk z$qnVX*9wL95^mN zFaghCQlK}=ONlTTi^uzFqhx1MtD@5q52vJ+NFxQ!u7FgleEERVM{9Q0KxyV+k(#!U zjP{AHSQz$~(Idp)Q>buZc_HZTh*;6r2LVj?1C+I;u46gWXMuJCdyY<=&+h zm4(^0&>UeXB@WOkTUHnuLdRJ}V^~#YwH&^#l%E<;i*sXUO>N1{m4ma@FJx=_#Nw;< z>DuvrnXPe9bTKX@WWBobWN|7oK=)Lm*uH{jQz)jjk}-j>shi7zn|@FwV-hX@U0v25h!EE-T`2>;fbnoybY~s9BLR+`KF%Q zDzbQ>Qv(mtg1L{<#PeylU~f84G=c~OVgw9kph^bB%mbG$j0Gi*<7%^`biLCi$6A3Ua2o<@&WZB%x_Qab`4f8RYu2zo&RGMRxDj1!RG($dfM3s(BZguTy zLQ~Oa_37Ex6x&lHa@^$nGLNS@^H2-MXqXBgn+7g$+NPHtFwcLI4Xtep*>ku19Ga^p zp#I$0_;mELs}quj#0<%t{k44%{7sS|V3?G1-3ZXqJ$R|-W>adjIc-=-Eg~5@2km53 z@Xnl(UkDbZjcc2EDxRKDmzlg3g;+`NXn<32Cs&Gr8M9>iNKNBkYED;3NV$c>%@2(7 zGuZSz;-4HW^C9IKoKie9{tDcJelMU3LgIin!vgno;{>zF^|F}Zn0+;$q2u1o;iwNQ z*ah^oyIql#CiRE(k02Ch-UkgWPBjjbKsFW>pRn$MumX$j zqFLTNU8r{i;*{D$hD+hOUa3_r7*l8 zv!m^zk9RI`jl^J^vt>t_yJad>q#1C=@BvNJ3MPiI931*tyGN(dfE8@a@$)+PFz%6ktHtd^7EFEspL&_D^Xzo&X6_DQ78wf zz1psXF}CZ($`6(2F%C09Pw5W0$pQWGyoi+#B$=AsBzZ;_@JF(*yWu_ba8?#NS)qv3 zq)8|X$tO8<*Cm-6pLzt=@HH~~Whyl@SnX7DTU)W*f~rdggk(W%Z<}b!YT6ltALyJV z&W{eSCYIj#IUky_2kCU`3+UF0CXWJ{R8hft0T~UY^%aGF@Oo1BC3Im`#{kkc7=7sS z8CyJwKM+!`5Ng(Bjw7C=YqBjR4pZ2q^G&dX1t1Bk9B9@gNUD)hE_4oC1LkMMj*Bml z!1|Cs$=oA49A5dB(J*y(pS)A`;qu&G&y}CmAx;G$aS6rh0|Wz#;j$XWiYE!A`t z-nl(heIYdB4%$A?#G8lH%12=MhxWT30nM>+I;h~}7?yr1=LE_C8i57|Wo6{sNQ^>; z76_DvAknlKbXXCYyWKW}OVJIAO$mR9f1kA z`gr)*`~ttfA25CqYm&2*ElP{2i^7qjnqohhLcekYd2ZllD!}7e;-T;lQF}5|iT6py z$l_@r6W(PRz>DAk+cMkZ60X498M-8S!#MJ%S_YjdN(}{_^tcey;R#>;6?L~{leV>u zPbWCJT!zM&*IJeiG+#{cHEvY+ z+Lzy+60#``hEJ4SM{BO+Om>~)RW=p6jE0QoZkC2X1^f$hGAhP8_=LV(#|^Z~1k`J`5Y4{&kph&!7&$xsda&#_|163LJY#sev-!dySjv~soVP|ZwnwS8hqE7eW=?jZIr zi|q0V2R4CbUK!WWlN?7FFNm=IV8vl((EGk<62$xUXcUio))$cnA|RzW;>9U(Bnp6*3SvPm@L)RUplH%j@jDW74248VZ*?j*TrNov+S$c>Dg~fOE1Sik8ABjAeJthLGdbJHnAQl>~+P~ z#8EO}Y7Or4mzgHx>OH=BF}4#ZoI}bJDIC?5J}a%Y(U;mvo%ZW1r2&8f2;ee-6!*6Q zFsae|^`2GCb)p)TzZ{-!^I1Vp@Gyr_M=`Yr)@w?iR~9Kw1~6sAY<}DOF4BFc>oH<+*sWy5S1`mn zF_U-HR381t#PQ`v5doZKTAbNU&Q!FVsUhGIj1!oSU@eSlp5BJPTk$s@L7bUstn`sLU5{#Kyg$T}jmaPaIaQUY)z>ik7Gtj+=Nj;AU=gg&6F~`6+*>>bh zaKRIBVV{_t+a0vt?L;AJae1#NN3)b4T4J^{&oTSdK$>TA&jL2srV0Bw&K~20G=K|j zcmh{_ur7h{M7$gy0P9R^qHnt{2bc55gi`-njR>CF3==d!!^0k-~D{^(9K>;EN-H(QO zcZVNtB+4?UGKW*dGw=#54>WJ8zmpFY%WPBA)rS~ zPf*sTprcOzJg7evUSu! zamXo{%o5}g-xEvC$qkF|h4Yc;6zl5`G@*CeNRuDYY_Il}tj5jasMb`Qx$ZH!@Y3k6 z+vHg^XC|{@Ma$u!yS5RwTtFrB_OZi>IH14e>hHj(Hr+h7{XhjbX zmagNjzDdLH2|so87G^T9=ht^OPok%n@-B7JZd+EBohHA~h|rvTnJWJ-cH5wU9a3e0 zvh1;5>}1vXA)efRhiI*5y=m#|(c|RZ5MCv^G^Vm~bPhcT-P#6llM1*B)Q=|}n#G%- z`-^P3y#>dghcZ-yeS&?^yJeObqdBxnZ6z*>=yfI!cY~2T5*cEWyWcUED2Q2p@DKoz z^OkzZ20>xZGW_|beg{&(M*r^H<#dy|iqOg^qS$Jzp;gQ?*iK&xyqwoSNqVV9;-wY>Bspr8Ti;34;h$o4MC1^b+y{g*55ZzjeWc6f)u8Ng9YEkK>jNC-{Gs}VJgcq(_Z-0ggT3-5t0G)sPE93~qXib;- z5LBi{NKsUJY%s)ymtC2A6uR|VkQQsmlZ8kUrOP}~K7(I=^oSkGxQw1GjA0^MV%;%L z0MBEeSY!ch`*juR$+7!jxlX!YaQFf2)qaVx6X=@~yOIY|;Q7Tu&urcxOemAGWQ(_% z&%;!GQtn8uG%}mcAx~*me%RC!O0xY2>NJ^*f>P#Kp-eBx45d;fTDndGZeXa&yJQ*0 za^P$+D(OSmdXmuwlJN$mZO$v0QWU^gG(CY-0dir%z;;(1zsS?Q1AKQj86wg$o7 ztaYCK?g)FeF_ehxGfp3bBUXIuApba`PhLixgH}sI7BA?5T!650fhsDPJussQVzT~L zP5z4y@!x}?g|=E(0Tcw}790dbGQ|XgAO(pKDn<8@0#K@EpoAuZF5va2QMp}pDk7RR zQo~vV)0?F%tU^IPdpV&b?6r{KV$U;U+A#_+^7mH^Q|6no{|gb${o(8lWT=GQf!OKn z7SHRJpQ4oz;O`yEFG^0h1{E6PX?mV5jwt~=Im%x9VoS4;QCgDzQhy8wG}fsV1JO1V zcM6lDQh@)v|NL%>uhf-KE=_w#{GDgG=1DGP^8y_P>Ioics)A5zUA;TspE3o<7$qF=&{j!*nQi@J1H*qy&fRj5}9W1>v(;&Vb7tAwk0(9 zX1sh-ItRzL-7*><-FadFS0C!q8K!i%5?|hQ67tW-8Q|}R+f@|t;Ic$CbWHI!seIY3 zIe^OgvEl}gt)2MvJ z;gtLYk>PVo4kG_^Iw>~XrqR+p-OR`089eK{vweJqASd7@vpFlX(jNH;^z~{Ws{A6+fmmO=-OL;THV; zus@QT@>O?g;0>5_oN7s6A7PvE~9pb-ae#N05e%sWJJtWYNI&ELSq4mldQ2=9# z`vU(jc>Y(av-6N3Ae1N|AOimb-s~ZM${Za5pr%El7L$$7&vy&yFYxq@%bWY6mo25l0o3OGDC2c!%j@--0`U3x+zz69A0F$wMN$02 zORhsol7=%CP5jV;jLF3iwdX9hOGcD6I_cCYPwEqhIezA^T%Q<77F`*0GiNr`~`L^B*Mo>e6ZO63)@J@Fqo>rU@%4g zBQ>m?f}iZCwpg7>R&Sj{rVPv+iupA-bbx1enWI+;``7|Oa603ZVjH;wL(-z&0Znn~ z5H9}mw0MTe1(!`*@n#Iwq7e=93k5VifES@sNo*bC9=`!3ii(saI8k~MU(3w{W)7{j zUX%$8JUix+_eX&S!K$iFTT_!=GiOa}i2>Qlq6IhOcG@ehjGEgLCyOEfv2W?$yv1pA zIb$!pW<8rs;3lQ>&p@Cd-A&~|d{)*yLI7wXBAv);-Uzk8`9NG(Ky@37L}C>qfUd6e zgMD-F76jWB3f@)Y8FvYnC7_nl=kLP-EIK8{+(i0@Bh^x9*Ey`dUcv1SFbl|8Wbv+X z+>Dkf5qZzB{ae|1+de+rvRmLoGeaFkTUW>|t2w31FZASyo~G8RV~8!DIzpA#uX0+B zXHtKPVE(#Qq>@_9kejW*=R5@qa7|1{-a~8>5rzd3_~-AbzRQ(`p<%kc!Q>RHp{|e4 z>=bO>kc~5O#H+3iU!9SYvvKvKb2bkFx_(qz&lP%RPW6rF=4zWu)Z>aAEaQj;Y>~C* zd`Ky5dZEUEtA5d*WDQDWo^GBzYRzxlwa^Miq`Dkc_xcY5)mpuSg>3PXOZ9jr@1l63yCA+^HtdWt8pJ@|jO!LFGFVy}u}e z`9~i8`sn_Hh=0)wWZv|J88rD}5%(K@m0GQ%LFkt2%%nt~pa*fxR4_oZ&z6)y*p{zV zRUn*J)hw+z%(U9$zKy`?{&d8xow>zdcD6xKtAXOU=+D5)B){w~17M;fWPpO18Wz$F zPpfrhxkK^mad29hK&^B(9#oyT-bQm*N)ngJ+l_Z0NGuDw{ zp-TM`@@k|JAodN{0HDOHmUqiSZjMZv*}sq(&f21cTnsw7^9vEr-tqJd5DV08SVD{1 zDi$GWtahLiXqnw(&tZ%5tDgmLru-2(yb4vjZ(qv5W3bNpeGw|#&y9OFCXZ9)J-kpE zU7p*%^z+d(+ha%34Ov~uopAsIdP(*$g;)#4oa*b1rnr}r77$-V?h9Y~C56Hp(qw%F zJ-9GRmRO`9g&Z|YW&CcEAca>8NAkmzX>yoQJ$j8rsV5k>5eX~uOPh3OcqOcP@HE!W znPD$aTWvp2dkyt=_;I>RMQkU?8!MSxIJ-YV*9F<(K+HWl zfgi3a;9LjJw*hu7#j*MvUvvTj?%W@Y7tDdn`!|@JbUr(@HCM^e?U%fAWYDIa&pXU9bBOn4OH)GDN@ z!C859;_}Q9pQ>Btil0}X`c44zc{qF2d0_zX_hEycusnBiKQCvX`r0HMy7gwSAF$ZS zf4Z#M1i(MwK8bchM%z_W2mBH^kcy2gXpsAiRk?@jO%5D#x#tT+1?*|L3_fb5`ZvWq zwB;P=M;{(_5>Bem&Y=Y(Z8m_}xu_*Vz#+%y9Z{{#P^mEPr}wM4p+l^Ba! z^ZK?EMLCCHGQ9UQ=|*cl&?WM3mGivfZtrv-tEkKkF~T?3@IW)kyU>5Lj(oVUsPtcx z_4F_A`2Q#Cc#iM@d1($xOUmeDf4%UwS21vCBNODsH^7<@l1M6GW+SkvvW=Msw6IpE zvu`k+_=@i1oSv56L{YwJaQt!9grhmvmP9@*uZn_1YHeMI>_XmPyjwHu}yYeQF zQ_0X$d+18Ra;isQFq1C8Dugvb=j^7A;-)T z8Kw>?m8MpJmwyhH10(K;hEnpTs$(9>q=neA*AeB=PclT})o$W0;XjvwlPGlY>qu$5 z%)3zAuD1jy#z8G)yz+!myes)LwIeKJcV+cauP-!z^ibZFRWn$Jj$HJypESxTxMs%E ze>(K3yoRkWh{Z1(r;RdLwaI*MJ@*htv`fr3Y+B?*Tk zPDkcp8W}1Y(Fcpzh&?}(5E+Ov{KJUC0zOyyw!#U|cpQBM6$~RJmDIz_zt>A?e1Af~ z|6Cl#{$l=BDx%hbDN2}Z!EU`yxISBGo=t!u;mK*g=+u*3cL+3ENWIM}%?^ecw&te5 zW_gC7GXcN&qcMoFNQF+E_xAt!FLiJ^!K!~m5C0?j|8;M>92CSQE(aatshs+g6eTnY z+j75!X?mS$FeESvi6JCto$$s|$T=AR!@b<75zp6Sfx(qnco*g)2L$0em0$*S%hbZ z`hR{Vo>@$__3*(XJr3L%zu&`(nXgo;G|8N=TXR&Gd5=~jJiw>ohjP*CYcIY4@=&rE z#Xct5tax4~5wZGoHx3C$T0J&7M{Gm8>ts5@f6=@3W}O+RDSWrtCR6kTzz-?+Jw^AQ zghRGphBr~sclWV>=aNiI7*K9ul%#XN0L_Sy$>YiW`mqe0N2Qjo%HtZJGoAims7@)$ zVV`7E#JR7X+f-JNM5O|kGMDB732L~GrrHBNKs{~ch6)pyDR{TwteT!X`9@2aHM;hy zz)X{d485vt%S>Lv)4<+}VBK;W9_yDArFAvn1fa4uq#NFBz%4(=Va{dR6{#y12G{=r zw|<4N=N`QNPIBsV%3PzXvTM0=e~VduZDwX>o`Fzcv^N#4``PH`*2NCcyi@AwT4&G9 zm|QqlDoM1640-GiR+*aX{SbyyNP-J8gwrG&2ECNMNaZ=;{(?ag;EJ`c^sO_m6WvU& z&KW{JWfJLc6TN_=I|p{1w+xMP3IYFTI>ua1UA^EfWIRHwk9uU_fq;KOET5Y30Cfb1 zk?ipC>Sui%?L`3!WtAX6cY{lOm!ucULQR)dG;3^!tTW=R%&CfK(}|8lW8zmCve^`iz7gS6@&q+I{Bt&^)2la;H9xqXTQ2Fm}r=k9Vqrd)7KLHr%9Fp6vDyI_5UvX;1dCZ4Zv>} z$ryCl=d0hZ1NyKUXwe#Ps)wBY*-M@Z=iYd)UZvQHuDZ1>wM;%h{+pgbM z)wWWm6In6A*7gjrvMBF64|94eJB^eNp6T@<>=JdtS@E8V!;aO+YJd^DfZO#Nj2wE6RN-CJ?_k8a;F8f z02oeQBD8u)&aFG<5~D*;8i7#oOmpg9UV#=Hc*jdM$QC3g*sfMlW@m?O*WxO5{6cd3 zX`ejZ3ysbJ4C^osr=4^_<}DyInJB!z@Tf3ms3<=>a}YcWQyM(IagxaqV5^+3PRm0S zETO@Ck9QOso5yG%6F3H6>UM8A{s|Z|+TQZKdP_YYw=42PI*Tz6EO+ZmT3cr0cyVA^y%#9?eYNQ2o-rbVekn1#E|tto40;x zKcvM&tt1g8<&8v4kVLh!d^QxbXF|0dDGpU)vO-C0#it~lciKZ0=teFhq38x5LHsW3 zmVFmKm-vu)H3_ccBrwtdF@;CkT(u*-lG9TC+)?U`%n}V%SHy4%WbPm557IYD&Mb8X(*P4x^A(SGZECio_ z*s4!Y947&NIu%xz8-5lJC+fEw@NF3@KZF}VwjNyT!HaQhw&u6R177I=cCNcov*|zL z4sKxdF&uJN0--#AC2sH_I?UBZ^j&k(?JP9jNu0gIORjh@^dCeLH$b;*K7N*MJdO03 zWg(1l!uXMI1#Dbp-GNQb85mVg|Kuo&%$_~6i#QO^jCanlgwna0MXz!njj2i_|HJs} z_=PkI8Q(iln)~HJ3Lw0pE`T1Vr8Mlqf1NhU=NF+#M(tAP-M(s9~Q+LW5xZ)iOJ z1(#je@5p6<(pG|a2{2uPbr}1k+3|h7!c&*6_haZcaoBWik=N?>@fi;aP7S7@xAUHE z*hn#x0M}eWpyz53`!jsehk_=6+;mtHtYVJ6*#Bs${WS;Y4k*=@q6a2jE}Ldvd@0RS zxX`!b5Q@(M9e0b9np0*xXq zOmUzs5|0}@2Q>f4|3$1sI>jOXD0tKvk4p3lRY@W&oln6`bg?^p6J>&7izET9lOlGX zab=n`!tbc^C|HpyPT>Uu^0LO)H)a$kVN8djN0gI8?-Sf1KJfI+?yp3OdW5L%Xo^b` zM-xA0ssWRA8Cb_r!LI=Mg}x9d6v2pyq`XmuCbQIADUu&UM+(y3T?u70KO-A&|4XT{ zLZAkCO1+p6VAp9;8U0(41|7~VXmgnd1BDA4Z>1L}mJ(G#e%vx-V`ztQzJc+0b<0!o zFO`x1!Z6fdkiXQ2oeVkK#3I=(r&9fodAGTn-`|gqSV3Sd4(2M&Nn#8MW1JV>rY2*e zp^1L`GEBZQfJHdqpb+Nd(mlJ4WVxXMC9@+r12TU!qw#5sgwj-wc}Q4jdCPPT{ETF?@Uj>Nt8%IAvk(o0faQv<++d z^?{2ephHKDBrzhm2lOkIhqLVJ^fhW2TD{@?xA_z1IGCgR-Mf!ATb5BBTW z<>EuEG9#_MtNM2?NFkdi`!x|invBmdf}BIi01*t0GdJHs_i+SZoI-BAG8E|ROq3vP z)j<=o%JEUO_Grn7S~%HV8Wa8z@6Wh1y7J9Q!l>En-QgU_Xmy8*^8Q#kxl~)->TA(v zef4ykvNXkEO(it9N^k|u9A#!R=ozZMO&PvT-a!#AIvk@yg9>dq<99g@HJO}R_J^FC zBn${l$A3ZpONaA}Hp2G5WVV9>0TKG2WM-Dsf=RQmWE$xFjS!((M_MX8>^?*%zX2k@Xy$a~*t`>n;%zt)IZVEq<~ z$RxOMPxD>j_Q8hmw|rme{S85It?&?zz~@bM$b^9G{?s3TV8Q=tjAaFXEeu^N=8ZyX z40~c_xY(@6`|CihpJU|>Ln1%kpy&^U(F}GKPNAjbhXuMv5@>(yYKiigyZ>OGMJ%P6 zN9rD0KLEWk!=(zRo}03Q@+Ww1$x(hyc9g7A%x$VaKU2#3UIk@}$Fg)IW%)%Wof>;q z)dV}iqeWM|E{}rB?0kv%n5nObtjBU?8ZOOJiT;=?#hpXeQ3kB91nr7!no-pXBb$a> z7i04gJV$ozM6Q2LI&Ob%<%B**Zh2eH^OS$-D*&{gUcDd7rb%0h4Ppuv|5*CM8+@|H z5~qGbwVz(ilVPn-I!lIP%bdt88T^TJug8iaNclGU|UAFJt|9q z96;UBx%57ZCC@F?B!Ie&(}=YOZsx+anhH%RudwPi=BCupCc^yN;saDfMU0y8boIs7 zpk`aQh{3}FhRt$rl*0xyw$*YLcH|(c?8af)PKtR^_J`a|oAvZ`_L{lbdYNPFr*2X%M5x^>k$K`6R_9iuS%>}$6YR!#e*x(9F^Y)fT zFJ8NQ5QCBlJJ?pKkf;nIXHUd&=BF(MGOOXAI9`0fqW_X z;!=^x<^JJaZOxT6?Q(J8R_XS*_D(i!;4!rv3WyX(?eL!^JdCE1GIXA;nG^FHq?vlj zk{WZ5s?kVJd_$`1_cg{ZiIR$V=z!DI12(eSSO-FRfl%V?SoULOtY-@HdHbTJ2|SON zSp-@bvu$}3baxB7TUSy?$P3Kk6b}utoD7@wj_IJYb6LpnoG}AYeTX|~Si6l`^agE? zPUQyM^{XM?;R!Gr(MV@dYC|j>=}a4nQ1H(1dPf-DnNK@BNBHh2obBYi34l?apkiBj zQ3xy+A}Y!pcrGQI2#}4{3KJemmHleLygC|QHAH2zN-TxjXuigz$H+A2C3G?ygw13v>_}Q)=jIGy(J;k;GZ)u$c9OXKm!Zk4L{=it zOtz-}!cADTgcd@Ua}TknHh?>i=Ah>2U!GV}D;)Qje1rwu#P2Z_|vpx0h50+0zWP@{TNcP;s0?A5KD4E$zWB(1)gq8MCVzJTr2npH)Wk9bQYzkJ0{|s zfSgN(g&S=+JF@WcLr9q_Raf|}Xg&C?AUuSv8p+*(Yw?O;hFO?VzK%Fb24G9H&7NO} zk}^N~6=L#03rmRt;CE-Jdj+sveP_3Vq$BS;uyy=h{ocMJ=^Ot%dEH;=h@gb8IW-IB*TzqHV`{AfTZAvjsWQMAAOx zrK8>Xt0X!Oi*?q+V4B^hE@UY}2NQvxD%I{*c_t6IMd3vi=ib29v~BMJnxMlYzrT@y zE!Ic%YM!YIz>0zJLuX|pr;SGF2?a2lx9c+nk@y`MiuEzQTDukma~(qgw+cq`LG8o{ zmG@7w2nz@&B6;zCAiNjq+mDAnAirig5-cQOOWYrrju?**(TNszhb!$iEKz`Z;n+LWu zM3sRu6IuFr$w7e;h6QO->}chMx_INTlVMSY5e5SOMoge~?tSG;Q&%lpRUfPI_0Zap zi`WZ*PJ%Ms-q8R3q;BeBFx79QY`MbqGQCMvEI*Oze3`^7isChyBns#+IESY?9A&sT z6y^2m)n>f92FQbl3RAk1EMViOCwMX^aul=@+Je9^I`v`2ZWlVuCYzn}(n4CvyE+on+*XzbWTn({Mq&|Lh!8xIr6BWqd4Y`+e(;ED! z8}OY%YYdEKpz)y7h4TdWYpcv~rcd%u#YpQ&4aHmW`#!ia=FXQ$k<}R8A9V=i7a-r@I|I}1Cc2k z$Hr64_0FCw9RBM@Yp*q6;_q^1fy4P z(bpznR@&%Kclg7aE87k#9EDJzM=(NYXL?PS6m%!s!P8 zt=)MxPIKMf7}{!W6SJd~s_shuy$C;q9?PW)AF(x#TrcHdIgSkro4 zahz;Q+4qLXxHZRNVdh4*uK=JD{PrYdb?~euzuzcniLv0(g_gGwGYE^SvMQq(|5*~a zM``!z@O|HDALpbIFaZACba;zWvX7U2?e%Vl;>vU2y79w%@?+mY5M-Ba+-LBhC$x5! zFcS>veT<7Aqj-Lc%i2_M#QP&@Z40Tl^UCJviNwemWb{X@_1W0?NfRtjkV@Qf z0QDZ+AlluNNsDoNPn~3VNdI7_u9L;D&6vjSB*~}X_~?M1gFOf zyGLns1g)gx_sIJxX9|0&nusXS)pfO3V_YTlcVb{ylxhIaP@laOTXBOyLN<&V z0}8fXRSSA4TB+swnqR~xi?rXWo)~KvS)?9PCHbg2E8Y(ISA5?Gg7jsK$#r$jeMn0Y zi*hLEt4TBVTVD2-7EFru>rN7p(dASs126pY#;EcVXcrBLbS{FM&(Nk|ZHJ&wKXJ57 z$(D@K%pBMVM==5Xad7u*>(NGsq&;$zuMG$V#Smi)v}DGU-YpX}))}Vm(lors^7a{& zVHRkf(o{u@;f$T2SW^m-6NbabD&K*Se8)Ub<5L~#JHuQ@V)`_IUmOoObtyuJzC1uY zH`mN`+83e`>x<(dBxj+`Zf2Z+YoYi8u_~*%k~8prXrVh``3XKSVW@?^J@^79zF=4l5r1YsRur~&`VroB>cy&XzE=IajU9avpDm28 zj?_Fcl8^d85er3&g)_fVA~K`RE_bu$?gYe=Bb7^&urdPA|y#{y*qP-Bnd!Gf@yZk>oc?|SUZ1E4fJcD>O|q7 za>m?fsDnGse3uJ6-GJS`hbSXZY5s#`Mw*4V53xznIp@qb*zj3J_g=+I`L|{AQdrWAXd}y3 zXs4q$<%((|qq6JC8WPVXH5ta?+pl4KsQVHAN)6gY$o+7}48I;a3O+6xm>PS9{0z4u z8s^ywr(LFNWFp&5?uF9bmsRuz_4(0@bP713{r52%w8v15Dkt5wKP@i(HDzT|ah~Rp z#xKnPWCRYw(Fju;{OQFsQ=QtL`3Mfo?$-ASjPO&R{ITCB`mOWi))ynZxa{?$HgoUn zrIFU1ea@i{sa&Bw8;8;@I0?Jc+&z0y>hOk>9VBK1CRdIG zzr2tP`Yw)=jVb&)7os6i>9}tF$P7SKXg2JsxuNruT+gWTYzo#rmv^2Ha$@;C-NUJA z`c@2=Hm^^`{iAn^&S`6t(}Cj-mO&i*a8)zq2N#G9Y5n#CFdwhw-*qGxZZ zNnM(8zlmYGE%88jxU7}B9R>4}Pb%bmOYjSKHY&Il~N#SFlVf}YJQ zEPU+9AOPD9{rANMT9aCS!066cpoLI24l5oWf6Sy&aJ}G;prH5R4ct54 zv;}C%13Kdhn%DLscVV*2`d8L}HwNH#CotTsmd~xeqwHd>;uu#x?lu{^uA_34rE%FR zynUIf6dY*pz}Pb`BjB_o0*+*i7sCp{#4z!^di6|YLhID}TojNXwggC0aI1~*8j1U= zu+dz3_z{LnOTRAH&r7LMCOm9*eq1SSI_Ia!k!t7D50ntNBN;s)+o2?CR{kp>@Csx1 zQ)vMxbl_TN5GTYkC1@275IK5J_VMHPfHhk%*`_tDi*I<4-lmOEZJ#7L)$B~Os(fJZ ziLf5qYiEontFR1G6a>Up8vXJ^m(XNqBQM8%yT5%yI<>5`tVdMrZ?Ma18!WMXUbM(oKC z;dZB286@@4LBTktO`7{TPx=n60%s?MqGVF3J!YkkRp5-(oFLp-Fef-GIMA1Kz-ZE+ z^2PWfK$zE)*Ad%4*4&@_g>ls{GC{UsH1VBtRsV2w*TUz5a9(c#AUM}VqcOZc{t{}Q z)l))30Q)YS{P-uKsQ!(IC{ylj@l$@CBLKqH_0*Px(ZAC%QDr+I)X|44h>=_GVQDL< z4_ZUmo>_k~$>~g*W-pu59pngseFrfKRv?X^Ros44k2M#HuFPge2y~ym1e`8@zrDZX z1+it${6rbTxf+Q4u{P`iM#ahuniH>J0GIE^&45qp9n{#r-B^*?(iTG^2_GN|*gYBPo&T~Vlmu#} z*|gG|0m(Xlf9)vPgRI#p;iaZG3%9(OdnP7<3dU73W$IDw?eD<2KgJ zgs$dS;DxRo#X3Co78@wp8O1S^s%D;SGmJHnA*{?c`?z&>9W-!U%;UfK;Q&jx83Jb3 zb3lHt80xjzvpFLl&juOp9VuGlG$B>*4XVP8auhtDuO8 zkdxIMcVp72m|D}oJ`=-EkpdQN+6j_vQy9uRIr%4Vuhim#wc9F~vFf6&qsKVtbT8G) zx$(=4bjY4EAeZb!t&n>8lVi<`|G-><8Q?Y)%$A97go3&2ZX%vZ5KUO(ivu{k5hYD8 zz1rs+;`5oLXEx5CwAg1$w>~km1qa@4`lu4rlUw7+t%=~_RqG0~uK-`%;1Ngr!x_&g z@D45*CkRQ4ie@*I(+Iil*Cz_*oXmT_874~CT5Aw@rquZ|{(`3OhTiU%FWrJ(XI|Icw^M z(FAMEe#t9+)LvXHG-_UOG=WC&Y0>+|{%_lO{hyx|`S-&Cq7>rGf7`|yyJ~nE=--Z< zIpG#)s?yZxy26{dpcEQ(ur_vj#JIS!6zJmBvlN{On~dEZ8^V8qf^W+ieP=04SVp{L zq8?=dOIhD!-@Xetc?&L*0q^L4>Q`fa2m6*Z6}RwJ85h* zww-*jZQE93+qTWdR&%;9&c)vUVLi`WbBr0WJ$0(TxqLxS^PB(X3S47h2m_CvjB zB7?Uy=zA>A7`#0RX!R2 z;o7Nr!cluI)=i!ozV4x|SQ56Da&V@1u$d0BagE$bBP#08#J&lWbU)&!rc7e3I~{2p zv>JsLOVU5L%K0_>gq*5Ae$T{uIB)?>`=$!3b6 zTBrT0a5kLQ{}wuon7oC4YIu}NA+T$WH1WB9m@J^_w9R9wH!9dFjqL{|-}QX`l~Cqh zn3l`wDa!&IM_uY*vogsvuKP^?d#mjpm=4Dc@jtCVC0q1*SB`!Yjhs9C?}@n`Bt1Fp zV*T}kFyfM_3%2|Uu2jB~*Q?mAgIp_l{N=_`YnkiB@F>4nE!Io3cK)#Tp1hpwR^E8& zT?YWh!J(*VRBJrQ#MaIz|88r^64~8Sf%j9(dW31rMA=;Cqxnz1x874+v$66THzFs? z!>mmj$Zc>4#u}6J=kL*yd?vE@kl`P%9rj6onBH0hFL0v6AGkHz0fhXAUYw?;=8zjO z^d-4w1n#wK>L)1HeTl&vRN_xr_q^N)2}U5M@`63zK0QO~5NWEMsa;7=N$n)3-j=$*Wn9dn+^T7noK(ucN@W9% z47Md5UMq809N9y}eC0a>Qbri^=ec`jhgpjp1}K*=;i2ZRh78$@XK2@j9-?26bFbfh z@asnq(O!^{o6ec_1i{t-BvJ{?!ebL+_4Fhe>?3E%7gxBrt9P`#0#IO-(?Y&j{5p?zJ- zoyysAuntO>Ym}of{o_W6edLMd73CSc8TRBgfo^1GKkPqlyF2|l6F6ky&M27V3#Ts@2vRIH*{iygOb~`f|oexMToOL4dkot;ZCLlfShXg?hY3*`P zTPqH5L{fWfRTDiz{0lCUolF#xtkXAcM2ktfHj6s;R%@uDQE#%2H2!*o^r=V~dxjJ1 z*vlm3mzr}qwm%(ZJYWoF$kB!uSiyQpxu?wIMjE1nUQT&lbxnl>89fa6JIuk?p70+P z2a>f0k(R0`6gy|9hk8(GZh+=nqjC41XK@MNgbS8@$^1~qzE!+aQSJtzD1j0Bk(-$| zIr8diKlRD6&y3?Zcm&d@o7{?N805=PMbXQz`|ck-X(-7=>iD_LI;WHRBk&Snp1-|3 z*rJ%TI6{JcYq$S+T?WWqsw-Zc81u)EL(2|Qe zE*ENq>O|eRvg$TDIrS~W6eq@WWJy@}de}C{sV=?BxxQjmts0_MjZPrh&%mFq+Db0j z*{`b?#d`s44Rzg7b12!*45f?JVHY3XgBpKIG8)Eh@9}$9YVy|DB1;jQpZ`>%?2%u` zo@dR7o}5LTW!8rFk;w@8hSLEJ#ygD5dMC(k4{A4urO9-M_Op%TXtJ zULnG0+8z1?5+54IVAqFLQOMJ0QAYYi`rYaUf=?M3=rOV;)aXQK=exsgN0BHYB&p}+ z{W(IbecGka*X=1FDGA{f(M{ERjkb^a=EqxXH_MVWM5r;8+Zxzouy3bwqYx(>0;(s* zxJ^-slyA3(pMbR%MJkp+QnW0|Cif+g#}`^&X!ib0=#DqIrx@rj#SBf|%`BpA@P5zH z8g0(csXG5dH4tJRx1cRVzR>=Rks$x(?T1hO*ZpJPMb zKvq;rmqeaa;-vxGL|5#bA5=U$i^A0>m`4xeb!P4Sbk>wj%`(~TYJTzextmh6Az11p z^E%V}*5^6L>#FS}=RViz>bL&aloKP$9L--P>Lp+fa6c6|>)}29Y%%vOpZ#(l6(e*% zb$Clo^_A#I(ZJque1c6pR9G~+y#=BW<@0c__ zx(vWc^}G8i0>8rE{m?V$93Ar1&pEpL+04$(fu&AiRyNp`3Z0YuC7o-M+uDG@mVm^Gfm67L>0tdcME^L5M z9;aNzjLZbb!1&JJd3U$HiOXnkax~9&ScvZWdV6uJvD#~8`Dt6Rt`yfg+v~x{^Os62 z0!PTCF&X>jq{=czY_Tk#sqIpsg*k@VUGtOO>g;w0E!yVx^q>%w5*yRh`sRj{s+|{A zQ)M++1AhOn*_!Ioj*hNsM4mtAaIV1b=ZELZb68hbNRi7lO~U^DBXrrn+fObRk<35Z z3UBue9b$sBZx8Jc?0+IkL=S&T@x}j0h|YFI$)Lee_5jU5^sQ?RWrBlNO2JOS3IWRNUR~Uz;ewb>#+%A(%H) z#f*>}gUf$=h7{&RH=%2%XW87=5vxQGMqNFe+LEr7UdQ0{&)o{~wW}(K53W*hPsKxj zcb%4P_K&!SJgE1n6E@F~N>M+__H-=p7-Cg!0~t6J^4_Sv-V}}@Pk`rFAW`sEbvXNh z(+Tkc7ZdOcU)DHwSx45lTiFwEy=H=(IzB_&OKONKN4y&1rk2|a>R+LS$8yQu@}F6M z=a@Nt*nwy;Ydk=!h3@6O`zq_z)RHP|gGR!OfG3?VIcCGYiLvY}3bEOW3$PX#f^V$v z;V_?w9>nDkEeJ^}JKd|BC6ua)Lmy+XE}E2_OyR4vrzcwXHJFtQlcED^Mz64=(#4re zBnG-HT5O@I4>W&2w5fYf>KjuTj^$+H?#7Pes4$85vIQ523WC{t$(+TdR!d#gX z>-!e<5Cs^`etP%!OIM=fG2glrVR4w*`Rp9I(FixK(tP5TNORc#=_E7$4h-Y=y*W+k zl9@j`^J9(L$xtRBXiR~?`VT4cVnpoEu~W2nmxA3AGe{9FXooD*^SyXgoG8In2vd zwy_A~#_d(@k~Q>d9JC<_3tCBkm?z^obvlV+87<(&>a`2mpnQR;xJgaDAsh<0%7*M@ z15=@nR?4*+%0lEmHjY@@9pMBA8-haZ0@!R1586ZB0%iGLlhM&+$)dosGFzNaE}1O- zP3_>3l$6LZnkot+XMi_+;RSYZ%-$eFSyv@MVzwElzOJ>%z1m-QoR+fGk=2dY1pRZ~ zohG-Hfs2#G78D2!gia-=W$cVA&o}p+SZY3VsW=2t^ANsucAQ1JjnRrbvPJ5|*%H%N ze1VJ>80N5iF!7Wu^g5H$R+9M{nuFud%5>W_%yByfyHjvW+^u>LdvAjS1R(xf(0}H# z{v{(^eo=nN8P3J%nz=D!d&Be5D~}~ z46>pkz{LOCYFPjB5(-TtFD{Z{yJlG|oT*Va6{vwiTo3rR;sK<~^omr5wp?OsMEhAS?(=bMc_|KrgcSOILA8 zal2i)CmrS5n){rG?08?f=u$>bE)8nzRS zR-At7_(`6UW1gH6x&I;!gFBtPfoR=zgHE7E-#}R2iNMPO<^9rraRAwDXbvg1Xq==uFW(SZ8Z|vW8mc9X6 zWX&%j|2~>q!a_GRuh~-5CidJIch{5EuLZaYx!fq2H4^_^XYBC*Vf|F^ zZ4%GMQ&K&a%6$3C_cd^A5G84?@6Gt(W`X?cPZ~B)8#o>Ovgd44&nTU%@a;sN*pdy) zo_wCs9orQ_1f_(FQv{$U_WdhA%(mpdEC$}F-JkccRQnX^tp!C1#wQD7*5)C6^X12I z?j$Y%d!TR|3i-8_@I^2`+mqTI_9T<{hlqpg zmcF+9sQnF9#W4Wy*P*vK^G@h;Amf}EYoyx3=joEhp9c^=sxLrGg`vf44HY(NG)J+| z|F?U2U_kV$f4xSVN0tuQufwaVu{g&Bm6DqFM3r%*Zb*E@1)0OknrZfV29iRO0Y;K6h1VcKwT!0*Za171EDtI+fsc@_|X>g|s zNk=>k9ZiZ0E6-{Lz%bU&j#34iXzzv_W z2D_9C?6=D=)@M#tf14cpSP_CZZ%J}Xf0&xQpY15NS`vU$89J3k;ZakLWw|a+-q1Sf zNppMF#yOe1wDEPAbLJ@w6t{^&-U#_r;o65=9~Hwp-A@0E@GGYUMy)A2`cmpuC`d$*xH`Q(~S z)I#_{A-VTwlQ$upw&Un*STJ3R3SNO8*A%K2k*2wUtpq|}{&)nn0b`9yM^+?Z1=mk+ zO0_MZYB0qslkYW?8q|d4XFKz1B7EPGyaoaeW=>7tV37Vg8P7eR5q*+wfymh&iaDd^ zN^smWa}TmP({jw(bfT=O865K){6a@r$6BUd<&vX>eueAMk(u!?Mavj8$KykMSd*Dq zfD8K~Hh(7ZG~pb<<_I*)x@IPgFAbF0CNnd; z(AwglQw8@c1&g4g+(vo)r^eALl*>f&SI|6l^EuEwmGfJSL19sOkmpcAzGQXi+8D|* z{O+Wc_>+=gvg!>I{!pu(M$`%0DGK?7GHTj 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 VwlMN}`%er%aGR6olj~j${vQ;P=LY}) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f42e62f372..2b22d057a0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb6c2..65dcd68d65 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,10 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' @@ -143,12 +143,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac diff --git a/gradlew.bat b/gradlew.bat index f127cfd49d..93e3f59f13 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% From 7cd146e65731734fd0cd037d6ae095078ca4a6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Fri, 2 Dec 2022 11:11:26 +0100 Subject: [PATCH 148/805] Add CodeQL workflow --- .github/workflows/codeql.yml | 181 +++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..0fdf5f35a4 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,181 @@ +name: "CodeQL" + +on: + push: + branches: [ 'master' ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ 'master' ] + schedule: + - cron: '16 7 * * 3' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' + CMAKE_VERSION: '3.14.7' + +permissions: + contents: read + +jobs: + + java-analyze: + name: Java Analyze ${{ matrix.java }} + runs-on: ubuntu-22.04 + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [ 'java' ] + java: [ '8' ] + + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Cache Gradle dependencies + uses: actions/cache@v3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache Gradle wrappers + uses: actions/cache@v3 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Setup java + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: ${{ matrix.java }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Build with Gradle + run: ./gradlew + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" + + csharp-analyze: + name: C# Analyze ${{ matrix.dotnet }} + runs-on: ubuntu-22.04 + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [ 'csharp' ] + dotnet: [ '3.1.301' ] + env: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Cache Gradle dependencies + uses: actions/cache@v3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache Gradle wrappers + uses: actions/cache@v3 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Cache NuGet dependencies + uses: actions/cache@v3 + with: + path: ~/.nuget/packages + key: ${{ runner.os }}-nuget-${{ hashFiles('csharp/**/*.sln') }} + restore-keys: | + ${{ runner.os }}-nuget- + - name: Setup dotnet + uses: actions/setup-dotnet@v2 + with: + dotnet-version: ${{ matrix.dotnet }} + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Build + run: ./csharp/build.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" + + cpp-gcc-2204-analyze: + name: C++ GCC Analyze ${{ matrix.version }} + runs-on: ubuntu-22.04 + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: ['cpp'] + version: [ '12' ] + env: + CC: gcc-${{ matrix.version }} + CXX: g++-${{ matrix.version }} + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Cache Gradle dependencies + uses: actions/cache@v3 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache Gradle wrappers + uses: actions/cache@v3 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Install compiler + run: | + sudo apt-get install -y g++-${{ matrix.version }} + curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz + tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz + echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Build + run: ./cppbuild/cppbuild + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" + From 2c62ef9def3781f7ff18ad212866ff03d4f07e88 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 15 Dec 2022 08:52:49 +0000 Subject: [PATCH 149/805] [Java] Upgrade to Mockito 4.10.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index abc3c3974d..23957d007f 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.9.0' +def mockitoVersion = '4.10.0' def junitVersion = '5.9.1' def jmhVersion = '1.36' def agronaVersion = '1.17.1' From 2b7f925532f913a02652961b819f03a669042d98 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 28 Dec 2022 15:19:04 +0100 Subject: [PATCH 150/805] [Java] Upgrade to Mockito 4.11.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 23957d007f..77ba3dcbbf 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.10.0' +def mockitoVersion = '4.11.0' def junitVersion = '5.9.1' def jmhVersion = '1.36' def agronaVersion = '1.17.1' From 8390e48afd31085c303060c0bf474330500d4bdc Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 1 Jan 2023 15:38:29 +0100 Subject: [PATCH 151/805] Update copyright. --- CMakeLists.txt | 2 +- CONTRIBUTING.md | 2 +- README.md | 2 +- build.gradle | 2 +- config/checkstyle/checkstyle.xml | 2 +- sbe-benchmarks/src/main/cpp/CMakeLists.txt | 2 +- sbe-benchmarks/src/main/cpp/CarBench.cpp | 2 +- sbe-benchmarks/src/main/cpp/CodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/MarketDataBench.cpp | 2 +- sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/benchlet-main.cpp | 2 +- sbe-benchmarks/src/main/cpp/benchlet.h | 2 +- .../src/main/java/uk/co/real_logic/sbe/CarBenchmark.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/package-info.java | 2 +- sbe-samples/src/main/cpp/CMakeLists.txt | 2 +- sbe-samples/src/main/cpp/GeneratedStubExample.cpp | 2 +- sbe-samples/src/main/cpp/OtfExample.cpp | 2 +- .../uk/co/real_logic/sbe/examples/ExampleTokenListener.java | 2 +- .../co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java | 2 +- .../sbe/examples/ExampleUsingGeneratedStubExtension.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java | 2 +- .../main/java/uk/co/real_logic/sbe/examples/package-info.java | 2 +- sbe-tool/src/main/cpp/CMakeLists.txt | 2 +- sbe-tool/src/main/cpp/otf/Encoding.h | 2 +- sbe-tool/src/main/cpp/otf/IrDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/Token.h | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java | 2 +- .../main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java | 2 +- .../java/uk/co/real_logic/sbe/codec/java/MethodSelector.java | 2 +- .../main/java/uk/co/real_logic/sbe/codec/java/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/CodeGenerator.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/Generators.java | 2 +- .../uk/co/real_logic/sbe/generation/TargetCodeGenerator.java | 2 +- .../co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/c/COutputManager.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/c/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java | 2 +- .../real_logic/sbe/generation/cpp/NamespaceOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/csharp/CSharp.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java | 2 +- .../sbe/generation/csharp/CSharpNamespaceOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/package-info.java | 2 +- .../uk/co/real_logic/sbe/generation/golang/GolangGenerator.java | 2 +- .../real_logic/sbe/generation/golang/GolangOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/golang/package-info.java | 2 +- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 2 +- .../uk/co/real_logic/sbe/generation/java/JavaOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/JavaUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/package-info.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/RustOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/RustUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/SubGroup.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/package-info.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/package-info.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java | 2 +- .../main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/json/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java | 2 +- .../main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java | 2 +- .../main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/otf/package-info.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java | 2 +- .../java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java | 2 +- .../main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java | 2 +- .../java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java | 2 +- .../uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/package-info.java | 2 +- sbe-tool/src/test/c/BoundsCheckTest.cpp | 2 +- sbe-tool/src/test/c/CComplianceTest.c | 2 +- sbe-tool/src/test/c/CMakeLists.txt | 2 +- sbe-tool/src/test/c/CodeGenTest.cpp | 2 +- sbe-tool/src/test/c/GroupWithDataTest.cpp | 2 +- sbe-tool/src/test/c/Issue889Test.cpp | 2 +- sbe-tool/src/test/cpp/BoundsCheckTest.cpp | 2 +- sbe-tool/src/test/cpp/CMakeLists.txt | 2 +- sbe-tool/src/test/cpp/CodeGenTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeElementsTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp | 2 +- sbe-tool/src/test/cpp/GroupWithDataTest.cpp | 2 +- sbe-tool/src/test/cpp/Issue835Test.cpp | 2 +- sbe-tool/src/test/cpp/Issue889Test.cpp | 2 +- sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp | 2 +- sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp | 2 +- .../src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java | 2 +- .../test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java | 2 +- sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java | 2 +- .../test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java | 2 +- .../real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java | 2 +- .../real_logic/sbe/generation/java/CharacterEncodingTest.java | 2 +- .../sbe/generation/java/CompositeElementsGenerationTest.java | 2 +- .../real_logic/sbe/generation/java/ConstantCharArrayTest.java | 2 +- .../sbe/generation/java/FixedSizeDataGeneratorTest.java | 2 +- .../real_logic/sbe/generation/java/GenerateFixBinaryTest.java | 2 +- .../real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java | 2 +- .../real_logic/sbe/generation/java/JavaOutputManagerTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java | 2 +- .../sbe/generation/java/PackageOutputManagerTest.java | 2 +- .../co/real_logic/sbe/generation/java/QualifiedYieldTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/ReflectionUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/RewindTest.java | 2 +- .../co/real_logic/sbe/generation/java/SchemaExtensionTest.java | 2 +- .../java/SinceVersionTransformedSchemaJavaGenerationTest.java | 2 +- .../sbe/generation/java/SkipAndDecodedLengthTest.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/ToStringTest.java | 2 +- .../real_logic/sbe/generation/java/WarningFormattingTest.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java | 2 +- .../uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java | 2 +- .../co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java | 2 +- .../uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java | 2 +- .../real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java | 2 +- 175 files changed, 175 insertions(+), 175 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8e7b0010c..878df9b951 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2022 Real Logic Limited. +# Copyright 2013-2023 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 656cc2e855..ab34fb164c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ If you are adding a new file it should have the following header: ``` /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index bc0984add5..6248e6a4cf 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ Or run test directly with `Cargo` License (See LICENSE file for full license) ------------------------------------------- -Copyright 2013-2022 Real Logic Limited. +Copyright 2013-2023 Real Logic Limited. Copyright 2017 MarketFactory Inc. Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/build.gradle b/build.gradle index 77ba3dcbbf..b128e5c48f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 28aab05fd6..84cd75c377 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -23,7 +23,7 @@ - + diff --git a/sbe-benchmarks/src/main/cpp/CMakeLists.txt b/sbe-benchmarks/src/main/cpp/CMakeLists.txt index 3e0da195d9..d35adebb49 100644 --- a/sbe-benchmarks/src/main/cpp/CMakeLists.txt +++ b/sbe-benchmarks/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2022 Real Logic Limited. +# Copyright 2013-2023 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/CarBench.cpp b/sbe-benchmarks/src/main/cpp/CarBench.cpp index 7f938c3fc9..101974e8de 100644 --- a/sbe-benchmarks/src/main/cpp/CarBench.cpp +++ b/sbe-benchmarks/src/main/cpp/CarBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/CodecBench.h b/sbe-benchmarks/src/main/cpp/CodecBench.h index 8028ef0bed..2cbb379e15 100644 --- a/sbe-benchmarks/src/main/cpp/CodecBench.h +++ b/sbe-benchmarks/src/main/cpp/CodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp b/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp index 4a01b81049..84cbee18ee 100644 --- a/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp +++ b/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h index 217f4eb39a..10f06ef65f 100644 --- a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h index e67807adb1..69cbf98890 100644 --- a/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/benchlet-main.cpp b/sbe-benchmarks/src/main/cpp/benchlet-main.cpp index dd6136b932..e292d64255 100644 --- a/sbe-benchmarks/src/main/cpp/benchlet-main.cpp +++ b/sbe-benchmarks/src/main/cpp/benchlet-main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/benchlet.h b/sbe-benchmarks/src/main/cpp/benchlet.h index 68e00b2427..37c39222fa 100644 --- a/sbe-benchmarks/src/main/cpp/benchlet.h +++ b/sbe-benchmarks/src/main/cpp/benchlet.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java index c15ebafeea..117dfefec0 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java index f459ae1dc9..a182c61331 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java index 568d9b0fad..974d94de21 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/CMakeLists.txt b/sbe-samples/src/main/cpp/CMakeLists.txt index 5c8664ca92..ea9213e665 100644 --- a/sbe-samples/src/main/cpp/CMakeLists.txt +++ b/sbe-samples/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2022 Real Logic Limited. +# Copyright 2013-2023 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/GeneratedStubExample.cpp b/sbe-samples/src/main/cpp/GeneratedStubExample.cpp index e2187c87ee..810c667be8 100644 --- a/sbe-samples/src/main/cpp/GeneratedStubExample.cpp +++ b/sbe-samples/src/main/cpp/GeneratedStubExample.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/OtfExample.cpp b/sbe-samples/src/main/cpp/OtfExample.cpp index c108bbf9ba..fe9ceeb64a 100644 --- a/sbe-samples/src/main/cpp/OtfExample.cpp +++ b/sbe-samples/src/main/cpp/OtfExample.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java index 820131c543..a64d203640 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java index 640458f767..8af8d1094d 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java index 06bf499719..f9b1233468 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java index 847df95550..7512257b57 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java index 1cafaea915..fd12f685ba 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/CMakeLists.txt b/sbe-tool/src/main/cpp/CMakeLists.txt index 3100de1e6b..a2c4081141 100644 --- a/sbe-tool/src/main/cpp/CMakeLists.txt +++ b/sbe-tool/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2022 Real Logic Limited. +# Copyright 2013-2023 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/Encoding.h b/sbe-tool/src/main/cpp/otf/Encoding.h index 33aa3cf1cd..bad608a880 100644 --- a/sbe-tool/src/main/cpp/otf/Encoding.h +++ b/sbe-tool/src/main/cpp/otf/Encoding.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index 381a7e9638..2b4571b5b7 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h b/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h index 3fdd955a45..78a49c8eda 100644 --- a/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h index f0a225b5f5..c61658aa35 100644 --- a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/Token.h b/sbe-tool/src/main/cpp/otf/Token.h index 9e2a3f0f18..b187a86198 100644 --- a/sbe-tool/src/main/cpp/otf/Token.h +++ b/sbe-tool/src/main/cpp/otf/Token.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java index ba6887f411..307e4a3b02 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java index 804b38bb21..70553f642b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index a0be516bf9..1134e90c0e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index ff01421e7f..eac6dd4ba1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java index 5407cf1237..a69e280d0d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java index fef09f50f0..4ebebf2f83 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java index ed53dc625a..4ffba79157 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java index 9216ed5548..df4040e2bf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java index 775d972e09..be906f06e0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java index 4f4c31c125..83afb9928b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 2dade346dd..5d81eb691b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index f82eec476c..258104e5bf 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java index 2158196b40..5877162f56 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java index 2b0346fb0e..cadc1399fb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java index 86782b9872..d0e6656cc4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 81b8da29d7..3965763d21 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java index ec19a53102..3e561bd207 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java index 59b0bccfc1..7616ad4b28 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java index e9158a3558..5c58a2d237 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java index 9c8643c277..5b4870a321 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index ec0b458d12..0550eb8bc0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java index b48c50611f..c2c500f5bc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index 0da828d02f..1140ae8b02 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java index 148b19f141..d1431f3343 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index cdefc9f7c0..24084e23ef 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java index 874b7769ec..c225f8b4a9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java index 0858cede34..d658a7e759 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java index 7cffab4c59..9bc17ee5fa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 9a7cef4b48..b3ac5a63fb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java index 9d34d89a81..516093b5f8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index 49bdbfdaa9..c29db9cbc2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java index dfd94ec902..e7ae8909e2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java index d23c989d0b..dd303f9a0e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 4913e30b9d..419f155e48 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 75aa4c49fc..d61f888f01 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index e7e26bcc31..3fc3cccdec 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java index 4426638193..2e28bd67c8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 731f57199d..4f71f0de84 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 79fb608f79..756e019fdf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java index 265a1f3e82..e2e3f52525 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java index 78a8b60935..6f1c114103 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java index aa2929c08e..0e020cae75 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java index 98d0592e22..57e946b0df 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java index 534827134e..4fef0d5394 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index f5af22d62b..0551dcdf02 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java index 1107511407..4bbcfaef95 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java index f791c1b02b..aca56530b3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java index bcdc380a4b..e4b14a08f4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java index 7d42b02599..a6845a15ae 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java index 8562868ba9..34a0ea2c56 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java index 99ef90556a..bd74f67e44 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java index a618463229..92a38128b7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java index 1c58dc66a6..22e7595740 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java index 9ea3194669..947f6fb053 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java index 6f09a7f85b..c480a328bc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java index 3e4a7266a7..f189284b5c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java index ef991ae99c..0a7671a020 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java index 2fb3ca07a2..8cd16555fc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java index cc994a9775..efd0d150b8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java index 7445a48574..bc5d5ee6c2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java index 037c01c8c8..966f5f0e2e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index ca81a4edc3..4e26bfded1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java index 3197c08c47..e805dd8fc0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java index 12fe0663a3..7fad3ab7ea 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java index 9170bbcdc5..dd93a87fb7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java index 6f4e655fe7..7def2d9aed 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index 6349ce760b..f135d9e2fa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java index 93586bbd67..1fbe750a2e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index 77be002e95..ee4ddffec0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java index 8ae645180a..9e38fd8c94 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java index 7609e46a0e..191f4e8279 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java index ea2e99b713..2c8b402f88 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java index 6c08d3706e..8f1ec8c23c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java index 3288ff0e03..63618fdebf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java index 7b4f97d0cb..2d65a39044 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java index 67a09d3152..8b54fb6cfc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index 8b95df9ff2..e407e675ff 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java index 6f79c9b6fa..3ffcf30830 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/BoundsCheckTest.cpp b/sbe-tool/src/test/c/BoundsCheckTest.cpp index 8cb984e0c7..f7656e2dd8 100644 --- a/sbe-tool/src/test/c/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/c/BoundsCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CComplianceTest.c b/sbe-tool/src/test/c/CComplianceTest.c index 61763dbb29..3ba67f78da 100644 --- a/sbe-tool/src/test/c/CComplianceTest.c +++ b/sbe-tool/src/test/c/CComplianceTest.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index 9d3c2b03dd..bb58cfc3cb 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2022 Real Logic Limited. +# Copyright 2013-2023 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CodeGenTest.cpp b/sbe-tool/src/test/c/CodeGenTest.cpp index d1c0c0fcae..961db64b2d 100644 --- a/sbe-tool/src/test/c/CodeGenTest.cpp +++ b/sbe-tool/src/test/c/CodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/GroupWithDataTest.cpp b/sbe-tool/src/test/c/GroupWithDataTest.cpp index 7d2b0efa2f..d8da323877 100644 --- a/sbe-tool/src/test/c/GroupWithDataTest.cpp +++ b/sbe-tool/src/test/c/GroupWithDataTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/Issue889Test.cpp b/sbe-tool/src/test/c/Issue889Test.cpp index c0f5ec36a1..c621653028 100644 --- a/sbe-tool/src/test/c/Issue889Test.cpp +++ b/sbe-tool/src/test/c/Issue889Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp index ee33ebd0cd..e3b81677dc 100644 --- a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 438844b066..03d1ab1cfb 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2022 Real Logic Limited. +# Copyright 2013-2023 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index 1bd387f46e..5c7ad29b77 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeElementsTest.cpp b/sbe-tool/src/test/cpp/CompositeElementsTest.cpp index d7b6fd6038..6b772b976e 100644 --- a/sbe-tool/src/test/cpp/CompositeElementsTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeElementsTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp index 632827a0fc..28bcbb1880 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp index 8ddb1101b9..2ef126a774 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/GroupWithDataTest.cpp b/sbe-tool/src/test/cpp/GroupWithDataTest.cpp index c9bc42621d..2c0c242d8b 100644 --- a/sbe-tool/src/test/cpp/GroupWithDataTest.cpp +++ b/sbe-tool/src/test/cpp/GroupWithDataTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Issue835Test.cpp b/sbe-tool/src/test/cpp/Issue835Test.cpp index b22fdf9277..01aa455037 100644 --- a/sbe-tool/src/test/cpp/Issue835Test.cpp +++ b/sbe-tool/src/test/cpp/Issue835Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Issue889Test.cpp b/sbe-tool/src/test/cpp/Issue889Test.cpp index 42c87b1720..f730936a16 100644 --- a/sbe-tool/src/test/cpp/Issue889Test.cpp +++ b/sbe-tool/src/test/cpp/Issue889Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp b/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp index 9767023f54..6ff568dd9d 100644 --- a/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp +++ b/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp b/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp index f3ad271857..ad46bab3a9 100644 --- a/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp +++ b/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java index f9ee2695ef..63bcc2e412 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java index 83b71ac815..a354a11d43 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java index 1911940443..eeea08ac0d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java index 7a5c92481e..4f5228f46f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java index 5ca540c2b6..9dcf95b8bb 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index b198de3073..dd7be3c505 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 3a7eeca34c..cd5342f7d8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java index 62657132b1..59fe07b2f3 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java index bc380a4665..8342f439e7 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java index 10eaedee62..124faba06c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java index 1141e5c983..75790252d2 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java index 8edb42474c..9e6a9f1706 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java index 09274ec5f7..0595da4469 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java index a8c9e2676a..e3facf38f6 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 297fc02ec0..c8d4d5870d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java index 97bab7f9ff..d953828de5 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java index 9c930485cb..2b29b64451 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java index 5152196ed0..6122cdfd13 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java index 701d50057a..e9f3573272 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java index 56f7ccbc8d..a48074eb89 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java index 9a4974ebf1..c2c3e07f4b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java index 78c6e2d5de..dcc8877b74 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java index 7a9a64c489..cdafc79fdb 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java index 23d6246566..8d8fcf3d4d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java index 3dde226e72..11b28123e1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java index def80db067..93a6a62183 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index cab7fc9f10..33f3a876d4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java index b7577f4100..b5932aa7f9 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java index 60a2538922..3e92466bbd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java index fa773de170..0e527f43e2 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java index aab8b540ab..8986a43923 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index 900ab99e38..ca89103961 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java index 83a274dbd3..5abe33da26 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java index 073ffca2f2..612b4a4a4e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java index eee71d141c..4116bf0a78 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java index 1134876d22..dc4bd822f0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java index a0b7ef5ae4..94c9fe680d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java index 0b29b1bcf2..d5821fffcc 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java index f8c3a3aa8a..fdba65bc5b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java index ca3a0d3dca..30f75080fc 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java index a129c7ecc1..70b73af2d0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java index 6763e2c50f..edd151623a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java index ec6162f05d..fcdb5d8a66 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java index 0f75157955..12292e4d65 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * Copyright 2017 MarketFactory Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java index ac203c3693..083e8dbd0d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java index 18176fb7b4..62b952f46b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java index bde5d84164..3e73957429 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java index 98d86e69d9..2b6dfa3607 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java index c57bddddde..dcd51baff4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java index eb2f9ad815..28ca3b8c0c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 Real Logic Limited. + * Copyright 2013-2023 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 0150476aea588b189555a70abd128ac658aa327d Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 10 Jan 2023 17:25:06 +0100 Subject: [PATCH 152/805] [Java] Upgrade to JUnit 5.9.2. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b128e5c48f..63b9ef5357 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' -def junitVersion = '5.9.1' +def junitVersion = '5.9.2' def jmhVersion = '1.36' def agronaVersion = '1.17.1' def agronaVersionRange = '[1.17.1,2.0[' // allow any release >= 1.17.1 and < 2.0.0 From 7630eef483de80abf6fd5ce593c904e4727522f3 Mon Sep 17 00:00:00 2001 From: Martin Thompson Date: Fri, 20 Jan 2023 17:04:13 +0000 Subject: [PATCH 153/805] Remove LGTM refs --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 6248e6a4cf..03c1eb03a3 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,6 @@ Simple Binary Encoding (SBE) [![GitHub](https://img.shields.io/github/license/real-logic/simple-binary-encoding.svg)](https://github.com/real-logic/simple-binary-encoding/blob/master/LICENSE) [![Actions Status](https://github.com/real-logic/simple-binary-encoding/workflows/Continuous%20Integration/badge.svg)](https://github.com/real-logic/simple-binary-encoding/actions) -[![Total Alerts](https://img.shields.io/lgtm/alerts/g/real-logic/simple-binary-encoding.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/real-logic/simple-binary-encoding/alerts) -[![Code Quality: Java](https://img.shields.io/lgtm/grade/java/g/real-logic/simple-binary-encoding.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/real-logic/simple-binary-encoding/context:java) [SBE](https://github.com/FIXTradingCommunity/fix-simple-binary-encoding) is an OSI layer 6 presentation for encoding and decoding binary application messages for low-latency financial applications. This repository contains From aa1a53e0c6b4e27ed531b3a655b8cb5d3513fb37 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:02:51 +0100 Subject: [PATCH 154/805] [Java] Use int for total. --- .../test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java index 9dcf95b8bb..11df1c5919 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java @@ -57,7 +57,7 @@ void shouldSetBitInByte() { final int bufferIndex = 8; - short total = 0; + int total = 0; for (int i = 0; i < 8; i++) { byte bits = buffer.getByte(bufferIndex); From 175ada06d9c8d1b721f1e273f4b7d0eb05250750 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:06:05 +0100 Subject: [PATCH 155/805] [CI] Run CodeQL when the `master` is being built. --- .github/workflows/ci.yml | 1 + .github/workflows/codeql.yml | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a88bfb8a8f..1ae520d882 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,5 @@ name: Continuous Integration + on: push: branches: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0fdf5f35a4..3dc7cd836c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,12 +2,12 @@ name: "CodeQL" on: push: - branches: [ 'master' ] + branches: + - master pull_request: - # The branches below must be a subset of the branches above - branches: [ 'master' ] - schedule: - - cron: '16 7 * * 3' + types: [opened, synchronize] + branches: + - master concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -178,4 +178,3 @@ jobs: uses: github/codeql-action/analyze@v2 with: category: "/language:${{matrix.language}}" - From 6a30c05b8597cd6e6eb916c9d7f61a14754c819c Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:09:04 +0100 Subject: [PATCH 156/805] [CI] Remove duplicate GCC and Clang versions. --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ae520d882..fd2ea4cbb8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,7 +111,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '6', '7', '8', '9', '10', '11' ] + version: [ '6', '7', '8', '9', '10' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} @@ -146,7 +146,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '9', '10', '11', '12' ] + version: [ '11', '12' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} @@ -180,7 +180,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '9', '10', '11', '12', '13', '14' ] + version: [ '9', '10', '11', '12' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} @@ -217,7 +217,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '11', '12', '13', '14' ] + version: [ '13', '14', '15' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} From 6bbc1306e2603bd9eda91d64b5e16657df53ef7a Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:11:27 +0100 Subject: [PATCH 157/805] [CI] Add CodeQL badge. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 03c1eb03a3..0de28a3b78 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Simple Binary Encoding (SBE) [![GitHub](https://img.shields.io/github/license/real-logic/simple-binary-encoding.svg)](https://github.com/real-logic/simple-binary-encoding/blob/master/LICENSE) [![Actions Status](https://github.com/real-logic/simple-binary-encoding/workflows/Continuous%20Integration/badge.svg)](https://github.com/real-logic/simple-binary-encoding/actions) +[![CodeQL Status](https://github.com/real-logic/simple-binary-encoding/workflows/CodeQL/badge.svg)](https://github.com/real-logic/simple-binary-encoding/workflows/actions) [SBE](https://github.com/FIXTradingCommunity/fix-simple-binary-encoding) is an OSI layer 6 presentation for encoding and decoding binary application messages for low-latency financial applications. This repository contains From d8104d5553cfa6aa038b9134bf7db87e515ce2f7 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:13:28 +0100 Subject: [PATCH 158/805] [CI] Fix Clang 15 installation. --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd2ea4cbb8..5a5cffc7ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -238,6 +238,8 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | + sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ matrix.version }} main" + sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz From 5033a408792a19d335ef7e238e5f4fd126ddd6a2 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:18:54 +0100 Subject: [PATCH 159/805] [CI] Add Clang GPG key. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a5cffc7ce..679e21e7ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -238,6 +238,7 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | + curl -L https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ matrix.version }} main" sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} From 9ffc9a4f0a5905594b9bd245b47cd6a1c8320912 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:29:05 +0100 Subject: [PATCH 160/805] [CI] Update list of .NET versions tested against. --- .github/workflows/ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 679e21e7ac..7f05ab33d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,7 +68,7 @@ jobs: strategy: fail-fast: false matrix: - dotnet: [ '3.1.301' ] + dotnet: [ '3.1.301', '5.x', '6.x', '7.x' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 @@ -95,9 +95,10 @@ jobs: restore-keys: | ${{ runner.os }}-nuget- - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ matrix.dotnet }} + dotnet-quality: 'ga' - name: Build run: ./csharp/build.sh - name: Run tests @@ -267,7 +268,7 @@ jobs: tar xf cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Darwin-x86_64/CMake.app/Contents/bin" >> $GITHUB_PATH - name: Build - run: cmake --version && ./cppbuild/cppbuild + run: ./cppbuild/cppbuild cpp-msvc-build: name: C++ MSVC (Windows) From 3e41d5dc6704f8b94102e6769424839039da77a1 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Jan 2023 15:32:06 +0100 Subject: [PATCH 161/805] Revert "[CI] Update list of .NET versions tested against." This reverts commit 9ffc9a4f0a5905594b9bd245b47cd6a1c8320912. --- .github/workflows/ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f05ab33d9..679e21e7ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,7 +68,7 @@ jobs: strategy: fail-fast: false matrix: - dotnet: [ '3.1.301', '5.x', '6.x', '7.x' ] + dotnet: [ '3.1.301' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 @@ -95,10 +95,9 @@ jobs: restore-keys: | ${{ runner.os }}-nuget- - name: Setup dotnet - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v2 with: dotnet-version: ${{ matrix.dotnet }} - dotnet-quality: 'ga' - name: Build run: ./csharp/build.sh - name: Run tests @@ -268,7 +267,7 @@ jobs: tar xf cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Darwin-x86_64/CMake.app/Contents/bin" >> $GITHUB_PATH - name: Build - run: ./cppbuild/cppbuild + run: cmake --version && ./cppbuild/cppbuild cpp-msvc-build: name: C++ MSVC (Windows) From f5fd9884c0c197c60069e5701bc97a227edcbfa1 Mon Sep 17 00:00:00 2001 From: Yong Jie Date: Fri, 27 Jan 2023 15:01:07 +0800 Subject: [PATCH 162/805] [Rust] bugfix: nested composite name should not be based on field name (#922) * [Rust] add failing test: nested composite should used composite name (instead of field name) as type name * [Rust] bugfix: nested composite should used composite name (instead of field name) as type name --- build.gradle | 1 + rust/Cargo.toml | 1 + .../sbe/generation/rust/RustGenerator.java | 4 +-- .../test/resources/nested-composite-name.xml | 29 +++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 sbe-tool/src/test/resources/nested-composite-name.xml diff --git a/build.gradle b/build.gradle index 63b9ef5357..abdc932a63 100644 --- a/build.gradle +++ b/build.gradle @@ -568,6 +568,7 @@ task generateRustTestCodecs(type: JavaExec) { args = ['sbe-tool/src/test/resources/issue435.xml', 'sbe-tool/src/test/resources/issue895.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', + 'sbe-tool/src/test/resources/nested-composite-name.xml', ] } diff --git a/rust/Cargo.toml b/rust/Cargo.toml index eb57d8b01c..8b7c1e774d 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -14,6 +14,7 @@ examples_uk_co_real_logic_sbe_benchmarks_fix = { path = "../generated/rust/uk_co issue_435 = { path = "../generated/rust/issue435" } issue_895 = { path = "../generated/rust/issue895" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } +nested_composite_name = { path = "../generated/rust/nested-composite-name" } [dev-dependencies] criterion = "0.3" diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 3fc3cccdec..98ed1c2554 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -473,7 +473,7 @@ private static void generateCompositeEncoder( final String name) throws IOException { final String encoderName = toLowerSnakeCase(encoderName(name)); - final String encoderTypeName = encoderName(formatStructName(typeToken.name())); + final String encoderTypeName = encoderName(formatStructName(typeToken.applicableTypeName())); indent(sb, level, "/// COMPOSITE ENCODER\n"); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(self) -> %2$s {\n", @@ -533,7 +533,7 @@ private static void generateCompositeDecoder( final String name) throws IOException { final String decoderName = toLowerSnakeCase(decoderName(name)); - final String decoderTypeName = decoderName(formatStructName(typeToken.name())); + final String decoderTypeName = decoderName(formatStructName(typeToken.applicableTypeName())); indent(sb, level, "/// COMPOSITE DECODER\n"); indent(sb, level, "#[inline]\n"); if (fieldToken.version() > 0) diff --git a/sbe-tool/src/test/resources/nested-composite-name.xml b/sbe-tool/src/test/resources/nested-composite-name.xml new file mode 100644 index 0000000000..e7fb3a0566 --- /dev/null +++ b/sbe-tool/src/test/resources/nested-composite-name.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + From f2ee9e315971545bb42d3eeccc0bc176b8e023da Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 27 Jan 2023 17:24:31 +0100 Subject: [PATCH 163/805] [CI] Allow manual runs. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 679e21e7ac..1959daf8ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,7 @@ name: Continuous Integration on: + workflow_dispatch: push: branches: - master From 21aef3d0074d48d8641eff681f02035abd74cd27 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 3 Feb 2023 16:08:31 +0100 Subject: [PATCH 164/805] [Java] Upgrade to versions plugin 0.45.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index abdc932a63..c7b707c1f4 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ import java.security.MessageDigest plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '7.1.2' apply false - id "com.github.ben-manes.versions" version "0.44.0" + id "com.github.ben-manes.versions" version "0.45.0" } defaultTasks 'clean', 'build' From 13d6092a010ad9529d3c53672075902ece187c4b Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 3 Feb 2023 15:32:49 +0000 Subject: [PATCH 165/805] [Java] Fix CodeQL link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0de28a3b78..8affd43e68 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Simple Binary Encoding (SBE) [![GitHub](https://img.shields.io/github/license/real-logic/simple-binary-encoding.svg)](https://github.com/real-logic/simple-binary-encoding/blob/master/LICENSE) [![Actions Status](https://github.com/real-logic/simple-binary-encoding/workflows/Continuous%20Integration/badge.svg)](https://github.com/real-logic/simple-binary-encoding/actions) -[![CodeQL Status](https://github.com/real-logic/simple-binary-encoding/workflows/CodeQL/badge.svg)](https://github.com/real-logic/simple-binary-encoding/workflows/actions) +[![CodeQL Status](https://github.com/real-logic/simple-binary-encoding/workflows/CodeQL/badge.svg)](https://github.com/real-logic/simple-binary-encoding/actions) [SBE](https://github.com/FIXTradingCommunity/fix-simple-binary-encoding) is an OSI layer 6 presentation for encoding and decoding binary application messages for low-latency financial applications. This repository contains From 060a95c9dcd7d21c1ce55f757162a292793e5ae5 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 3 Feb 2023 16:41:43 +0100 Subject: [PATCH 166/805] [CI] Try autobuild for Java CodeQL. --- .github/workflows/codeql.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3dc7cd836c..063bb2ea9f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -64,15 +64,15 @@ jobs: - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: - languages: ${{ matrix.language }} - - - name: Build with Gradle - run: ./gradlew + languages: 'java' + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: - category: "/language:${{matrix.language}}" + category: '/language:java' csharp-analyze: name: C# Analyze ${{ matrix.dotnet }} From e5cf91eb5cc0ca22d8538328cc305bffe1dd76f7 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 3 Feb 2023 16:53:02 +0100 Subject: [PATCH 167/805] Revert "[CI] Try autobuild for Java CodeQL." This reverts commit 060a95c9dcd7d21c1ce55f757162a292793e5ae5. --- .github/workflows/codeql.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 063bb2ea9f..3dc7cd836c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -64,15 +64,15 @@ jobs: - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: - languages: 'java' - - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + languages: ${{ matrix.language }} + + - name: Build with Gradle + run: ./gradlew - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: - category: '/language:java' + category: "/language:${{matrix.language}}" csharp-analyze: name: C# Analyze ${{ matrix.dotnet }} From 8efe53c0e9a3768f5a00039028ac0133090348db Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 3 Feb 2023 16:54:35 +0100 Subject: [PATCH 168/805] [CI] Enable `security-and-quality` CodeQL checks. --- .github/workflows/codeql.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3dc7cd836c..044cc76de0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -65,6 +65,7 @@ jobs: uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} + queries: +security-and-quality - name: Build with Gradle run: ./gradlew @@ -120,6 +121,7 @@ jobs: uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} + queries: +security-and-quality - name: Build run: ./csharp/build.sh @@ -170,6 +172,7 @@ jobs: uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} + queries: +security-and-quality - name: Build run: ./cppbuild/cppbuild From d734e60d78f8520c0615c0a7640ee9ba8ab772c3 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 3 Feb 2023 16:09:09 +0000 Subject: [PATCH 169/805] [C++] Ensure values are initialised for test. --- sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h index 10f06ef65f..f55c4bed4c 100644 --- a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h @@ -83,10 +83,10 @@ class SbeCarCodecBench : public CodecBench { car.wrapForDecode((char *)buffer, 0, Car::sbeBlockLength(), Car::sbeSchemaVersion(), bufferLength); - volatile int64_t tmpInt; - volatile const char *tmpChar; - volatile double tmpDouble; - volatile bool tmpBool; + volatile int64_t tmpInt = 0; + volatile const char *tmpChar = nullptr; + volatile double tmpDouble = 0; + volatile bool tmpBool = 0; tmpInt = car.serialNumber(); tmpInt = car.modelYear(); From 20cff02a4b53777598587f1161ef835503fe3963 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 3 Feb 2023 16:13:15 +0000 Subject: [PATCH 170/805] [Java] Validate IR file for decoding is not greater than Integer.MAX_VALUE. --- .../main/java/uk/co/real_logic/sbe/ir/IrDecoder.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index 0551dcdf02..d80ca04b46 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -46,7 +46,7 @@ public class IrDecoder implements AutoCloseable private final FrameCodecDecoder frameDecoder = new FrameCodecDecoder(); private final TokenCodecDecoder tokenDecoder = new TokenCodecDecoder(); private int offset; - private final long length; + private final int length; private String irPackageName = null; private String irNamespaceName = null; private String semanticVersion = null; @@ -67,9 +67,15 @@ public IrDecoder(final String fileName) { channel = FileChannel.open(Paths.get(fileName), READ); final long fileLength = channel.size(); + + if (fileLength > Integer.MAX_VALUE) + { + throw new IllegalStateException("Invalid IR file: length=" + fileLength + " > Integer.MAX_VALUE"); + } + final MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength); directBuffer = new UnsafeBuffer(buffer); - length = fileLength; + length = (int)fileLength; offset = 0; } catch (final IOException ex) From 702df4e1bfdcee2cae76502463d697bf94f00736 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 15:19:38 +0000 Subject: [PATCH 171/805] [Java] Add CodeQL config. --- .github/codeql/codeql-config.yml | 8 ++++++++ .github/workflows/codeql.yml | 3 +++ 2 files changed, 11 insertions(+) create mode 100644 .github/codeql/codeql-config.yml diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000000..00f0562196 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,8 @@ +name: "SBE CodeQL Scanning" + +queries: + - uses: security-and-quality + +query-filters: + - exclude: + id: java/iterator-implements-iterable diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 044cc76de0..54d4a46dc6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -66,6 +66,7 @@ jobs: with: languages: ${{ matrix.language }} queries: +security-and-quality + config-file: ./.github/codeql/codeql-config.yml - name: Build with Gradle run: ./gradlew @@ -122,6 +123,7 @@ jobs: with: languages: ${{ matrix.language }} queries: +security-and-quality + config-file: ./.github/codeql/codeql-config.yml - name: Build run: ./csharp/build.sh @@ -173,6 +175,7 @@ jobs: with: languages: ${{ matrix.language }} queries: +security-and-quality + config-file: ./.github/codeql/codeql-config.yml - name: Build run: ./cppbuild/cppbuild From 826a101f718dde5af3ceeac8441bf398a77797fe Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 15:37:10 +0000 Subject: [PATCH 172/805] [C#] Remove useless assignment warnings. --- .github/codeql/codeql-config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 00f0562196..afc903892e 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -6,3 +6,5 @@ queries: query-filters: - exclude: id: java/iterator-implements-iterable + - exclude: + id: cs/useless-assignment-to-local From 08309a4263c672d3cddcaf447e35b55564c630f7 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 16:19:49 +0000 Subject: [PATCH 173/805] [Java] Fix warnings in IrUtil. --- .../java/uk/co/real_logic/sbe/ir/IrUtil.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java index aca56530b3..9b57dee5bf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java @@ -48,14 +48,14 @@ static ByteOrder mapByteOrder(final ByteOrderCodec byteOrder) { switch (byteOrder) { - case SBE_LITTLE_ENDIAN: - return ByteOrder.LITTLE_ENDIAN; - case SBE_BIG_ENDIAN: return ByteOrder.BIG_ENDIAN; - } - return ByteOrder.LITTLE_ENDIAN; + default: + case SBE_LITTLE_ENDIAN: + case NULL_VAL: + return ByteOrder.LITTLE_ENDIAN; + } } static SignalCodec mapSignal(final Signal signal) @@ -414,9 +414,11 @@ static Encoding.Presence mapPresence(final PresenceCodec presence) case SBE_CONSTANT: return Encoding.Presence.CONSTANT; - } - return Encoding.Presence.REQUIRED; + default: + case SBE_REQUIRED: + return Encoding.Presence.REQUIRED; + } } static PresenceCodec mapPresence(final Encoding.Presence presence) @@ -428,8 +430,10 @@ static PresenceCodec mapPresence(final Encoding.Presence presence) case CONSTANT: return PresenceCodec.SBE_CONSTANT; - } - return PresenceCodec.SBE_REQUIRED; + default: + case REQUIRED: + return PresenceCodec.SBE_REQUIRED; + } } } From d1909acaade7b772539e42a492706c540f0d60a8 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 16:28:09 +0000 Subject: [PATCH 174/805] [C#] Warnings cleanup. --- .github/codeql/codeql-config.yml | 2 ++ csharp/sbe-samples-car/CarExample.cs | 2 +- csharp/sbe-samples-extension/ExtensionExample.cs | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index afc903892e..da536ab06f 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -6,5 +6,7 @@ queries: query-filters: - exclude: id: java/iterator-implements-iterable + - exclude: + id: java/missing-override-annotation - exclude: id: cs/useless-assignment-to-local diff --git a/csharp/sbe-samples-car/CarExample.cs b/csharp/sbe-samples-car/CarExample.cs index 3a51103d8a..3706ab959a 100644 --- a/csharp/sbe-samples-car/CarExample.cs +++ b/csharp/sbe-samples-car/CarExample.cs @@ -261,7 +261,7 @@ public static void Decode(Car car, sb.Append("\ncar.size=").Append(car.Size); - Console.WriteLine(sb.ToString()); + Console.WriteLine(sb); } } } diff --git a/csharp/sbe-samples-extension/ExtensionExample.cs b/csharp/sbe-samples-extension/ExtensionExample.cs index 73b3956aa0..9e11ee3b35 100644 --- a/csharp/sbe-samples-extension/ExtensionExample.cs +++ b/csharp/sbe-samples-extension/ExtensionExample.cs @@ -74,7 +74,7 @@ public static void ExampleMain() // And now let's encode an extension and decode it as baseline Extension.ExtensionExample.Encode(extensionCar, directBuffer, Extension.MessageHeader.Size); - Baseline.ExtensionExample.Decode(baselineCar, directBuffer, (int)Baseline.MessageHeader.Size, (int)Extension.Car.BlockLength, (int)Baseline.Car.SchemaVersion); + Baseline.ExtensionExample.Decode(baselineCar, directBuffer, Baseline.MessageHeader.Size, (int)Extension.Car.BlockLength, (int)Baseline.Car.SchemaVersion); } } @@ -283,7 +283,7 @@ public static void Decode(Car car, sb.Append("\ncar.size=").Append(car.Size); - Console.WriteLine(sb.ToString()); + Console.WriteLine(sb); } } } @@ -539,7 +539,7 @@ public static void Decode(Car car, sb.Append("\ncar.size=").Append(car.Size); - Console.WriteLine(sb.ToString()); + Console.WriteLine(sb); } } } From 77666f96c15645e0abec05655195f4947f105487 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 16:38:08 +0000 Subject: [PATCH 175/805] [Java] More efficient attribute parsing in XML with more precise error message. --- .../uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index e407e675ff..da8c0e1483 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -16,6 +16,7 @@ */ package uk.co.real_logic.sbe.xml; +import org.agrona.Strings; import org.agrona.collections.ObjectHashSet; import org.w3c.dom.*; import org.xml.sax.InputSource; @@ -298,13 +299,20 @@ public static String getAttributeValue(final Node elementNode, final String attr final NamedNodeMap attributes = elementNode.getAttributes(); final Node attrNode = attributes.getNamedItemNS(null, attrName); - if (null == attrNode || "".equals(attrNode.getNodeValue())) + if (null == attrNode) { throw new IllegalStateException( - "element '" + elementNode.getNodeName() + "' has empty or missing attribute: " + attrName); + "element '" + elementNode.getNodeName() + "' has missing attribute: " + attrName); } - return attrNode.getNodeValue(); + final String nodeValue = attrNode.getNodeValue(); + if (Strings.isEmpty(nodeValue)) + { + throw new IllegalStateException( + "element '" + elementNode.getNodeName() + "' has empty attribute: " + attrName); + } + + return nodeValue; } /** From 76d01f7bef470dd7767f0f8d0be3a3841b24d311 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 16:43:04 +0000 Subject: [PATCH 176/805] [C++] Allow trivial switch statements. --- .github/codeql/codeql-config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index da536ab06f..889b4fe698 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -10,3 +10,5 @@ query-filters: id: java/missing-override-annotation - exclude: id: cs/useless-assignment-to-local + - exclude: + id: cpp/trivial-switch From 15f395e748686e5d5a90ac3afb0d52a7619bbc2c Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 17:05:33 +0000 Subject: [PATCH 177/805] [Java] Close resources in test. --- .../csharp/Issue567GroupSizeTest.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index cd5342f7d8..48b436b289 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -58,10 +58,14 @@ void shouldThrowWhenUsingATypeThatIsNotConstrainedToFitInAnIntAsTheGroupSize() t .stopOnError(true) .build(); final InputStream in = Tests.getLocalResource("issue567-invalid.xml"); - final InputSource is = new InputSource(new InputStreamReader(in, StandardCharsets.UTF_8)); - assertThrows(IllegalArgumentException.class, () -> XmlSchemaParser.parse(is, options)); - verify(mockErr).println(ERR_MSG); + try (InputStreamReader characterStream = new InputStreamReader(in, StandardCharsets.UTF_8)) + { + final InputSource is = new InputSource(characterStream); + + assertThrows(IllegalArgumentException.class, () -> XmlSchemaParser.parse(is, options)); + verify(mockErr).println(ERR_MSG); + } } @Test @@ -72,21 +76,25 @@ void shouldGenerateWhenUsingATypeThatIsConstrainedToFitInAnIntAsTheGroupSize() t .stopOnError(true) .build(); final InputStream in = Tests.getLocalResource("issue567-valid.xml"); - final InputSource is = new InputSource(new InputStreamReader(in, StandardCharsets.UTF_8)); - final MessageSchema schema = XmlSchemaParser.parse(is, options); - verify(mockErr).println(ERR_MSG); + try (InputStreamReader characterStream = new InputStreamReader(in, StandardCharsets.UTF_8)) + { + final InputSource is = new InputSource(characterStream); + + final MessageSchema schema = XmlSchemaParser.parse(is, options); + verify(mockErr).println(ERR_MSG); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); - final StringWriterOutputManager outputManager = new StringWriterOutputManager(); - outputManager.setPackageName(ir.applicableNamespace()); - final CSharpGenerator generator = new CSharpGenerator(ir, outputManager); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + final CSharpGenerator generator = new CSharpGenerator(ir, outputManager); - generator.generate(); + generator.generate(); - final String source = outputManager.getSource("tests.Issue567").toString(); - assertThat(source, containsString(EXPECTED_COUNT_CHECK)); + final String source = outputManager.getSource("tests.Issue567").toString(); + assertThat(source, containsString(EXPECTED_COUNT_CHECK)); + } } } From f77d5e99a651b7b1edf90bfd668ed40c4fa72a1e Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 18:26:10 +0000 Subject: [PATCH 178/805] [Java] Fix resource leaks in tests. --- .../real_logic/sbe/xml/XmlSchemaParser.java | 2 +- .../sbe/generation/cpp/CppGeneratorTest.java | 27 +- .../java/ConstantCharArrayTest.java | 75 +-- .../java/FixedSizeDataGeneratorTest.java | 22 +- .../java/GenerateFixBinaryTest.java | 112 +++-- .../java/GenerateIlinkBinaryTest.java | 112 +++-- .../generation/java/JavaGeneratorTest.java | 169 ++++--- .../generation/java/NullEnumTypedTest.java | 40 +- .../generation/java/QualifiedYieldTest.java | 43 +- .../generation/java/SchemaExtensionTest.java | 18 +- ...onTransformedSchemaJavaGenerationTest.java | 41 +- .../java/WarningFormattingTest.java | 36 +- .../sbe/ir/BasicXmlIrGenerationTest.java | 471 +++++++++--------- .../sbe/ir/CompositeElementsIrTest.java | 289 +++++------ .../sbe/ir/CompositeOffsetsTest.java | 40 +- .../real_logic/sbe/ir/CompositeRefsTest.java | 17 +- .../co/real_logic/sbe/ir/EncodedIrTest.java | 227 +++++---- .../sbe/ir/GroupWithDataIrTest.java | 231 +++++---- .../sbe/ir/SinceVersionValidationTest.java | 8 +- .../co/real_logic/sbe/ir/ValueRefsTest.java | 21 +- .../sbe/xml/BasicSchemaFileTest.java | 38 +- .../sbe/xml/CompositeElementsTest.java | 49 +- .../sbe/xml/CyclicReferencesTest.java | 7 +- .../xml/EmbeddedLengthAndCountFileTest.java | 24 +- .../co/real_logic/sbe/xml/EnumTypeTest.java | 30 +- .../real_logic/sbe/xml/ErrorHandlerTest.java | 33 +- .../real_logic/sbe/xml/GroupWithDataTest.java | 25 +- .../co/real_logic/sbe/xml/OffsetFileTest.java | 209 ++++---- .../uk/co/real_logic/sbe/xml/SetTypeTest.java | 31 +- .../SinceVersionSchemaTransformerTest.java | 19 +- 30 files changed, 1344 insertions(+), 1122 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index da8c0e1483..d9ecb33df3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -172,7 +172,7 @@ public static MessageSchema parse(final InputStream in, final ParserOptions opti } /** - * Scan XML for all types (encodedDataType, compositeType, enumType, and setType) and save in map. + * Scan XML for all types (encodedDataType, compositeType, enumType, and setType) and save in a map. * * @param document for the XML parsing. * @param xPath for XPath expression reuse. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index dd7be3c505..73fa7664f2 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -23,6 +23,8 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.not; @@ -33,18 +35,21 @@ class CppGeneratorTest @Test void shouldUseGeneratedLiteralForConstantOneWhenGeneratingBitsetCode() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("issue827.xml"), options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final StringWriterOutputManager outputManager = new StringWriterOutputManager(); - outputManager.setPackageName(ir.applicableNamespace()); + try (InputStream in = Tests.getLocalResource("issue827.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); - final CppGenerator generator = new CppGenerator(ir, false, outputManager); - generator.generate(); + final CppGenerator generator = new CppGenerator(ir, false, outputManager); + generator.generate(); - final String source = outputManager.getSource("issue827.FlagsSet").toString(); - assertThat(source, not(containsString("1u << "))); - assertThat(source, containsString("UINT64_C(0x1) << ")); + final String source = outputManager.getSource("issue827.FlagsSet").toString(); + assertThat(source, not(containsString("1u << "))); + assertThat(source, containsString("UINT64_C(0x1) << ")); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java index 75790252d2..7b823d5a86 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java @@ -24,10 +24,12 @@ import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import uk.co.real_logic.sbe.xml.XmlSchemaParser; + +import java.io.InputStream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.StringContains.containsString; -import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; class ConstantCharArrayTest { @@ -39,45 +41,48 @@ class ConstantCharArrayTest @Test void shouldGenerateConstCharArrayMethods() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("issue505.xml"), options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); + try (InputStream in = Tests.getLocalResource("issue505.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = XmlSchemaParser.parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); - final StringWriterOutputManager outputManager = new StringWriterOutputManager(); - outputManager.setPackageName(ir.applicableNamespace()); - final JavaGenerator generator = new JavaGenerator( - ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); - generator.generate(); - final String sources = outputManager.getSources().toString(); + generator.generate(); + final String sources = outputManager.getSources().toString(); - final String expectedOne = - " public byte sourceOne()\n" + - " {\n" + - " return (byte)67;\n" + - " }"; - assertThat(sources, containsString(expectedOne)); + final String expectedOne = + " public byte sourceOne()\n" + + " {\n" + + " return (byte)67;\n" + + " }"; + assertThat(sources, containsString(expectedOne)); - final String expectedTwo = - " public byte sourceTwo()\n" + - " {\n" + - " return (byte)68;\n" + - " }"; - assertThat(sources, containsString(expectedTwo)); + final String expectedTwo = + " public byte sourceTwo()\n" + + " {\n" + + " return (byte)68;\n" + + " }"; + assertThat(sources, containsString(expectedTwo)); - final String expectedThree = - " public String sourceThree()\n" + - " {\n" + - " return \"EF\";\n" + - " }"; - assertThat(sources, containsString(expectedThree)); + final String expectedThree = + " public String sourceThree()\n" + + " {\n" + + " return \"EF\";\n" + + " }"; + assertThat(sources, containsString(expectedThree)); - final String expectedFour = - " public String sourceFour()\n" + - " {\n" + - " return \"GH\";\n" + - " }"; - assertThat(sources, containsString(expectedFour)); + final String expectedFour = + " public String sourceFour()\n" + + " {\n" + + " return \"GH\";\n" + + " }"; + assertThat(sources, containsString(expectedFour)); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java index 9e6a9f1706..7827dac2b3 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java @@ -27,14 +27,15 @@ import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import uk.co.real_logic.sbe.xml.XmlSchemaParser; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.is; import static uk.co.real_logic.sbe.generation.java.ReflectionUtil.*; -import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; class FixedSizeDataGeneratorTest { @@ -50,15 +51,18 @@ class FixedSizeDataGeneratorTest @BeforeEach void setUp() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("extension-schema.xml"), options); - final IrGenerator irg = new IrGenerator(); - ir = irg.generate(schema); + try (InputStream in = Tests.getLocalResource("extension-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = XmlSchemaParser.parse(in, options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); - outputManager.clear(); - outputManager.setPackageName(ir.applicableNamespace()); + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); - generator().generate(); + generator().generate(); + } } @Test diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java index 0595da4469..82a280ed5e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java @@ -22,9 +22,14 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.SbeTool; import uk.co.real_logic.sbe.Tests; -import uk.co.real_logic.sbe.ir.*; -import uk.co.real_logic.sbe.xml.*; - +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.IrDecoder; +import uk.co.real_logic.sbe.ir.IrEncoder; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; import java.nio.ByteBuffer; import java.util.Map; @@ -46,32 +51,35 @@ void shouldGenerateValidJava() throws Exception { System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("FixBinary.xml"), options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final JavaGenerator generator = new JavaGenerator( - ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); - - outputManager.setPackageName(ir.applicableNamespace()); - generator.generateMessageHeaderStub(); - generator.generateTypeStubs(); - generator.generate(); - - final Map sources = outputManager.getSources(); - + try (InputStream in = Tests.getLocalResource("FixBinary.xml")) { - final String className = "MDIncrementalRefreshTradeSummary42Encoder"; - final String fqClassName = ir.applicableNamespace() + "." + className; - final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); - assertNotNull(aClass); - } - - { - final String className = "MDIncrementalRefreshTradeSummary42Decoder"; - final String fqClassName = ir.applicableNamespace() + "." + className; - final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); - assertNotNull(aClass); + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); + + outputManager.setPackageName(ir.applicableNamespace()); + generator.generateMessageHeaderStub(); + generator.generateTypeStubs(); + generator.generate(); + + final Map sources = outputManager.getSources(); + + { + final String className = "MDIncrementalRefreshTradeSummary42Encoder"; + final String fqClassName = ir.applicableNamespace() + "." + className; + final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); + assertNotNull(aClass); + } + + { + final String className = "MDIncrementalRefreshTradeSummary42Decoder"; + final String fqClassName = ir.applicableNamespace() + "." + className; + final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); + assertNotNull(aClass); + } } } @@ -80,25 +88,33 @@ void shouldGenerateAndEncodeIr() throws Exception { System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("FixBinary.xml"), options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); - - final IrEncoder irEncoder = new IrEncoder(buffer, ir); - irEncoder.encode(); - - buffer.flip(); - final IrDecoder irDecoder = new IrDecoder(buffer); - final Ir decodedIr = irDecoder.decode(); - - assertEquals(ir.id(), decodedIr.id()); - assertEquals(ir.version(), decodedIr.version()); - assertEquals(ir.byteOrder(), decodedIr.byteOrder()); - assertEquals(ir.applicableNamespace(), decodedIr.applicableNamespace()); - assertEquals(ir.packageName(), decodedIr.packageName()); - assertEquals(ir.types().size(), decodedIr.types().size()); - assertEquals(ir.messages().size(), decodedIr.messages().size()); + try (InputStream in = Tests.getLocalResource("FixBinary.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); + + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) + { + irEncoder.encode(); + } + + buffer.flip(); + + try (IrDecoder irDecoder = new IrDecoder(buffer)) + { + final Ir decodedIr = irDecoder.decode(); + + assertEquals(ir.id(), decodedIr.id()); + assertEquals(ir.version(), decodedIr.version()); + assertEquals(ir.byteOrder(), decodedIr.byteOrder()); + assertEquals(ir.applicableNamespace(), decodedIr.applicableNamespace()); + assertEquals(ir.packageName(), decodedIr.packageName()); + assertEquals(ir.types().size(), decodedIr.types().size()); + assertEquals(ir.messages().size(), decodedIr.messages().size()); + } + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java index e3facf38f6..6448428ff8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java @@ -22,9 +22,14 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.SbeTool; import uk.co.real_logic.sbe.Tests; -import uk.co.real_logic.sbe.ir.*; -import uk.co.real_logic.sbe.xml.*; - +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.IrDecoder; +import uk.co.real_logic.sbe.ir.IrEncoder; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; import java.nio.ByteBuffer; import java.util.Map; @@ -46,32 +51,35 @@ void shouldGenerateValidJava() throws Exception { System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("ilinkbinary.xml"), options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final JavaGenerator generator = new JavaGenerator( - ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); - - outputManager.setPackageName(ir.applicableNamespace()); - generator.generateMessageHeaderStub(); - generator.generateTypeStubs(); - generator.generate(); - - final Map sources = outputManager.getSources(); - + try (InputStream in = Tests.getLocalResource("ilinkbinary.xml")) { - final String className = "NewOrderSingle514Encoder"; - final String fqClassName = ir.applicableNamespace() + "." + className; - final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); - assertNotNull(aClass); - } - - { - final String className = "NewOrderSingle514Decoder"; - final String fqClassName = ir.applicableNamespace() + "." + className; - final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); - assertNotNull(aClass); + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); + + outputManager.setPackageName(ir.applicableNamespace()); + generator.generateMessageHeaderStub(); + generator.generateTypeStubs(); + generator.generate(); + + final Map sources = outputManager.getSources(); + + { + final String className = "NewOrderSingle514Encoder"; + final String fqClassName = ir.applicableNamespace() + "." + className; + final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); + assertNotNull(aClass); + } + + { + final String className = "NewOrderSingle514Decoder"; + final String fqClassName = ir.applicableNamespace() + "." + className; + final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); + assertNotNull(aClass); + } } } @@ -80,25 +88,33 @@ void shouldGenerateAndEncodeIr() throws Exception { System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("ilinkbinary.xml"), options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); - - final IrEncoder irEncoder = new IrEncoder(buffer, ir); - irEncoder.encode(); - - buffer.flip(); - final IrDecoder irDecoder = new IrDecoder(buffer); - final Ir decodedIr = irDecoder.decode(); - - assertEquals(ir.id(), decodedIr.id()); - assertEquals(ir.version(), decodedIr.version()); - assertEquals(ir.byteOrder(), decodedIr.byteOrder()); - assertEquals(ir.applicableNamespace(), decodedIr.applicableNamespace()); - assertEquals(ir.packageName(), decodedIr.packageName()); - assertEquals(ir.types().size(), decodedIr.types().size()); - assertEquals(ir.messages().size(), decodedIr.messages().size()); + try (InputStream in = Tests.getLocalResource("ilinkbinary.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024); + + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) + { + irEncoder.encode(); + } + + buffer.flip(); + + try (IrDecoder irDecoder = new IrDecoder(buffer)) + { + final Ir decodedIr = irDecoder.decode(); + + assertEquals(ir.id(), decodedIr.id()); + assertEquals(ir.version(), decodedIr.version()); + assertEquals(ir.byteOrder(), decodedIr.byteOrder()); + assertEquals(ir.applicableNamespace(), decodedIr.applicableNamespace()); + assertEquals(ir.packageName(), decodedIr.packageName()); + assertEquals(ir.types().size(), decodedIr.types().size()); + assertEquals(ir.messages().size(), decodedIr.messages().size()); + } + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index c8d4d5870d..f12fef3751 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -29,6 +29,7 @@ import uk.co.real_logic.sbe.xml.ParserOptions; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Method; import java.nio.ByteOrder; import java.util.Map; @@ -58,13 +59,16 @@ class JavaGeneratorTest @BeforeEach void setUp() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("code-generation-schema.xml"), options); - final IrGenerator irg = new IrGenerator(); - ir = irg.generate(schema); + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); - outputManager.clear(); - outputManager.setPackageName(ir.applicableNamespace()); + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + } } @Test @@ -461,88 +465,97 @@ void shouldGenerateRepeatingGroupCountLimits() throws Exception @Test void shouldMarkDeprecatedClasses() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("deprecated-msg-test-schema.xml"), options); - final IrGenerator irg = new IrGenerator(); - ir = irg.generate(schema); - - outputManager.clear(); - outputManager.setPackageName(ir.applicableNamespace()); - - generator().generate(); - final String encoderFqcn = ir.applicableNamespace() + ".DeprecatedMessageEncoder"; - final Class encoderClazz = compile(encoderFqcn); - assertNotNull(encoderClazz); - assertTrue(encoderClazz.isAnnotationPresent(Deprecated.class)); - - final String decoderFqcn = ir.applicableNamespace() + ".DeprecatedMessageDecoder"; - final Class decoderClazz = compile(decoderFqcn); - assertNotNull(decoderClazz); - assertTrue(decoderClazz.isAnnotationPresent(Deprecated.class)); + try (InputStream in = Tests.getLocalResource("deprecated-msg-test-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + + generator().generate(); + final String encoderFqcn = ir.applicableNamespace() + ".DeprecatedMessageEncoder"; + final Class encoderClazz = compile(encoderFqcn); + assertNotNull(encoderClazz); + assertTrue(encoderClazz.isAnnotationPresent(Deprecated.class)); + + final String decoderFqcn = ir.applicableNamespace() + ".DeprecatedMessageDecoder"; + final Class decoderClazz = compile(decoderFqcn); + assertNotNull(decoderClazz); + assertTrue(decoderClazz.isAnnotationPresent(Deprecated.class)); + } } @Test void shouldCreateTypesInDifferentPackages() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("explicit-package-test-schema.xml"), options); - final IrGenerator irg = new IrGenerator(); - ir = irg.generate(schema); - - outputManager.clear(); - outputManager.setPackageName(ir.applicableNamespace()); - - final JavaGenerator generator = new JavaGenerator(ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, - true, outputManager); - - generator.generate(); - final String encoderFqcn = ir.applicableNamespace() + ".TestMessageEncoder"; - final Class encoderClazz = compile(encoderFqcn); - assertNotNull(encoderClazz); - - final String decoderFqcn = ir.applicableNamespace() + ".TestMessageDecoder"; - final Class decoderClazz = compile(decoderFqcn); - assertNotNull(decoderClazz); - - final Map sources = outputManager.getSources(); - assertNotNull(sources.get("test.message.schema.common.CarEncoder")); - assertNotNull(sources.get("test.message.schema.common.CarDecoder")); - assertNotNull(sources.get("outside.schema.BooleanType")); - assertNotNull(sources.get("outside.schema.DaysEncoder")); - assertNotNull(sources.get("outside.schema.DaysDecoder")); - assertNotNull(sources.get(ir.applicableNamespace() + ".MessageHeaderEncoder")); + try (InputStream in = Tests.getLocalResource("explicit-package-test-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, true, outputManager); + + generator.generate(); + final String encoderFqcn = ir.applicableNamespace() + ".TestMessageEncoder"; + final Class encoderClazz = compile(encoderFqcn); + assertNotNull(encoderClazz); + + final String decoderFqcn = ir.applicableNamespace() + ".TestMessageDecoder"; + final Class decoderClazz = compile(decoderFqcn); + assertNotNull(decoderClazz); + + final Map sources = outputManager.getSources(); + assertNotNull(sources.get("test.message.schema.common.CarEncoder")); + assertNotNull(sources.get("test.message.schema.common.CarDecoder")); + assertNotNull(sources.get("outside.schema.BooleanType")); + assertNotNull(sources.get("outside.schema.DaysEncoder")); + assertNotNull(sources.get("outside.schema.DaysDecoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".MessageHeaderEncoder")); + } } @Test void shouldCreateTypesInSamePackageIfSupportDisabled() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("explicit-package-test-schema.xml"), options); - final IrGenerator irg = new IrGenerator(); - ir = irg.generate(schema); - - outputManager.clear(); - outputManager.setPackageName(ir.applicableNamespace()); - - final JavaGenerator generator = new JavaGenerator(ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, - false, outputManager); - - generator.generate(); - final String encoderFqcn = ir.applicableNamespace() + ".TestMessageEncoder"; - final Class encoderClazz = compile(encoderFqcn); - assertNotNull(encoderClazz); - - final String decoderFqcn = ir.applicableNamespace() + ".TestMessageDecoder"; - final Class decoderClazz = compile(decoderFqcn); - assertNotNull(decoderClazz); - - final Map sources = outputManager.getSources(); - assertNotNull(sources.get(ir.applicableNamespace() + ".CarEncoder")); - assertNotNull(sources.get(ir.applicableNamespace() + ".CarDecoder")); - assertNotNull(sources.get(ir.applicableNamespace() + ".BooleanType")); - assertNotNull(sources.get(ir.applicableNamespace() + ".DaysEncoder")); - assertNotNull(sources.get(ir.applicableNamespace() + ".DaysDecoder")); - assertNotNull(sources.get(ir.applicableNamespace() + ".MessageHeaderEncoder")); + try (InputStream in = Tests.getLocalResource("explicit-package-test-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, false, outputManager); + + generator.generate(); + final String encoderFqcn = ir.applicableNamespace() + ".TestMessageEncoder"; + final Class encoderClazz = compile(encoderFqcn); + assertNotNull(encoderClazz); + + final String decoderFqcn = ir.applicableNamespace() + ".TestMessageDecoder"; + final Class decoderClazz = compile(decoderFqcn); + assertNotNull(decoderClazz); + + final Map sources = outputManager.getSources(); + assertNotNull(sources.get(ir.applicableNamespace() + ".CarEncoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".CarDecoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".BooleanType")); + assertNotNull(sources.get(ir.applicableNamespace() + ".DaysEncoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".DaysDecoder")); + assertNotNull(sources.get(ir.applicableNamespace() + ".MessageHeaderEncoder")); + } } private Class getModelClass(final Object encoder) throws ClassNotFoundException diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java index 2b29b64451..09d6f5b00e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java @@ -24,12 +24,13 @@ import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import uk.co.real_logic.sbe.xml.XmlSchemaParser; +import java.io.InputStream; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.StringContains.containsString; -import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; class NullEnumTypedTest { @@ -41,26 +42,29 @@ class NullEnumTypedTest @Test void shouldGenerateEnumWithNonDefaultNullType() throws Exception { - final ParserOptions options = ParserOptions.builder() - .stopOnError(true) - .build(); - final MessageSchema schema = parse(Tests.getLocalResource("issue889.xml"), options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); + try (InputStream in = Tests.getLocalResource("issue889.xml")) + { + final ParserOptions options = ParserOptions.builder() + .stopOnError(true) + .build(); + final MessageSchema schema = XmlSchemaParser.parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); - final StringWriterOutputManager outputManager = new StringWriterOutputManager(); - final JavaGenerator generator = new JavaGenerator( - ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, true, outputManager); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, true, outputManager); - outputManager.setPackageName(ir.applicableNamespace()); - generator.generateMessageHeaderStub(); - generator.generateTypeStubs(); - generator.generate(); + outputManager.setPackageName(ir.applicableNamespace()); + generator.generateMessageHeaderStub(); + generator.generateTypeStubs(); + generator.generate(); - final Map sources = outputManager.getSources(); - final String source = sources.get("issue889.LotType").toString(); + final Map sources = outputManager.getSources(); + final String source = sources.get("issue889.LotType").toString(); - assertThat(source, containsString("NULL_VAL((short)0);")); - assertThat(source, containsString("case 0: return NULL_VAL;")); + assertThat(source, containsString("NULL_VAL((short)0);")); + assertThat(source, containsString("case 0: return NULL_VAL;")); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java index e9f3573272..36ef9bed42 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java @@ -15,8 +15,6 @@ */ package uk.co.real_logic.sbe.generation.java; -import java.util.Map; - import org.agrona.DirectBuffer; import org.agrona.MutableDirectBuffer; import org.agrona.generation.CompilerUtil; @@ -24,16 +22,16 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledForJreRange; import org.junit.jupiter.api.condition.JRE; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - - import uk.co.real_logic.sbe.Tests; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; public class QualifiedYieldTest @@ -49,24 +47,27 @@ public class QualifiedYieldTest @EnabledForJreRange(min = JRE.JAVA_17) void shouldGenerateValidJava() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("issue910.xml"), options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final JavaGenerator generator = new JavaGenerator( - ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, false, outputManager); + try (InputStream in = Tests.getLocalResource("issue910.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, false, outputManager); - outputManager.setPackageName(ir.applicableNamespace()); - generator.generateMessageHeaderStub(); - generator.generateTypeStubs(); - generator.generate(); + outputManager.setPackageName(ir.applicableNamespace()); + generator.generateMessageHeaderStub(); + generator.generateTypeStubs(); + generator.generate(); - final Map sources = outputManager.getSources(); + final Map sources = outputManager.getSources(); - { - final String fqClassName = ir.applicableNamespace() + "." + "Issue910FieldDecoder"; - final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); - assertNotNull(aClass); + { + final String fqClassName = ir.applicableNamespace() + "." + "Issue910FieldDecoder"; + final Class aClass = CompilerUtil.compileInMemory(fqClassName, sources); + assertNotNull(aClass); + } } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java index dcc8877b74..1774666139 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java @@ -27,16 +27,19 @@ import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import uk.co.real_logic.sbe.xml.XmlSchemaParser; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static uk.co.real_logic.sbe.generation.java.ReflectionUtil.*; -import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @SuppressWarnings("MethodLength") class SchemaExtensionTest @@ -53,10 +56,13 @@ class SchemaExtensionTest @BeforeEach void setup() throws Exception { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(Tests.getLocalResource("extension-schema.xml"), options); - final IrGenerator irg = new IrGenerator(); - ir = irg.generate(schema); + try (InputStream in = Tests.getLocalResource("extension-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = XmlSchemaParser.parse(in, options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + } outputManager.clear(); outputManager.setPackageName(ir.applicableNamespace()); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java index cdafc79fdb..c626e044d4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java @@ -22,6 +22,7 @@ import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.xml.*; +import java.io.InputStream; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -35,28 +36,30 @@ public class SinceVersionTransformedSchemaJavaGenerationTest @CsvSource({ "0,4", "4,5", "5,6" }) void shouldGenerateCodeForOlderVersion(final int versionIncluded, final int versionExcluded) throws Exception { - final MessageSchema schema = parse( - Tests.getLocalResource("since-version-filter-schema.xml"), ParserOptions.DEFAULT); - final SchemaTransformer transformer = new SchemaTransformerFactory("*:" + versionIncluded); - final MessageSchema transformedSchema = transformer.transform(schema); - final Ir ir = new IrGenerator().generate(transformedSchema); - final StringWriterOutputManager outputManager = new StringWriterOutputManager(); - outputManager.setPackageName("test"); + try (InputStream in = Tests.getLocalResource("since-version-filter-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final SchemaTransformer transformer = new SchemaTransformerFactory("*:" + versionIncluded); + final MessageSchema transformedSchema = transformer.transform(schema); + final Ir ir = new IrGenerator().generate(transformedSchema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName("test"); - final JavaGenerator javaGenerator = new JavaGenerator( - ir, - JAVA_DEFAULT_ENCODING_BUFFER_TYPE, - JAVA_DEFAULT_DECODING_BUFFER_TYPE, - false, - false, - false, - outputManager); + final JavaGenerator javaGenerator = new JavaGenerator( + ir, + JAVA_DEFAULT_ENCODING_BUFFER_TYPE, + JAVA_DEFAULT_DECODING_BUFFER_TYPE, + false, + false, + false, + outputManager); - javaGenerator.generate(); + javaGenerator.generate(); - final Map sources = outputManager.getSources(); - assertTrue(containsCodeWithSinceVersion(sources, versionIncluded)); - assertTrue(doesNotContainsCodeWithSinceVersion(sources, versionExcluded)); + final Map sources = outputManager.getSources(); + assertTrue(containsCodeWithSinceVersion(sources, versionIncluded)); + assertTrue(doesNotContainsCodeWithSinceVersion(sources, versionExcluded)); + } } private static boolean containsCodeWithSinceVersion(final Map sources, final int version) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java index 93a6a62183..f48ce8e830 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java @@ -19,36 +19,40 @@ import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import uk.co.real_logic.sbe.xml.XmlSchemaParser; import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.io.PrintStream; import java.nio.charset.StandardCharsets; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static uk.co.real_logic.sbe.Tests.getLocalResource; -import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; class WarningFormattingTest { @Test void shouldGenerateCorrectWarning() throws Exception { - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final ParserOptions options = new ParserOptions.Builder() - .stopOnError(true) - .errorPrintStream(new PrintStream(out)) - .build(); - final MessageSchema schema = parse(getLocalResource("npe-small-header.xml"), options); - final IrGenerator irg = new IrGenerator(); - irg.generate(schema); + try (InputStream in = getLocalResource("npe-small-header.xml")) + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final ParserOptions options = new ParserOptions.Builder() + .stopOnError(true) + .errorPrintStream(new PrintStream(out)) + .build(); + final MessageSchema schema = XmlSchemaParser.parse(in, options); + final IrGenerator irg = new IrGenerator(); + irg.generate(schema); - final String warnings = out.toString(StandardCharsets.US_ASCII.name()); - assertThat(warnings, containsString( - "WARNING: at \"blockLength\" should be UINT16")); - assertThat(warnings, containsString( - "WARNING: at \"templateId\" should be UINT16")); - assertThat(warnings, containsString( - "WARNING: at \"version\" should be UINT16")); + final String warnings = out.toString(StandardCharsets.US_ASCII.name()); + assertThat(warnings, containsString( + "WARNING: at \"blockLength\" should be UINT16")); + assertThat(warnings, containsString( + "WARNING: at \"templateId\" should be UINT16")); + assertThat(warnings, containsString( + "WARNING: at \"version\" should be UINT16")); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java index b5932aa7f9..e99a73f272 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java @@ -21,6 +21,7 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; import java.nio.ByteOrder; import java.util.List; @@ -34,263 +35,277 @@ class BasicXmlIrGenerationTest @Test void shouldGenerateIrForMessageHeader() throws Exception { - final MessageSchema schema = parse(getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - - final Ir ir = irg.generate(schema); - final List tokens = ir.headerStructure().tokens(); - - assertThat(tokens.size(), is(6)); - - /* assert all elements of node 0 */ - assertThat(tokens.get(0).signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(tokens.get(0).name(), is("messageHeader")); - assertThat(tokens.get(0).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(0).encodedLength(), is(8)); - assertThat(tokens.get(0).offset(), is(0)); - - /* assert all elements of node 1 */ - assertThat(tokens.get(1).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(1).name(), is("blockLength")); - assertThat(tokens.get(1).encoding().primitiveType(), is(PrimitiveType.UINT16)); - assertThat(tokens.get(1).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(1).encodedLength(), is(2)); - assertThat(tokens.get(1).offset(), is(0)); - assertThat(tokens.get(1).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); - - /* assert all elements of node 2 */ - assertThat(tokens.get(2).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(2).name(), is("templateId")); - assertThat(tokens.get(2).encoding().primitiveType(), is(PrimitiveType.UINT16)); - assertThat(tokens.get(2).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(2).encodedLength(), is(2)); - assertThat(tokens.get(2).offset(), is(2)); - assertThat(tokens.get(2).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); - - /* assert all elements of node 3 */ - assertThat(tokens.get(3).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(3).name(), is("schemaId")); - assertThat(tokens.get(3).encoding().primitiveType(), is(PrimitiveType.UINT16)); - assertThat(tokens.get(3).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(3).encodedLength(), is(2)); - assertThat(tokens.get(3).offset(), is(4)); - assertThat(tokens.get(3).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); - - /* assert all elements of node 4 */ - assertThat(tokens.get(4).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(4).name(), is("version")); - assertThat(tokens.get(4).encoding().primitiveType(), is(PrimitiveType.UINT16)); - assertThat(tokens.get(4).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(4).encodedLength(), is(2)); - assertThat(tokens.get(4).offset(), is(6)); - assertThat(tokens.get(4).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); - - /* assert all elements of node 6 */ - assertThat(tokens.get(5).signal(), is(Signal.END_COMPOSITE)); - assertThat(tokens.get(5).name(), is("messageHeader")); - assertThat(tokens.get(5).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(5).encodedLength(), is(8)); - assertThat(tokens.get(5).offset(), is(0)); + try (InputStream in = getLocalResource("basic-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + + final Ir ir = irg.generate(schema); + final List tokens = ir.headerStructure().tokens(); + + assertThat(tokens.size(), is(6)); + + /* assert all elements of node 0 */ + assertThat(tokens.get(0).signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(tokens.get(0).name(), is("messageHeader")); + assertThat(tokens.get(0).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(0).encodedLength(), is(8)); + assertThat(tokens.get(0).offset(), is(0)); + + /* assert all elements of node 1 */ + assertThat(tokens.get(1).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(1).name(), is("blockLength")); + assertThat(tokens.get(1).encoding().primitiveType(), is(PrimitiveType.UINT16)); + assertThat(tokens.get(1).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(1).encodedLength(), is(2)); + assertThat(tokens.get(1).offset(), is(0)); + assertThat(tokens.get(1).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); + + /* assert all elements of node 2 */ + assertThat(tokens.get(2).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(2).name(), is("templateId")); + assertThat(tokens.get(2).encoding().primitiveType(), is(PrimitiveType.UINT16)); + assertThat(tokens.get(2).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(2).encodedLength(), is(2)); + assertThat(tokens.get(2).offset(), is(2)); + assertThat(tokens.get(2).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); + + /* assert all elements of node 3 */ + assertThat(tokens.get(3).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(3).name(), is("schemaId")); + assertThat(tokens.get(3).encoding().primitiveType(), is(PrimitiveType.UINT16)); + assertThat(tokens.get(3).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(3).encodedLength(), is(2)); + assertThat(tokens.get(3).offset(), is(4)); + assertThat(tokens.get(3).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); + + /* assert all elements of node 4 */ + assertThat(tokens.get(4).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(4).name(), is("version")); + assertThat(tokens.get(4).encoding().primitiveType(), is(PrimitiveType.UINT16)); + assertThat(tokens.get(4).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(4).encodedLength(), is(2)); + assertThat(tokens.get(4).offset(), is(6)); + assertThat(tokens.get(4).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); + + /* assert all elements of node 6 */ + assertThat(tokens.get(5).signal(), is(Signal.END_COMPOSITE)); + assertThat(tokens.get(5).name(), is("messageHeader")); + assertThat(tokens.get(5).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(5).encodedLength(), is(8)); + assertThat(tokens.get(5).offset(), is(0)); + } } @Test void shouldGenerateIrForBasicMessage() throws Exception { - final MessageSchema schema = parse(getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - - final List tokens = ir.getMessage(50001); - - assertThat(tokens.size(), is(5)); - - /* assert all elements of node 0 */ - assertThat(tokens.get(0).signal(), is(Signal.BEGIN_MESSAGE)); - assertThat(tokens.get(0).name(), is("TestMessage50001")); - assertThat(tokens.get(0).id(), is(50001)); - assertThat(tokens.get(0).encodedLength(), is(16)); - assertThat(tokens.get(0).offset(), is(0)); - - /* assert all elements of node 1 */ - assertThat(tokens.get(1).signal(), is(Signal.BEGIN_FIELD)); - assertThat(tokens.get(1).name(), is("Tag40001")); - assertThat(tokens.get(1).id(), is(40001)); - assertThat(tokens.get(1).encodedLength(), is(4)); - assertThat(tokens.get(1).offset(), is(0)); - - /* assert all elements of node 2 */ - assertThat(tokens.get(2).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(2).name(), is("uint32")); - assertThat(tokens.get(2).encoding().primitiveType(), is(PrimitiveType.UINT32)); - assertThat(tokens.get(2).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(2).encodedLength(), is(4)); - assertThat(tokens.get(2).offset(), is(0)); - assertThat(tokens.get(2).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); - - /* assert all elements of node 3 */ - assertThat(tokens.get(3).signal(), is(Signal.END_FIELD)); - assertThat(tokens.get(3).name(), is("Tag40001")); - assertThat(tokens.get(3).id(), is(40001)); - assertThat(tokens.get(3).encodedLength(), is(4)); - assertThat(tokens.get(3).offset(), is(0)); - - /* assert all elements of node 4 */ - assertThat(tokens.get(4).signal(), is(Signal.END_MESSAGE)); - assertThat(tokens.get(4).name(), is("TestMessage50001")); - assertThat(tokens.get(4).id(), is(50001)); - assertThat(tokens.get(4).encodedLength(), is(16)); - assertThat(tokens.get(4).offset(), is(0)); + try (InputStream in = getLocalResource("basic-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + final List tokens = ir.getMessage(50001); + + assertThat(tokens.size(), is(5)); + + /* assert all elements of node 0 */ + assertThat(tokens.get(0).signal(), is(Signal.BEGIN_MESSAGE)); + assertThat(tokens.get(0).name(), is("TestMessage50001")); + assertThat(tokens.get(0).id(), is(50001)); + assertThat(tokens.get(0).encodedLength(), is(16)); + assertThat(tokens.get(0).offset(), is(0)); + + /* assert all elements of node 1 */ + assertThat(tokens.get(1).signal(), is(Signal.BEGIN_FIELD)); + assertThat(tokens.get(1).name(), is("Tag40001")); + assertThat(tokens.get(1).id(), is(40001)); + assertThat(tokens.get(1).encodedLength(), is(4)); + assertThat(tokens.get(1).offset(), is(0)); + + /* assert all elements of node 2 */ + assertThat(tokens.get(2).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(2).name(), is("uint32")); + assertThat(tokens.get(2).encoding().primitiveType(), is(PrimitiveType.UINT32)); + assertThat(tokens.get(2).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(2).encodedLength(), is(4)); + assertThat(tokens.get(2).offset(), is(0)); + assertThat(tokens.get(2).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); + + /* assert all elements of node 3 */ + assertThat(tokens.get(3).signal(), is(Signal.END_FIELD)); + assertThat(tokens.get(3).name(), is("Tag40001")); + assertThat(tokens.get(3).id(), is(40001)); + assertThat(tokens.get(3).encodedLength(), is(4)); + assertThat(tokens.get(3).offset(), is(0)); + + /* assert all elements of node 4 */ + assertThat(tokens.get(4).signal(), is(Signal.END_MESSAGE)); + assertThat(tokens.get(4).name(), is("TestMessage50001")); + assertThat(tokens.get(4).id(), is(50001)); + assertThat(tokens.get(4).encodedLength(), is(16)); + assertThat(tokens.get(4).offset(), is(0)); + } } @Test void shouldGenerateIrForMessageWithVariableLengthField() throws Exception { - final MessageSchema schema = parse(getLocalResource( - "basic-variable-length-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - - final List tokens = ir.getMessage(1); - - assertThat(tokens.size(), is(8)); - - assertThat(tokens.get(0).signal(), is(Signal.BEGIN_MESSAGE)); - assertThat(tokens.get(0).name(), is("TestMessage1")); - assertThat(tokens.get(0).id(), is(1)); - assertThat(tokens.get(0).encodedLength(), is(0)); - assertThat(tokens.get(0).offset(), is(0)); - - assertThat(tokens.get(1).signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(tokens.get(1).name(), is("encryptedNewPassword")); - assertThat(tokens.get(1).id(), is(1404)); - assertThat(tokens.get(1).encodedLength(), is(0)); - assertThat(tokens.get(1).offset(), is(0)); - - assertThat(tokens.get(2).signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(tokens.get(2).name(), is("varDataEncoding")); - assertThat(tokens.get(2).encodedLength(), is(-1)); - assertThat(tokens.get(2).offset(), is(0)); - - assertThat(tokens.get(3).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(3).name(), is("length")); - assertThat(tokens.get(3).encoding().primitiveType(), is(PrimitiveType.UINT8)); - assertThat(tokens.get(3).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(3).encodedLength(), is(1)); - assertThat(tokens.get(3).offset(), is(0)); - assertThat(tokens.get(3).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); - - assertThat(tokens.get(4).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(4).name(), is("varData")); - assertThat(tokens.get(4).encoding().primitiveType(), is(PrimitiveType.CHAR)); - assertThat(tokens.get(4).id(), is(Token.INVALID_ID)); - assertThat(tokens.get(4).encodedLength(), is(-1)); - assertThat(tokens.get(4).offset(), is(1)); - assertThat(tokens.get(4).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); - - assertThat(tokens.get(5).signal(), is(Signal.END_COMPOSITE)); - assertThat(tokens.get(5).name(), is("varDataEncoding")); - assertThat(tokens.get(5).encodedLength(), is(-1)); - assertThat(tokens.get(5).offset(), is(0)); - - assertThat(tokens.get(6).signal(), is(Signal.END_VAR_DATA)); - assertThat(tokens.get(6).name(), is("encryptedNewPassword")); - assertThat(tokens.get(6).id(), is(1404)); - assertThat(tokens.get(6).encodedLength(), is(0)); - assertThat(tokens.get(6).offset(), is(0)); - - assertThat(tokens.get(7).signal(), is(Signal.END_MESSAGE)); - assertThat(tokens.get(7).name(), is("TestMessage1")); - assertThat(tokens.get(7).id(), is(1)); - assertThat(tokens.get(7).encodedLength(), is(0)); - assertThat(tokens.get(7).offset(), is(0)); + try (InputStream in = getLocalResource("basic-variable-length-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + final List tokens = ir.getMessage(1); + + assertThat(tokens.size(), is(8)); + + assertThat(tokens.get(0).signal(), is(Signal.BEGIN_MESSAGE)); + assertThat(tokens.get(0).name(), is("TestMessage1")); + assertThat(tokens.get(0).id(), is(1)); + assertThat(tokens.get(0).encodedLength(), is(0)); + assertThat(tokens.get(0).offset(), is(0)); + + assertThat(tokens.get(1).signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(tokens.get(1).name(), is("encryptedNewPassword")); + assertThat(tokens.get(1).id(), is(1404)); + assertThat(tokens.get(1).encodedLength(), is(0)); + assertThat(tokens.get(1).offset(), is(0)); + + assertThat(tokens.get(2).signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(tokens.get(2).name(), is("varDataEncoding")); + assertThat(tokens.get(2).encodedLength(), is(-1)); + assertThat(tokens.get(2).offset(), is(0)); + + assertThat(tokens.get(3).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(3).name(), is("length")); + assertThat(tokens.get(3).encoding().primitiveType(), is(PrimitiveType.UINT8)); + assertThat(tokens.get(3).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(3).encodedLength(), is(1)); + assertThat(tokens.get(3).offset(), is(0)); + assertThat(tokens.get(3).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); + + assertThat(tokens.get(4).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(4).name(), is("varData")); + assertThat(tokens.get(4).encoding().primitiveType(), is(PrimitiveType.CHAR)); + assertThat(tokens.get(4).id(), is(Token.INVALID_ID)); + assertThat(tokens.get(4).encodedLength(), is(-1)); + assertThat(tokens.get(4).offset(), is(1)); + assertThat(tokens.get(4).encoding().byteOrder(), is(ByteOrder.LITTLE_ENDIAN)); + + assertThat(tokens.get(5).signal(), is(Signal.END_COMPOSITE)); + assertThat(tokens.get(5).name(), is("varDataEncoding")); + assertThat(tokens.get(5).encodedLength(), is(-1)); + assertThat(tokens.get(5).offset(), is(0)); + + assertThat(tokens.get(6).signal(), is(Signal.END_VAR_DATA)); + assertThat(tokens.get(6).name(), is("encryptedNewPassword")); + assertThat(tokens.get(6).id(), is(1404)); + assertThat(tokens.get(6).encodedLength(), is(0)); + assertThat(tokens.get(6).offset(), is(0)); + + assertThat(tokens.get(7).signal(), is(Signal.END_MESSAGE)); + assertThat(tokens.get(7).name(), is("TestMessage1")); + assertThat(tokens.get(7).id(), is(1)); + assertThat(tokens.get(7).encodedLength(), is(0)); + assertThat(tokens.get(7).offset(), is(0)); + } } @Test void shouldGenerateIrForMessageWithRepeatingGroupWithEmbeddedDimensions() throws Exception { - final MessageSchema schema = parse(getLocalResource( - "basic-group-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - - /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ - final int groupIdx = 4; - final int dimensionsCompIdx = 5; - final int dimensionsBlEncIdx = 6; - final int dimensionsNigEncIdx = 7; - - final List tokens = ir.getMessage(1); - - /* assert on the group token */ - assertThat(tokens.get(groupIdx).signal(), is(Signal.BEGIN_GROUP)); - assertThat(tokens.get(groupIdx).name(), is("Entries")); - assertThat(tokens.get(groupIdx).id(), is(2)); - - /* assert on the comp token for dimensions */ - assertThat(tokens.get(dimensionsCompIdx).signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(tokens.get(dimensionsCompIdx).name(), is("groupSizeEncoding")); - - /* assert on the enc token for dimensions blockLength */ - assertThat(tokens.get(dimensionsBlEncIdx).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(dimensionsBlEncIdx).name(), is("blockLength")); - - /* assert on the enc token for dimensions numInGroup */ - assertThat(tokens.get(dimensionsNigEncIdx).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(dimensionsNigEncIdx).name(), is("numInGroup")); + try (InputStream in = getLocalResource("basic-group-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ + final int groupIdx = 4; + final int dimensionsCompIdx = 5; + final int dimensionsBlEncIdx = 6; + final int dimensionsNigEncIdx = 7; + + final List tokens = ir.getMessage(1); + + /* assert on the group token */ + assertThat(tokens.get(groupIdx).signal(), is(Signal.BEGIN_GROUP)); + assertThat(tokens.get(groupIdx).name(), is("Entries")); + assertThat(tokens.get(groupIdx).id(), is(2)); + + /* assert on the comp token for dimensions */ + assertThat(tokens.get(dimensionsCompIdx).signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(tokens.get(dimensionsCompIdx).name(), is("groupSizeEncoding")); + + /* assert on the enc token for dimensions blockLength */ + assertThat(tokens.get(dimensionsBlEncIdx).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(dimensionsBlEncIdx).name(), is("blockLength")); + + /* assert on the enc token for dimensions numInGroup */ + assertThat(tokens.get(dimensionsNigEncIdx).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(dimensionsNigEncIdx).name(), is("numInGroup")); + } } @Test void shouldGenerateIrForMessageWithRepeatingGroupWithEmbeddedDimensionsDefaultDimensionType() throws Exception { - final MessageSchema schema = parse(getLocalResource( - "embedded-length-and-count-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); + try (InputStream in = getLocalResource("embedded-length-and-count-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); - /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, 9=field, ... */ - final int groupIdx = 4; - final int dimensionsCompIdx = 5; - final int fieldInGroupIdx = 9; + /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, 9=field, ... */ + final int groupIdx = 4; + final int dimensionsCompIdx = 5; + final int fieldInGroupIdx = 9; - final List tokens = ir.getMessage(1); + final List tokens = ir.getMessage(1); - assertThat(tokens.get(groupIdx).signal(), is(Signal.BEGIN_GROUP)); - assertThat(tokens.get(groupIdx).name(), is("ListOrdGrp")); - assertThat(tokens.get(groupIdx).id(), is(73)); + assertThat(tokens.get(groupIdx).signal(), is(Signal.BEGIN_GROUP)); + assertThat(tokens.get(groupIdx).name(), is("ListOrdGrp")); + assertThat(tokens.get(groupIdx).id(), is(73)); - assertThat(tokens.get(dimensionsCompIdx).signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(tokens.get(dimensionsCompIdx).name(), is("groupSizeEncoding")); + assertThat(tokens.get(dimensionsCompIdx).signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(tokens.get(dimensionsCompIdx).name(), is("groupSizeEncoding")); - assertThat(tokens.get(fieldInGroupIdx).signal(), is(Signal.BEGIN_FIELD)); - assertThat(tokens.get(fieldInGroupIdx).name(), is("ClOrdID")); + assertThat(tokens.get(fieldInGroupIdx).signal(), is(Signal.BEGIN_FIELD)); + assertThat(tokens.get(fieldInGroupIdx).name(), is("ClOrdID")); + } } @Test void shouldGenerateIrForMessageWithVariableLengthFieldWithEmbeddedLength() throws Exception { - final MessageSchema schema = parse(getLocalResource( - "embedded-length-and-count-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - - /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=field, 5=comp, 6=enc, 7=enc, 8=compend, 9=fieldend */ - final int lengthFieldIdx = 4; - final int lengthEncIdx = 6; - final int dataEncIdx = 7; - - final List tokens = ir.getMessage(2); - - /* assert the varDataEncoding field node is formed correctly */ - assertThat(tokens.get(lengthFieldIdx).signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(tokens.get(lengthFieldIdx).name(), is("EncryptedPassword")); - assertThat(tokens.get(lengthFieldIdx).id(), is(1402)); - - /* assert the length node has correct values */ - assertThat(tokens.get(lengthEncIdx).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(lengthEncIdx).encoding().primitiveType(), is(PrimitiveType.UINT8)); - - /* assert the group node has the right IrId and xRefIrId, etc. */ - assertThat(tokens.get(dataEncIdx).signal(), is(Signal.ENCODING)); - assertThat(tokens.get(dataEncIdx).encoding().primitiveType(), is(PrimitiveType.CHAR)); + try (InputStream in = getLocalResource("embedded-length-and-count-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=field, 5=comp, 6=enc, 7=enc, 8=compend, 9=fieldend */ + final int lengthFieldIdx = 4; + final int lengthEncIdx = 6; + final int dataEncIdx = 7; + + final List tokens = ir.getMessage(2); + + /* assert the varDataEncoding field node is formed correctly */ + assertThat(tokens.get(lengthFieldIdx).signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(tokens.get(lengthFieldIdx).name(), is("EncryptedPassword")); + assertThat(tokens.get(lengthFieldIdx).id(), is(1402)); + + /* assert the length node has correct values */ + assertThat(tokens.get(lengthEncIdx).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(lengthEncIdx).encoding().primitiveType(), is(PrimitiveType.UINT8)); + + /* assert the group node has the right IrId and xRefIrId, etc. */ + assertThat(tokens.get(dataEncIdx).signal(), is(Signal.ENCODING)); + assertThat(tokens.get(dataEncIdx).encoding().primitiveType(), is(PrimitiveType.CHAR)); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java index 3e92466bbd..cf900c22d0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java @@ -21,6 +21,7 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -33,156 +34,162 @@ class CompositeElementsIrTest @Test void shouldGenerateIrForCompositeElementsSchema() throws Exception { - final MessageSchema schema = parse(getLocalResource( - "composite-elements-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final List tokens = ir.getMessage(1); - - final Token fieldToken = tokens.get(1); - final Token outerCompositeToken = tokens.get(2); - final Token enumToken = tokens.get(3); - final Token zerothToken = tokens.get(7); - final Token setToken = tokens.get(8); - final Token innerCompositeToken = tokens.get(13); - final Token firstToken = tokens.get(14); - final Token secondToken = tokens.get(15); - final Token endOuterCompositeToken = tokens.get(17); - - assertThat(fieldToken.signal(), is(Signal.BEGIN_FIELD)); - assertThat(fieldToken.name(), is("structure")); - - assertThat(outerCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(outerCompositeToken.name(), is("outer")); - assertThat(outerCompositeToken.componentTokenCount(), is(16)); - - assertThat(enumToken.signal(), is(Signal.BEGIN_ENUM)); - assertThat(enumToken.name(), is("enumOne")); - assertThat(enumToken.encodedLength(), is(1)); - assertThat(enumToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); - assertThat(enumToken.offset(), is(0)); - assertThat(enumToken.componentTokenCount(), is(4)); - - assertThat(zerothToken.signal(), is(Signal.ENCODING)); - assertThat(zerothToken.offset(), is(1)); - assertThat(zerothToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); - - assertThat(setToken.signal(), is(Signal.BEGIN_SET)); - assertThat(setToken.name(), is("setOne")); - assertThat(setToken.encodedLength(), is(4)); - assertThat(setToken.encoding().primitiveType(), is(PrimitiveType.UINT32)); - assertThat(setToken.offset(), is(2)); - assertThat(setToken.componentTokenCount(), is(5)); - - assertThat(innerCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(innerCompositeToken.name(), is("inner")); - assertThat(innerCompositeToken.offset(), is(6)); - assertThat(innerCompositeToken.componentTokenCount(), is(4)); - - assertThat(firstToken.signal(), is(Signal.ENCODING)); - assertThat(firstToken.name(), is("first")); - assertThat(firstToken.offset(), is(0)); - assertThat(firstToken.encoding().primitiveType(), is(PrimitiveType.INT64)); - - assertThat(secondToken.signal(), is(Signal.ENCODING)); - assertThat(secondToken.name(), is("second")); - assertThat(secondToken.offset(), is(8)); - assertThat(secondToken.encoding().primitiveType(), is(PrimitiveType.INT64)); - - assertThat(endOuterCompositeToken.signal(), is(Signal.END_COMPOSITE)); - assertThat(endOuterCompositeToken.name(), is("outer")); + try (InputStream in = getLocalResource("composite-elements-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final List tokens = ir.getMessage(1); + + final Token fieldToken = tokens.get(1); + final Token outerCompositeToken = tokens.get(2); + final Token enumToken = tokens.get(3); + final Token zerothToken = tokens.get(7); + final Token setToken = tokens.get(8); + final Token innerCompositeToken = tokens.get(13); + final Token firstToken = tokens.get(14); + final Token secondToken = tokens.get(15); + final Token endOuterCompositeToken = tokens.get(17); + + assertThat(fieldToken.signal(), is(Signal.BEGIN_FIELD)); + assertThat(fieldToken.name(), is("structure")); + + assertThat(outerCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(outerCompositeToken.name(), is("outer")); + assertThat(outerCompositeToken.componentTokenCount(), is(16)); + + assertThat(enumToken.signal(), is(Signal.BEGIN_ENUM)); + assertThat(enumToken.name(), is("enumOne")); + assertThat(enumToken.encodedLength(), is(1)); + assertThat(enumToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); + assertThat(enumToken.offset(), is(0)); + assertThat(enumToken.componentTokenCount(), is(4)); + + assertThat(zerothToken.signal(), is(Signal.ENCODING)); + assertThat(zerothToken.offset(), is(1)); + assertThat(zerothToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); + + assertThat(setToken.signal(), is(Signal.BEGIN_SET)); + assertThat(setToken.name(), is("setOne")); + assertThat(setToken.encodedLength(), is(4)); + assertThat(setToken.encoding().primitiveType(), is(PrimitiveType.UINT32)); + assertThat(setToken.offset(), is(2)); + assertThat(setToken.componentTokenCount(), is(5)); + + assertThat(innerCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(innerCompositeToken.name(), is("inner")); + assertThat(innerCompositeToken.offset(), is(6)); + assertThat(innerCompositeToken.componentTokenCount(), is(4)); + + assertThat(firstToken.signal(), is(Signal.ENCODING)); + assertThat(firstToken.name(), is("first")); + assertThat(firstToken.offset(), is(0)); + assertThat(firstToken.encoding().primitiveType(), is(PrimitiveType.INT64)); + + assertThat(secondToken.signal(), is(Signal.ENCODING)); + assertThat(secondToken.name(), is("second")); + assertThat(secondToken.offset(), is(8)); + assertThat(secondToken.encoding().primitiveType(), is(PrimitiveType.INT64)); + + assertThat(endOuterCompositeToken.signal(), is(Signal.END_COMPOSITE)); + assertThat(endOuterCompositeToken.name(), is("outer")); + } } @Test void shouldGenerateIrForCompositeElementsWithOffsetsSchemaRc4() throws Exception { - final MessageSchema schema = parse(getLocalResource( - "composite-elements-schema-rc4.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final List tokens = ir.getMessage(2); - - final Token outerCompositeToken = tokens.get(2); - final Token enumToken = tokens.get(3); - final Token zerothToken = tokens.get(7); - final Token setToken = tokens.get(8); - final Token innerCompositeToken = tokens.get(13); - final Token firstToken = tokens.get(14); - final Token secondToken = tokens.get(15); - final Token endOuterCompositeToken = tokens.get(17); - - assertThat(outerCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(outerCompositeToken.name(), is("outerWithOffsets")); - assertThat(outerCompositeToken.encodedLength(), is(32)); - - assertThat(enumToken.signal(), is(Signal.BEGIN_ENUM)); - assertThat(enumToken.encodedLength(), is(1)); - assertThat(enumToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); - assertThat(enumToken.offset(), is(2)); - - assertThat(zerothToken.signal(), is(Signal.ENCODING)); - assertThat(zerothToken.offset(), is(3)); - assertThat(zerothToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); - - assertThat(setToken.signal(), is(Signal.BEGIN_SET)); - assertThat(setToken.name(), is("setOne")); - assertThat(setToken.encodedLength(), is(4)); - assertThat(setToken.encoding().primitiveType(), is(PrimitiveType.UINT32)); - assertThat(setToken.offset(), is(8)); - - assertThat(innerCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(innerCompositeToken.name(), is("inner")); - assertThat(innerCompositeToken.offset(), is(16)); - - assertThat(firstToken.signal(), is(Signal.ENCODING)); - assertThat(firstToken.name(), is("first")); - assertThat(firstToken.offset(), is(0)); - assertThat(firstToken.encoding().primitiveType(), is(PrimitiveType.INT64)); - - assertThat(secondToken.signal(), is(Signal.ENCODING)); - assertThat(secondToken.name(), is("second")); - assertThat(secondToken.offset(), is(8)); - assertThat(secondToken.encoding().primitiveType(), is(PrimitiveType.INT64)); - - assertThat(endOuterCompositeToken.signal(), is(Signal.END_COMPOSITE)); - assertThat(endOuterCompositeToken.name(), is("outerWithOffsets")); + try (InputStream in = getLocalResource("composite-elements-schema-rc4.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final List tokens = ir.getMessage(2); + + final Token outerCompositeToken = tokens.get(2); + final Token enumToken = tokens.get(3); + final Token zerothToken = tokens.get(7); + final Token setToken = tokens.get(8); + final Token innerCompositeToken = tokens.get(13); + final Token firstToken = tokens.get(14); + final Token secondToken = tokens.get(15); + final Token endOuterCompositeToken = tokens.get(17); + + assertThat(outerCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(outerCompositeToken.name(), is("outerWithOffsets")); + assertThat(outerCompositeToken.encodedLength(), is(32)); + + assertThat(enumToken.signal(), is(Signal.BEGIN_ENUM)); + assertThat(enumToken.encodedLength(), is(1)); + assertThat(enumToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); + assertThat(enumToken.offset(), is(2)); + + assertThat(zerothToken.signal(), is(Signal.ENCODING)); + assertThat(zerothToken.offset(), is(3)); + assertThat(zerothToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); + + assertThat(setToken.signal(), is(Signal.BEGIN_SET)); + assertThat(setToken.name(), is("setOne")); + assertThat(setToken.encodedLength(), is(4)); + assertThat(setToken.encoding().primitiveType(), is(PrimitiveType.UINT32)); + assertThat(setToken.offset(), is(8)); + + assertThat(innerCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(innerCompositeToken.name(), is("inner")); + assertThat(innerCompositeToken.offset(), is(16)); + + assertThat(firstToken.signal(), is(Signal.ENCODING)); + assertThat(firstToken.name(), is("first")); + assertThat(firstToken.offset(), is(0)); + assertThat(firstToken.encoding().primitiveType(), is(PrimitiveType.INT64)); + + assertThat(secondToken.signal(), is(Signal.ENCODING)); + assertThat(secondToken.name(), is("second")); + assertThat(secondToken.offset(), is(8)); + assertThat(secondToken.encoding().primitiveType(), is(PrimitiveType.INT64)); + + assertThat(endOuterCompositeToken.signal(), is(Signal.END_COMPOSITE)); + assertThat(endOuterCompositeToken.name(), is("outerWithOffsets")); + } } @Test void shouldGenerateIrForCompositeWithRefSchema() throws Exception { - final MessageSchema schema = parse(getLocalResource( - "composite-elements-schema-rc4.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final List tokens = ir.getMessage(3); - - final Token beginCompositeToken = tokens.get(2); - final Token mantissaToken = tokens.get(3); - final Token exponentToken = tokens.get(4); - final Token enumToken = tokens.get(5); - final Token endCompositeToken = tokens.get(9); - - assertThat(beginCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(beginCompositeToken.name(), is("futuresPrice")); - assertThat(beginCompositeToken.encodedLength(), is(11)); - - assertThat(mantissaToken.signal(), is(Signal.ENCODING)); - assertThat(mantissaToken.name(), is("mantissa")); - assertThat(mantissaToken.offset(), is(0)); - assertThat(mantissaToken.encoding().primitiveType(), is(PrimitiveType.INT64)); - - assertThat(exponentToken.signal(), is(Signal.ENCODING)); - assertThat(exponentToken.name(), is("exponent")); - assertThat(exponentToken.offset(), is(8)); - assertThat(exponentToken.encoding().primitiveType(), is(PrimitiveType.INT8)); - - assertThat(enumToken.signal(), is(Signal.BEGIN_ENUM)); - assertThat(enumToken.encodedLength(), is(1)); - assertThat(enumToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); - assertThat(enumToken.offset(), is(10)); - - assertThat(endCompositeToken.signal(), is(Signal.END_COMPOSITE)); - assertThat(endCompositeToken.name(), is("futuresPrice")); + try (InputStream in = getLocalResource("composite-elements-schema-rc4.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final List tokens = ir.getMessage(3); + + final Token beginCompositeToken = tokens.get(2); + final Token mantissaToken = tokens.get(3); + final Token exponentToken = tokens.get(4); + final Token enumToken = tokens.get(5); + final Token endCompositeToken = tokens.get(9); + + assertThat(beginCompositeToken.signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(beginCompositeToken.name(), is("futuresPrice")); + assertThat(beginCompositeToken.encodedLength(), is(11)); + + assertThat(mantissaToken.signal(), is(Signal.ENCODING)); + assertThat(mantissaToken.name(), is("mantissa")); + assertThat(mantissaToken.offset(), is(0)); + assertThat(mantissaToken.encoding().primitiveType(), is(PrimitiveType.INT64)); + + assertThat(exponentToken.signal(), is(Signal.ENCODING)); + assertThat(exponentToken.name(), is("exponent")); + assertThat(exponentToken.offset(), is(8)); + assertThat(exponentToken.encoding().primitiveType(), is(PrimitiveType.INT8)); + + assertThat(enumToken.signal(), is(Signal.BEGIN_ENUM)); + assertThat(enumToken.encodedLength(), is(1)); + assertThat(enumToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); + assertThat(enumToken.offset(), is(10)); + + assertThat(endCompositeToken.signal(), is(Signal.END_COMPOSITE)); + assertThat(endCompositeToken.name(), is("futuresPrice")); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java index 0e527f43e2..0f20f59520 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java @@ -20,6 +20,7 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -32,29 +33,32 @@ class CompositeOffsetsTest @Test void shouldGenerateOffsetsForFieldsWithEmbeddedComposite() throws Exception { - final MessageSchema schema = parse(getLocalResource("composite-offsets-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); + try (InputStream in = getLocalResource("composite-offsets-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final List message2 = ir.getMessage(2); + final Ir ir = irg.generate(schema); + final List message2 = ir.getMessage(2); - final int fieldOneIndex = 1; - assertThat(message2.get(fieldOneIndex).offset(), is(0)); - assertThat(message2.get(fieldOneIndex + 1).encodedLength(), is(4)); + final int fieldOneIndex = 1; + assertThat(message2.get(fieldOneIndex).offset(), is(0)); + assertThat(message2.get(fieldOneIndex + 1).encodedLength(), is(4)); - final int fieldTwoIndex = 4; - assertThat(message2.get(fieldTwoIndex).offset(), is(8)); - assertThat(message2.get(fieldTwoIndex + 1).encodedLength(), is(16)); + final int fieldTwoIndex = 4; + assertThat(message2.get(fieldTwoIndex).offset(), is(8)); + assertThat(message2.get(fieldTwoIndex + 1).encodedLength(), is(16)); - assertThat(message2.get(fieldTwoIndex + 2).offset(), is(0)); - assertThat(message2.get(fieldTwoIndex + 2).encodedLength(), is(1)); - assertThat(message2.get(fieldTwoIndex + 3).offset(), is(8)); - assertThat(message2.get(fieldTwoIndex + 3).encodedLength(), is(8)); + assertThat(message2.get(fieldTwoIndex + 2).offset(), is(0)); + assertThat(message2.get(fieldTwoIndex + 2).encodedLength(), is(1)); + assertThat(message2.get(fieldTwoIndex + 3).offset(), is(8)); + assertThat(message2.get(fieldTwoIndex + 3).encodedLength(), is(8)); - final int fieldThreeIndex = 10; - assertThat(message2.get(fieldThreeIndex).offset(), is(24)); - assertThat(message2.get(fieldThreeIndex + 1).encodedLength(), is(8)); + final int fieldThreeIndex = 10; + assertThat(message2.get(fieldThreeIndex).offset(), is(24)); + assertThat(message2.get(fieldThreeIndex + 1).encodedLength(), is(8)); - assertThat(message2.get(0).encodedLength(), is(32)); + assertThat(message2.get(0).encodedLength(), is(32)); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java index 8986a43923..1cab824202 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java @@ -20,6 +20,8 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; + import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.Tests.getLocalResource; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -29,12 +31,15 @@ class CompositeRefsTest @Test void shouldGenerateIrForCompositeRefs() throws Exception { - final MessageSchema schema = parse(getLocalResource("issue496.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); + try (InputStream in = getLocalResource("issue496.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); - assertNotNull(ir.getType("compositeOne")); - assertNotNull(ir.getType("compositeTwo")); - assertNotNull(ir.getType("compositeThree")); + assertNotNull(ir.getType("compositeOne")); + assertNotNull(ir.getType("compositeTwo")); + assertNotNull(ir.getType("compositeThree")); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index ca89103961..824e3acd1f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -21,10 +21,12 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; import java.nio.ByteBuffer; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.core.Is.is; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -35,137 +37,178 @@ class EncodedIrTest @Test void shouldEncodeIr() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final ByteBuffer buffer = ByteBuffer.allocateDirect(CAPACITY); - final IrEncoder irEncoder = new IrEncoder(buffer, ir); - - irEncoder.encode(); + try (InputStream in = Tests.getLocalResource("basic-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(CAPACITY); + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) + { + irEncoder.encode(); + assertThat(buffer.position(), greaterThan(0)); + } + } } @Test void shouldEncodeThenDecodeIr() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final ByteBuffer buffer = ByteBuffer.allocateDirect(CAPACITY); - final IrEncoder irEncoder = new IrEncoder(buffer, ir); + try (InputStream in = Tests.getLocalResource("basic-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(CAPACITY); + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) + { + irEncoder.encode(); + } - irEncoder.encode(); - buffer.flip(); + buffer.flip(); - final IrDecoder decoder = new IrDecoder(buffer); - decoder.decode(); + try (IrDecoder decoder = new IrDecoder(buffer)) + { + decoder.decode(); + } + } } @Test void shouldHandleRightSizedBuffer() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final ByteBuffer buffer = ByteBuffer.allocateDirect(CAPACITY); - final IrEncoder irEncoder = new IrEncoder(buffer, ir); + try (InputStream in = Tests.getLocalResource("basic-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(CAPACITY); + + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) + { + irEncoder.encode(); + } - irEncoder.encode(); - buffer.flip(); + buffer.flip(); - final ByteBuffer readBuffer = ByteBuffer.allocateDirect(buffer.remaining()); - readBuffer.put(buffer); - readBuffer.flip(); + final ByteBuffer readBuffer = ByteBuffer.allocate(buffer.remaining()); + readBuffer.put(buffer); + readBuffer.flip(); - final IrDecoder irDecoder = new IrDecoder(readBuffer); - irDecoder.decode(); + try (IrDecoder irDecoder = new IrDecoder(readBuffer)) + { + irDecoder.decode(); + } + } } @Test void shouldDecodeFrame() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "code-generation-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final ByteBuffer buffer = ByteBuffer.allocateDirect(CAPACITY); - final IrEncoder irEncoder = new IrEncoder(buffer, ir); - - irEncoder.encode(); - buffer.flip(); - - final IrDecoder irDecoder = new IrDecoder(buffer); - final Ir decodedIr = irDecoder.decode(); - - assertThat(decodedIr.id(), is(ir.id())); - assertThat(decodedIr.version(), is(ir.version())); - assertThat(decodedIr.semanticVersion(), is(ir.semanticVersion())); - assertThat(decodedIr.packageName(), is(ir.packageName())); - assertThat(decodedIr.namespaceName(), is(ir.namespaceName())); + final InputStream in = Tests.getLocalResource("code-generation-schema.xml"); + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(CAPACITY); + + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) + { + irEncoder.encode(); + } + + buffer.flip(); + + try (IrDecoder irDecoder = new IrDecoder(buffer)) + { + final Ir decodedIr = irDecoder.decode(); + + assertThat(decodedIr.id(), is(ir.id())); + assertThat(decodedIr.version(), is(ir.version())); + assertThat(decodedIr.semanticVersion(), is(ir.semanticVersion())); + assertThat(decodedIr.packageName(), is(ir.packageName())); + assertThat(decodedIr.namespaceName(), is(ir.namespaceName())); + } + } } @Test void shouldDecodeHeader() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "code-generation-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final ByteBuffer buffer = ByteBuffer.allocateDirect(CAPACITY); - final IrEncoder irEncoder = new IrEncoder(buffer, ir); - - irEncoder.encode(); - buffer.flip(); - - final IrDecoder irDecoder = new IrDecoder(buffer); - final Ir decodedIr = irDecoder.decode(); - final List tokens = decodedIr.headerStructure().tokens(); - - assertThat(tokens.size(), is(ir.headerStructure().tokens().size())); - for (int i = 0, size = tokens.size(); i < size; i++) + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) { - assertEqual(tokens.get(i), ir.headerStructure().tokens().get(i)); + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(CAPACITY); + + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) + { + irEncoder.encode(); + } + + buffer.flip(); + + try (IrDecoder irDecoder = new IrDecoder(buffer)) + { + final Ir decodedIr = irDecoder.decode(); + final List tokens = decodedIr.headerStructure().tokens(); + + assertThat(tokens.size(), is(ir.headerStructure().tokens().size())); + for (int i = 0, size = tokens.size(); i < size; i++) + { + assertEqual(tokens.get(i), ir.headerStructure().tokens().get(i)); + } + } } } @Test void shouldDecodeMessagesAndTypes() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "code-generation-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final ByteBuffer buffer = ByteBuffer.allocateDirect(CAPACITY); - final IrEncoder irEncoder = new IrEncoder(buffer, ir); - - irEncoder.encode(); - buffer.flip(); - - final IrDecoder irDecoder = new IrDecoder(buffer); - final Ir decodedIr = irDecoder.decode(); - - assertThat(decodedIr.messages().size(), is(ir.messages().size())); - for (final List decodedTokenList : decodedIr.messages()) + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) { - final List tokens = ir.getMessage(decodedTokenList.get(0).id()); + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(CAPACITY); - assertThat(decodedTokenList.size(), is(tokens.size())); - for (int i = 0, size = decodedTokenList.size(); i < size; i++) + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) { - assertEqual(decodedTokenList.get(i), tokens.get(i)); + irEncoder.encode(); } - } - assertThat(decodedIr.types().size(), is(ir.types().size())); - for (final List decodedTokenList : decodedIr.types()) - { - final Token t = decodedTokenList.get(0); - final String name = t.referencedName() != null ? t.referencedName() : t.name(); - final List tokens = ir.getType(name); + buffer.flip(); - assertThat(name + " token count", decodedTokenList.size(), is(tokens.size())); - for (int i = 0, size = decodedTokenList.size(); i < size; i++) + try (IrDecoder irDecoder = new IrDecoder(buffer)) { - assertEqual(decodedTokenList.get(i), tokens.get(i)); + final Ir decodedIr = irDecoder.decode(); + + assertThat(decodedIr.messages().size(), is(ir.messages().size())); + for (final List decodedTokenList : decodedIr.messages()) + { + final List tokens = ir.getMessage(decodedTokenList.get(0).id()); + + assertThat(decodedTokenList.size(), is(tokens.size())); + for (int i = 0, size = decodedTokenList.size(); i < size; i++) + { + assertEqual(decodedTokenList.get(i), tokens.get(i)); + } + } + + assertThat(decodedIr.types().size(), is(ir.types().size())); + for (final List decodedTokenList : decodedIr.types()) + { + final Token t = decodedTokenList.get(0); + final String name = t.referencedName() != null ? t.referencedName() : t.name(); + final List tokens = ir.getType(name); + + assertThat(name + " token count", decodedTokenList.size(), is(tokens.size())); + for (int i = 0, size = decodedTokenList.size(); i < size; i++) + { + assertEqual(decodedTokenList.get(i), tokens.get(i)); + } + } } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java index 5abe33da26..80ccc9f1a2 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java @@ -21,6 +21,7 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -33,129 +34,141 @@ class GroupWithDataIrTest @Test void shouldGenerateIrForSingleVarDataInRepeatingGroup() throws Exception { - final MessageSchema schema = parse(getLocalResource("group-with-data-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final List tokens = ir.getMessage(1); - - /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ - - final Token groupToken = tokens.get(4); - final Token dimensionsCompToken = tokens.get(5); - final Token dimensionsBlEncToken = tokens.get(6); - final Token varDataFieldToken = tokens.get(15); - final Token lengthEncToken = tokens.get(17); - final Token dataEncToken = tokens.get(18); - - /* assert on the group token */ - assertThat(groupToken.signal(), is(Signal.BEGIN_GROUP)); - assertThat(groupToken.name(), is("Entries")); - assertThat(groupToken.id(), is(2)); - - /* assert on the comp token for dimensions */ - assertThat(dimensionsCompToken.signal(), is(Signal.BEGIN_COMPOSITE)); - assertThat(dimensionsCompToken.name(), is("groupSizeEncoding")); - - /* assert on the enc token for dimensions blockLength */ - assertThat(dimensionsBlEncToken.signal(), is(Signal.ENCODING)); - assertThat(dimensionsBlEncToken.name(), is("blockLength")); - - assertThat(varDataFieldToken.signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(varDataFieldToken.name(), is("varDataField")); - assertThat(varDataFieldToken.id(), is(5)); - - assertThat(lengthEncToken.signal(), is(Signal.ENCODING)); - assertThat(lengthEncToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); - - assertThat(dataEncToken.signal(), is(Signal.ENCODING)); - assertThat(dataEncToken.encoding().primitiveType(), is(PrimitiveType.CHAR)); + try (InputStream in = getLocalResource("group-with-data-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final List tokens = ir.getMessage(1); + + /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ + + final Token groupToken = tokens.get(4); + final Token dimensionsCompToken = tokens.get(5); + final Token dimensionsBlEncToken = tokens.get(6); + final Token varDataFieldToken = tokens.get(15); + final Token lengthEncToken = tokens.get(17); + final Token dataEncToken = tokens.get(18); + + /* assert on the group token */ + assertThat(groupToken.signal(), is(Signal.BEGIN_GROUP)); + assertThat(groupToken.name(), is("Entries")); + assertThat(groupToken.id(), is(2)); + + /* assert on the comp token for dimensions */ + assertThat(dimensionsCompToken.signal(), is(Signal.BEGIN_COMPOSITE)); + assertThat(dimensionsCompToken.name(), is("groupSizeEncoding")); + + /* assert on the enc token for dimensions blockLength */ + assertThat(dimensionsBlEncToken.signal(), is(Signal.ENCODING)); + assertThat(dimensionsBlEncToken.name(), is("blockLength")); + + assertThat(varDataFieldToken.signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(varDataFieldToken.name(), is("varDataField")); + assertThat(varDataFieldToken.id(), is(5)); + + assertThat(lengthEncToken.signal(), is(Signal.ENCODING)); + assertThat(lengthEncToken.encoding().primitiveType(), is(PrimitiveType.UINT8)); + + assertThat(dataEncToken.signal(), is(Signal.ENCODING)); + assertThat(dataEncToken.encoding().primitiveType(), is(PrimitiveType.CHAR)); + } } @Test void shouldGenerateIrForMultipleVarDataInRepeatingGroup() throws Exception { - final MessageSchema schema = parse(getLocalResource("group-with-data-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final List tokens = ir.getMessage(2); - - /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ - - final Token groupToken = tokens.get(4); - final Token varDataField1Token = tokens.get(15); - final Token varDataField2Token = tokens.get(21); - - /* assert on the group token */ - assertThat(groupToken.signal(), is(Signal.BEGIN_GROUP)); - assertThat(groupToken.name(), is("Entries")); - assertThat(groupToken.id(), is(2)); - - assertThat(varDataField1Token.signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(varDataField1Token.name(), is("varDataField1")); - assertThat(varDataField1Token.id(), is(5)); - - assertThat(varDataField2Token.signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(varDataField2Token.name(), is("varDataField2")); - assertThat(varDataField2Token.id(), is(6)); + try (InputStream inputStream = getLocalResource("group-with-data-schema.xml")) + { + final MessageSchema schema = parse(inputStream, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final List tokens = ir.getMessage(2); + + /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ + + final Token groupToken = tokens.get(4); + final Token varDataField1Token = tokens.get(15); + final Token varDataField2Token = tokens.get(21); + + /* assert on the group token */ + assertThat(groupToken.signal(), is(Signal.BEGIN_GROUP)); + assertThat(groupToken.name(), is("Entries")); + assertThat(groupToken.id(), is(2)); + + assertThat(varDataField1Token.signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(varDataField1Token.name(), is("varDataField1")); + assertThat(varDataField1Token.id(), is(5)); + + assertThat(varDataField2Token.signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(varDataField2Token.name(), is("varDataField2")); + assertThat(varDataField2Token.id(), is(6)); + } } @Test void shouldGenerateIrForVarDataInNestedRepeatingGroup() throws Exception { - final MessageSchema schema = parse(getLocalResource("group-with-data-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final List tokens = ir.getMessage(3); - - /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ - - final Token groupToken = tokens.get(4); - final Token nestedGroupToken = tokens.get(12); - final Token varDataFieldNestedToken = tokens.get(20); - final Token varDataFieldToken = tokens.get(27); - - assertThat(groupToken.signal(), is(Signal.BEGIN_GROUP)); - assertThat(groupToken.name(), is("Entries")); - assertThat(groupToken.id(), is(2)); - - assertThat(nestedGroupToken.signal(), is(Signal.BEGIN_GROUP)); - assertThat(nestedGroupToken.name(), is("NestedEntries")); - assertThat(nestedGroupToken.id(), is(4)); - - assertThat(varDataFieldNestedToken.signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(varDataFieldNestedToken.name(), is("varDataFieldNested")); - assertThat(varDataFieldNestedToken.id(), is(6)); - - assertThat(varDataFieldToken.signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(varDataFieldToken.name(), is("varDataField")); - assertThat(varDataFieldToken.id(), is(7)); + try (InputStream in = getLocalResource("group-with-data-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final List tokens = ir.getMessage(3); + + /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ + + final Token groupToken = tokens.get(4); + final Token nestedGroupToken = tokens.get(12); + final Token varDataFieldNestedToken = tokens.get(20); + final Token varDataFieldToken = tokens.get(27); + + assertThat(groupToken.signal(), is(Signal.BEGIN_GROUP)); + assertThat(groupToken.name(), is("Entries")); + assertThat(groupToken.id(), is(2)); + + assertThat(nestedGroupToken.signal(), is(Signal.BEGIN_GROUP)); + assertThat(nestedGroupToken.name(), is("NestedEntries")); + assertThat(nestedGroupToken.id(), is(4)); + + assertThat(varDataFieldNestedToken.signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(varDataFieldNestedToken.name(), is("varDataFieldNested")); + assertThat(varDataFieldNestedToken.id(), is(6)); + + assertThat(varDataFieldToken.signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(varDataFieldToken.name(), is("varDataField")); + assertThat(varDataFieldToken.id(), is(7)); + } } @Test void shouldGenerateIrForOnlyMultipleVarDataInRepeatingGroup() throws Exception { - final MessageSchema schema = parse(getLocalResource("group-with-data-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final List tokens = ir.getMessage(4); - - /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ - - final Token groupToken = tokens.get(4); - final Token varDataField1Token = tokens.get(9); - final Token varDataField2Token = tokens.get(15); - - /* assert on the group token */ - assertThat(groupToken.signal(), is(Signal.BEGIN_GROUP)); - assertThat(groupToken.name(), is("Entries")); - assertThat(groupToken.id(), is(2)); - - assertThat(varDataField1Token.signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(varDataField1Token.name(), is("varDataField1")); - assertThat(varDataField1Token.id(), is(5)); - - assertThat(varDataField2Token.signal(), is(Signal.BEGIN_VAR_DATA)); - assertThat(varDataField2Token.name(), is("varDataField2")); - assertThat(varDataField2Token.id(), is(6)); + try (InputStream in = getLocalResource("group-with-data-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final List tokens = ir.getMessage(4); + + /* 0=msg, 1=field, 2=enc, 3=fieldend, 4=group, 5=comp, 6=enc, 7=enc, 8=compend, ... */ + + final Token groupToken = tokens.get(4); + final Token varDataField1Token = tokens.get(9); + final Token varDataField2Token = tokens.get(15); + + /* assert on the group token */ + assertThat(groupToken.signal(), is(Signal.BEGIN_GROUP)); + assertThat(groupToken.name(), is("Entries")); + assertThat(groupToken.id(), is(2)); + + assertThat(varDataField1Token.signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(varDataField1Token.name(), is("varDataField1")); + assertThat(varDataField1Token.id(), is(5)); + + assertThat(varDataField2Token.signal(), is(Signal.BEGIN_VAR_DATA)); + assertThat(varDataField2Token.name(), is("varDataField2")); + assertThat(varDataField2Token.id(), is(6)); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java index 612b4a4a4e..9306e75f95 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java @@ -18,6 +18,8 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; import static uk.co.real_logic.sbe.Tests.getLocalResource; @@ -28,10 +30,10 @@ class SinceVersionValidationTest @Test void shouldErrorOnTypeWithGreaterSinceVersion() throws Exception { - try + final ParserOptions options = ParserOptions.builder().suppressOutput(true).build(); + try (InputStream in = getLocalResource("error-handler-since-version.xml")) { - final ParserOptions options = ParserOptions.builder().suppressOutput(true).build(); - parse(getLocalResource("error-handler-since-version.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java index 4116bf0a78..f6eea310f5 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java @@ -20,6 +20,8 @@ import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import java.io.InputStream; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static uk.co.real_logic.sbe.Tests.getLocalResource; @@ -30,14 +32,17 @@ class ValueRefsTest @Test void shouldGenerateValueRefToEnum() throws Exception { - final MessageSchema schema = parse(getLocalResource("value-ref-schema.xml"), ParserOptions.DEFAULT); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); + try (InputStream in = getLocalResource("value-ref-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); - assertThat(ir.getMessage(1).get(1).encodedLength(), is(8)); - assertThat(ir.getMessage(2).get(1).encodedLength(), is(0)); - assertThat(ir.getMessage(3).get(1).encodedLength(), is(0)); - assertThat(ir.getMessage(4).get(1).encodedLength(), is(0)); - assertThat(ir.getMessage(5).get(1).encodedLength(), is(0)); + assertThat(ir.getMessage(1).get(1).encodedLength(), is(8)); + assertThat(ir.getMessage(2).get(1).encodedLength(), is(0)); + assertThat(ir.getMessage(3).get(1).encodedLength(), is(0)); + assertThat(ir.getMessage(4).get(1).encodedLength(), is(0)); + assertThat(ir.getMessage(5).get(1).encodedLength(), is(0)); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java index 94c9fe680d..73999d9fd4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import java.io.InputStream; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -29,37 +30,52 @@ class BasicSchemaFileTest @Test void shouldHandleBasicFile() throws Exception { - parse(Tests.getLocalResource("basic-schema.xml"), ParserOptions.DEFAULT); + try (InputStream in = Tests.getLocalResource("basic-schema.xml")) + { + parse(in, ParserOptions.DEFAULT); + } } @Test void shouldHandleConstantHeaderField() throws Exception { - parse(Tests.getLocalResource("basic-schema-constant-header-field.xml"), ParserOptions.DEFAULT); + try (InputStream in = Tests.getLocalResource("basic-schema-constant-header-field.xml")) + { + parse(in, ParserOptions.DEFAULT); + } } @Test void shouldHandleBasicFileWithGroup() throws Exception { - parse(Tests.getLocalResource("basic-group-schema.xml"), ParserOptions.DEFAULT); + try (InputStream in = Tests.getLocalResource("basic-group-schema.xml")) + { + parse(in, ParserOptions.DEFAULT); + } } @Test void shouldHandleBasicFileWithVariableLengthData() throws Exception { - parse(Tests.getLocalResource("basic-variable-length-schema.xml"), ParserOptions.DEFAULT); + try (InputStream in = Tests.getLocalResource("basic-variable-length-schema.xml")) + { + parse(in, ParserOptions.DEFAULT); + } } @Test void shouldHandleBasicAllTypes() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource("basic-types-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(1).fields(); + try (InputStream in = Tests.getLocalResource("basic-types-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(1).fields(); - assertThat(fields.get(0).name(), is("header")); - assertThat(fields.get(1).name(), is("EDTField")); - assertThat(fields.get(2).name(), is("ENUMField")); - assertThat(fields.get(3).name(), is("SETField")); - assertThat(fields.get(4).name(), is("int64Field")); + assertThat(fields.get(0).name(), is("header")); + assertThat(fields.get(1).name(), is("EDTField")); + assertThat(fields.get(2).name(), is("ENUMField")); + assertThat(fields.get(3).name(), is("SETField")); + assertThat(fields.get(4).name(), is("int64Field")); + } } } \ No newline at end of file diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java index d5821fffcc..b726352632 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import java.io.InputStream; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -29,36 +30,38 @@ class CompositeElementsTest @Test void shouldParseSchemaSuccessfully() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "composite-elements-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(1).fields(); - final Field composite = fields.get(0); + try (InputStream in = Tests.getLocalResource("composite-elements-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(1).fields(); + final Field composite = fields.get(0); - assertThat(composite.name(), is("structure")); - final CompositeType compositeType = (CompositeType)composite.type(); + assertThat(composite.name(), is("structure")); + final CompositeType compositeType = (CompositeType)composite.type(); - assertThat(compositeType.name(), is("outer")); - final List elements = compositeType.getTypeList(); + assertThat(compositeType.name(), is("outer")); + final List elements = compositeType.getTypeList(); - final EnumType enumType = (EnumType)elements.get(0); - final EncodedDataType encodedDataType = (EncodedDataType)elements.get(1); - final SetType setType = (SetType)elements.get(2); - final CompositeType nestedCompositeType = (CompositeType)elements.get(3); + final EnumType enumType = (EnumType)elements.get(0); + final EncodedDataType encodedDataType = (EncodedDataType)elements.get(1); + final SetType setType = (SetType)elements.get(2); + final CompositeType nestedCompositeType = (CompositeType)elements.get(3); - assertThat(enumType.name(), is("enumOne")); - assertThat(encodedDataType.name(), is("zeroth")); - assertThat(setType.name(), is("setOne")); - assertThat(nestedCompositeType.name(), is("inner")); + assertThat(enumType.name(), is("enumOne")); + assertThat(encodedDataType.name(), is("zeroth")); + assertThat(setType.name(), is("setOne")); + assertThat(nestedCompositeType.name(), is("inner")); - final List nestedElements = nestedCompositeType.getTypeList(); + final List nestedElements = nestedCompositeType.getTypeList(); - final EncodedDataType first = (EncodedDataType)nestedElements.get(0); - final EncodedDataType second = (EncodedDataType)nestedElements.get(1); + final EncodedDataType first = (EncodedDataType)nestedElements.get(0); + final EncodedDataType second = (EncodedDataType)nestedElements.get(1); - assertThat(first.name(), is("first")); - assertThat(second.name(), is("second")); + assertThat(first.name(), is("first")); + assertThat(second.name(), is("second")); - assertThat(nestedCompositeType.encodedLength(), is(16)); - assertThat(compositeType.encodedLength(), is(22)); + assertThat(nestedCompositeType.encodedLength(), is(16)); + assertThat(compositeType.encodedLength(), is(22)); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java index 30f75080fc..d982667e8a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java @@ -18,6 +18,8 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import java.io.InputStream; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -27,11 +29,10 @@ class CyclicReferencesTest @Test void shouldTestForCyclicRefs() throws Exception { - try + try (InputStream in = Tests.getLocalResource("cyclic-refs-schema.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); - - parse(Tests.getLocalResource("cyclic-refs-schema.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java index 70b73af2d0..cd32bde628 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import java.io.InputStream; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -30,21 +31,26 @@ class EmbeddedLengthAndCountFileTest @Test void shouldHandleEmbeddedCountForGroup() throws Exception { - final MessageSchema schema = parse( - Tests.getLocalResource("embedded-length-and-count-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(1).fields(); + try (InputStream in = Tests.getLocalResource("embedded-length-and-count-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(1).fields(); - assertThat(fields.get(1).name(), is("ListOrdGrp")); - assertThat(fields.get(1).id(), is(73)); - assertNotNull(fields.get(1).dimensionType()); + assertThat(fields.get(1).name(), is("ListOrdGrp")); + assertThat(fields.get(1).id(), is(73)); + assertNotNull(fields.get(1).dimensionType()); - final List groupFields = fields.get(1).groupFields(); - assertNotNull(groupFields); + final List groupFields = fields.get(1).groupFields(); + assertNotNull(groupFields); + } } @Test void shouldHandleEmbeddedLengthForData() throws Exception { - parse(Tests.getLocalResource("embedded-length-and-count-schema.xml"), ParserOptions.DEFAULT); + try (InputStream in = Tests.getLocalResource("embedded-length-and-count-schema.xml")) + { + parse(in, ParserOptions.DEFAULT); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java index fcdb5d8a66..08c0132c6e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java @@ -274,28 +274,30 @@ void shouldThrowExceptionWhenIntValueIsOutOfRange(final long value) @Test void shouldThrowExceptionIfEnumValueIsOutOfCustomValueRange() throws IOException { - final InputStream file = Tests.getLocalResource("error-handler-enum-violates-min-max-value-range.xml"); - final IllegalStateException exception = assertThrows(IllegalStateException.class, - () -> parse(file, ParserOptions.builder().suppressOutput(true).build())); - assertEquals("had 4 errors", exception.getMessage()); + try (InputStream in = Tests.getLocalResource("error-handler-enum-violates-min-max-value-range.xml")) + { + final IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> parse(in, ParserOptions.builder().suppressOutput(true).build())); + assertEquals("had 4 errors", exception.getMessage()); + } } @Test void shouldHandleEncodingTypesWithNamedTypes() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "encoding-types-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(1).fields(); - - assertNotNull(fields); - - EnumType type = (EnumType)fields.get(1).type(); + try (InputStream in = Tests.getLocalResource("encoding-types-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(1).fields(); - assertThat(type.encodingType(), is(PrimitiveType.CHAR)); + assertNotNull(fields); - type = (EnumType)fields.get(2).type(); + EnumType type = (EnumType)fields.get(1).type(); + assertThat(type.encodingType(), is(PrimitiveType.CHAR)); - assertThat(type.encodingType(), is(PrimitiveType.UINT8)); + type = (EnumType)fields.get(2).type(); + assertThat(type.encodingType(), is(PrimitiveType.UINT8)); + } } private static Map parseTestXmlWithMap(final String xPathExpr, final String xml) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java index 12292e4d65..fd36fc3de3 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java @@ -32,6 +32,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.HashMap; import java.util.Map; @@ -95,10 +96,10 @@ void shouldNotExitOnTypeErrorsAndWarnings() throws Exception @Test void shouldExitAfterTypes() throws Exception { - try + try (InputStream in = Tests.getLocalResource("error-handler-types-schema.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).build(); - parse(Tests.getLocalResource("error-handler-types-schema.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { @@ -112,10 +113,10 @@ void shouldExitAfterTypes() throws Exception @Test void shouldExitAfterTypesWhenDupTypesDefined() throws Exception { - try + try (InputStream in = Tests.getLocalResource("error-handler-types-dup-schema.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); - parse(Tests.getLocalResource("error-handler-types-dup-schema.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { @@ -129,10 +130,10 @@ void shouldExitAfterTypesWhenDupTypesDefined() throws Exception @Test void shouldExitAfterMessageWhenDupMessageIdsDefined() throws Exception { - try + try (InputStream in = Tests.getLocalResource("error-handler-dup-message-schema.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); - parse(Tests.getLocalResource("error-handler-dup-message-schema.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { @@ -146,10 +147,10 @@ void shouldExitAfterMessageWhenDupMessageIdsDefined() throws Exception @Test void shouldExitAfterMessage() throws Exception { - try + try (InputStream in = Tests.getLocalResource("error-handler-message-schema.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); - parse(Tests.getLocalResource("error-handler-message-schema.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { @@ -163,10 +164,10 @@ void shouldExitAfterMessage() throws Exception @Test void shouldExitAfterMessageWhenGroupDimensionsNotComposite() throws Exception { - try + try (InputStream in = Tests.getLocalResource("error-handler-group-dimensions-schema.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); - parse(Tests.getLocalResource("error-handler-group-dimensions-schema.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { @@ -180,10 +181,10 @@ void shouldExitAfterMessageWhenGroupDimensionsNotComposite() throws Exception @Test void shouldExitAfterTypesWhenCompositeOffsetsIncorrect() throws Exception { - try + try (InputStream in = Tests.getLocalResource("error-handler-invalid-composite-offsets-schema.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); - parse(Tests.getLocalResource("error-handler-invalid-composite-offsets-schema.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { @@ -197,10 +198,10 @@ void shouldExitAfterTypesWhenCompositeOffsetsIncorrect() throws Exception @Test void shouldExitAfterTypesWhenCompositeHasInvalidTypes() throws Exception { - try + try (InputStream in = Tests.getLocalResource("error-handler-invalid-composite.xml");) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); - parse(Tests.getLocalResource("error-handler-invalid-composite.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { @@ -214,10 +215,10 @@ void shouldExitAfterTypesWhenCompositeHasInvalidTypes() throws Exception @Test void shouldExitInvalidFieldNames() throws Exception { - try + try (InputStream in = Tests.getLocalResource("error-handler-invalid-name.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); - parse(Tests.getLocalResource("error-handler-invalid-name.xml"), options); + parse(in, options); } catch (final IllegalStateException ex) { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java index 083e8dbd0d..3a45e114bd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import java.io.InputStream; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -30,18 +31,20 @@ class GroupWithDataTest @Test void shouldParseSchemaSuccessfully() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "group-with-data-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(1).fields(); - final Field entriesGroup = fields.get(1); - final CompositeType dimensionType = entriesGroup.dimensionType(); - final List entriesFields = entriesGroup.groupFields(); + try (InputStream in = Tests.getLocalResource("group-with-data-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(1).fields(); + final Field entriesGroup = fields.get(1); + final CompositeType dimensionType = entriesGroup.dimensionType(); + final List entriesFields = entriesGroup.groupFields(); - assertThat(entriesGroup.name(), is("Entries")); - assertThat(dimensionType.name(), is("groupSizeEncoding")); + assertThat(entriesGroup.name(), is("Entries")); + assertThat(dimensionType.name(), is("groupSizeEncoding")); - final Field varDataField = entriesFields.get(2); - assertThat(varDataField.name(), is("varDataField")); - assertTrue(varDataField.isVariableLength()); + final Field varDataField = entriesFields.get(2); + assertThat(varDataField.name(), is("varDataField")); + assertTrue(varDataField.isVariableLength()); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java index 62b952f46b..1e784cffcc 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import java.io.InputStream; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -33,138 +34,154 @@ class OffsetFileTest @Test void shouldHandleAllTypeOffsets() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "basic-types-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(1).fields(); - - assertThat(fields.get(0).computedOffset(), is(0)); - assertThat(fields.get(0).type().encodedLength(), is(8)); - assertThat(fields.get(1).computedOffset(), is(8)); - assertThat(fields.get(1).type().encodedLength(), is(20)); - assertThat(fields.get(2).computedOffset(), is(28)); - assertThat(fields.get(2).type().encodedLength(), is(1)); - assertThat(fields.get(3).computedOffset(), is(29)); - assertThat(fields.get(3).type().encodedLength(), is(4)); - assertThat(fields.get(4).computedOffset(), is(33)); - assertThat(fields.get(4).type().encodedLength(), is(8)); + try (InputStream in = Tests.getLocalResource("basic-types-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(1).fields(); + + assertThat(fields.get(0).computedOffset(), is(0)); + assertThat(fields.get(0).type().encodedLength(), is(8)); + assertThat(fields.get(1).computedOffset(), is(8)); + assertThat(fields.get(1).type().encodedLength(), is(20)); + assertThat(fields.get(2).computedOffset(), is(28)); + assertThat(fields.get(2).type().encodedLength(), is(1)); + assertThat(fields.get(3).computedOffset(), is(29)); + assertThat(fields.get(3).type().encodedLength(), is(4)); + assertThat(fields.get(4).computedOffset(), is(33)); + assertThat(fields.get(4).type().encodedLength(), is(8)); + } } @Test void shouldHandleAllTypeOffsetsSetByXml() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "basic-types-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(2).fields(); - - assertThat(fields.get(0).computedOffset(), is(0)); - assertThat(fields.get(0).type().encodedLength(), is(8)); - assertThat(fields.get(1).computedOffset(), is(8)); - assertThat(fields.get(1).type().encodedLength(), is(20)); - assertThat(fields.get(2).computedOffset(), is(32)); - assertThat(fields.get(2).type().encodedLength(), is(1)); - assertThat(fields.get(3).computedOffset(), is(128)); - assertThat(fields.get(3).type().encodedLength(), is(4)); - assertThat(fields.get(4).computedOffset(), is(136)); - assertThat(fields.get(4).type().encodedLength(), is(8)); + try (InputStream in = Tests.getLocalResource("basic-types-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(2).fields(); + + assertThat(fields.get(0).computedOffset(), is(0)); + assertThat(fields.get(0).type().encodedLength(), is(8)); + assertThat(fields.get(1).computedOffset(), is(8)); + assertThat(fields.get(1).type().encodedLength(), is(20)); + assertThat(fields.get(2).computedOffset(), is(32)); + assertThat(fields.get(2).type().encodedLength(), is(1)); + assertThat(fields.get(3).computedOffset(), is(128)); + assertThat(fields.get(3).type().encodedLength(), is(4)); + assertThat(fields.get(4).computedOffset(), is(136)); + assertThat(fields.get(4).type().encodedLength(), is(8)); + } } @Test void shouldCalculateGroupOffsetWithNoPaddingFromBlockLength() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "block-length-schema.xml"), ParserOptions.DEFAULT); - final Message msg = schema.getMessage(1); - - assertThat(msg.blockLength(), is(8)); - - final List fields = msg.fields(); - assertThat(fields.get(0).computedOffset(), is(0)); - assertThat(fields.get(0).type().encodedLength(), is(8)); - assertThat(fields.get(1).computedOffset(), is(8)); - assertNull(fields.get(1).type()); - - final List groupFields = fields.get(1).groupFields(); - assertThat(groupFields.size(), is(2)); - assertThat(groupFields.get(0).computedOffset(), is(0)); - assertThat(groupFields.get(0).type().encodedLength(), is(4)); - assertThat(groupFields.get(1).computedOffset(), is(4)); - assertThat(groupFields.get(1).type().encodedLength(), is(8)); + try (InputStream in = Tests.getLocalResource("block-length-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final Message msg = schema.getMessage(1); + + assertThat(msg.blockLength(), is(8)); + + final List fields = msg.fields(); + assertThat(fields.get(0).computedOffset(), is(0)); + assertThat(fields.get(0).type().encodedLength(), is(8)); + assertThat(fields.get(1).computedOffset(), is(8)); + assertNull(fields.get(1).type()); + + final List groupFields = fields.get(1).groupFields(); + assertThat(groupFields.size(), is(2)); + assertThat(groupFields.get(0).computedOffset(), is(0)); + assertThat(groupFields.get(0).type().encodedLength(), is(4)); + assertThat(groupFields.get(1).computedOffset(), is(4)); + assertThat(groupFields.get(1).type().encodedLength(), is(8)); + } } @Test void shouldCalculateGroupOffsetWithPaddingFromBlockLength() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "block-length-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(2).fields(); - - assertThat(fields.get(0).computedOffset(), is(0)); - assertThat(fields.get(0).type().encodedLength(), is(8)); - assertThat(fields.get(1).computedOffset(), is(64)); - assertNull(fields.get(1).type()); - assertThat(fields.get(1).computedBlockLength(), is(12)); - - final List groupFields = fields.get(1).groupFields(); - - assertThat(groupFields.size(), is(2)); - assertThat(groupFields.get(0).computedOffset(), is(0)); - assertThat(groupFields.get(0).type().encodedLength(), is(4)); - assertThat(groupFields.get(1).computedOffset(), is(4)); - assertThat(groupFields.get(1).type().encodedLength(), is(8)); + try (InputStream in = Tests.getLocalResource("block-length-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(2).fields(); + + assertThat(fields.get(0).computedOffset(), is(0)); + assertThat(fields.get(0).type().encodedLength(), is(8)); + assertThat(fields.get(1).computedOffset(), is(64)); + assertNull(fields.get(1).type()); + assertThat(fields.get(1).computedBlockLength(), is(12)); + + final List groupFields = fields.get(1).groupFields(); + + assertThat(groupFields.size(), is(2)); + assertThat(groupFields.get(0).computedOffset(), is(0)); + assertThat(groupFields.get(0).type().encodedLength(), is(4)); + assertThat(groupFields.get(1).computedOffset(), is(4)); + assertThat(groupFields.get(1).type().encodedLength(), is(8)); + } } @Test void shouldCalculateGroupOffsetWithPaddingFromBlockLengthAndGroupBlockLength() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "block-length-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(3).fields(); - - assertThat(fields.get(0).computedOffset(), is(0)); - assertThat(fields.get(0).type().encodedLength(), is(8)); - assertThat(fields.get(1).computedOffset(), is(64)); - assertNull(fields.get(1).type()); - assertThat(fields.get(1).computedBlockLength(), is(16)); - - final List groupFields = fields.get(1).groupFields(); - - assertThat(groupFields.size(), is(2)); - assertThat(groupFields.get(0).computedOffset(), is(0)); - assertThat(groupFields.get(0).type().encodedLength(), is(4)); - assertThat(groupFields.get(1).computedOffset(), is(4)); - assertThat(groupFields.get(1).type().encodedLength(), is(8)); + try (InputStream in = Tests.getLocalResource("block-length-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(3).fields(); + + assertThat(fields.get(0).computedOffset(), is(0)); + assertThat(fields.get(0).type().encodedLength(), is(8)); + assertThat(fields.get(1).computedOffset(), is(64)); + assertNull(fields.get(1).type()); + assertThat(fields.get(1).computedBlockLength(), is(16)); + + final List groupFields = fields.get(1).groupFields(); + + assertThat(groupFields.size(), is(2)); + assertThat(groupFields.get(0).computedOffset(), is(0)); + assertThat(groupFields.get(0).type().encodedLength(), is(4)); + assertThat(groupFields.get(1).computedOffset(), is(4)); + assertThat(groupFields.get(1).type().encodedLength(), is(8)); + } } @Test void shouldCalculateDataOffsetWithPaddingFromBlockLength() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "block-length-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(4).fields(); - - assertThat(fields.get(0).computedOffset(), is(0)); - assertThat(fields.get(0).type().encodedLength(), is(8)); - assertThat(fields.get(1).computedOffset(), is(64)); - assertThat(fields.get(1).type().encodedLength(), is(-1)); + try (InputStream in = Tests.getLocalResource("block-length-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(4).fields(); + + assertThat(fields.get(0).computedOffset(), is(0)); + assertThat(fields.get(0).type().encodedLength(), is(8)); + assertThat(fields.get(1).computedOffset(), is(64)); + assertThat(fields.get(1).type().encodedLength(), is(-1)); + } } @Test void shouldCalculateCompositeSizeWithOffsetsSpecified() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "composite-offsets-schema.xml"), ParserOptions.DEFAULT); - final CompositeType header = schema.messageHeader(); + try (InputStream in = Tests.getLocalResource("composite-offsets-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final CompositeType header = schema.messageHeader(); - assertThat(header.encodedLength(), is(12)); + assertThat(header.encodedLength(), is(12)); + } } @Test void shouldCalculateDimensionSizeWithOffsetsSpecified() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "composite-offsets-schema.xml"), ParserOptions.DEFAULT); - final CompositeType dimensions = schema.getMessage(1).fields().get(0).dimensionType(); + try (InputStream in = Tests.getLocalResource("composite-offsets-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final CompositeType dimensions = schema.getMessage(1).fields().get(0).dimensionType(); - assertThat(dimensions.encodedLength(), is(8)); + assertThat(dimensions.encodedLength(), is(8)); + } } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java index dcd51baff4..b04463d244 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java @@ -31,6 +31,7 @@ import javax.xml.xpath.XPathFactory; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -177,27 +178,25 @@ void shouldThrowExceptionWhenValueOutOfBoundsSpecified() @Test void shouldHandleEncodingTypesWithNamedTypes() throws Exception { - final MessageSchema schema = parse(Tests.getLocalResource( - "encoding-types-schema.xml"), ParserOptions.DEFAULT); - final List fields = schema.getMessage(1).fields(); - - assertNotNull(fields); - - SetType type = (SetType)fields.get(3).type(); - - assertThat(type.encodingType(), is(PrimitiveType.UINT8)); - - type = (SetType)fields.get(4).type(); + try (InputStream in = Tests.getLocalResource("encoding-types-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final List fields = schema.getMessage(1).fields(); - assertThat(type.encodingType(), is(PrimitiveType.UINT16)); + assertNotNull(fields); - type = (SetType)fields.get(5).type(); + SetType type = (SetType)fields.get(3).type(); + assertThat(type.encodingType(), is(PrimitiveType.UINT8)); - assertThat(type.encodingType(), is(PrimitiveType.UINT32)); + type = (SetType)fields.get(4).type(); + assertThat(type.encodingType(), is(PrimitiveType.UINT16)); - type = (SetType)fields.get(6).type(); + type = (SetType)fields.get(5).type(); + assertThat(type.encodingType(), is(PrimitiveType.UINT32)); - assertThat(type.encodingType(), is(PrimitiveType.UINT64)); + type = (SetType)fields.get(6).type(); + assertThat(type.encodingType(), is(PrimitiveType.UINT64)); + } } private static Map parseTestXmlWithMap(final String xPathExpr, final String xml) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java index 28ca3b8c0c..7a06142707 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.params.provider.ValueSource; import uk.co.real_logic.sbe.Tests; +import java.io.InputStream; import java.util.*; import static java.util.Comparator.comparing; @@ -31,16 +32,18 @@ public class SinceVersionSchemaTransformerTest @ValueSource(ints = { 0, 4, 5 }) void shouldFilterAllVersionedFields(final int filteringVersion) throws Exception { - final MessageSchema schema = parse( - Tests.getLocalResource("since-version-filter-schema.xml"), ParserOptions.DEFAULT); + try (InputStream in = Tests.getLocalResource("since-version-filter-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); - final SinceVersionSchemaTransformer sinceVersionSchemaTransformer = new SinceVersionSchemaTransformer( - filteringVersion); - final MessageSchema transformedSchema = sinceVersionSchemaTransformer.transform(schema); + final SinceVersionSchemaTransformer sinceVersionSchemaTransformer = new SinceVersionSchemaTransformer( + filteringVersion); + final MessageSchema transformedSchema = sinceVersionSchemaTransformer.transform(schema); - assertEquals(filteringVersion, transformedSchema.version()); - assertTypeSinceVersionLessOrEqualTo(filteringVersion, schema, transformedSchema); - assertMessageSinceVersionLessOrEqualTo(filteringVersion, schema, transformedSchema); + assertEquals(filteringVersion, transformedSchema.version()); + assertTypeSinceVersionLessOrEqualTo(filteringVersion, schema, transformedSchema); + assertMessageSinceVersionLessOrEqualTo(filteringVersion, schema, transformedSchema); + } } private static void assertMessageSinceVersionLessOrEqualTo( From d5efe5ca6b3d19d0f2d84ccb486b3288b6d34782 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 18:47:06 +0000 Subject: [PATCH 179/805] [C#] Fix warning about using is in Equals method. --- csharp/sbe-dll/PrimitiveValue.cs | 2 +- csharp/sbe-tests/Issue435Tests.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/csharp/sbe-dll/PrimitiveValue.cs b/csharp/sbe-dll/PrimitiveValue.cs index 01d57bc1fd..c455ab2dcd 100644 --- a/csharp/sbe-dll/PrimitiveValue.cs +++ b/csharp/sbe-dll/PrimitiveValue.cs @@ -485,7 +485,7 @@ public override string ToString() /// equivalence of values public override bool Equals(object value) { - if (null != value && value is PrimitiveValue) + if (null != value && this.GetType().Equals(value.GetType())) { var rhs = (PrimitiveValue) value; diff --git a/csharp/sbe-tests/Issue435Tests.cs b/csharp/sbe-tests/Issue435Tests.cs index 9f67c3734d..a40e19f77f 100644 --- a/csharp/sbe-tests/Issue435Tests.cs +++ b/csharp/sbe-tests/Issue435Tests.cs @@ -75,6 +75,5 @@ public void Issue435RefTest() Assert.AreEqual(Issue435.EnumRef.Two, _issue435.Example.E, "Incorrect EnuRef"); } - } } From 42dd81d04b95e47f774e0cdcb0cdcec282e49599 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 18:53:00 +0000 Subject: [PATCH 180/805] [C++] Suppress large function documentation warning. --- .github/codeql/codeql-config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 889b4fe698..aa139de9c0 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -12,3 +12,5 @@ query-filters: id: cs/useless-assignment-to-local - exclude: id: cpp/trivial-switch + - exclude: + id: cpp/poorly-documented-function From 56029aad5a47f3f2ca494682bd9d64e6725c0f22 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 18:56:16 +0000 Subject: [PATCH 181/805] [C#] Use DirectBuffer in using block for Dispose. --- csharp/sbe-tests/DirectBufferTests.cs | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/csharp/sbe-tests/DirectBufferTests.cs b/csharp/sbe-tests/DirectBufferTests.cs index 4c37ebe1f0..566588a39c 100644 --- a/csharp/sbe-tests/DirectBufferTests.cs +++ b/csharp/sbe-tests/DirectBufferTests.cs @@ -103,21 +103,21 @@ public void ConstructFromArraySegment() [TestMethod] public void Recycle() { - var directBuffer = new DirectBuffer(); - var firstBuffer = new Byte[16]; - directBuffer.Wrap(firstBuffer); - - directBuffer.Int64PutLittleEndian(0, 1); - Assert.AreEqual(1, BitConverter.ToInt64(firstBuffer, 0)); - - var secondBuffer = new byte[16]; - var secondBufferHandle = GCHandle.Alloc(secondBuffer, GCHandleType.Pinned); - var secondUnmanagedBuffer = (byte*)secondBufferHandle.AddrOfPinnedObject().ToPointer(); - directBuffer.Wrap(secondUnmanagedBuffer, 16); - directBuffer.Int64PutLittleEndian(0, 2); - Assert.AreEqual(2, BitConverter.ToInt64(secondBuffer, 0)); - - directBuffer.Dispose(); + using (var directBuffer = new DirectBuffer()) + { + var firstBuffer = new Byte[16]; + directBuffer.Wrap(firstBuffer); + + directBuffer.Int64PutLittleEndian(0, 1); + Assert.AreEqual(1, BitConverter.ToInt64(firstBuffer, 0)); + + var secondBuffer = new byte[16]; + var secondBufferHandle = GCHandle.Alloc(secondBuffer, GCHandleType.Pinned); + var secondUnmanagedBuffer = (byte*)secondBufferHandle.AddrOfPinnedObject().ToPointer(); + directBuffer.Wrap(secondUnmanagedBuffer, 16); + directBuffer.Int64PutLittleEndian(0, 2); + Assert.AreEqual(2, BitConverter.ToInt64(secondBuffer, 0)); + } } [TestMethod] From 9cf915f960bd74b6a2735eff3c60d74a1c9736a6 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 7 Feb 2023 19:06:11 +0000 Subject: [PATCH 182/805] [Java] Filter out uncaught NumberFormatException. --- .github/codeql/codeql-config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index aa139de9c0..5e1a52ef54 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -8,6 +8,8 @@ query-filters: id: java/iterator-implements-iterable - exclude: id: java/missing-override-annotation + - exclude: + id: java/uncaught-number-format-exception - exclude: id: cs/useless-assignment-to-local - exclude: From 31a2453dc90f9be9c1f6123adbe94c9e199c3941 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 10:02:13 +0000 Subject: [PATCH 183/805] [C++] Filter out third party code for CodeQL. --- .github/workflows/codeql.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 54d4a46dc6..5455fd9ed0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -183,4 +183,19 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: - category: "/language:${{matrix.language}}" + category: "/language:${{ matrix.language }}" + upload: false + output: sarif-results + + - name: filter-sarif + uses: advanced-security/filter-sarif@v1 + with: + patterns: | + -**/thirdparty/** + input: sarif-results/${{ matrix.language }}.sarif + output: sarif-results/${{ matrix.language }}.sarif + + - name: Upload SARIF + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: sarif-results/${{ matrix.language }}.sarif From 232ab9a4a073bb5b7a65a84d953e0417194a74fc Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 10:32:27 +0000 Subject: [PATCH 184/805] [Java] Default some missing enum cases. --- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java | 3 +++ .../java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java | 6 ++++++ .../src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java | 3 +++ 3 files changed, 12 insertions(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java index 4fef0d5394..2f7a309a99 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java @@ -301,6 +301,9 @@ private void captureTypes(final List tokens, final int beginIndex, final case BEGIN_SET: i = captureType(tokens, i, Signal.END_SET, token.name(), token.referencedName()); break; + + default: + break; } } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java index f189284b5c..23910e4910 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java @@ -131,6 +131,9 @@ private static int decodeFields( case ENCODING: listener.onEncoding(fieldToken, buffer, bufferOffset + offset, typeToken, actingVersion); break; + + default: + break; } i = nextFieldIdx; @@ -257,6 +260,9 @@ private static void decodeComposite( case ENCODING: listener.onEncoding(typeToken, buffer, bufferOffset + offset, typeToken, actingVersion); break; + + default: + break; } i += typeToken.componentTokenCount(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index f135d9e2fa..de4ceff388 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -505,6 +505,9 @@ private Encoding.Presence mapPresence(final Presence presence) case CONSTANT: encodingPresence = Encoding.Presence.CONSTANT; break; + + default: + break; } } From 73ab905bfafd16849d1be09688c2e5281f0beeb7 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 11:46:06 +0000 Subject: [PATCH 185/805] [Java] Add missing cases for enums in switch statements. --- .../sbe/generation/c/CGenerator.java | 9 +++++ .../sbe/generation/cpp/CppGenerator.java | 15 ++++++++ .../generation/csharp/CSharpGenerator.java | 15 ++++++-- .../generation/golang/GolangGenerator.java | 19 +++++++++- .../sbe/generation/java/JavaGenerator.java | 36 +++++++++++++++++++ .../sbe/generation/rust/RustGenerator.java | 10 ++++-- 6 files changed, 98 insertions(+), 6 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 258104e5bf..61f6cb87c7 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -89,6 +89,9 @@ List generateTypeStubs(final CharSequence[] scope) throws IOException case BEGIN_COMPOSITE: generateComposite(scope, tokens); break; + + default: + break; } typesToInclude.add(tokens.get(0).applicableTypeName()); @@ -110,6 +113,9 @@ List generateTypesToIncludes(final List tokens) case BEGIN_COMPOSITE: typesToInclude.add(token.applicableTypeName()); break; + + default: + break; } } @@ -1236,6 +1242,9 @@ private void generatePropertyFunctions( encodingToken, containingStructName); break; + + default: + break; } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 3965763d21..0dba1dfc6d 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -98,6 +98,9 @@ private List generateTypeStubs() throws IOException case BEGIN_COMPOSITE: generateComposite(tokens); break; + + default: + break; } typesToInclude.add(tokens.get(0).applicableTypeName()); @@ -119,6 +122,9 @@ private List generateTypesToIncludes(final List tokens) case BEGIN_COMPOSITE: typesToInclude.add(token.applicableTypeName()); break; + + default: + break; } } @@ -1242,6 +1248,9 @@ private CharSequence generateCompositePropertyElements( case BEGIN_COMPOSITE: generateCompositeProperty(sb, propertyName, fieldToken, indent); break; + + default: + break; } i += tokens.get(i).componentTokenCount(); @@ -2188,6 +2197,9 @@ private void generateFields( case BEGIN_COMPOSITE: generateCompositeProperty(sb, propertyName, encodingToken, indent); break; + + default: + break; } } } @@ -2803,6 +2815,9 @@ private void writeTokenDisplay( typeToken.signal() == Signal.BEGIN_SET ? "\"[]\"" : "\"{}\""); } break; + + default: + break; } sb.append('\n'); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 0550eb8bc0..f55bd11c9f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -104,6 +104,9 @@ public void generateTypeStubs() throws IOException case BEGIN_COMPOSITE: generateComposite(tokens); break; + + default: + break; } } } @@ -586,7 +589,6 @@ private CharSequence generateCompositePropertyElements(final List tokens, final Token token = tokens.get(i); final String propertyName = formatPropertyName(token.name()); - // FIXME: do I need to pass classname down here for disambiguation switch (token.signal()) { case ENCODING: @@ -604,6 +606,9 @@ private CharSequence generateCompositePropertyElements(final List tokens, case BEGIN_COMPOSITE: sb.append(generateCompositeProperty(propertyName, token, token, indent)); break; + + default: + break; } i += tokens.get(i).componentTokenCount(); @@ -1271,6 +1276,9 @@ private CharSequence generateFields(final List tokens, final String inden case BEGIN_COMPOSITE: sb.append(generateCompositeProperty(propertyName, signalToken, encodingToken, indent)); break; + + default: + break; } } } @@ -1739,7 +1747,6 @@ private int writeTokenDisplay( break; case BEGIN_COMPOSITE: - { append(sb, indent, "if (this." + fieldName + " != null)"); append(sb, indent, "{"); append(sb, indent, " this." + fieldName + ".BuildString(builder);"); @@ -1749,7 +1756,9 @@ private int writeTokenDisplay( append(sb, indent, " builder.Append(\"null\");"); append(sb, indent, "}"); break; - } + + default: + break; } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index 24084e23ef..e059524da8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -812,6 +812,9 @@ private int generateEncodeDecode( // And we can move over this group i += signalToken.componentTokenCount() - 1; break; + + default: + break; } } @@ -1114,6 +1117,9 @@ private int generateFieldEncodeDecode( generateDecodePrimitive(decode, primitive, encodingToken); generateRangeCheckPrimitive(rc, primitive, encodingToken, signalToken.isOptionalEncoding()); break; + + default: + break; } return encodingToken.encodedLength() + gap; @@ -1729,6 +1735,9 @@ private void generateTypeBody( case END_GROUP: i = tokens.size(); // terminate the loop break; + + default: + break; } } @@ -1974,7 +1983,7 @@ private void generateTypeBodyComposite( final String typeName, final List tokens) throws IOException { - // gofmt lines up the types and we don't want it to have to rewrite + // gofmt lines up the types, and we don't want it to have to rewrite // our generated files. To line things up we need to know the longest // string length and then fill with whitespace int longest = 0; @@ -2001,6 +2010,9 @@ private void generateTypeBodyComposite( case END_COMPOSITE: i = tokens.size(); // terminate the loop break; + + default: + break; } } @@ -2055,6 +2067,9 @@ private void generateTypeBodyComposite( .append((arrayLength > 1) ? ("[" + arrayLength + "]") : "") .append(typeName).append(propertyType).append("\n"); break; + + default: + break; } } sb.append("}\n"); @@ -2306,6 +2321,8 @@ private CharSequence generateNullValueLiteral(final PrimitiveType primitiveType, case UINT64: imports.peek().add("math"); return "math.MaxUint64"; + default: + break; } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index b3ac5a63fb..30aea38815 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -173,6 +173,9 @@ public void generateTypeStubs() throws IOException case BEGIN_COMPOSITE: generateComposite(tokens); break; + + default: + break; } } } @@ -1377,6 +1380,9 @@ private void generateComposite(final List tokens) throws IOException generateCompositeProperty( sb, true, DECODER, propertyName, encodingToken, encodingToken, BASE_INDENT, typeName); break; + + default: + break; } out.append(sb); @@ -1424,6 +1430,9 @@ private void generateComposite(final List tokens) throws IOException generateCompositeProperty( sb, true, ENCODER, propertyName, encodingToken, encodingToken, BASE_INDENT, typeName); break; + + default: + break; } out.append(sb); @@ -2941,6 +2950,9 @@ private void generateDecoderFields(final StringBuilder sb, final List tok generateCompositeProperty( sb, false, DECODER, propertyName, fieldToken, typeToken, indent, typeName); break; + + default: + break; } }); } @@ -3226,6 +3238,9 @@ private String generateGet(final PrimitiveType type, final String index, final S case DOUBLE: return "buffer.getDouble(" + index + byteOrder + ")"; + + default: + break; } throw new IllegalArgumentException("primitive type not supported: " + type); @@ -3264,6 +3279,9 @@ private String generatePut( case DOUBLE: return "buffer.putDouble(" + index + ", " + value + byteOrder + ")"; + + default: + break; } throw new IllegalArgumentException("primitive type not supported: " + type); @@ -3293,6 +3311,9 @@ private String generateChoiceIsEmptyInner(final PrimitiveType type) case UINT64: return "0 == buffer.getLong(offset)"; + + default: + break; } throw new IllegalArgumentException("primitive type not supported: " + type); @@ -3313,6 +3334,9 @@ private String generateChoiceGet(final PrimitiveType type, final String bitIndex case UINT64: return "0 != (buffer.getLong(offset" + byteOrder + ") & (1L << " + bitIndex + "))"; + + default: + break; } throw new IllegalArgumentException("primitive type not supported: " + type); @@ -3329,6 +3353,9 @@ private String generateStaticChoiceGet(final PrimitiveType type, final String bi case UINT64: return "0 != (value & (1L << " + bitIndex + "))"; + + default: + break; } throw new IllegalArgumentException("primitive type not supported: " + type); @@ -3361,6 +3388,9 @@ private String generateChoicePut(final PrimitiveType type, final String bitIdx, " long bits = buffer.getLong(offset" + byteOrder + ");\n" + " bits = value ? bits | (1L << " + bitIdx + ") : bits & ~(1L << " + bitIdx + ");\n" + " buffer.putLong(offset, bits" + byteOrder + ");"; + + default: + break; } throw new IllegalArgumentException("primitive type not supported: " + type); @@ -3385,6 +3415,9 @@ private String generateStaticChoicePut(final PrimitiveType type, final String bi case UINT64: return " return value ? bits | (1L << " + bitIdx + ") : bits & ~(1L << " + bitIdx + ");\n"; + + default: + break; } throw new IllegalArgumentException("primitive type not supported: " + type); @@ -3748,6 +3781,9 @@ private int writeTokenDisplay( append(sb, indent, "}"); break; } + + default: + break; } final int lengthBeforeFieldSeparator = sb.length(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 98ed1c2554..fe58ce4874 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -229,6 +229,8 @@ static void generateEncoderFields( case BEGIN_COMPOSITE: generateCompositeEncoder(sb, level, typeToken, name); break; + default: + break; } } catch (final IOException ex) @@ -1391,6 +1393,8 @@ private static void generateCompositeEncoder( case BEGIN_COMPOSITE: generateCompositeEncoder(sb, 2, encodingToken, encodingToken.name()); break; + default: + break; } out.append(sb); @@ -1439,8 +1443,8 @@ private static void generateCompositeDecoder( switch (encodingToken.signal()) { case ENCODING: - generatePrimitiveDecoder(sb, 2, encodingToken, encodingToken, encodingToken.name(), - encodingToken.encoding()); + generatePrimitiveDecoder( + sb, 2, encodingToken, encodingToken, encodingToken.name(), encodingToken.encoding()); break; case BEGIN_ENUM: generateEnumDecoder(sb, 2, encodingToken, encodingToken, encodingToken.name()); @@ -1451,6 +1455,8 @@ private static void generateCompositeDecoder( case BEGIN_COMPOSITE: generateCompositeDecoder(sb, 2, encodingToken, encodingToken, encodingToken.name()); break; + default: + break; } out.append(sb); From 8a3794bfbd8dfd38caf3f260211af3422ad392b4 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 11:53:01 +0000 Subject: [PATCH 186/805] [C#] Filter out complex block warning in CodeQL --- .github/codeql/codeql-config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 5e1a52ef54..a5ea05694f 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -12,7 +12,9 @@ query-filters: id: java/uncaught-number-format-exception - exclude: id: cs/useless-assignment-to-local + - exclude: + id: cs/complex-block - exclude: id: cpp/trivial-switch - exclude: - id: cpp/poorly-documented-function + id: cpp/poorly-documented-function \ No newline at end of file From 8b8a7200db10baa329dae9919ed03dfbf0d62d99 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 11:54:31 +0000 Subject: [PATCH 187/805] [C#] Remove redundant ToString() methods. --- .../co/real_logic/sbe/generation/csharp/CSharpGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index f55bd11c9f..732b322e8d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1789,10 +1789,11 @@ private CharSequence generateChoiceDisplay(final String enumName) append(sb, TWO_INDENT, "internal static void BuildString(this " + enumName + " val, StringBuilder builder)"); append(sb, TWO_INDENT, "{"); Separators.BEGIN_SET.appendToGeneratedBuilder(sb, THREE_INDENT); - append(sb, THREE_INDENT, "builder.Append(val.ToString());"); + append(sb, THREE_INDENT, "builder.Append(val);"); Separators.END_SET.appendToGeneratedBuilder(sb, THREE_INDENT); append(sb, TWO_INDENT, "}"); append(sb, INDENT, "}"); + return sb; } From 882f9a37e4440c3b000bba2b9509f81b42fcb2e0 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 12:04:08 +0000 Subject: [PATCH 188/805] [Java] Make use of schema id to avoid warning. --- .../main/java/uk/co/real_logic/sbe/examples/OtfExample.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java index 7512257b57..86a754fa3c 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java @@ -79,6 +79,11 @@ public static void main(final String[] args) throws Exception final int actingVersion = headerDecoder.getSchemaVersion(buffer, bufferOffset); final int blockLength = headerDecoder.getBlockLength(buffer, bufferOffset); + if (schemaId != MessageHeaderEncoder.SCHEMA_ID) + { + throw new IllegalStateException("Invalid schema id: " + schemaId); + } + bufferOffset += headerDecoder.encodedLength(); // Given the header information we can select the appropriate message template to do the decode operation. From bd7db860d2d25cc03981bb2597d251b51b031838 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 12:13:09 +0000 Subject: [PATCH 189/805] [Java] Warnings cleanup. --- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 3 +++ .../main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java | 4 ++-- .../src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 30aea38815..233c9aecbe 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -2912,6 +2912,9 @@ private void generateEncoderFields( generateCompositeProperty( sb, false, ENCODER, propertyName, fieldToken, typeToken, indent, typeName); break; + + default: + break; } }); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index 4e26bfded1..f205802aae 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -98,8 +98,8 @@ public EncodedDataType(final Node node, final String givenName, final String ref } else { - final String characterEncoding = getAttributeValueOrNull(node, "characterEncoding"); - this.characterEncoding = characterEncoding == null ? null : characterEncoding.trim(); + final String configuredCharacterEncoding = getAttributeValueOrNull(node, "characterEncoding"); + characterEncoding = configuredCharacterEncoding == null ? null : configuredCharacterEncoding.trim(); } if (presence() == CONSTANT) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index ee4ddffec0..a196df56d0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -63,8 +63,8 @@ public class MessageSchema this.typeByNameMap = typeByNameMap; this.messageByIdMap = messageByIdMap; - final String headerType = getAttributeValueOrNull(schemaNode, "headerType"); - this.headerType = null == headerType ? HEADER_TYPE_DEFAULT : headerType; + final String configuredHeaderType = getAttributeValueOrNull(schemaNode, "headerType"); + headerType = null == configuredHeaderType ? HEADER_TYPE_DEFAULT : configuredHeaderType; Verify.present(typeByNameMap, this.headerType, "Message header"); final Node messageHeaderNode = findNode(schemaNode, "types/composite[@name='" + this.headerType + "']"); From 844678320357f661d45e5361ed8fa05cd7c3c4c0 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 12:23:23 +0000 Subject: [PATCH 190/805] [Java] Filter unused parameter warnings. --- .github/codeql/codeql-config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index a5ea05694f..30aba2fe02 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -10,6 +10,8 @@ query-filters: id: java/missing-override-annotation - exclude: id: java/uncaught-number-format-exception + - exclude: + id: java/unused-parameter - exclude: id: cs/useless-assignment-to-local - exclude: From df74daf054442e4a728b6e6f6e16e53990f4c0d1 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 8 Feb 2023 13:27:20 +0100 Subject: [PATCH 191/805] [CI] Remove `queries: +security-and-quality` as those are specified in the config file. --- .github/workflows/codeql.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5455fd9ed0..fba15354c6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -65,7 +65,6 @@ jobs: uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} - queries: +security-and-quality config-file: ./.github/codeql/codeql-config.yml - name: Build with Gradle @@ -122,7 +121,6 @@ jobs: uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} - queries: +security-and-quality config-file: ./.github/codeql/codeql-config.yml - name: Build @@ -174,7 +172,6 @@ jobs: uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} - queries: +security-and-quality config-file: ./.github/codeql/codeql-config.yml - name: Build From bc4d34d250c4ad9cca5e2d63704e24cb2a9ba7a9 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 16:03:39 +0000 Subject: [PATCH 192/805] [C++] Generate different body to *InActionVersion check if property version is 0 so avoid warnings. --- .../sbe/generation/cpp/CppGenerator.java | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 0dba1dfc6d..f587b3eb7e 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -440,6 +440,9 @@ private static void generateGroupProperty( propertyName, cppTypeForNumInGroup); + final int version = token.version(); + final String versionCheck = 0 == version ? + " return true;\n" : " return m_actingVersion >= %1$sSinceVersion();\n"; new Formatter(sb).format("\n" + indent + " SBE_NODISCARD static SBE_CONSTEXPR std::uint64_t %1$sSinceVersion() SBE_NOEXCEPT\n" + indent + " {\n" + @@ -448,17 +451,10 @@ private static void generateGroupProperty( indent + " SBE_NODISCARD bool %1$sInActingVersion() const SBE_NOEXCEPT\n" + indent + " {\n" + - indent + "#if defined(__clang__)\n" + - indent + "#pragma clang diagnostic push\n" + - indent + "#pragma clang diagnostic ignored \"-Wtautological-compare\"\n" + - indent + "#endif\n" + - indent + " return m_actingVersion >= %1$sSinceVersion();\n" + - indent + "#if defined(__clang__)\n" + - indent + "#pragma clang diagnostic pop\n" + - indent + "#endif\n" + + indent + versionCheck + indent + " }\n", propertyName, - token.version()); + version); } private void generateVarData( @@ -662,6 +658,9 @@ private void generateVarDataDescriptors( toLowerFirstChar(propertyName), characterEncoding); + final int version = token.version(); + final String versionCheck = 0 == version ? + " return true;\n" : " return m_actingVersion >= %1$sSinceVersion();\n"; new Formatter(sb).format("\n" + indent + " static SBE_CONSTEXPR std::uint64_t %1$sSinceVersion() SBE_NOEXCEPT\n" + indent + " {\n" + @@ -670,14 +669,7 @@ private void generateVarDataDescriptors( indent + " bool %1$sInActingVersion() SBE_NOEXCEPT\n" + indent + " {\n" + - indent + "#if defined(__clang__)\n" + - indent + "#pragma clang diagnostic push\n" + - indent + "#pragma clang diagnostic ignored \"-Wtautological-compare\"\n" + - indent + "#endif\n" + - indent + " return m_actingVersion >= %1$sSinceVersion();\n" + - indent + "#if defined(__clang__)\n" + - indent + "#pragma clang diagnostic pop\n" + - indent + "#endif\n" + + indent + versionCheck + indent + " }\n\n" + indent + " static SBE_CONSTEXPR std::uint16_t %1$sId() SBE_NOEXCEPT\n" + @@ -685,7 +677,7 @@ private void generateVarDataDescriptors( indent + " return %3$d;\n" + indent + " }\n", toLowerFirstChar(propertyName), - token.version(), + version, token.id()); new Formatter(sb).format("\n" + @@ -705,7 +697,7 @@ private void generateVarDataDescriptors( indent + " return %3$s(length);\n" + indent + " }\n", toLowerFirstChar(propertyName), - generateArrayFieldNotPresentCondition(token.version(), BASE_INDENT), + generateArrayFieldNotPresentCondition(version, BASE_INDENT), formatByteOrderEncoding(lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType()), lengthCppType); } @@ -2220,6 +2212,9 @@ private void generateFieldCommonMethods( propertyName, fieldToken.id()); + final int version = fieldToken.version(); + final String versionCheck = 0 == version ? + " return true;\n" : " return m_actingVersion >= %1$sSinceVersion();\n"; new Formatter(sb).format("\n" + indent + " SBE_NODISCARD static SBE_CONSTEXPR std::uint64_t %1$sSinceVersion() SBE_NOEXCEPT\n" + indent + " {\n" + @@ -2228,17 +2223,10 @@ private void generateFieldCommonMethods( indent + " SBE_NODISCARD bool %1$sInActingVersion() SBE_NOEXCEPT\n" + indent + " {\n" + - indent + "#if defined(__clang__)\n" + - indent + "#pragma clang diagnostic push\n" + - indent + "#pragma clang diagnostic ignored \"-Wtautological-compare\"\n" + - indent + "#endif\n" + - indent + " return m_actingVersion >= %1$sSinceVersion();\n" + - indent + "#if defined(__clang__)\n" + - indent + "#pragma clang diagnostic pop\n" + - indent + "#endif\n" + + indent + versionCheck + indent + " }\n", propertyName, - fieldToken.version()); + version); new Formatter(sb).format("\n" + indent + " SBE_NODISCARD static SBE_CONSTEXPR std::size_t %1$sEncodingOffset() SBE_NOEXCEPT\n" + From 2acfc424a386de1f8f9df4303f40bd367a5fc704 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 16:18:06 +0000 Subject: [PATCH 193/805] [Java] More filters for warnings about overloads in generated code. --- .github/codeql/codeql-config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 30aba2fe02..224ed0e44c 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -12,6 +12,10 @@ query-filters: id: java/uncaught-number-format-exception - exclude: id: java/unused-parameter + - exclude: + id: java/confusing-method-signature + - exclude: + id: java/local-shadows-field - exclude: id: cs/useless-assignment-to-local - exclude: From 4551cb7460811f24e778b036dfdded6d5e33e8ca Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 18:23:22 +0000 Subject: [PATCH 194/805] [C++] Address duplicate guard issues. --- .../uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index f587b3eb7e..f06863b356 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1048,8 +1048,8 @@ private static CharSequence generateFileHeader( sb.append("/* Generated SBE (Simple Binary Encoding) message codec */\n"); sb.append(String.format( - "#ifndef _%1$s_%2$s_H_\n" + - "#define _%1$s_%2$s_H_\n\n" + + "#ifndef _%1$s_%2$s_CXX_H_\n" + + "#define _%1$s_%2$s_CXX_H_\n\n" + "#if defined(SBE_HAVE_CMATH)\n" + "/* cmath needed for std::numeric_limits::quiet_NaN() */\n" + @@ -1164,8 +1164,8 @@ private static CharSequence generateEnumFileHeader(final CharSequence[] namespac sb.append("/* Generated SBE (Simple Binary Encoding) message codec */\n"); sb.append(String.format( - "#ifndef _%1$s_%2$s_H_\n" + - "#define _%1$s_%2$s_H_\n\n" + + "#ifndef _%1$s_%2$s_CXX_H_\n" + + "#define _%1$s_%2$s_CXX_H_\n\n" + "#if !defined(__STDC_LIMIT_MACROS)\n" + "# define __STDC_LIMIT_MACROS 1\n" + From 1973c86f84b190d5b2507786e6445970c390ea62 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 18:43:10 +0000 Subject: [PATCH 195/805] [C++] Pass by reference rather than value when streaming to a string. --- .../uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index f06863b356..54fa183222 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -2556,7 +2556,7 @@ private void generateDisplay( new Formatter(sb).format("\n" + "template\n" + "friend std::basic_ostream & operator << (\n" + - " std::basic_ostream &builder, %1$s _writer)\n" + + " std::basic_ostream &builder, %1$s &_writer)\n" + "{\n" + " %1$s writer(\n" + " _writer.m_buffer,\n" + @@ -2587,7 +2587,7 @@ private CharSequence generateGroupDisplay( return String.format("\n" + indent + "template\n" + indent + "friend std::basic_ostream & operator << (\n" + - indent + " std::basic_ostream &builder, %1$s writer)\n" + + indent + " std::basic_ostream &builder, %1$s &writer)\n" + indent + "{\n" + indent + " builder << '{';\n" + "%2$s" + @@ -2603,7 +2603,7 @@ private CharSequence generateCompositeDisplay(final String name, final List\n" + "friend std::basic_ostream & operator << (\n" + - " std::basic_ostream &builder, %1$s writer)\n" + + " std::basic_ostream &builder, %1$s &writer)\n" + "{\n" + " builder << '{';\n" + "%2$s" + @@ -2822,7 +2822,7 @@ private CharSequence generateChoicesDisplay(final String name, final List new Formatter(sb).format("\n" + indent + "template\n" + indent + "friend std::basic_ostream & operator << (\n" + - indent + " std::basic_ostream &builder, %1$s writer)\n" + + indent + " std::basic_ostream &builder, %1$s &writer)\n" + indent + "{\n" + indent + " builder << '[';\n", name); From de5ab5646cd807b470dff53a22bbaac8c0999c09 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 18:58:26 +0000 Subject: [PATCH 196/805] [C#] Fix warnings. --- csharp/sbe-tests/BigEndianTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csharp/sbe-tests/BigEndianTests.cs b/csharp/sbe-tests/BigEndianTests.cs index 8e1358800a..41adc1da4b 100644 --- a/csharp/sbe-tests/BigEndianTests.cs +++ b/csharp/sbe-tests/BigEndianTests.cs @@ -26,12 +26,11 @@ public unsafe class BigendianTests { // The byte array is from the java example made by running // with -Dsbe.encoding.filename and then decoded using od -tu1 - private byte[] _decodeBuffer = { 0, 49, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 210, 7, 221, 1, 65, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 97, 98, 99, 100, 101, 102, 6, 7, 208, 4, 49, 50, 51, 35, 1, 78, 200, 0, 6, 0, 3, 0, 30, 66, 15, 153, 154, 0, 0, 0, 11, 85, 114, 98, 97, 110, 32, 67, 121, 99, 108, 101, 0, 55, 66, 68, 0, 0, 0, 0, 0, 14, 67, 111, 109, 98, 105, 110, 101, 100, 32, 67, 121, 99, 108, 101, 0, 75, 66, 32, 0, 0, 0, 0, 0, 13, 72, 105, 103, 104, 119, 97, 121, 32, 67, 121, 99, 108, 101, 0, 1, 0, 2, 95, 0, 6, 0, 3, 0, 30, 64, 128, 0, 0, 0, 60, 64, 240, 0, 0, 0, 100, 65, 67, 51, 51, 99, 0, 6, 0, 3, 0, 30, 64, 115, 51, 51, 0, 60, 64, 227, 51, 51, 0, 100, 65, 60, 204, 205, 0, 0, 0, 5, 72, 111, 110, 100, 97, 0, 0, 0, 9, 67, 105, 118, 105, 99, 32, 86, 84, 105, 0, 0, 0, 6, 97, 98, 99, 100, 101, 102 }; + private readonly byte[] _decodeBuffer = { 0, 49, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 210, 7, 221, 1, 65, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 97, 98, 99, 100, 101, 102, 6, 7, 208, 4, 49, 50, 51, 35, 1, 78, 200, 0, 6, 0, 3, 0, 30, 66, 15, 153, 154, 0, 0, 0, 11, 85, 114, 98, 97, 110, 32, 67, 121, 99, 108, 101, 0, 55, 66, 68, 0, 0, 0, 0, 0, 14, 67, 111, 109, 98, 105, 110, 101, 100, 32, 67, 121, 99, 108, 101, 0, 75, 66, 32, 0, 0, 0, 0, 0, 13, 72, 105, 103, 104, 119, 97, 121, 32, 67, 121, 99, 108, 101, 0, 1, 0, 2, 95, 0, 6, 0, 3, 0, 30, 64, 128, 0, 0, 0, 60, 64, 240, 0, 0, 0, 100, 65, 67, 51, 51, 99, 0, 6, 0, 3, 0, 30, 64, 115, 51, 51, 0, 60, 64, 227, 51, 51, 0, 100, 65, 60, 204, 205, 0, 0, 0, 5, 72, 111, 110, 100, 97, 0, 0, 0, 9, 67, 105, 118, 105, 99, 32, 86, 84, 105, 0, 0, 0, 6, 97, 98, 99, 100, 101, 102 }; private byte[] _encodeBuffer; private DirectBuffer _directBuffer; private MessageHeader _messageHeader; - private Car Car; [TestInitialize] public void SetUp() From deed84d19c461b3c260d2f7c0d1c342946e14c86 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 19:06:29 +0000 Subject: [PATCH 197/805] [C#] Put back Car type. --- csharp/sbe-tests/BigEndianTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp/sbe-tests/BigEndianTests.cs b/csharp/sbe-tests/BigEndianTests.cs index 41adc1da4b..e2369fb220 100644 --- a/csharp/sbe-tests/BigEndianTests.cs +++ b/csharp/sbe-tests/BigEndianTests.cs @@ -31,6 +31,7 @@ public unsafe class BigendianTests private DirectBuffer _directBuffer; private MessageHeader _messageHeader; + private Car Car; [TestInitialize] public void SetUp() From 2e02a195830fce4289bc183d86ff063a5dfd437b Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 19:13:44 +0000 Subject: [PATCH 198/805] [C#] Address static field issues. --- csharp/sbe-tests/InteropTests.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/csharp/sbe-tests/InteropTests.cs b/csharp/sbe-tests/InteropTests.cs index 6d9e46fa84..57338e0bfb 100644 --- a/csharp/sbe-tests/InteropTests.cs +++ b/csharp/sbe-tests/InteropTests.cs @@ -30,19 +30,21 @@ public unsafe class InteropTests // The byte array is from the java example for interop test made by // running with -Dsbe.encoding.filename and then decoded using od -tu1 - static byte[] _decodeBuffer; - static byte[] _encodeBuffer; + private byte[] _decodeBuffer; + private byte[] _encodeBuffer; - static DirectBuffer _directBuffer; - static MessageHeader _messageHeader; - static Car Car; + private DirectBuffer _directBuffer; + private MessageHeader _messageHeader; + private Car Car; [TestInitialize] public void Setup() { const string interopFile = "../../../ExampleUsingGeneratedStub.sbe"; if (!File.Exists(interopFile)) + { Assert.Inconclusive($"Could not read interop file: {interopFile}"); + } _decodeBuffer = File.ReadAllBytes(interopFile); _encodeBuffer = new byte[_decodeBuffer.Length]; _messageHeader = new MessageHeader(); From da97c0303350f04edf38ec3d314802df3f63ac61 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 8 Feb 2023 19:29:08 +0000 Subject: [PATCH 199/805] [C#] Catch more specific exception when getting bytes from an encoding. --- csharp/sbe-samples-car/CarExample.cs | 4 ++-- csharp/sbe-samples-extension/ExtensionExample.cs | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/csharp/sbe-samples-car/CarExample.cs b/csharp/sbe-samples-car/CarExample.cs index 3706ab959a..0229cacc59 100644 --- a/csharp/sbe-samples-car/CarExample.cs +++ b/csharp/sbe-samples-car/CarExample.cs @@ -80,9 +80,9 @@ static CarExample() ManufacturerCode = Engine.ManufacturerCodeResolvedCharacterEncoding.GetBytes("123"); ActivationCode = Car.ActivationCodeResolvedCharacterEncoding.GetBytes("abcdef"); } - catch (Exception ex) + catch (EncoderFallbackException ex) { - throw new Exception("An error occured while reading encodings", ex); + throw new Exception("An error occurred while reading encodings", ex); } } diff --git a/csharp/sbe-samples-extension/ExtensionExample.cs b/csharp/sbe-samples-extension/ExtensionExample.cs index 9e11ee3b35..eb8c5b1802 100644 --- a/csharp/sbe-samples-extension/ExtensionExample.cs +++ b/csharp/sbe-samples-extension/ExtensionExample.cs @@ -100,14 +100,13 @@ static ExtensionExample() Model = Encoding.GetEncoding(Car.ModelCharacterEncoding).GetBytes("Civic VTi"); ActivationCode = Encoding.GetEncoding(Car.ActivationCodeCharacterEncoding).GetBytes("abcdef"); } - catch (Exception ex) + catch (EncoderFallbackException ex) { - throw new Exception("An error occured while reading encodings", ex); + throw new Exception("An error occurred while reading encodings", ex); } } - public static int Encode(Car car, DirectBuffer directBuffer, int bufferOffset) { const int srcOffset = 0; @@ -312,7 +311,7 @@ static ExtensionExample() Model = Encoding.GetEncoding(Car.ModelCharacterEncoding).GetBytes("Civic VTi"); ActivationCode = Encoding.GetEncoding(Car.ActivationCodeCharacterEncoding).GetBytes("abcdef"); } - catch (Exception ex) + catch (EncoderFallbackException ex) { throw new Exception("An error occurred while reading encodings", ex); } @@ -390,7 +389,7 @@ public static int Encode(Car car, DirectBuffer directBuffer, int bufferOffset) // we have written all the constant length fields, now we can write the repeatable groups - var fuelFigures = car.FuelFiguresCount(3); // we specify that we are going to write 3 FueldFigures (the API is not very .NET friendly yet, we will address that) + var fuelFigures = car.FuelFiguresCount(3); // we specify that we are going to write 3 FuelFigures (the API is not very .NET friendly yet, we will address that) fuelFigures.Next(); // move to the first element fuelFigures.Speed = 30; fuelFigures.Mpg = 35.9f; From 79eb75d5f672fed320fe23bce805eebcfec6d264 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 09:21:27 +0000 Subject: [PATCH 200/805] [C#] Override ToString to give name of PrimitiveType. --- csharp/sbe-dll/PrimitiveType.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp/sbe-dll/PrimitiveType.cs b/csharp/sbe-dll/PrimitiveType.cs index 5643f747ea..2d4b09689c 100644 --- a/csharp/sbe-dll/PrimitiveType.cs +++ b/csharp/sbe-dll/PrimitiveType.cs @@ -207,5 +207,7 @@ public SbePrimitiveType Type { get { return _sbePrimitiveType; } } + + public override string ToString() => PrimitiveName; } } From 21409b60e92893f471fc8a6ea9f86fa84613cc20 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 09:39:47 +0000 Subject: [PATCH 201/805] [C#] Try fix shadowing issues in InteropTests. --- csharp/sbe-tests/InteropTests.cs | 85 ++++++++++++++++---------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/csharp/sbe-tests/InteropTests.cs b/csharp/sbe-tests/InteropTests.cs index 57338e0bfb..43ef7fd0c3 100644 --- a/csharp/sbe-tests/InteropTests.cs +++ b/csharp/sbe-tests/InteropTests.cs @@ -35,7 +35,6 @@ public unsafe class InteropTests private DirectBuffer _directBuffer; private MessageHeader _messageHeader; - private Car Car; [TestInitialize] public void Setup() @@ -56,36 +55,36 @@ public void InteropDecodeTest() _directBuffer = new DirectBuffer(_decodeBuffer); _messageHeader.Wrap(_directBuffer, 0, Baseline.MessageHeader.SbeSchemaVersion); - var Car = new Car(); - Car.WrapForDecode(_directBuffer, MessageHeader.Size, _messageHeader.BlockLength, _messageHeader.Version); + var car = new Car(); + car.WrapForDecode(_directBuffer, MessageHeader.Size, _messageHeader.BlockLength, _messageHeader.Version); Assert.AreEqual(1234UL, Car.SerialNumber); Assert.AreEqual((ushort)2013, Car.ModelYear); Assert.AreEqual(BooleanType.T, Car.Available); Assert.AreEqual(Model.A, Car.Code); - for (int i = 0, size = Car.SomeNumbersLength; i < size; i++) + for (int i = 0, size = car.SomeNumbersLength; i < size; i++) { - Assert.AreEqual(Car.GetSomeNumbers(i), (uint)i+1); + Assert.AreEqual(car.GetSomeNumbers(i), (uint)i+1); } var btmp = new byte[6]; - Car.GetVehicleCode(btmp, 0); + car.GetVehicleCode(btmp, 0); var s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("abcdef", s); - Assert.AreEqual(OptionalExtras.CruiseControl | OptionalExtras.SportsPack, Car.Extras); - Assert.AreEqual((ushort)2000, Car.Engine.Capacity); - Assert.AreEqual((byte)4, Car.Engine.NumCylinders); + Assert.AreEqual(OptionalExtras.CruiseControl | OptionalExtras.SportsPack, car.Extras); + Assert.AreEqual((ushort)2000, car.Engine.Capacity); + Assert.AreEqual((byte)4, car.Engine.NumCylinders); btmp = new byte[3]; - Car.Engine.GetManufacturerCode(btmp, 0); + car.Engine.GetManufacturerCode(btmp, 0); s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("123", s); - Assert.AreEqual((sbyte)35, Car.Engine.Efficiency); - Assert.AreEqual(BooleanType.T, Car.Engine.BoosterEnabled); - Assert.AreEqual(BoostType.NITROUS, Car.Engine.Booster.BoostType); - Assert.AreEqual((byte)200, Car.Engine.Booster.HorsePower); + Assert.AreEqual((sbyte)35, car.Engine.Efficiency); + Assert.AreEqual(BooleanType.T, car.Engine.BoosterEnabled); + Assert.AreEqual(BoostType.NITROUS, car.Engine.Booster.BoostType); + Assert.AreEqual((byte)200, car.Engine.Booster.HorsePower); - var fuelFigures = Car.FuelFigures; + var fuelFigures = car.FuelFigures; Assert.AreEqual(3, fuelFigures.Count); fuelFigures.Next(); @@ -112,7 +111,7 @@ public void InteropDecodeTest() s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("Highway Cycle", s); - var perfFigures = Car.PerformanceFigures; + var perfFigures = car.PerformanceFigures; Assert.AreEqual(2, perfFigures.Count); perfFigures.Next(); @@ -144,15 +143,15 @@ public void InteropDecodeTest() Assert.AreEqual(11.8f, acceleration.Seconds); btmp = new byte[5]; - Car.GetManufacturer(btmp, 0, 5); + car.GetManufacturer(btmp, 0, 5); s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("Honda", s); btmp = new byte[9]; - Car.GetModel(btmp, 0, 9); + car.GetModel(btmp, 0, 9); s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("Civic VTi", s); btmp = new byte[6]; - Car.GetActivationCode(btmp, 0, 6); + car.GetActivationCode(btmp, 0, 6); s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("abcdef", s); } @@ -160,7 +159,7 @@ public void InteropDecodeTest() [TestMethod] public void InteropEncodeTest() { - Car = new Car(); + car = new Car(); _directBuffer = new DirectBuffer(_encodeBuffer); _messageHeader.Wrap(_directBuffer, 0, Baseline.MessageHeader.SbeSchemaVersion); _messageHeader.BlockLength = Car.BlockLength; @@ -169,27 +168,27 @@ public void InteropEncodeTest() _messageHeader.Version = Car.SchemaVersion; // Populate the car with the known interop values - Car.WrapForEncode(_directBuffer, Baseline.MessageHeader.Size); - Car.SerialNumber = 1234; - Car.ModelYear = 2013; - Car.Available = BooleanType.T; - Car.Code = Model.A; - for (int i = 0, size = Car.SomeNumbersLength; i < size; i++) + car.WrapForEncode(_directBuffer, Baseline.MessageHeader.Size); + car.SerialNumber = 1234; + car.ModelYear = 2013; + car.Available = BooleanType.T; + car.Code = Model.A; + for (int i = 0, size = car.SomeNumbersLength; i < size; i++) { - Car.SetSomeNumbers(i, (uint)i+1); + car.SetSomeNumbers(i, (uint)i+1); } - Car.SetVehicleCode(System.Text.Encoding.ASCII.GetBytes("abcdef"), 0); - Car.Extras = OptionalExtras.CruiseControl | OptionalExtras.SportsPack; - - Car.Engine.Capacity = 2000; - Car.Engine.NumCylinders = 4; - Car.Engine.SetManufacturerCode(System.Text.Encoding.ASCII.GetBytes("123"), 0); - Car.Engine.Efficiency = 35; - Car.Engine.BoosterEnabled = BooleanType.T; - Car.Engine.Booster.BoostType = BoostType.NITROUS; - Car.Engine.Booster.HorsePower = 200; - - var fuelFigures = Car.FuelFiguresCount(3); + car.SetVehicleCode(System.Text.Encoding.ASCII.GetBytes("abcdef"), 0); + car.Extras = OptionalExtras.CruiseControl | OptionalExtras.SportsPack; + + car.Engine.Capacity = 2000; + car.Engine.NumCylinders = 4; + car.Engine.SetManufacturerCode(System.Text.Encoding.ASCII.GetBytes("123"), 0); + car.Engine.Efficiency = 35; + car.Engine.BoosterEnabled = BooleanType.T; + car.Engine.Booster.BoostType = BoostType.NITROUS; + car.Engine.Booster.HorsePower = 200; + + var fuelFigures = car.FuelFiguresCount(3); fuelFigures.Next(); fuelFigures.Speed = 30; fuelFigures.Mpg = 35.9f; @@ -205,7 +204,7 @@ public void InteropEncodeTest() fuelFigures.Mpg = 40.0f; fuelFigures.SetUsageDescription(System.Text.Encoding.ASCII.GetBytes("Highway Cycle"), 0, 13); - var perfFigures = Car.PerformanceFiguresCount(2); + var perfFigures = car.PerformanceFiguresCount(2); perfFigures.Next(); perfFigures.OctaneRating = 95; @@ -236,9 +235,9 @@ public void InteropEncodeTest() acceleration.Mph = 100; acceleration.Seconds = 11.8f; - Car.SetManufacturer(System.Text.Encoding.ASCII.GetBytes("Honda"), 0, 5); - Car.SetModel(System.Text.Encoding.ASCII.GetBytes("Civic VTi"), 0, 9); - Car.SetActivationCode(System.Text.Encoding.ASCII.GetBytes("abcdef"), 0, 6); + car.SetManufacturer(System.Text.Encoding.ASCII.GetBytes("Honda"), 0, 5); + car.SetModel(System.Text.Encoding.ASCII.GetBytes("Civic VTi"), 0, 9); + car.SetActivationCode(System.Text.Encoding.ASCII.GetBytes("abcdef"), 0, 6); for (int i = 0; i < _decodeBuffer.Length; i++) { From 553010e5c1d9e3551472a3a528677eec0455250a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 09:44:21 +0000 Subject: [PATCH 202/805] [C#] Add ToString doc. --- csharp/sbe-dll/PrimitiveType.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csharp/sbe-dll/PrimitiveType.cs b/csharp/sbe-dll/PrimitiveType.cs index 2d4b09689c..d0d183eabc 100644 --- a/csharp/sbe-dll/PrimitiveType.cs +++ b/csharp/sbe-dll/PrimitiveType.cs @@ -208,6 +208,9 @@ public SbePrimitiveType Type get { return _sbePrimitiveType; } } + /// + /// The PrimitiveName as a string. + /// public override string ToString() => PrimitiveName; } } From 2da83043fffb7b9ef5a25ec9f032b5468dcc9877 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 09:44:38 +0000 Subject: [PATCH 203/805] [C#] Try fix compilation errors. --- csharp/sbe-tests/InteropTests.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/csharp/sbe-tests/InteropTests.cs b/csharp/sbe-tests/InteropTests.cs index 43ef7fd0c3..24638dbd42 100644 --- a/csharp/sbe-tests/InteropTests.cs +++ b/csharp/sbe-tests/InteropTests.cs @@ -58,10 +58,10 @@ public void InteropDecodeTest() var car = new Car(); car.WrapForDecode(_directBuffer, MessageHeader.Size, _messageHeader.BlockLength, _messageHeader.Version); - Assert.AreEqual(1234UL, Car.SerialNumber); - Assert.AreEqual((ushort)2013, Car.ModelYear); - Assert.AreEqual(BooleanType.T, Car.Available); - Assert.AreEqual(Model.A, Car.Code); + Assert.AreEqual(1234UL, car.SerialNumber); + Assert.AreEqual((ushort)2013, car.ModelYear); + Assert.AreEqual(BooleanType.T, car.Available); + Assert.AreEqual(Model.A, car.Code); for (int i = 0, size = car.SomeNumbersLength; i < size; i++) { Assert.AreEqual(car.GetSomeNumbers(i), (uint)i+1); @@ -159,7 +159,6 @@ public void InteropDecodeTest() [TestMethod] public void InteropEncodeTest() { - car = new Car(); _directBuffer = new DirectBuffer(_encodeBuffer); _messageHeader.Wrap(_directBuffer, 0, Baseline.MessageHeader.SbeSchemaVersion); _messageHeader.BlockLength = Car.BlockLength; @@ -167,6 +166,8 @@ public void InteropEncodeTest() _messageHeader.TemplateId = Car.TemplateId; _messageHeader.Version = Car.SchemaVersion; + var car = new Car(); + // Populate the car with the known interop values car.WrapForEncode(_directBuffer, Baseline.MessageHeader.Size); car.SerialNumber = 1234; From fd93ad690e95cdd63a1912e5e592804e0e2c58de Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 09:47:38 +0000 Subject: [PATCH 204/805] [C#] Qualify static methods with type. --- csharp/sbe-tests/InteropTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/sbe-tests/InteropTests.cs b/csharp/sbe-tests/InteropTests.cs index 24638dbd42..74d9014f13 100644 --- a/csharp/sbe-tests/InteropTests.cs +++ b/csharp/sbe-tests/InteropTests.cs @@ -62,7 +62,7 @@ public void InteropDecodeTest() Assert.AreEqual((ushort)2013, car.ModelYear); Assert.AreEqual(BooleanType.T, car.Available); Assert.AreEqual(Model.A, car.Code); - for (int i = 0, size = car.SomeNumbersLength; i < size; i++) + for (int i = 0, size = Car.SomeNumbersLength; i < size; i++) { Assert.AreEqual(car.GetSomeNumbers(i), (uint)i+1); } @@ -174,7 +174,7 @@ public void InteropEncodeTest() car.ModelYear = 2013; car.Available = BooleanType.T; car.Code = Model.A; - for (int i = 0, size = car.SomeNumbersLength; i < size; i++) + for (int i = 0, size = Car.SomeNumbersLength; i < size; i++) { car.SetSomeNumbers(i, (uint)i+1); } From 1019f1df26626dd89b1eed248da369ceedd567c8 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 09:55:36 +0000 Subject: [PATCH 205/805] [C#] Fix shadowing for BigEndianTests. --- csharp/sbe-tests/BigEndianTests.cs | 90 +++++++++++++++--------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/csharp/sbe-tests/BigEndianTests.cs b/csharp/sbe-tests/BigEndianTests.cs index e2369fb220..66d24e5df8 100644 --- a/csharp/sbe-tests/BigEndianTests.cs +++ b/csharp/sbe-tests/BigEndianTests.cs @@ -31,7 +31,6 @@ public unsafe class BigendianTests private DirectBuffer _directBuffer; private MessageHeader _messageHeader; - private Car Car; [TestInitialize] public void SetUp() @@ -46,36 +45,36 @@ public void BigendianDecodeTest() _directBuffer = new DirectBuffer(_decodeBuffer); _messageHeader.Wrap(_directBuffer, 0, Baseline.MessageHeader.SbeSchemaVersion); - var Car = new Car(); - Car.WrapForDecode(_directBuffer, MessageHeader.Size, _messageHeader.BlockLength, _messageHeader.Version); + var car = new Car(); + car.WrapForDecode(_directBuffer, MessageHeader.Size, _messageHeader.BlockLength, _messageHeader.Version); - Assert.AreEqual(1234UL, Car.SerialNumber); - Assert.AreEqual((ushort)2013, Car.ModelYear); - Assert.AreEqual(BooleanType.T, Car.Available); - Assert.AreEqual(Model.A, Car.Code); + Assert.AreEqual(1234UL, car.SerialNumber); + Assert.AreEqual((ushort)2013, car.ModelYear); + Assert.AreEqual(BooleanType.T, car.Available); + Assert.AreEqual(Model.A, car.Code); for (int i = 0, size = Car.SomeNumbersLength; i < size; i++) { - Assert.AreEqual(Car.GetSomeNumbers(i), (uint)i); + Assert.AreEqual(car.GetSomeNumbers(i), (uint)i); } var btmp = new byte[6]; - Car.GetVehicleCode(btmp, 0); + car.GetVehicleCode(btmp, 0); var s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("abcdef", s); - Assert.AreEqual(OptionalExtras.CruiseControl | OptionalExtras.SportsPack, Car.Extras); - Assert.AreEqual((ushort)2000, Car.Engine.Capacity); - Assert.AreEqual((byte)4, Car.Engine.NumCylinders); + Assert.AreEqual(OptionalExtras.CruiseControl | OptionalExtras.SportsPack, car.Extras); + Assert.AreEqual((ushort)2000, car.Engine.Capacity); + Assert.AreEqual((byte)4, car.Engine.NumCylinders); btmp = new byte[3]; - Car.Engine.GetManufacturerCode(btmp, 0); + car.Engine.GetManufacturerCode(btmp, 0); s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("123", s); - Assert.AreEqual((sbyte)35, Car.Engine.Efficiency); - Assert.AreEqual(BooleanType.T, Car.Engine.BoosterEnabled); - Assert.AreEqual(BoostType.NITROUS, Car.Engine.Booster.BoostType); - Assert.AreEqual((byte)200, Car.Engine.Booster.HorsePower); + Assert.AreEqual((sbyte)35, car.Engine.Efficiency); + Assert.AreEqual(BooleanType.T, car.Engine.BoosterEnabled); + Assert.AreEqual(BoostType.NITROUS, car.Engine.Booster.BoostType); + Assert.AreEqual((byte)200, car.Engine.Booster.HorsePower); - var fuelFigures = Car.FuelFigures; + var fuelFigures = car.FuelFigures; Assert.AreEqual(3, fuelFigures.Count); fuelFigures.Next(); @@ -102,7 +101,7 @@ public void BigendianDecodeTest() s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("Highway Cycle", s); - var perfFigures = Car.PerformanceFigures; + var perfFigures = car.PerformanceFigures; Assert.AreEqual(2, perfFigures.Count); perfFigures.Next(); @@ -134,15 +133,15 @@ public void BigendianDecodeTest() Assert.AreEqual(11.8f, acceleration.Seconds); btmp = new byte[5]; - Car.GetManufacturer(btmp, 0, 5); + car.GetManufacturer(btmp, 0, 5); s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("Honda", s); btmp = new byte[9]; - Car.GetModel(btmp, 0, 9); + car.GetModel(btmp, 0, 9); s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("Civic VTi", s); btmp = new byte[6]; - Car.GetActivationCode(btmp, 0, 6); + car.GetActivationCode(btmp, 0, 6); s = System.Text.Encoding.UTF8.GetString(btmp, 0, btmp.Length); Assert.AreEqual("abcdef", s); } @@ -150,7 +149,6 @@ public void BigendianDecodeTest() [TestMethod] public void BigendianEncodeTest() { - Car = new Car(); _directBuffer = new DirectBuffer(_encodeBuffer); _messageHeader.Wrap(_directBuffer, 0, Baseline.MessageHeader.SbeSchemaVersion); _messageHeader.BlockLength = Car.BlockLength; @@ -158,28 +156,30 @@ public void BigendianEncodeTest() _messageHeader.TemplateId = Car.TemplateId; _messageHeader.Version = Car.SchemaVersion; + var car = new Car(); + // Populate the car with the known values - Car.WrapForEncode(_directBuffer, Baseline.MessageHeader.Size); - Car.SerialNumber = 1234; - Car.ModelYear = 2013; - Car.Available = BooleanType.T; - Car.Code = Model.A; + car.WrapForEncode(_directBuffer, Baseline.MessageHeader.Size); + car.SerialNumber = 1234; + car.ModelYear = 2013; + car.Available = BooleanType.T; + car.Code = Model.A; for (int i = 0, size = Car.SomeNumbersLength; i < size; i++) { - Car.SetSomeNumbers(i, (uint)i); + car.SetSomeNumbers(i, (uint)i); } - Car.SetVehicleCode(System.Text.Encoding.ASCII.GetBytes("abcdef"), 0); - Car.Extras = OptionalExtras.CruiseControl | OptionalExtras.SportsPack; - - Car.Engine.Capacity = 2000; - Car.Engine.NumCylinders = 4; - Car.Engine.SetManufacturerCode(System.Text.Encoding.ASCII.GetBytes("123"), 0); - Car.Engine.Efficiency = 35; - Car.Engine.BoosterEnabled = BooleanType.T; - Car.Engine.Booster.BoostType = BoostType.NITROUS; - Car.Engine.Booster.HorsePower = 200; - - var fuelFigures = Car.FuelFiguresCount(3); + car.SetVehicleCode(System.Text.Encoding.ASCII.GetBytes("abcdef"), 0); + car.Extras = OptionalExtras.CruiseControl | OptionalExtras.SportsPack; + + car.Engine.Capacity = 2000; + car.Engine.NumCylinders = 4; + car.Engine.SetManufacturerCode(System.Text.Encoding.ASCII.GetBytes("123"), 0); + car.Engine.Efficiency = 35; + car.Engine.BoosterEnabled = BooleanType.T; + car.Engine.Booster.BoostType = BoostType.NITROUS; + car.Engine.Booster.HorsePower = 200; + + var fuelFigures = car.FuelFiguresCount(3); fuelFigures.Next(); fuelFigures.Speed = 30; fuelFigures.Mpg = 35.9f; @@ -195,7 +195,7 @@ public void BigendianEncodeTest() fuelFigures.Mpg = 40.0f; fuelFigures.SetUsageDescription(System.Text.Encoding.ASCII.GetBytes("Highway Cycle"), 0, 13); - var perfFigures = Car.PerformanceFiguresCount(2); + var perfFigures = car.PerformanceFiguresCount(2); perfFigures.Next(); perfFigures.OctaneRating = 95; @@ -226,9 +226,9 @@ public void BigendianEncodeTest() acceleration.Mph = 100; acceleration.Seconds = 11.8f; - Car.SetManufacturer(System.Text.Encoding.ASCII.GetBytes("Honda"), 0, 5); - Car.SetModel(System.Text.Encoding.ASCII.GetBytes("Civic VTi"), 0, 9); - Car.SetActivationCode(System.Text.Encoding.ASCII.GetBytes("abcdef"), 0, 6); + car.SetManufacturer(System.Text.Encoding.ASCII.GetBytes("Honda"), 0, 5); + car.SetModel(System.Text.Encoding.ASCII.GetBytes("Civic VTi"), 0, 9); + car.SetActivationCode(System.Text.Encoding.ASCII.GetBytes("abcdef"), 0, 6); for (int i = 0; i < _decodeBuffer.Length; i++) { From d5057a42d572659bb4fdece7a70b7bb2d25a3161 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 10:15:07 +0000 Subject: [PATCH 206/805] [C#] Filter constant comparison checks. --- .github/codeql/codeql-config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 224ed0e44c..e7c7cc873b 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -20,6 +20,8 @@ query-filters: id: cs/useless-assignment-to-local - exclude: id: cs/complex-block + - exclude: + id: cs/constant-comparison - exclude: id: cpp/trivial-switch - exclude: From be8d12d9c3695c34ac7248e67e9d2371bdc0af4a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 10:35:20 +0000 Subject: [PATCH 207/805] [C#] Compare doubles with a tolerance. --- csharp/sbe-dll/PrimitiveValue.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/csharp/sbe-dll/PrimitiveValue.cs b/csharp/sbe-dll/PrimitiveValue.cs index c455ab2dcd..49c5ba0aff 100644 --- a/csharp/sbe-dll/PrimitiveValue.cs +++ b/csharp/sbe-dll/PrimitiveValue.cs @@ -500,7 +500,11 @@ public override bool Equals(object value) return _unsignedLongValue == rhs._unsignedLongValue; case Representation.Double: - return _doubleValue == rhs._doubleValue; + { + const double EPSILON = 1e-10; + return (_doubleValue == rhs._doubleValue) || + (Math.Abs(_doubleValue - rhs._doubleValue) < EPSILON); + } case Representation.ByteArray: return _byteArrayValue.SequenceEqual(rhs._byteArrayValue); From a1ea4e8b40e9b75e01aa753eb3ab891932c62034 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 10:59:45 +0000 Subject: [PATCH 208/805] [C#] Use Double.Equals to compare double values in PrimitiveValue. --- csharp/sbe-dll/PrimitiveValue.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/csharp/sbe-dll/PrimitiveValue.cs b/csharp/sbe-dll/PrimitiveValue.cs index 49c5ba0aff..00b9707bdf 100644 --- a/csharp/sbe-dll/PrimitiveValue.cs +++ b/csharp/sbe-dll/PrimitiveValue.cs @@ -501,9 +501,7 @@ public override bool Equals(object value) case Representation.Double: { - const double EPSILON = 1e-10; - return (_doubleValue == rhs._doubleValue) || - (Math.Abs(_doubleValue - rhs._doubleValue) < EPSILON); + return _doubleValue.Equals(rhs._doubleValue); } case Representation.ByteArray: From 8d6f29b76f6c5f4067d7c11a2aadc512e0fcbd42 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 11:12:59 +0000 Subject: [PATCH 209/805] [C#] Compare PrimitiveValue with doubles in the same way as Java by the raw bits, so NaN and Infinity are correctly handled. --- csharp/sbe-dll/PrimitiveValue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/sbe-dll/PrimitiveValue.cs b/csharp/sbe-dll/PrimitiveValue.cs index 00b9707bdf..14e1d191d9 100644 --- a/csharp/sbe-dll/PrimitiveValue.cs +++ b/csharp/sbe-dll/PrimitiveValue.cs @@ -501,7 +501,7 @@ public override bool Equals(object value) case Representation.Double: { - return _doubleValue.Equals(rhs._doubleValue); + return BitConverter.DoubleToInt64Bits(_doubleValue) == BitConverter.DoubleToInt64Bits(rhs._doubleValue); } case Representation.ByteArray: From 84bbf2eed852a56d403f206e9dc9683cd9fba8f7 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 9 Feb 2023 11:13:23 +0000 Subject: [PATCH 210/805] [C#] Formatting. --- csharp/sbe-dll/PrimitiveValue.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/csharp/sbe-dll/PrimitiveValue.cs b/csharp/sbe-dll/PrimitiveValue.cs index 14e1d191d9..a579baa158 100644 --- a/csharp/sbe-dll/PrimitiveValue.cs +++ b/csharp/sbe-dll/PrimitiveValue.cs @@ -500,9 +500,7 @@ public override bool Equals(object value) return _unsignedLongValue == rhs._unsignedLongValue; case Representation.Double: - { return BitConverter.DoubleToInt64Bits(_doubleValue) == BitConverter.DoubleToInt64Bits(rhs._doubleValue); - } case Representation.ByteArray: return _byteArrayValue.SequenceEqual(rhs._byteArrayValue); From a640a451c31256f5efb83a4b44b51c660176c512 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 15 Feb 2023 10:18:15 +0000 Subject: [PATCH 211/805] [Java] Warnings cleanup. --- build.gradle | 8 ++++---- .../main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java | 4 ++-- .../java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index c7b707c1f4..d5102e37f9 100644 --- a/build.gradle +++ b/build.gradle @@ -138,7 +138,7 @@ allprojects { mavenCentral() } - configurations.all { + configurations.configureEach { resolutionStrategy { failOnVersionConflict() } @@ -166,18 +166,18 @@ subprojects { checkstyle.toolVersion = "${checkstyleVersion}" - tasks.withType(Sign) { + tasks.withType(Sign).configureEach { onlyIf { isReleaseVersion && gradle.taskGraph.hasTask(tasks.publish) } } - tasks.withType(Jar) { + tasks.withType(Jar).configureEach { enabled = true includeEmptyDirs = false } - tasks.withType(JavaCompile) { + tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' options.deprecation = true options.compilerArgs.addAll(['-Xlint:all', '-Werror']) // Enable all warnings and treat them as errors diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java index 0e020cae75..744fb0c15c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java @@ -133,10 +133,10 @@ public static int findEndSignal( } /** - * Find a list of sub-group names. + * Find a list of subgroup names. * * @param tokens to search. - * @return list of names for the sub-groups. + * @return list of names for the subgroups. */ public static List findSubGroupNames(final List tokens) { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java index fd36fc3de3..bda3393aa9 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java @@ -198,7 +198,7 @@ void shouldExitAfterTypesWhenCompositeOffsetsIncorrect() throws Exception @Test void shouldExitAfterTypesWhenCompositeHasInvalidTypes() throws Exception { - try (InputStream in = Tests.getLocalResource("error-handler-invalid-composite.xml");) + try (InputStream in = Tests.getLocalResource("error-handler-invalid-composite.xml")) { final ParserOptions options = ParserOptions.builder().suppressOutput(true).warningsFatal(true).build(); parse(in, options); From e208bb51f63c739a090cba5afd72bce34ea7e032 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 24 Feb 2023 15:39:44 +0100 Subject: [PATCH 212/805] [Java] Upgrade to versions plugin 0.46.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d5102e37f9..d7dbd02bdd 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ import java.security.MessageDigest plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '7.1.2' apply false - id "com.github.ben-manes.versions" version "0.45.0" + id 'com.github.ben-manes.versions' version '0.46.0' } defaultTasks 'clean', 'build' From d9bb75b8d401448095faec1884b367db3c88dc1a Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 24 Feb 2023 15:47:04 +0100 Subject: [PATCH 213/805] [Gradle] Use lazy task configuration. --- build.gradle | 215 ++++++++++++++++++++++++++------------------------- 1 file changed, 111 insertions(+), 104 deletions(-) diff --git a/build.gradle b/build.gradle index d7dbd02bdd..b58ba21e0f 100644 --- a/build.gradle +++ b/build.gradle @@ -260,14 +260,15 @@ project(':sbe-tool') { compileTestJava.dependsOn compileGeneratedJava - task generateTestCodecs(dependsOn: 'compileJava', type: JavaExec) { + tasks.register('generateTestCodecs', JavaExec) { + dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': generatedDir, - 'sbe.target.language': 'Java', - 'sbe.validation.stop.on.error': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': generatedDir, + 'sbe.target.language': 'Java', + 'sbe.validation.stop.on.error': 'true', + 'sbe.validation.xsd': validationXsdPath) args = ['src/test/resources/json-printer-test-schema.xml', 'src/test/resources/composite-elements-schema.xml'] } @@ -283,10 +284,10 @@ project(':sbe-tool') { ) } - task sourcesJar(type: Jar) { + tasks.register('sourcesJar', Jar) { archiveClassifier.set('sources') from sourceSets.main.allSource - from ('src/main/cpp/otf') { + from('src/main/cpp/otf') { into 'cpp' } } @@ -344,10 +345,10 @@ project(':sbe-all') { jar.finalizedBy shadowJar - task sourcesJar(type: Jar) { + tasks.register('sourcesJar', Jar) { archiveClassifier.set('sources') from project(':sbe-tool').sourceSets.main.allSource - from (project(':sbe-tool').file('src/main/cpp/otf')) { + from(project(':sbe-tool').file('src/main/cpp/otf')) { into 'cpp' } } @@ -356,7 +357,8 @@ project(':sbe-all') { source += project(':sbe-tool').sourceSets.main.allJava } - task javadocJar(type: Jar, dependsOn: javadoc) { + tasks.register('javadocJar', Jar) { + dependsOn javadoc archiveClassifier.set('javadoc') from javadoc.destinationDir } @@ -406,39 +408,42 @@ project(':sbe-samples') { compileJava.dependsOn 'compileGeneratedJava' compileGeneratedJava.dependsOn 'generateCodecs' - task generateCodecs(type: JavaExec) { + tasks.register('generateCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-all').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': generatedDir, - 'sbe.target.language': 'Java', - 'sbe.java.generate.interfaces': 'true', - 'sbe.validation.stop.on.error': 'true', - 'sbe.decode.unknown.enum.values': 'true', - 'sbe.xinclude.aware': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': generatedDir, + 'sbe.target.language': 'Java', + 'sbe.java.generate.interfaces': 'true', + 'sbe.validation.stop.on.error': 'true', + 'sbe.decode.unknown.enum.values': 'true', + 'sbe.xinclude.aware': 'true', + 'sbe.validation.xsd': validationXsdPath) args = ['src/main/resources/example-schema.xml', 'src/main/resources/example-extension-schema.xml'] } - task runExampleUsingGeneratedStub(dependsOn: 'compileJava', type: JavaExec) { + tasks.register('runExampleUsingGeneratedStub', JavaExec) { + dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.examples.ExampleUsingGeneratedStub') classpath = sourceSets.main.runtimeClasspath systemProperties System.getProperties() } - task runExampleUsingGeneratedStubExtension(dependsOn: 'compileJava', type: JavaExec) { + tasks.register('runExampleUsingGeneratedStubExtension', JavaExec) { + dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.examples.ExampleUsingGeneratedStubExtension') classpath = sourceSets.main.runtimeClasspath systemProperties System.getProperties() } - task runOtfExample(dependsOn: 'compileJava', type: JavaExec) { + tasks.register('runOtfExample', JavaExec) { + dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.examples.OtfExample') classpath = sourceSets.main.runtimeClasspath workingDir = 'src/main/resources' } - task runJavaExamples { + tasks.register('runJavaExamples') { dependsOn 'runExampleUsingGeneratedStub', 'runExampleUsingGeneratedStubExtension', 'runOtfExample' } @@ -456,7 +461,7 @@ project(':sbe-samples') { ) } - task sourcesJar(type: Jar) { + tasks.register('sourcesJar', Jar) { archiveClassifier.set('sources') from sourceSets.main.allSource from sourceSets.generated.allSource @@ -516,16 +521,16 @@ project(':sbe-benchmarks') { compileGeneratedJava.dependsOn 'generateCodecs' compileJava.dependsOn 'compileGeneratedJava' - task generateCodecs(type: JavaExec) { + tasks.register('generateCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-all').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'build/generated-src', - 'sbe.target.language': 'Java', - 'sbe.validation.stop.on.error': 'true', - 'sbe.validation.xsd': validationXsdPath, - 'sbe.java.encoding.buffer.type': 'org.agrona.concurrent.UnsafeBuffer', - 'sbe.java.decoding.buffer.type': 'org.agrona.concurrent.UnsafeBuffer') + 'sbe.output.dir': 'build/generated-src', + 'sbe.target.language': 'Java', + 'sbe.validation.stop.on.error': 'true', + 'sbe.validation.xsd': validationXsdPath, + 'sbe.java.encoding.buffer.type': 'org.agrona.concurrent.UnsafeBuffer', + 'sbe.java.decoding.buffer.type': 'org.agrona.concurrent.UnsafeBuffer') args = ['src/main/resources/car.xml', 'src/main/resources/fix-message-samples.xml'] } @@ -539,10 +544,7 @@ project(':sbe-benchmarks') { javadoc.enabled = false } -/* - * Rust codec targets used for testing - */ -task generateRustExamples(type: JavaExec) { +tasks.register('generateRustExamples', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-all').sourceSets.main.runtimeClasspath systemProperties( @@ -557,7 +559,7 @@ task generateRustExamples(type: JavaExec) { ] } -task generateRustTestCodecs(type: JavaExec) { +tasks.register('generateRustTestCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-all').sourceSets.main.runtimeClasspath systemProperties( @@ -572,7 +574,7 @@ task generateRustTestCodecs(type: JavaExec) { ] } -task generateCarExampleDataFile(type: JavaExec) { +tasks.register('generateCarExampleDataFile', JavaExec) { mainClass.set('uk.co.real_logic.sbe.examples.ExampleUsingGeneratedStub') classpath = project(':sbe-samples').sourceSets.main.runtimeClasspath systemProperties('sbe.encoding.filename': 'rust/car_example_baseline_data.sbe') @@ -580,7 +582,7 @@ task generateCarExampleDataFile(type: JavaExec) { standardOutput = new ByteArrayOutputStream() } -task generateCarExampleExtensionDataFile(type: JavaExec) { +tasks.register('generateCarExampleExtensionDataFile', JavaExec) { mainClass.set('uk.co.real_logic.sbe.examples.ExampleUsingGeneratedStubExtension') classpath = project(':sbe-samples').sourceSets.main.runtimeClasspath systemProperties('sbe.encoding.filename': 'rust/car_example_extension_data.sbe') @@ -588,13 +590,13 @@ task generateCarExampleExtensionDataFile(type: JavaExec) { standardOutput = new ByteArrayOutputStream() } -task generateRustCodecs { +tasks.register('generateRustCodecs') { description = 'Generate rust test codecs' dependsOn 'generateRustExamples', 'generateRustTestCodecs', 'generateCarExampleDataFile', 'generateCarExampleExtensionDataFile' } -task runRustTests(type: Exec) { +tasks.register('runRustTests', Exec) { workingDir = './rust' executable = 'cargo' args = ['test'] @@ -610,62 +612,62 @@ task runRustTests(type: Exec) { * as they generate into the same directory and golang won't allow that. * *) Some examples need to fiddle with WorkingDir to deal with XInclude */ -task generateGolangCodecTestComposite(type: JavaExec) { +tasks.register('generateGolangCodecTestComposite', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src', - 'sbe.target.language': 'golang') + 'sbe.output.dir': 'gocode/src', + 'sbe.target.language': 'golang') args = ['sbe-tool/src/test/resources/composite-elements-schema-rc4.xml'] } -task generateGolangCodecTestBasic(type: JavaExec) { +tasks.register('generateGolangCodecTestBasic', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src/basic', - 'sbe.target.language': 'golang') + 'sbe.output.dir': 'gocode/src/basic', + 'sbe.target.language': 'golang') args = ['sbe-tool/src/test/resources/basic-types-schema.xml'] } -task generateGolangCodecTestGroup(type: JavaExec) { +tasks.register('generateGolangCodecTestGroup', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src/group', - 'sbe.target.language': 'golang') + 'sbe.output.dir': 'gocode/src/group', + 'sbe.target.language': 'golang') args = ['sbe-tool/src/test/resources/basic-group-schema.xml'] } -task generateGolangCodecTestVarData(type: JavaExec) { +tasks.register('generateGolangCodecTestVarData', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src/vardata', - 'sbe.target.language': 'golang') + 'sbe.output.dir': 'gocode/src/vardata', + 'sbe.target.language': 'golang') args = ['sbe-tool/src/test/resources/basic-variable-length-schema.xml'] } -task generateGolangCodecsWithXIncludes(type: JavaExec) { +tasks.register('generateGolangCodecsWithXIncludes', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src', - 'sbe.target.language': 'golang', - 'sbe.xinclude.aware': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': 'gocode/src', + 'sbe.target.language': 'golang', + 'sbe.xinclude.aware': 'true', + 'sbe.validation.xsd': validationXsdPath) args = ['sbe-samples/src/main/resources/example-schema.xml', 'sbe-samples/src/main/resources/example-extension-schema.xml'] } -task generateGolangCodecsWithXSD(type: JavaExec) { +tasks.register('generateGolangCodecsWithXSD', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src', - 'sbe.target.language': 'golang', - 'sbe.xinclude.aware': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': 'gocode/src', + 'sbe.target.language': 'golang', + 'sbe.xinclude.aware': 'true', + 'sbe.validation.xsd': validationXsdPath) args = ['sbe-tool/src/test/resources/group-with-data-schema.xml', 'sbe-tool/src/test/resources/FixBinary.xml', 'sbe-tool/src/test/resources/issue435.xml', @@ -684,40 +686,40 @@ task generateGolangCodecsWithXSD(type: JavaExec) { 'gocode/resources/simple.xml'] } -task generateGolangCodecs { +tasks.register('generateGolangCodecs') { description = 'Generate golang test codecs' dependsOn 'generateGolangCodecTestVarData', - 'generateGolangCodecTestGroup', - 'generateGolangCodecTestBasic', - 'generateGolangCodecTestComposite', - 'generateGolangCodecsWithXIncludes', - 'generateGolangCodecsWithXSD' + 'generateGolangCodecTestGroup', + 'generateGolangCodecTestBasic', + 'generateGolangCodecTestComposite', + 'generateGolangCodecsWithXIncludes', + 'generateGolangCodecsWithXSD' } /* * CSharp codec targets used for testing, benchmarking etc. We have * multiple targets as XInclude forces us to change working dir */ -task generateCSharpCodecsWithXIncludes(type: JavaExec) { +tasks.register('generateCSharpCodecsWithXIncludes', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'csharp/sbe-generated', - 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', - 'sbe.xinclude.aware': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': 'csharp/sbe-generated', + 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', + 'sbe.xinclude.aware': 'true', + 'sbe.validation.xsd': validationXsdPath) args = ['sbe-samples/src/main/resources/example-schema.xml', 'sbe-samples/src/main/resources/example-extension-schema.xml'] } -task generateCSharpCodecsTests(type: JavaExec) { +tasks.register('generateCSharpCodecsTests', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'csharp/sbe-generated', - 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', - 'sbe.xinclude.aware': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': 'csharp/sbe-generated', + 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', + 'sbe.xinclude.aware': 'true', + 'sbe.validation.xsd': validationXsdPath) args = ['sbe-tool/src/test/resources/FixBinary.xml', 'sbe-tool/src/test/resources/issue435.xml', 'sbe-tool/src/test/resources/issue483.xml', @@ -727,55 +729,57 @@ task generateCSharpCodecsTests(type: JavaExec) { 'sbe-benchmarks/src/main/resources/fix-message-samples.xml'] } -task generateCSharpCodecs { +tasks.register('generateCSharpCodecs') { description = 'Generate csharp codecs' dependsOn 'generateCSharpCodecsTests', - 'generateCSharpCodecsWithXIncludes' + 'generateCSharpCodecsWithXIncludes' } -task generateJavaIrCodecs(type: JavaExec, dependsOn: 'computeOriginalIrHash') { +tasks.register('generateJavaIrCodecs', JavaExec) { + dependsOn 'computeOriginalIrHash' mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-all').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'sbe-tool/src/main/java', - 'sbe.target.language': 'Java', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': 'sbe-tool/src/main/java', + 'sbe.target.language': 'Java', + 'sbe.validation.xsd': validationXsdPath) args = ['sbe-tool/src/main/resources/sbe-ir.xml'] } -task generateCppIrCodecs(type: JavaExec) { +tasks.register('generateCppIrCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'sbe-tool/src/main/cpp', - 'sbe.target.language': 'cpp', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': 'sbe-tool/src/main/cpp', + 'sbe.target.language': 'cpp', + 'sbe.validation.xsd': validationXsdPath) args = ['sbe-tool/src/main/resources/sbe-ir.xml'] } -task generateGolangIrCodecs(type: JavaExec) { +tasks.register('generateGolangIrCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'sbe-tool/src/main/golang', - 'sbe.target.language': 'golang', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.output.dir': 'sbe-tool/src/main/golang', + 'sbe.target.language': 'golang', + 'sbe.validation.xsd': validationXsdPath) args = ['sbe-tool/src/main/resources/sbe-ir.xml'] } -task generateIrCodecs { +tasks.register('generateIrCodecs') { description = 'Generate Java, C++, and golang IR Codecs' dependsOn 'generateJavaIrCodecs', 'generateCppIrCodecs', 'generateGolangIrCodecs' } -task runJavaBenchmarks(type: Exec, dependsOn: 'sbe-benchmarks:jar') { +tasks.register('runJavaBenchmarks', Exec) { + dependsOn 'sbe-benchmarks:jar' commandLine toolchainLauncher.get().executablePath, - '-jar', 'sbe-benchmarks/build/libs/sbe-benchmarks.jar', - '-jvmArgs', '-Dagrona.disable.bounds.checks=true -XX:+UseParallelGC', - '-w', '1s', '-r', '1s','-wi', '3', '-i', '5', '-tu', 'ns', '-f', '5' + '-jar', 'sbe-benchmarks/build/libs/sbe-benchmarks.jar', + '-jvmArgs', '-Dagrona.disable.bounds.checks=true -XX:+UseParallelGC', + '-w', '1s', '-r', '1s', '-wi', '3', '-i', '5', '-tu', 'ns', '-f', '5' } -task testReport(type: TestReport) { +tasks.register('testReport', TestReport) { destinationDirectory = file("$buildDir/reports/allTests") // Include the results from the `test` task in all sub-projects testResults.setFrom(subprojects*.test) @@ -786,27 +790,32 @@ final outputDir = project.file('sbe-tool/build') final oldHashFile = new File(outputDir, 'old.sha256') final newHashFile = new File(outputDir, 'new.sha256') -task computeOriginalIrHash(type: ChecksumTask) { +tasks.register('computeOriginalIrHash', ChecksumTask) { inputDirectory = codecsDir outputFile = oldHashFile } -task computeUpdatedIrHash(type: ChecksumTask, dependsOn: 'generateJavaIrCodecs') { +tasks.register('computeUpdatedIrHash', ChecksumTask) { + dependsOn 'generateJavaIrCodecs' inputDirectory = codecsDir outputFile = newHashFile } -task verifyJavaIrCodecsInSync(dependsOn: 'computeUpdatedIrHash') { +tasks.register('verifyJavaIrCodecsInSync') { + dependsOn 'computeUpdatedIrHash' doLast { final byte[] oldHash = Files.readAllBytes(oldHashFile.toPath()) final byte[] newHash = Files.readAllBytes(newHashFile.toPath()) - if (!Arrays.equals(oldHash, newHash)) - { + if (!Arrays.equals(oldHash, newHash)) { throw new GradleException("Java Ir codecs are out of sync! Please execute the `generateJavaIrCodecs` task and commit the changes.") } } } +tasks.named('build').configure { + dependsOn 'verifyJavaIrCodecsInSync' +} + def isNonStable = { String version -> def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { it -> version.toUpperCase().contains(it) } def regex = /^[0-9,.v-]+(-r)?$/ @@ -820,8 +829,6 @@ tasks.named('dependencyUpdates').configure { } } -tasks.findByName('build').dependsOn verifyJavaIrCodecsInSync - wrapper { gradleVersion = '7.6' distributionType = 'ALL' From ef309b21ceed242f90010604a13c3e349608c7aa Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 28 Feb 2023 14:05:25 +0100 Subject: [PATCH 214/805] [Gradle] Upgrade to Gradle 8.0.1 and Shadow 8.1.0. --- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index b58ba21e0f..5d3bf9e3e9 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ import java.security.MessageDigest plugins { id 'java-library' - id 'com.github.johnrengelman.shadow' version '7.1.2' apply false + id 'com.github.johnrengelman.shadow' version '8.1.0' apply false id 'com.github.ben-manes.versions' version '0.46.0' } @@ -830,7 +830,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '7.6' + gradleVersion = '8.0.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2b22d057a0..6ec1567a0f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 3296c5e1cd3ea5ba1d19b641dae3e32d4a7a420f Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 28 Feb 2023 15:43:12 +0100 Subject: [PATCH 215/805] [Java] Add JDK 20-ea to the build matrix. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1959daf8ab..2bc7b1a537 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '8', '11', '17', '18' ] + java: [ '8', '11', '17', '20-ea' ] os: [ 'ubuntu-22.04', 'windows-latest' ] steps: - name: Checkout code From 7186909547e00ea8d623312b460c9859e573970c Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 28 Feb 2023 23:48:33 +0100 Subject: [PATCH 216/805] [Gradle] Revert back to Gradle 7.6. --- .github/workflows/ci.yml | 2 +- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 61608 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bc7b1a537..ed6e5ae9bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '8', '11', '17', '20-ea' ] + java: [ '8', '11', '17' ] os: [ 'ubuntu-22.04', 'windows-latest' ] steps: - name: Checkout code diff --git a/build.gradle b/build.gradle index 5d3bf9e3e9..b58ba21e0f 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ import java.security.MessageDigest plugins { id 'java-library' - id 'com.github.johnrengelman.shadow' version '8.1.0' apply false + id 'com.github.johnrengelman.shadow' version '7.1.2' apply false id 'com.github.ben-manes.versions' version '0.46.0' } @@ -830,7 +830,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '8.0.1' + gradleVersion = '7.6' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..ccebba7710deaf9f98673a68957ea02138b60d0a 100644 GIT binary patch delta 5094 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 delta 5107 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 I6Xdi10eY*&F8}}l diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6ec1567a0f..2b22d057a0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68d65..79a61d421c 100755 --- a/gradlew +++ b/gradlew @@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac From 0385eb72e4be40ca3b3373400639ffbec3f2fe7b Mon Sep 17 00:00:00 2001 From: Renan Date: Sun, 12 Mar 2023 09:13:00 -0300 Subject: [PATCH 217/805] Added semantic version as a static public member (#931) * Added semantic version as a static public member accessible in the generated stubs. * Added generated java ir codecs. * Added constexpr in static c++ semanticVersion. * Fixing cpp codeGenTest. * Adjustments based on the pr comments. * Adjustments based on the pr comments. --- .../sbe/generation/c/CGenerator.java | 9 ++++++- .../sbe/generation/cpp/CppGenerator.java | 24 +++++++++++++++++-- .../generation/csharp/CSharpGenerator.java | 7 ++++-- .../generation/golang/GolangGenerator.java | 7 +++++- .../sbe/generation/java/JavaGenerator.java | 10 ++++++-- .../sbe/generation/rust/RustGenerator.java | 4 +++- .../sbe/ir/generated/FrameCodecDecoder.java | 1 + .../sbe/ir/generated/FrameCodecEncoder.java | 1 + .../ir/generated/MessageHeaderDecoder.java | 1 + .../ir/generated/MessageHeaderEncoder.java | 1 + .../sbe/ir/generated/TokenCodecDecoder.java | 1 + .../sbe/ir/generated/TokenCodecEncoder.java | 1 + .../ir/generated/VarDataEncodingDecoder.java | 1 + .../ir/generated/VarDataEncodingEncoder.java | 1 + sbe-tool/src/test/c/CodeGenTest.cpp | 1 + sbe-tool/src/test/cpp/CodeGenTest.cpp | 1 + 16 files changed, 62 insertions(+), 9 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 61f6cb87c7..8b71264be2 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1894,6 +1894,7 @@ private CharSequence generateMessageFlyweightFunctions( final String schemaVersionType = cTypeName(ir.headerStructure().schemaVersionType()); final String semanticType = token.encoding().semanticType() == null ? "" : token.encoding().semanticType(); final String messageHeaderStruct = formatScopedName(scope, "messageHeader"); + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); return String.format("\n" + "SBE_ONE_DEF uint64_t %10$s_sbe_position(\n" + @@ -1974,6 +1975,11 @@ private CharSequence generateMessageFlyweightFunctions( " return %8$s;\n" + "}\n\n" + + "SBE_ONE_DEF const char* %10$s_sbe_semantic_version(void)\n" + + "{\n" + + " return \"%12$s\";\n" + + "}\n\n" + + "SBE_ONE_DEF const char *%10$s_sbe_semantic_type(void)\n" + "{\n" + " return \"%9$s\";\n" + @@ -2093,7 +2099,8 @@ private CharSequence generateMessageFlyweightFunctions( generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), semanticType, structName, - messageHeaderStruct); + messageHeaderStruct, + semanticVersion); } private CharSequence generateFieldFunctions( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 54fa183222..ddbc1aadcf 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -169,6 +169,7 @@ public void generate() throws IOException generateDisplay(sb, msgToken.name(), fields, groups, varData); sb.append(generateMessageLength(groups, varData, BASE_INDENT)); sb.append("};\n"); + sb.append(generateStaticVariablesInitialization(className)); sb.append(CppUtil.closingBraces(ir.namespaces().length)).append("#endif\n"); out.append(sb); } @@ -1973,6 +1974,7 @@ private CharSequence generateMessageFlyweightCode(final String className, final final String schemaVersionType = cppTypeName(ir.headerStructure().schemaVersionType()); final String semanticType = token.encoding().semanticType() == null ? "" : token.encoding().semanticType(); final String headerType = ir.headerStructure().tokens().get(0).name(); + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); return String.format( "private:\n" + @@ -1992,7 +1994,8 @@ private CharSequence generateMessageFlyweightCode(final String className, final " static const %1$s SBE_BLOCK_LENGTH = %2$s;\n" + " static const %3$s SBE_TEMPLATE_ID = %4$s;\n" + " static const %5$s SBE_SCHEMA_ID = %6$s;\n" + - " static const %7$s SBE_SCHEMA_VERSION = %8$s;\n\n" + + " static const %7$s SBE_SCHEMA_VERSION = %8$s;\n" + + " static const char* SBE_SEMANTIC_VERSION;\n\n" + " enum MetaAttribute\n" + " {\n" + @@ -2039,6 +2042,11 @@ private CharSequence generateMessageFlyweightCode(final String className, final " return %8$s;\n" + " }\n\n" + + " SBE_NODISCARD static const char *sbeSemanticVersion() SBE_NOEXCEPT\n" + + " {\n" + + " return \"%13$s\";\n" + + " }\n\n" + + " SBE_NODISCARD static SBE_CONSTEXPR const char *sbeSemanticType() SBE_NOEXCEPT\n" + " {\n" + " return \"%9$s\";\n" + @@ -2151,7 +2159,8 @@ private CharSequence generateMessageFlyweightCode(final String className, final semanticType, className, generateConstructorsAndOperators(className), - formatClassName(headerType)); + formatClassName(headerType), + semanticVersion); } private void generateFields( @@ -3184,4 +3193,15 @@ private CharSequence generateMessageLength(final List groups, final List< return sb; } + + private CharSequence generateStaticVariablesInitialization(final String className) + { + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); + + return String.format( + "\n" + + "const char* %1$s::SBE_SEMANTIC_VERSION = \"%2$s\";\n\n", + className, + semanticVersion); + } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 732b322e8d..5a607a8414 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1163,13 +1163,15 @@ private CharSequence generateMessageFlyweightCode(final String className, final final String schemaIdType = cSharpTypeName(ir.headerStructure().schemaIdType()); final String schemaVersionType = cSharpTypeName(ir.headerStructure().schemaVersionType()); final String semanticType = token.encoding().semanticType() == null ? "" : token.encoding().semanticType(); + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); return String.format( indent + INDENT + "public const %1$s BlockLength = %2$s;\n" + indent + INDENT + "public const %3$s TemplateId = %4$s;\n" + indent + INDENT + "public const %5$s SchemaId = %6$s;\n" + indent + INDENT + "public const %7$s SchemaVersion = %8$s;\n" + - indent + INDENT + "public const string SemanticType = \"%9$s\";\n\n" + + indent + INDENT + "public const string SemanticType = \"%9$s\";\n" + + indent + INDENT + "public const string SemanticVersion = \"%11$s\";\n\n" + indent + INDENT + "private readonly %10$s _parentMessage;\n" + indent + INDENT + "private DirectBuffer _buffer;\n" + indent + INDENT + "private int _offset;\n" + @@ -1238,7 +1240,8 @@ private CharSequence generateMessageFlyweightCode(final String className, final schemaVersionType, generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), semanticType, - className); + className, + semanticVersion); } private CharSequence generateFields(final List tokens, final String indent) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index e059524da8..1f5e238bff 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -2099,6 +2099,7 @@ private void generateMessageCode( final String templateIdType = golangTypeName(ir.headerStructure().templateIdType()); final String schemaIdType = golangTypeName(ir.headerStructure().schemaIdType()); final String schemaVersionType = golangTypeName(ir.headerStructure().schemaVersionType()); + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); generateEncodeDecode(sb, typeName, tokens, true, true); @@ -2117,6 +2118,9 @@ private void generateMessageCode( "}\n" + "\nfunc (*%1$s) SbeSemanticType() (semanticType []byte) {\n" + "\treturn []byte(\"%10$s\")\n" + + "}\n" + + "\nfunc (*%1$s) SbeSemanticVersion() (semanticVersion string) {\n" + + "\treturn \"%11$s\"\n" + "}\n", typeName, blockLengthType, @@ -2127,7 +2131,8 @@ private void generateMessageCode( generateLiteral(ir.headerStructure().schemaIdType(), Integer.toString(ir.id())), schemaVersionType, generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), - semanticType)); + semanticType, + semanticVersion)); } // Used for groups which need to know the schema's definition diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 233c9aecbe..d44bf668b8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -2611,10 +2611,12 @@ private CharSequence generateFixedFlyweightCode( final String schemaIdAccessorType = shouldGenerateInterfaces ? "int" : schemaIdType; final String schemaVersionType = javaTypeName(ir.headerStructure().schemaVersionType()); final String schemaVersionAccessorType = shouldGenerateInterfaces ? "int" : schemaVersionType; + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); return String.format( " public static final %5$s SCHEMA_ID = %6$s;\n" + " public static final %7$s SCHEMA_VERSION = %8$s;\n" + + " public static final String SEMANTIC_VERSION = \"%11$s\";\n" + " public static final int ENCODED_LENGTH = %2$d;\n" + " public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.%4$s;\n\n" + " private int offset;\n" + @@ -2657,7 +2659,8 @@ private CharSequence generateFixedFlyweightCode( schemaVersionType, generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), schemaIdAccessorType, - schemaVersionAccessorType); + schemaVersionAccessorType, + semanticVersion); } private CharSequence generateDecoderFlyweightCode(final String className, final Token token) @@ -2735,6 +2738,7 @@ private CharSequence generateFlyweightCode( final String schemaVersionType = javaTypeName(headerStructure.schemaVersionType()); final String schemaVersionAccessorType = shouldGenerateInterfaces ? "int" : schemaVersionType; final String semanticType = token.encoding().semanticType() == null ? "" : token.encoding().semanticType(); + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); final String actingFields = codecType == CodecType.ENCODER ? "" : " int actingBlockLength;\n" + @@ -2745,6 +2749,7 @@ private CharSequence generateFlyweightCode( " public static final %3$s TEMPLATE_ID = %4$s;\n" + " public static final %5$s SCHEMA_ID = %6$s;\n" + " public static final %7$s SCHEMA_VERSION = %8$s;\n" + + " public static final String SEMANTIC_VERSION = \"%19$s\";\n" + " public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.%14$s;\n\n" + " private final %9$s parentMessage = this;\n" + " private %11$s buffer;\n" + @@ -2815,7 +2820,8 @@ private CharSequence generateFlyweightCode( blockLengthAccessorType, templateIdAccessorType, schemaIdAccessorType, - schemaVersionAccessorType); + schemaVersionAccessorType, + semanticVersion); } private CharSequence generateEncoderFlyweightCode(final String className, final Token token) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index fe58ce4874..0514463237 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -157,10 +157,12 @@ public void generate() throws IOException final String templateIdType = rustTypeName(ir.headerStructure().templateIdType()); final String schemaIdType = rustTypeName(ir.headerStructure().schemaIdType()); final String schemaVersionType = schemaVersionType(); + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); indent(out, 0, "pub const SBE_BLOCK_LENGTH: %s = %d;\n", blockLengthType, msgToken.encodedLength()); indent(out, 0, "pub const SBE_TEMPLATE_ID: %s = %d;\n", templateIdType, msgToken.id()); indent(out, 0, "pub const SBE_SCHEMA_ID: %s = %d;\n", schemaIdType, ir.id()); - indent(out, 0, "pub const SBE_SCHEMA_VERSION: %s = %d;\n\n", schemaVersionType, ir.version()); + indent(out, 0, "pub const SBE_SCHEMA_VERSION: %s = %d;\n", schemaVersionType, ir.version()); + indent(out, 0, "pub const SBE_SEMANTIC_VERSION: &str = \"%s\";\n\n", semanticVersion); MessageCoderDef.generateEncoder(ir, out, msgToken, fields, groups, varData); MessageCoderDef.generateDecoder(ir, out, msgToken, fields, groups, varData); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index 12fc62b74b..2bdd4647fc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -15,6 +15,7 @@ public final class FrameCodecDecoder public static final int TEMPLATE_ID = 1; public static final int SCHEMA_ID = 1; public static final int SCHEMA_VERSION = 0; + public static final String SEMANTIC_VERSION = ""; public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.LITTLE_ENDIAN; private final FrameCodecDecoder parentMessage = this; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java index 4bcc266652..0fd115d556 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java @@ -15,6 +15,7 @@ public final class FrameCodecEncoder public static final int TEMPLATE_ID = 1; public static final int SCHEMA_ID = 1; public static final int SCHEMA_VERSION = 0; + public static final String SEMANTIC_VERSION = ""; public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.LITTLE_ENDIAN; private final FrameCodecEncoder parentMessage = this; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java index b0f47e2bd5..380c8a649e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java @@ -12,6 +12,7 @@ public final class MessageHeaderDecoder { public static final int SCHEMA_ID = 1; public static final int SCHEMA_VERSION = 0; + public static final String SEMANTIC_VERSION = ""; public static final int ENCODED_LENGTH = 8; public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.LITTLE_ENDIAN; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java index f295379b98..b1255198e5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java @@ -12,6 +12,7 @@ public final class MessageHeaderEncoder { public static final int SCHEMA_ID = 1; public static final int SCHEMA_VERSION = 0; + public static final String SEMANTIC_VERSION = ""; public static final int ENCODED_LENGTH = 8; public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.LITTLE_ENDIAN; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index 5f23d9ef9e..244fb30ec1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -15,6 +15,7 @@ public final class TokenCodecDecoder public static final int TEMPLATE_ID = 2; public static final int SCHEMA_ID = 1; public static final int SCHEMA_VERSION = 0; + public static final String SEMANTIC_VERSION = ""; public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.LITTLE_ENDIAN; private final TokenCodecDecoder parentMessage = this; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java index 1f429e09b5..793f10756f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java @@ -15,6 +15,7 @@ public final class TokenCodecEncoder public static final int TEMPLATE_ID = 2; public static final int SCHEMA_ID = 1; public static final int SCHEMA_VERSION = 0; + public static final String SEMANTIC_VERSION = ""; public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.LITTLE_ENDIAN; private final TokenCodecEncoder parentMessage = this; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java index aad78db9fe..fef5471086 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java @@ -12,6 +12,7 @@ public final class VarDataEncodingDecoder { public static final int SCHEMA_ID = 1; public static final int SCHEMA_VERSION = 0; + public static final String SEMANTIC_VERSION = ""; public static final int ENCODED_LENGTH = -1; public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.LITTLE_ENDIAN; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java index d86d2879a2..69ecabf325 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java @@ -12,6 +12,7 @@ public final class VarDataEncodingEncoder { public static final int SCHEMA_ID = 1; public static final int SCHEMA_VERSION = 0; + public static final String SEMANTIC_VERSION = ""; public static final int ENCODED_LENGTH = -1; public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.LITTLE_ENDIAN; diff --git a/sbe-tool/src/test/c/CodeGenTest.cpp b/sbe-tool/src/test/c/CodeGenTest.cpp index 961db64b2d..68494c7993 100644 --- a/sbe-tool/src/test/c/CodeGenTest.cpp +++ b/sbe-tool/src/test/c/CodeGenTest.cpp @@ -432,6 +432,7 @@ TEST_F(CodeGenTest, shouldReturnCorrectValuesForCarStaticFields) EXPECT_EQ(CGT(car_sbe_schema_id)(), 6u); EXPECT_EQ(CGT(car_sbe_schema_version)(), 0u); EXPECT_EQ(std::string(CGT(car_sbe_semantic_type)()), std::string("")); + EXPECT_EQ(CGT(car_sbe_semantic_version)(), "5.2"); } TEST_F(CodeGenTest, shouldBeAbleToEncodeMessageHeaderCorrectly) diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index 5c7ad29b77..698d7ec849 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -331,6 +331,7 @@ TEST_F(CodeGenTest, shouldReturnCorrectValuesForCarStaticFields) EXPECT_EQ(Car::sbeSchemaId(), 6u); EXPECT_EQ(Car::sbeSchemaVersion(), 0u); EXPECT_EQ(std::string(Car::sbeSemanticType()), std::string("")); + EXPECT_EQ(std::string(Car::sbeSemanticVersion()), std::string("5.2")); } TEST_F(CodeGenTest, shouldBeAbleToEncodeMessageHeaderCorrectly) From 0f99a8219b1b79c779b734e4f02c3923d6691c1b Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 26 Mar 2023 18:50:22 +0200 Subject: [PATCH 218/805] [CI] Add Clang 16 to the build matrix. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed6e5ae9bf..7c3f07c143 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -218,7 +218,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '13', '14', '15' ] + version: [ '13', '14', '15', '16' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} From 3529fdb053624c29bba051c7f042ff683b8575db Mon Sep 17 00:00:00 2001 From: James Watson Date: Wed, 29 Mar 2023 12:09:15 +0100 Subject: [PATCH 219/805] [Java] Upgrade to Agrona 1.18.0. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index b58ba21e0f..3527c6a0c2 100644 --- a/build.gradle +++ b/build.gradle @@ -47,8 +47,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.9.2' def jmhVersion = '1.36' -def agronaVersion = '1.17.1' -def agronaVersionRange = '[1.17.1,2.0[' // allow any release >= 1.17.1 and < 2.0.0 +def agronaVersion = '1.18.0' +def agronaVersionRange = '[1.18.0,2.0[' // allow any release >= 1.18.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 8f940f0407da54584e5322b17925df107f3991e8 Mon Sep 17 00:00:00 2001 From: James Watson Date: Wed, 29 Mar 2023 12:21:06 +0100 Subject: [PATCH 220/805] 1.27.1 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f9aacd1c13..08002f86cc 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.27.1-SNAPSHOT +1.27.1 From 7995b239eec3db734339386ec0784f68a7a6529e Mon Sep 17 00:00:00 2001 From: James Watson Date: Wed, 29 Mar 2023 12:25:13 +0100 Subject: [PATCH 221/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 08002f86cc..42c4c68219 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.27.1 +1.27.2-SNAPSHOT From ac613b0c5326556b33efe416dd94d6af8cab3695 Mon Sep 17 00:00:00 2001 From: James Watson Date: Wed, 29 Mar 2023 13:37:36 +0100 Subject: [PATCH 222/805] 1.28.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 42c4c68219..cfc730712d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.27.2-SNAPSHOT +1.28.0 From 57011d1b0a3c65ed17dfd9227ccb8922fe2c2fef Mon Sep 17 00:00:00 2001 From: James Watson Date: Wed, 29 Mar 2023 13:39:32 +0100 Subject: [PATCH 223/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index cfc730712d..f2ec2d3b39 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.28.0 +1.29.0-SNAPSHOT From 259655249cd36bccc555bf540d9abedb52aa56d9 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 29 Mar 2023 17:35:00 +0200 Subject: [PATCH 224/805] [Java] Fix SBE_SEMANTIC_VERSION field generation for C++. --- .../sbe/generation/cpp/CppGenerator.java | 14 +------------ .../sbe/generation/cpp/CppGeneratorTest.java | 20 +++++++++++++++++++ version.txt | 2 +- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index ddbc1aadcf..1aed7b0df4 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -169,7 +169,6 @@ public void generate() throws IOException generateDisplay(sb, msgToken.name(), fields, groups, varData); sb.append(generateMessageLength(groups, varData, BASE_INDENT)); sb.append("};\n"); - sb.append(generateStaticVariablesInitialization(className)); sb.append(CppUtil.closingBraces(ir.namespaces().length)).append("#endif\n"); out.append(sb); } @@ -1995,7 +1994,7 @@ private CharSequence generateMessageFlyweightCode(final String className, final " static const %3$s SBE_TEMPLATE_ID = %4$s;\n" + " static const %5$s SBE_SCHEMA_ID = %6$s;\n" + " static const %7$s SBE_SCHEMA_VERSION = %8$s;\n" + - " static const char* SBE_SEMANTIC_VERSION;\n\n" + + " static constexpr const char* SBE_SEMANTIC_VERSION = \"%13$s\";\n\n" + " enum MetaAttribute\n" + " {\n" + @@ -3193,15 +3192,4 @@ private CharSequence generateMessageLength(final List groups, final List< return sb; } - - private CharSequence generateStaticVariablesInitialization(final String className) - { - final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); - - return String.format( - "\n" + - "const char* %1$s::SBE_SEMANTIC_VERSION = \"%2$s\";\n\n", - className, - semanticVersion); - } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index 73fa7664f2..63e2f6010b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -52,4 +52,24 @@ void shouldUseGeneratedLiteralForConstantOneWhenGeneratingBitsetCode() throws Ex assertThat(source, containsString("UINT64_C(0x1) << ")); } } + + @Test + void shouldUseConstexprWhenInitializingSemanticVersion() throws Exception + { + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CppGenerator generator = new CppGenerator(ir, false, outputManager); + generator.generate(); + + final String source = outputManager.getSource("code.generation.test.Car").toString(); + assertThat(source, containsString("static constexpr const char* SBE_SEMANTIC_VERSION = \"5.2\"")); + } + } } diff --git a/version.txt b/version.txt index f2ec2d3b39..abf37a154b 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.29.0-SNAPSHOT +1.28.1-SNAPSHOT From b14ba4d6421734ece6e37d4bca2bb820c005cb02 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 29 Mar 2023 18:53:44 +0200 Subject: [PATCH 225/805] 1.28.1 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index abf37a154b..e787e4c523 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.28.1-SNAPSHOT +1.28.1 \ No newline at end of file From 2c7979e6912eea789e6f8910546bbed140d55673 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 29 Mar 2023 18:54:18 +0200 Subject: [PATCH 226/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index e787e4c523..5daec50998 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.28.1 \ No newline at end of file +1.29.0-SNAPSHOT \ No newline at end of file From 9b2f42d9e42eba938050154f7f703532fa9c869a Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Apr 2023 01:12:06 +0200 Subject: [PATCH 227/805] [Java] Upgrade to Agrona 1.18.1. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 3527c6a0c2..d0c1566e38 100644 --- a/build.gradle +++ b/build.gradle @@ -47,8 +47,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.9.2' def jmhVersion = '1.36' -def agronaVersion = '1.18.0' -def agronaVersionRange = '[1.18.0,2.0[' // allow any release >= 1.18.0 and < 2.0.0 +def agronaVersion = '1.18.1' +def agronaVersionRange = '[1.18.1,2.0[' // allow any release >= 1.18.1 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From f4c6618b0d3ea9c05c60e5922860ead3be375c1c Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Apr 2023 09:02:41 +0200 Subject: [PATCH 228/805] 1.28.2 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 5daec50998..d0792325d8 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.29.0-SNAPSHOT \ No newline at end of file +1.28.2 \ No newline at end of file From 74e9df73e457a6abdd46479bbb5b93841b3d3c86 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Apr 2023 09:03:16 +0200 Subject: [PATCH 229/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index d0792325d8..5daec50998 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.28.2 \ No newline at end of file +1.29.0-SNAPSHOT \ No newline at end of file From 663934c5ef6f12f2430604c4300cee7e02db40c5 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Apr 2023 12:35:11 +0200 Subject: [PATCH 230/805] Upgrade to Gradle 8.1. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 61608 -> 62076 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 7 ++++--- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index d0c1566e38..0008d80f84 100644 --- a/build.gradle +++ b/build.gradle @@ -830,7 +830,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '7.6' + gradleVersion = '8.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ccebba7710deaf9f98673a68957ea02138b60d0a..c1962a79e29d3e0ab67b14947c167a862655af9b 100644 GIT binary patch delta 8979 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 F{TFmrHLU;u delta 8469 zcmY*q~ZGqoW{=01$bgB@1Nex`%9%S2I04)5Jw9+UyLS&r+9O2bq{gY;dCa zHW3WY0%Dem?S7n5JZO%*yiT9fb!XGk9^Q`o-EO{a^j%&)ZsxsSN@2k2eFx1*psqn0e*crIbAO}Rd~_BifMu*q7SUn{>WD$=7n_$uiQ0wGc$?u1hM%gf??nL?m22h!8{ zYmFMLvx6fjz*nwF^tAqx1uv0yEW9-tcIV5Q{HNh`9PMsuqD8VE%oAs5FsWa0mLV$L zPAF5e^$tJ8_Kwp!$N1M<#Z154n!X6hFpk8)eMLu; zaXS71&`24 zV`x~}yAxBw##Oj@qo_@DcBqc+2TB&=bJyZWTeR55zG<{Z@T^hSbMdm~Ikkr?4{7WT zcjPyu>0sDjl7&?TL@ z)cW?lW@Pfwu#nm7E1%6*nBIzQrKhHl`t54$-m>j8f%0vVr?N0PTz`}VrYAl+8h^O~ zuWQj@aZSZmGPtcVjGq-EQ1V`)%x{HZ6pT-tZttJOQm?q-#KzchbH>>5-jEX*K~KDa z#oO&Qf4$@}ZGQ7gxn<;D$ziphThbi6zL^YC;J#t0GCbjY)NHdqF=M4e(@|DUPY_=F zLcX1HAJ+O-3VkU#LW`4;=6szwwo%^R4#UK}HdAXK` z{m!VZj5q9tVYL=^TqPH*6?>*yr>VxyYF4tY{~?qJ*eIoIU0}-TLepzga4g}}D7#Qu zn;6I;l!`xaL^8r*Tz*h`^(xJCnuVR_O@Gl*Q}y$lp%!kxD`%zN19WTIf`VX*M=cDp z*s4<9wP|ev;PARRV`g$R*QV@rr%Ku~z(2-s>nt{JI$357vnFAz9!ZsiiH#4wOt+!1 zM;h;EN__zBn)*-A^l!`b?b*VI-?)Sj6&Ov3!j9k$5+#w)M>`AExCm0!#XL+E{Bp)s;Hochs+-@@)7_XDMPby#p<9mLu+S{8e2Jn`1`1nrffBfy4u)p7FFQWzgYt zXC}GypRdkTUS+mP!jSH$K71PYI%QI-{m;DvlRb*|4GMPmvURv0uD2bvS%FOSe_$4zc--*>gfRMKN|D ztP^WFfGEkcm?sqXoyRmuCgb?bSG17#QSv4~XsbPH>BE%;bZQ_HQb?q%CjykL7CWDf z!rtrPk~46_!{V`V<;AjAza;w-F%t1^+b|r_um$#1cHZ1|WpVUS&1aq?Mnss|HVDRY z*sVYNB+4#TJAh4#rGbr}oSnxjD6_LIkanNvZ9_#bm?$HKKdDdg4%vxbm-t@ZcKr#x z6<$$VPNBpWM2S+bf5IBjY3-IY2-BwRfW_DonEaXa=h{xOH%oa~gPW6LTF26Y*M)$N z=9i`Y8};Qgr#zvU)_^yU5yB;9@yJjrMvc4T%}a|jCze826soW-d`V~eo%RTh)&#XR zRe<8$42S2oz|NVcB%rG(FP2U&X>3 z4M^}|K{v64>~rob;$GO55t;Nb&T+A3u(>P6;wtp6DBGWbX|3EZBDAM2DCo&4w|WGpi;~qUY?Ofg$pX&`zR~)lr)8}z^U3U38Nrtnmf~e7$i=l>+*R%hQgDrj%P7F zIjyBCj2$Td=Fp=0Dk{=8d6cIcW6zhK!$>k*uC^f}c6-NR$ zd<)oa+_fQDyY-}9DsPBvh@6EvLZ}c)C&O-+wY|}RYHbc2cdGuNcJ7#yE}9=!Vt-Q~ z4tOePK!0IJ0cW*jOkCO? zS-T!bE{5LD&u!I4tqy;dI*)#e^i)uIDxU?8wK1COP3Qk{$vM3Sm8(F2VwM?1A+dle z6`M6bbZye|kew%w9l`GS74yhLluJU5R=#!&zGwB7lmTt}&eCt0g(-a;Mom-{lL6u~ zFgjyUs1$K*0R51qQTW_165~#WRrMxiUx{0F#+tvgtcjV$U|Z}G*JWo6)8f!+(4o>O zuaAxLfUl;GHI}A}Kc>A8h^v6C-9bb}lw@rtA*4Q8)z>0oa6V1>N4GFyi&v69#x&CwK*^!w&$`dv zQKRMKcN$^=$?4to7X4I`?PKGi(=R}d8cv{74o|9FwS zvvTg0D~O%bQpbp@{r49;r~5`mcE^P<9;Zi$?4LP-^P^kuY#uBz$F!u1d{Ens6~$Od zf)dV+8-4!eURXZZ;lM4rJw{R3f1Ng<9nn2_RQUZDrOw5+DtdAIv*v@3ZBU9G)sC&y!vM28daSH7(SKNGcV z&5x#e#W2eY?XN@jyOQiSj$BlXkTG3uAL{D|PwoMp$}f3h5o7b4Y+X#P)0jlolgLn9xC%zr3jr$gl$8?II`DO6gIGm;O`R`bN{;DlXaY4b`>x6xH=Kl@ z!>mh~TLOo)#dTb~F;O z8hpjW9Ga?AX&&J+T#RM6u*9x{&%I8m?vk4eDWz^l2N_k(TbeBpIwcV4FhL(S$4l5p z@{n7|sax){t!3t4O!`o(dYCNh90+hl|p%V_q&cwBzT*?Nu*D0wZ)fPXv z@*;`TO7T0WKtFh8~mQx;49VG_`l`g|&VK}LysK%eU4})Cvvg3YN)%;zI?;_Nr z)5zuU1^r3h;Y+mJov*->dOOj>RV^u2*|RraaQWsY5N?Uu)fKJOCSL2^G=RB%(4K{* zx!^cB@I|kJR`b+5IK}(6)m=O{49P5E^)!XvD5zVuzJH{01^#$@Cn514w41BB;FAoS2SYl3SRrOBDLfl5MvgA3 zU6{T?BW}l~8vU;q@p9IOM(=;WdioeQmt?X|=L9kyM&ZsNc*-Knv8@U*O96T@4ZiJ$ zeFL2}pw_~Tm3d4#q!zZS0km@vYgym33C0h(6D)6|Y)*UXI^T`(QPQh$WF?&h(3QYh zqGw@?BTk@VA_VxK@z?a@UrMhY zUD16oqx4$$6J_k0HnXgARm}N#(^yA1MLdbwmEqHnX*JdHN>$5k2E|^_bL< zGf5Z+D!9dXR>^(5F&5gIew1%kJtFUwI5P1~I$4LL_6)3RPzw|@2vV;Q^MeQUKzc=KxSTTX`}u%z?h~;qI#%dE@OZwehZyDBsWTc&tOC1c%HS#AyTJ= zQixj=BNVaRS*G!;B$}cJljeiVQabC25O+xr4A+32HVb;@+%r}$^u4-R?^3yij)0xb z86i@aoVxa%?bfOE;Bgvm&8_8K(M-ZEj*u9ms_Hk#2eL`PSnD#At!0l{f!v`&Kg}M$n(&R)?AigC5Z?T7Jv^lrDL!yYS{4 zq_H}oezX-Svu>dp)wE@khE@aR5vY=;{C-8Hws++5LDpArYd)U47jc-;f~07_TPa^1 zO`0+uIq)@?^!%JXCDid+nt|c@NG1+ce@ijUX&@rV9UiT|m+t-nqVB7?&UX*|{yDBFw9x52&dTh@;CL)Q?6s1gL=CUQTX7#TJPs9cpw<4>GFMUKo|f{! z&(%2hP6ghr%UFVO-N^v9l|tKy>&e%8us}wT0N*l(tezoctVtLmNdGPOF6oaAGJI5R zZ*|k@z3H!~Mm9fXw{bbP6?lV-j#Rfgnjf++O7*|5vz2#XK;kk ztJbi%r0{U5@QwHYfwdjtqJ6?;X{Ul3?W0O0bZ$k*y z4jWsNedRoCb7_|>nazmq{T3Y_{<5IO&zQ?9&uS@iL+|K|eXy^F>-60HDoVvovHelY zy6p(}H^7b+$gu@7xLn_^oQryjVu#pRE5&-w5ZLCK&)WJ5jJF{B>y;-=)C;xbF#wig zNxN^>TwzZbV+{+M?}UfbFSe#(x$c)|d_9fRLLHH?Xbn!PoM{(+S5IEFRe4$aHg~hP zJYt`h&?WuNs4mVAmk$yeM;8?R6;YBMp8VilyM!RXWj<95=yp=4@y?`Ua8 znR^R?u&g%`$Wa~usp|pO$aMF-en!DrolPjD_g#{8X1f=#_7hH8i|WF+wMqmxUm*!G z*4p980g{sgR9?{}B+a0yiOdR()tWE8u)vMPxAdK)?$M+O_S+;nB34@o<%lGJbXbP` z5)<({mNpHp&45UvN`b&K5SD#W){}6Y_d4v~amZPGg|3GdlWDB;;?a=Z{dd zELTfXnjCqq{Dgbh9c%LjK!Epi1TGI{A7AP|eg2@TFQiUd4Bo!JsCqsS-8ml`j{gM& zEd7yU`djX!EX2I{WZq=qasFzdDWD`Z?ULFVIP!(KQP=fJh5QC9D|$JGV95jv)!sYWY?irpvh06rw&O?iIvMMj=X zr%`aa(|{Ad=Vr9%Q(61{PB-V_(3A%p&V#0zGKI1O(^;tkS{>Y<`Ql@_-b7IOT&@?l zavh?#FW?5otMIjq+Bp?Lq)w7S(0Vp0o!J*~O1>av;)Cdok@h&JKaoHDV6IVtJ?N#XY=lknPN+SN8@3Gb+D-X*y5pQ)wnIpQlRR!Rd)@0LdA85}1 zu7W6tJ*p26ovz+`YCPePT>-+p@T_QsW$uE`McLlXb;k}!wwWuh$YC4qHRd=RS!s>2 zo39VCB-#Ew?PAYOx`x!@0qa5lZKrE?PJEwVfkww#aB_$CLKlkzHSIi4p3#IeyA@u@ z`x^!`0HJxe>#V7+Grku^in>Ppz|TD*`Ca4X%R3Yo|J=!)l$vYks|KhG{1CEfyuzK( zLjCz{5l}9>$J=FC?59^85awK0$;^9t9UxwOU8kP7ReVCc*rPOr(9uMY*aCZi2=JBu z(D0svsJRB&a9nY;6|4kMr1Er5kUVOh1TuBwa3B2C<+rS|xJo&Lnx3K-*P83eXQCJ= z(htQSA3hgOMcs`#NdYB17#zP_1N_P0peHrNo1%NsYn=;PgLXTic6b#{Y0Z~x9Ffav z^3eO+diquPfo1AXW*>G(JcGn{yN?segqKL$Wc9po(Kex z#tw_};zd++we+MPhOOgaXSmguul67JOvBysmg?wRf=OUeh(XyRcyY@8RTV@xck_c~ zLFMWAWb4^7xwR)3iO1PIs1<}L3CMJ1L-}s=>_y!`!FvYf^pJO|&nII{!Dz+b?=bUd zPJUUn))z)-TcpqKF(1tr-x1;lS?SB@mT#O7skl0sER{a|d?&>EKKaw* zQ>D^m*pNgV`54BKv?knU-T5bcvBKnI@KZo^UYjKp{2hpCo?_6v(Sg77@nQa{tSKbn zUgMtF>A3hndGocRY+Snm#)Q4%`|Qq3YTOU^uG}BGlz!B=zb?vB16sN&6J`L(k1r+$ z5G6E9tJ~Iwd!d!NH7Q%Z@BR@0e{p6#XF2))?FLAVG`npIjih*I+0!f6;+DM zLOP-qDsm9=ZrI!lfSDn%XuF17$j~gZE@I}S(Ctw&Te75P5?Fj%FLT;p-tm33FaUQc z5cR;$SwV|N0xmjox3V~XL3sV?YN}U0kkfmygW@a5JOCGgce6JyzGmgN$?NM%4;wEhUMg0uTTB~L==1Fvc(6)KMLmU z(12l^#g&9OpF7+Ll30F6(q=~>NIY=-YUJJ}@&;!RYnq*xA9h!iMi`t;B2SUqbyNGn zye@*0#Uu`OQy%utS%IA%$M1f4B|bOH={!3K1=Tc7Ra|%qZgZ{mjAGKXb)}jUu1mQ_ zRW7<;tkHv(m7E0m>**8D;+2ddTL>EcH_1YqCaTTu_#6Djm z*64!w#=Hz<>Fi1n+P}l#-)0e0P4o+D8^^Mk& zhHeJoh2paKlO+8r?$tx`qEcm|PSt6|1$1q?r@VvvMd1!*zAy3<`X9j?ZI|;jE-F(H zIn1+sm(zAnoJArtytHC|0&F0`i*dy-PiwbD-+j`ezvd4C`%F1y^7t}2aww}ZlPk)t z=Y`tm#jNM$d`pG%F42Xmg_pZnEnvC%avz=xNs!=6b%%JSuc(WObezkCeZ#C|3PpXj zkR8hDPyTIUv~?<%*)6=8`WfPPyB9goi+p$1N2N<%!tS2wopT2x`2IZi?|_P{GA|I5 z?7DP*?Gi#2SJZ!x#W9Npm)T;=;~Swyeb*!P{I^s@o5m_3GS2Lg?VUeBdOeae7&s5$ zSL_VuTJih_fq7g8O8b0g+GbmE+xG}^Wx`g~{mWTyr@=h zKlAymoHeZa`DgR?Pj8Yc+I|MrSB>X*ts#wNFOJxs!3aGE)xeTHlF`fC5^g(DTacl$ zx!ezQJdwIyc$8RyNS~Wh{0pp>8NcW)*J=7AQYdT?(QhJuq4u`QniZ!%6l{KWp-0Xp z4ZC6(E(_&c$$U_cmGFslsyX6(62~m*z8Yx2p+F5xmD%6A7eOnx`1lJA-Mrc#&xZWJ zzXV{{OIgzYaq|D4k^j%z|8JB8GnRu3hw#8Z@({sSmsF(x>!w0Meg5y(zg!Z0S^0k# z5x^g1@L;toCK$NB|Fn Date: Mon, 17 Apr 2023 12:35:35 +0200 Subject: [PATCH 231/805] Upgrade to Shadow 8.1.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0008d80f84..4b9be03a11 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ import java.security.MessageDigest plugins { id 'java-library' - id 'com.github.johnrengelman.shadow' version '7.1.2' apply false + id 'com.github.johnrengelman.shadow' version '8.1.1' apply false id 'com.github.ben-manes.versions' version '0.46.0' } From b52591a6dde57e27363ee62417a192554bd06445 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Apr 2023 12:49:35 +0200 Subject: [PATCH 232/805] [CI] Add JDK 20 to the build matrix. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c3f07c143..1110358ff1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '8', '11', '17' ] + java: [ '8', '11', '17', '20' ] os: [ 'ubuntu-22.04', 'windows-latest' ] steps: - name: Checkout code From 8d50a5e80530f2980f88cac8295c213586b52bc4 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:14:25 +0200 Subject: [PATCH 233/805] [CI] Add JDK 21-ea to the build matrix. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1110358ff1..e89e54c175 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '8', '11', '17', '20' ] + java: [ '8', '11', '17', '21-ea' ] os: [ 'ubuntu-22.04', 'windows-latest' ] steps: - name: Checkout code From 3cbb6f438c8803e14c0c70800109c44e8fb239a5 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:32:33 +0200 Subject: [PATCH 234/805] [Gradle] Upgrade ASM dependency to the latest version to build on JDK 21. --- build.gradle | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build.gradle b/build.gradle index 4b9be03a11..e2e7ebf89c 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,17 @@ import java.nio.file.Files import java.nio.file.StandardOpenOption import java.security.MessageDigest +buildscript { + repositories { + gradlePluginPortal() + mavenCentral() + } + dependencies { + classpath 'org.ow2.asm:asm:9.5' + classpath 'org.ow2.asm:asm-commons:9.5' + } +} + plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '8.1.1' apply false From 2387ab4b258eb898400c249e7377dcea9c6f8e72 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 23 Apr 2023 10:09:37 +0200 Subject: [PATCH 235/805] Force CRLF for Windows files. --- .gitattributes | 64 ++------------------------------------------------ 1 file changed, 2 insertions(+), 62 deletions(-) diff --git a/.gitattributes b/.gitattributes index 1ff0c42304..94a7377068 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,63 +1,3 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### * text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain +*.bat text eol=crlf +*.cmd text eol=crlf From c803dd105dc051c30002943aae3b02a31cb738c3 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 23 Apr 2023 10:09:46 +0200 Subject: [PATCH 236/805] [Java] Upgrade to Gradle 8.1.1. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index e2e7ebf89c..bcf3f5d988 100644 --- a/build.gradle +++ b/build.gradle @@ -841,7 +841,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '8.1' + gradleVersion = '8.1.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a21c6ebe28..8707e8b506 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 224fc95dd2096274dde8d5582a097283383213b3 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 28 Apr 2023 15:52:25 +0100 Subject: [PATCH 237/805] [Java] Upgrade to JUnit 5.9.3. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bcf3f5d988..3188587a49 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' -def junitVersion = '5.9.2' +def junitVersion = '5.9.3' def jmhVersion = '1.36' def agronaVersion = '1.18.1' def agronaVersionRange = '[1.18.1,2.0[' // allow any release >= 1.18.1 and < 2.0.0 From 461204a39c4d958490afc0ec09e9db41133e78f0 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 1 May 2023 15:24:32 +0200 Subject: [PATCH 238/805] [Java] Add `@SuppressWarnings("this-escape")` to fix the JDK 21-ea build. --- .../src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index f205802aae..ac175bb37b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -69,6 +69,7 @@ public EncodedDataType(final Node node) * @param givenName for this node. * @param referencedName of the type when created from a ref in a composite. */ + @SuppressWarnings("this-escape") public EncodedDataType(final Node node, final String givenName, final String referencedName) { super(node, givenName, referencedName); From b8a0247d2025983c031cc460600b1f7070442068 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 17 May 2023 09:40:15 +0200 Subject: [PATCH 239/805] [Rust] Add derive Copy Clone traits for decoders --- .../uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 2 +- .../sbe/generation/rust/MessageCoderDef.java | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 419f155e48..90078b796e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -149,7 +149,7 @@ static void generateEitherEnum(final Writer writer) throws IOException static void generateReadBuf(final Appendable writer, final ByteOrder byteOrder) throws IOException { - indent(writer, 0, "#[derive(Debug, Default)]\n"); + indent(writer, 0, "#[derive(Clone, Copy, Debug, Default)]\n"); indent(writer, 0, "pub struct %s<%s> {\n", READ_BUF_TYPE, BUF_LIFETIME); RustUtil.indent(writer, 1, "data: &%s [u8],\n", BUF_LIFETIME); indent(writer, 0, "}\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index d61f888f01..56b5e10cf2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -155,7 +155,15 @@ void appendMessageHeaderDecoderFn(final Appendable out) throws IOException void appendMessageStruct(final Appendable out, final String structName) throws IOException { - indent(out, 1, "#[derive(Debug, Default)]\n"); + if (this.codecType == Decoder) + { + indent(out, 1, "#[derive(Clone, Copy, Debug, Default)]\n"); + } + else + { + indent(out, 1, "#[derive(Debug, Default)]\n"); + } + indent(out, 1, "pub struct %s {\n", withLifetime(structName)); indent(out, 2, "buf: %s,\n", withLifetime(this.codecType.bufType())); indent(out, 2, "initial_offset: usize,\n"); From 0d4c36a475bebe657d30dba7f2606e63f32d0e0e Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 17 May 2023 10:13:43 +0200 Subject: [PATCH 240/805] [Rust] Fix clippy lint --- .../java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 419f155e48..2f92a0f611 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -131,7 +131,7 @@ static void generateSbeErrorEnum(final Writer writer) throws IOException indent(writer, 0, "impl core::fmt::Display for SbeErr {\n"); indent(writer, 1, "#[inline]\n"); indent(writer, 1, "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n"); - indent(writer, 2, "write!(f, \"{:?}\", self)\n"); + indent(writer, 2, "write!(f, \"{self:?}\")\n"); indent(writer, 1, "}\n"); indent(writer, 0, "}\n"); From d2ec8f8a225808a1392872473f6e5e85b828056e Mon Sep 17 00:00:00 2001 From: Philippe Serreault Date: Fri, 19 May 2023 15:44:42 +0200 Subject: [PATCH 241/805] CppGenerator: operator<< take messages as const-ref (#939) Following commit 1973c86f84b190d5b2507786e6445970c390ea62, using generated operator<< would require a mutable ref message. This is unnecessary and can be problematic. Ex: using wrappers such as fmt::streamed ( https://fmt.dev/latest/api.html#std-ostream-support ) --- .../java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 1aed7b0df4..482335b269 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -2564,7 +2564,7 @@ private void generateDisplay( new Formatter(sb).format("\n" + "template\n" + "friend std::basic_ostream & operator << (\n" + - " std::basic_ostream &builder, %1$s &_writer)\n" + + " std::basic_ostream &builder, const %1$s &_writer)\n" + "{\n" + " %1$s writer(\n" + " _writer.m_buffer,\n" + From 76696c21b24a89a7db99cb69c5c20a847055eb9e Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 8 Jun 2023 17:27:21 +0200 Subject: [PATCH 242/805] [Java] Upgrade to Agrona 1.18.2. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 3188587a49..792ef3856e 100644 --- a/build.gradle +++ b/build.gradle @@ -58,8 +58,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.9.3' def jmhVersion = '1.36' -def agronaVersion = '1.18.1' -def agronaVersionRange = '[1.18.1,2.0[' // allow any release >= 1.18.1 and < 2.0.0 +def agronaVersion = '1.18.2' +def agronaVersionRange = '[1.18.2,2.0[' // allow any release >= 1.18.2 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From bd602f949af8e9e4640c9c6a08d8aad0264051b8 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 8 Jun 2023 17:28:02 +0200 Subject: [PATCH 243/805] 1.28.3 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 5daec50998..ab461d1584 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.29.0-SNAPSHOT \ No newline at end of file +1.28.3 \ No newline at end of file From 7d7b2773d9308c58a08319f26943832da62aca22 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 8 Jun 2023 17:30:47 +0200 Subject: [PATCH 244/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index ab461d1584..5daec50998 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.28.3 \ No newline at end of file +1.29.0-SNAPSHOT \ No newline at end of file From 2f51c36b72fa5999aced0e10b7658ad544c8ac1f Mon Sep 17 00:00:00 2001 From: Eric Stokes Date: Thu, 15 Jun 2023 18:39:28 -0400 Subject: [PATCH 245/805] fix array syntax error --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 0514463237..bff76d43a0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -641,7 +641,7 @@ private static void generatePrimitiveArrayDecoder( if (fieldToken.version() > 0) { indent(sb, level + 1, "if self.acting_version < %d {\n", fieldToken.version()); - indent(sb, level + 2, "return [%s, %d];\n", encoding.applicableNullValue(), arrayLength); + indent(sb, level + 2, "return [%s; %d];\n", encoding.applicableNullValue(), arrayLength); indent(sb, level + 1, "}\n\n"); } From 83e4a3a090d5046d5705eb86fd9fcf4bf82dad1e Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 18 Jul 2023 21:58:33 +0200 Subject: [PATCH 246/805] [Java] Upgrade to versions 0.47.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 792ef3856e..bd4f38eeab 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '8.1.1' apply false - id 'com.github.ben-manes.versions' version '0.46.0' + id 'com.github.ben-manes.versions' version '0.47.0' } defaultTasks 'clean', 'build' From b0bfc35c168bfba3903f2e6de5ccf037bdc966d2 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 18 Jul 2023 21:59:19 +0200 Subject: [PATCH 247/805] [Java] Upgrade to Agrona 1.19.0. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index bd4f38eeab..8dba679bfd 100644 --- a/build.gradle +++ b/build.gradle @@ -58,8 +58,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.9.3' def jmhVersion = '1.36' -def agronaVersion = '1.18.2' -def agronaVersionRange = '[1.18.2,2.0[' // allow any release >= 1.18.2 and < 2.0.0 +def agronaVersion = '1.19.0' +def agronaVersionRange = '[1.19.0,2.0[' // allow any release >= 1.19.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 4454c853492051e30c09229bcd4f57c49c9c2906 Mon Sep 17 00:00:00 2001 From: ywhrh <115807920+ywhrh@users.noreply.github.com> Date: Wed, 19 Jul 2023 05:18:30 -0400 Subject: [PATCH 248/805] JsonPrinter remove trailing garbage after non-printable char (#950) --- .../sbe/json/JsonTokenListener.java | 23 +++++++++---- .../real_logic/sbe/json/JsonPrinterTest.java | 32 +++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java index 92a38128b7..f889af19a8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java @@ -336,12 +336,7 @@ private void appendEncodingAsString( if (size > 1 && encoding.primitiveType() == CHAR) { doubleQuote(); - - for (int i = 0; i < size; i++) - { - escape((char)buffer.getByte(index + (i * elementSize))); - } - + escapePrintableChar(buffer, index, size, elementSize); doubleQuote(); } else @@ -369,6 +364,22 @@ private void appendEncodingAsString( } } + private void escapePrintableChar(final DirectBuffer buffer, final int index, final int size, final int elementSize) + { + for (int i = 0; i < size; i++) + { + final byte c = buffer.getByte(index + (i * elementSize)); + if (c > 0) + { + escape((char)c); + } + else + { + break; + } + } + } + private void backup() { final int newLength = output.length() - 2; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java index dc4bd822f0..40c59916e7 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java @@ -15,6 +15,7 @@ */ package uk.co.real_logic.sbe.json; +import baseline.CarEncoder; import baseline.CredentialsEncoder; import baseline.MessageHeaderEncoder; import org.agrona.concurrent.UnsafeBuffer; @@ -155,6 +156,37 @@ public void exampleVarData() throws Exception result); } + @Test + public void removeTrailingGarbage() throws Exception + { + final ByteBuffer encodedSchemaBuffer = ByteBuffer.allocate(SCHEMA_BUFFER_CAPACITY); + encodeSchema(encodedSchemaBuffer); + + final ByteBuffer encodedMsgBuffer = ByteBuffer.allocate(MSG_BUFFER_CAPACITY); + final UnsafeBuffer buffer = new UnsafeBuffer(encodedMsgBuffer); + final CarEncoder encoder = new CarEncoder(); + encoder.wrapAndApplyHeader(buffer, 0, new MessageHeaderEncoder()); + encoder.vehicleCode("vc\0ノ�"); + encodedMsgBuffer.position(encoder.encodedLength()); + encodedSchemaBuffer.flip(); + final Ir ir = decodeIr(encodedSchemaBuffer); + + final JsonPrinter printer = new JsonPrinter(ir); + final String result = printer.print(encodedMsgBuffer); + assertEquals("{\n" + " \"serialNumber\": 0,\n" + + " \"modelYear\": 0,\n" + + " \"available\": \"F\",\n" + " \"code\": \"null\",\n" + " \"someNumbers\": [0, 0, 0, 0, 0],\n" + + " \"vehicleCode\": \"vc\",\n" + //trailing garbage removed + " \"extras\": { \"sunRoof\": false, \"sportsPack\": false, \"cruiseControl\": false },\n" + + " \"engine\": \n" + " {\n" + " \"capacity\": 0,\n" + " \"numCylinders\": 0,\n" + + " \"maxRpm\": 9000,\n" + " \"manufacturerCode\": \"\",\n" + + " \"fuel\": \"Petrol\"\n" + " },\n" + " \"uuid\": [0, 0],\n" + " \"cupHolderCount\": 0,\n" + + " \"fuelFigures\": [],\n" + " \"performanceFigures\": [],\n" + " \"manufacturer\": \"\",\n" + + " \"model\": \"\",\n" + " \"activationCode\": \"\"\n" + "}", + result); + } + + private static void encodeSchema(final ByteBuffer buffer) throws Exception { final Path path = Paths.get("src/test/resources/json-printer-test-schema.xml"); From 09499a01556d68ee740e6c44677d80b09d9c7d7a Mon Sep 17 00:00:00 2001 From: jordy25519 Date: Thu, 20 Jul 2023 04:45:38 +1200 Subject: [PATCH 249/805] improve rust performance (#944) * rust specialize get_u8_at & put_u8_at improve performance use copy_from_slice instead of split_at when r/w u8 array * remove pointless comment * get_bytes_at crate scoped * fix java style lints --- .../sbe/generation/rust/LibRsDef.java | 23 ++++++++++++++----- .../sbe/generation/rust/RustGenerator.java | 15 ++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 349bc79c97..3d38b28aa2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -175,14 +175,21 @@ static void generateReadBuf(final Appendable writer, final ByteOrder byteOrder) indent(writer, 1, "}\n\n"); indent(writer, 1, "#[inline]\n"); - indent(writer, 1, "fn get_bytes_at(slice: &[u8], index: usize) -> [u8; COUNT] {\n"); - indent(writer, 2, "Self::get_bytes(slice.split_at(index).1.split_at(COUNT).0)\n"); + indent(writer, 1, "pub(crate) fn get_bytes_at(slice: &[u8], index: usize) -> [u8; N] {\n"); + indent(writer, 2, "slice[index..index+N].try_into().expect(\"slice with incorrect length\")\n"); indent(writer, 1, "}\n"); final LinkedHashSet uniquePrimitiveTypes = new LinkedHashSet<>(TYPE_NAME_BY_PRIMITIVE_TYPE_MAP.values()); final String endianness = byteOrder == LITTLE_ENDIAN ? "le" : "be"; + uniquePrimitiveTypes.remove("u8"); + indent(writer, 0, "\n"); + indent(writer, 1, "#[inline]\n"); + indent(writer, 1, "pub fn get_u8_at(&self, index: usize) -> u8 {\n"); + indent(writer, 2, "self.data[index]\n"); + indent(writer, 1, "}\n"); + for (final String primitiveType : uniquePrimitiveTypes) { // get__at @@ -197,7 +204,7 @@ static void generateReadBuf(final Appendable writer, final ByteOrder byteOrder) indent(writer, 0, "\n"); indent(writer, 1, "#[inline]\n"); indent(writer, 1, "pub fn get_slice_at(&self, index: usize, len: usize) -> &[u8] {\n"); - indent(writer, 2, "self.data.split_at(index).1.split_at(len).0\n"); + indent(writer, 2, "&self.data[index..index+len]\n"); indent(writer, 1, "}\n\n"); writer.append("}\n"); @@ -219,9 +226,7 @@ static void generateWriteBuf(final Writer writer, final ByteOrder byteOrder) thr indent(writer, 1, "#[inline]\n"); indent(writer, 1, "pub fn put_bytes_at(&mut self, index: usize, bytes: [u8; COUNT]) -> usize {\n"); - indent(writer, 2, "for (i, byte) in bytes.iter().enumerate() {\n"); - indent(writer, 3, "self.data[index + i] = *byte;\n"); - indent(writer, 2, "}\n"); + indent(writer, 2, "self.data[index..index + COUNT].copy_from_slice(&bytes);\n"); indent(writer, 2, "COUNT\n"); indent(writer, 1, "}\n\n"); @@ -229,6 +234,12 @@ static void generateWriteBuf(final Writer writer, final ByteOrder byteOrder) thr = new LinkedHashSet<>(TYPE_NAME_BY_PRIMITIVE_TYPE_MAP.values()); final String endianness = byteOrder == LITTLE_ENDIAN ? "le" : "be"; + uniquePrimitiveTypes.remove("u8"); + indent(writer, 1, "#[inline]\n"); + indent(writer, 1, "pub fn put_u8_at(&mut self, index: usize, value: u8) {\n"); + indent(writer, 2, "self.data[index] = value;\n"); + indent(writer, 1, "}\n\n"); + for (final String primitiveType : uniquePrimitiveTypes) { // put__at diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index bff76d43a0..25e200a268 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -376,6 +376,13 @@ private static void generatePrimitiveEncoder( indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); indent(sb, level + 1, "let buf = self.get_buf_mut();\n"); + if (rustPrimitiveType.equals("u8")) + { + indent(sb, level + 1, "buf.put_bytes_at(offset, value);\n"); + indent(sb, level, "}\n\n"); + return; + } + for (int i = 0; i < arrayLength; i++) { if (i == 0) @@ -646,6 +653,14 @@ private static void generatePrimitiveArrayDecoder( } indent(sb, level + 1, "let buf = self.get_buf();\n"); + if (rustPrimitiveType.equals("u8")) + { + indent(sb, level + 1, "ReadBuf::get_bytes_at(buf.data, self.%s)\n", + getBufOffset(typeToken)); + indent(sb, level, "}\n\n"); + return; + } + indent(sb, level + 1, "[\n"); for (int i = 0; i < arrayLength; i++) { From 85f46058399a5b5f08a88ed632944af0894d9a47 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 21 Jul 2023 16:39:42 +0200 Subject: [PATCH 250/805] 1.29.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 5daec50998..72f3c1dacc 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.29.0-SNAPSHOT \ No newline at end of file +1.29.0 \ No newline at end of file From 8680408574722b1934cb32b0bdf36dc1efbb5c5a Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 21 Jul 2023 17:14:22 +0200 Subject: [PATCH 251/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 72f3c1dacc..f407f84d1d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.29.0 \ No newline at end of file +1.30.0-SNAPSHOT \ No newline at end of file From abd25b49ed42eae44f90832f8611f2aa97a7246a Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:38:39 +0200 Subject: [PATCH 252/805] [Java] Upgrade to JUnit 5.10.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8dba679bfd..c19f043865 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' -def junitVersion = '5.9.3' +def junitVersion = '5.10.0' def jmhVersion = '1.36' def agronaVersion = '1.19.0' def agronaVersionRange = '[1.19.0,2.0[' // allow any release >= 1.19.0 and < 2.0.0 From 7503aed720de09c894394aed06f3c2c32f497c10 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:35:52 +0200 Subject: [PATCH 253/805] [Java] Upgrade to Gradle 8.2.1. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 62076 -> 63375 bytes gradle/wrapper/gradle-wrapper.properties | 3 ++- gradlew | 5 ++++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index c19f043865..c712f1a35b 100644 --- a/build.gradle +++ b/build.gradle @@ -841,7 +841,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '8.1.1' + gradleVersion = '8.2.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c1962a79e29d3e0ab67b14947c167a862655af9b..033e24c4cdf41af1ab109bc7f253b2b887023340 100644 GIT binary patch delta 16170 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 delta 14892 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8707e8b506..c747538fb3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index aeb74cbb43..fcb6fca147 100755 --- a/gradlew +++ b/gradlew @@ -130,10 +130,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. From 18c0862d97abe4426a96245993bde078670df985 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:50:38 +0200 Subject: [PATCH 254/805] [Java] Fix Gradle 8.2.1 Junit warning. --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index c712f1a35b..c4e255f11c 100644 --- a/build.gradle +++ b/build.gradle @@ -250,6 +250,7 @@ project(':sbe-tool') { testImplementation "org.mockito:mockito-core:${mockitoVersion}" testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } def generatedDir = 'build/generated-src' From 9f0c43abe91150cd90ab8bea024a19e1bf465d47 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 3 Aug 2023 21:12:23 +0200 Subject: [PATCH 255/805] Revert "[Java] Fix Gradle 8.2.1 Junit warning." This reverts commit 18c0862d97abe4426a96245993bde078670df985. --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index c4e255f11c..c712f1a35b 100644 --- a/build.gradle +++ b/build.gradle @@ -250,7 +250,6 @@ project(':sbe-tool') { testImplementation "org.mockito:mockito-core:${mockitoVersion}" testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" - testRuntimeOnly("org.junit.platform:junit-platform-launcher") } def generatedDir = 'build/generated-src' From 384e0219322ed6bc44184705d5a9f759efd1038d Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 3 Aug 2023 21:12:23 +0200 Subject: [PATCH 256/805] Revert "[Java] Upgrade to Gradle 8.2.1." This reverts commit 7503aed720de09c894394aed06f3c2c32f497c10. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 63375 -> 62076 bytes gradle/wrapper/gradle-wrapper.properties | 3 +-- gradlew | 5 +---- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index c712f1a35b..c19f043865 100644 --- a/build.gradle +++ b/build.gradle @@ -841,7 +841,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '8.2.1' + gradleVersion = '8.1.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 033e24c4cdf41af1ab109bc7f253b2b887023340..c1962a79e29d3e0ab67b14947c167a862655af9b 100644 GIT binary patch delta 14892 zcmZ9z1yJQo8#Rc#yE_c-?(Q(S!{F}j7k6iHcbDPfHu&J~?p)lRft~-Y-P-*&ovJ=b zPCcEZ(n&v^a}uv1KMo-qHSCbPyRfYTA;G}#V8Fm=QcdiL0D3mg>h?Cy%x3l`Zf@Zk z3SJA+Sf4aal*3xyaB2f3RRkn*SV?+h;Z&T^;?_1w-kD)ErLoZ*yb=~;X(Oel*}4?iD#$8Yf!k8VzF5ri5)v$q$PmQzX#Mo_b>H9f*}wI2bh=zdc02i z;^4S!nnA%cfQQqR@Co07R@RcgmP`h7cPDz8z?<;!8ogf2z0PnSL>@*)EN9FgD7y@s z^W_ap{$|BPvj8b+wJA2d1I!7ej#qC9)(e&~Sw?Q#a|)ln6^VJ?vi5;Ni+ououb+G^ zbm|dvYPlMrwgWuk=$t>1Ao1yvB?XbREP9B>-xvpj0Y61>sF)?`*NhIiIs+}cAHqbA z#70YORkWhxs)3kJHE`d?Kk|%P`D&hpDy-YSd=k`&l|TIr>W@?Z zL7A=7dW%+}=x=8RUBgWhY%o=)t?9h8a`vU_2*AxQzi`Q2Y&Xrknv0Mr<8iwXf)>)3 z<**xfFVfQ9Sj^S9l~kQrqzQej1}+|6<=p28(#4VzP*g|RLouQ|xL>)e?aY5C>-_7U9h9=6~`#trpq4ttaDv%2@Bl~{dtJGpZ!6iID=J3 z37~>*=BRr#3KFW2AQdid5m84OEL(CEP>E7qhjqrN;Lp%DwroXr!VM6>`@|fHNuBr` z{t>g6<~8>PalEtbbZBC(`aFly>9EhKigz9(ES}BLoM_Q|0o6Y{>SY{Aqqc4{Zr5*X zI`0OfN6X1}#y5Q7{PX6LhG+)g-ed;_2H^Dz0Bd=reHdru2l_+HFbl$Q#)))JFfVY0 z2mR(+8#b?wl@n0{x}?#FCITWSS^Ug%A)%Hfx4n<~VD+7|HDFIv$_ejs2eU?=a*N{T zbIheH;rgJ*?Y3!+jzB+&$C0PmaqFD$%TezQvT3GYTt)iTq zKjmqowDPDslv)ivU4X%#$N@K1ECF-hDp-2mrNhn?-^)4v+I>70b9f3qV+6V*@Ditv zb?`iIy7gXnom^~L%>eu%cA5N(D5IbCW+T{4M#9HV&8H(>#QsQilZqi^42@e5YqO&F zQ{n_Ho;R!ioIe(8K6g+`BsTc^Pq`94ZV7ENxc#v* zh8_@c;!6i4@7cb=K{P<|HTI$9Ix`Hlv{(c9KJ?5ivi$Cko0J%$i}krLp%;KdU&p4i z4Z0o?`Er31_N$*JS@>}w5(i-p%jdZe%tXWI4*>I$5;@K6-V~>|_&3QZ_v-F}*>vV@ z?v=^f!M_*r9pa9@de-xk@={dBQ9U5bsC2`~lsBm>jlTqW7o4HJsRrh87~-$faUFnl zja&?aygao`O(WNP8hDL`4V}xQh?C@#qwMHi2k(g~9LtKU^w(;q4wPS@!c-<6`?Hjc z0dpgIuOY91h3z8zosxE7X~rhZ@F7z_duOVZ4j2Jw!~^n@*Rc>X4@S9gqE8nIv&ICO z6hBj9OjKkV?_smM&Sbj}nbBGYD<6<}s)JfM!ZTHpPA2#RRJ&)X?e{) zsaJ?h!r5?}%q*t+iG5!WDiRlaNNO@wUF%HX<#?EP$b`BL4+#U|b$((L+gKw-^%k+o zemdq-`Ne!PEp&>Tu>;}L@i#@uIGVw!OYF&BWThXI93thPv}67vGrbVAeTc~dFi1e( z4(1{k?mCs^4QQ+&_(a{#rT{eCZE$nAc-IacUt9?my^(i_4~kBH&Y1LT@2F^H!=e-q zkj+wipZG3pNGbPh1LSa8G3Fi!1Z%%RO#cm>xaTldF4rrw)c~ZsNNkAZi%!mJ z&dOE#v(cX2Uu+cMjFxKjdHWL02{j_*or_hD6i*MyP^80napiFY|9~zp%j4gPXb(R^SuO z15FztfoYjWtwwZasY41y?<|FinhI;cFDDhf;L9mx-&rtGtk{ioh|zetBQM%YyCxZ3X>aQex*ifMvglV(FS&z3q(GUXhLL$HS;V=k%cV` z(NT{50gFjSd8OANbvr}{XhW^)u4KXjKcnVr##Sp{*rPks)5Zr-yOdJB)9Ccp_GfZUcyN0U9hImp{JVS8Yx8f6Q|Ck7G~m?W5yAoAnzr8^t` zK~AvPGzZzue5g$|Da;?}^wSfkZz<&+xLJ6|9&lf=4s9UgqgZWtLm#<`a`8efYc$jR zk)y(I`f4D>OSsCPZDpHHmWxo4S0$}*%ufBWWS$m>!_5GQS>zU4+SFi*q|#5)$UU6c z#Y35zp4!y0lO|O>Ap1rDUm$Be8%_poL5B6W5kcpwZM7FG~axmn>+LqRc_JB{A zHgs|13VDKZ+eT3WG44un=ElhbCE9E9>P@^g8!YC(!<1M?q~$D6zrp^uD@QhJylr8C zfd$clfsy~~$|V1ua3ny-SMQ{&6AceJJ{fBiE4{)K9ECB2Dh39edA}kAj7B#V&sd*1 z&Ge>;OC6%4X3f%aUH#Jha+$RSg!C|TaZBC)ypsO=Q}4=??#}0%k;9wF$@W?b+x+v} zd&|dU$BF-mz{y5N>dX3dfnRb|`rXW3RaoFjQ6lJ>WO9U!H5w3%J$;{)LrmfulLvia z>IE(|7K5h|evc??mKYggKxU~2F4P~6fD0c5>2=4+h80^RY0?lW@6)L>i8iPxR;Y2L zyT53k7Jx8wJ1ZzWHt61CZKnIARXVZu+l16GF@y+@Ee1l;`AHjiTRDPF5qBlKZNcD-0iG71$bXvso z%9wU8XfRVVRI~)qq_+nXKJ%nPDWD-N8sP`6=!Rymtc77w2G;i8p753S8k!dptzhL%(zsZfS9Q0-QPTKe$e+eS5>+3` zqgc&^Y9jSD4Ziw2M;GVB0YB{RKcy`ZgVN1(rGHGN<7__l%tR9-CtH$*_EaRVcd+7- zq~mpJneYG{$Ykt3;OkvZN}ELN1D1{7c__h@&rerZ=Q_&F-j9##MeVF$XV*Q?x*pe) zNJwgtGv|!G8}q9g=`a$qd{;MXBljc5Ggz5)Ha45eE9(6GWZa(9r|aW4y7V`41pGSN z+S*!MT41ts_yv|>GTWELn%gt03V&6Um37$p6?y>dI7BUmG@7ew+zhqd$QpZWgkGHC z7&tm4lKaK_Z{!@3LB^NH8rP`!Eq=vsqfzK}4yifDa{ZkWq}*u8nGW2=zl^CSH3Zq^ zZq5vz{d4o3-CXQRj|W%5i}A76^DOD89bqI|F5lpi?jZa78y!bVjCUt5wlq_@c=6|h z1Y!UK5gp$!ww8#AxG7vPiyIIkLM$nMz^VzRz>8siW%N?$*w^`Py5Zxnl5Dvrh}<+vFZv>ZLEKZM61 znA=^jf_H6OdpUq?II^raf|U3x8OOcE)sX;9GJh!Pbl0bNDr}8{^G`*6ud7v?hpfj` z@`2@WaP{kraJM_|a2CxM_HY&}TM@S4@2geyne(CmMXFr5VR$X{)_{kZ(LQ)vxkjI( z0`>3ga3t>&+CLB7m_t0sc%w9Ueua$2ozr5<+Wwv*l25*z8+B|EGOT+V?w55?U^NHG zZZY@*exrfWu@Yii6z@c3^*081sXpmKx!rFIn@QU5JG-P<+O2XHn+SzL-e#g3a#*jX zA-MEV3bT?`i*C0{qoMqX>_X}{55{MERLMan;f!Q=WPeK~+YVaHVx&<@ZYK+7gf|Ro zSj)0+E8>knKQTriVvovC*+!9k^TY>~=k2LaLe7wL1lq{=O}F!5@D%w-kdAm7vF6I# ztU4fDInuKQ^ns!yXh02hMtclcy=r^k>HO0Mv>E)B5cozpokC2;ztMjkGKw1iSY3R! zyd}b2`8nVl@5{K#Glx0uMiAJP5{Bsgre?>R*r;dcO%~E>8A-yC&SHo1Jhl&LsbrLK zm{=;pLM15opj~&<9n)R)#TJ#Dfdgt80PvpGq2)GZ@yB2ELOD03@a$JT0x7brT~( zAnYt*w8|r>_G6GF+aBl@EiH1B4E1w1gU0GD=*7lPV#jmKa^qySDD%0+jdu68!kHV)wu* zR6Hl-u7WhPx~aEPw_+yIu4Yd({{qvix|hTG$+=T|%j91(Qn0s?S$+bbJt5ecZnOE& zeN#CQ7`jmYBqErj8=3`ay~Rnl&9xA0DYIJq#TrEvE|P;C{P2kvR`9ZR=h-Tp1G>Wr zbD3vTa#2z|Be>c6g}NH*BH?vEk_k#t{|%_34w#d{W!h-2VT_g%G;8UOzG=+KZ3sz!eQ~ygG=)) zT%Q=Evo8}L*zv#VBmTU?#}^z{aDEbyYP{IQ7wk3IeK781b7sj#=2aD%-BE`>T+f+( z7RoNpy+qkOtiYW`Vkuh-jz@9{56rM7510{%%s9v4hIyU<#H*zNhstr;Bi^i3W}Q@W z_@ZB;oa`4XFH*wv5gBOVpWwv&rw#Wx%Xy#dzwVI_=k|0ub}w^AC9>G+Z`;C70`!qs z5V46cf!aei^f0+EDBUhGMDe8=maT|fh+!Pu6>YK+AC^NR#WH3QKW0mR%r(qODR|Al zaD6f_d@|W}^6LozmS6o$#hV_twsJn$58i?5y&@qr+YOOL51Dh3F#QG7XCbmp)o(7N zzmTq}q^VvZ=3= z@!L11xFzPe*9n}Fvm?L}zIy!5K>>xpk*sf>oq7*wO#Ntx8nmq9f&fGSFa6%2Zvt_S zOU>abG@r6(XZ4$EIm{8IdSVOCf~MIS#@ABWdcqZucU5F^*vD=vqFBl@UYox*F&T2?sE_)xkp3FI&R!yngE?oVegg-Dzp zd*Mm7WYf`qE)6MMpIz0c4i4P#`4a`o)=pOv=EqOD|BMGT$z*^`i9^K^V_h3lQ(xB9 zy(9tZ4$L|f@Z~}_11xufY=g~Rh(k)!=b7Q(u9L0`Wx$(rTX}7wA2=q2x@$!6!fVTZQBG?g>`Xy$nKNu-=yKs( zHygJ-npfA8B>GB}f$Rdk$MO4WW-x>}`cP#J3s!XWbL%S7!Pyz6Z^v4l#$TupA~66b zI)J&BZ`gBqu|7quLQV*y^oA{)NyNpu>+H5C}aRx7EQVnp{ z>8+Pm9_4cT;D7k?RCK)*=tgW{s!x`A*yeVsEkGlAq{E*9jLPf2YTb;vCewwCF_;!?~_F zj#y&cdU^jL2UCO(gkM5O(z0tH03ea6YX1I$GBs{O_YkImG*gjabqd1W{)C2+G!}EzMTwUoOezvH| zmI(3@ll&>VK#pt){tAp0ngH*msdJfCLo$T6Yi9y#Yrf|SYme=lZr~&!>2vm9*p)FN zJbnQ4*8z+k;+9`fXAcJKmYBK7m+k7rdv40#>VJ`~sF{v=kau#N2 zMp{qNK||@X8HyW2t*))ItW+;M#nwi?x{R(Wy}VSI|r79A-N{?=nPMZu*9baTTuQUH5DMjq?K&GXOOJ`PG3SY)+^Px zY5C=H`qRe^QP%ssvTmNlRfncZewGfN-$Nl>W!vVo638r!nlK;xy8QFRQvaQm_*dOC zQT*QFeF~mB-aT&05RqRI{B7ipTYKoaL0Y7ZSP0H?#~*9eYdoea=)ERY`sd9enjIUlGcW5Zlz$g@9=&rYg6zpL6%NdGuNe8Gd)#SceU? z4;}utA=4nk{DNmPL+8wNYS5%#rE^^Rv#)mC{CG(jG{^n(IRk<`;!#`UzgKJ?S1#b> zZ>h-y@N3%7CLs);0YS{sliIipTBdSaX-RmAjRPPeR)Z3^6Ipke(1@i0Ay$F$G# zT!I#60qDdPsMhf>cmCGzkit@dOkVA{fy(aW4}s|ZO0Zg_QzhW$Ddg4S@w)N?$!VVC zz5t1vXOpvtver4c%fi^ba8=`BYo083>S0y8rvczIISNbJw^MfS^P>lcH!RR~ML{8Z zPvZDPTi+Wr{XDEYSAgtFQ0iX;u@x64!UoEq!O!jI;#?i93&=)X-9F6dv@? z19vPwE$Ab}Q^KfBe`kzxC(~nakuH#aAwUPLJ_2Mhi9r6x3k|WM?~ib)o-a0o)Qjdk zB^yu(gJXj7z8(Dapz9C})xN;PMJOP#7Zn-%R?RnWI|vZN%BKu{K&Dx#5-sk4K&%Z? z3g1=(IfQQ~XSqeKM$3}Q&?<%xW1Kh7yRbGK4oQ%cM8@gnm^=Lvx0A+t>*vML0Jtzi zy_2f2#z~AOmL#JmR=)%^6Qx(nxi zQ-6jmd?Z_ZN8|Mgvn+~wQ?=JFnJxEAi_jpjlP&uN^F~KRg<7FKKV$BT>o1}Ey97eV zQ(C@YBKSf0@84Th9}prj`wO}YVd>=hl$7;cy!aK`azMsW?(_|(O8a3?mf}nH z3yLH>f`QJ7=#Y3m9$oY|78@E#0f00~47qn@b@_an z(;cKui-(z}*W5^|N3n4)6%UbOn40r}W2dAx#sa!ue%S(4HC?H-tz$>|_F_-vP{|Vk zV-|Vp^(=CAhOPlNwwF&vTD9^r{UdRr4Sfappztne-z{P7LhaiQ$R1mZ!nRezaIq>B zqVfsU@@z1MY@I07apAC0#48=~}&cWqTPT5bE`GNbS%`Z*cQUYku zPN}rkg5{gn8e>Zd_B-mNLAw>--*1*zrfHwCpBvovOuZBoWs)`#n;7k^B~vbQPSksX zZ=`&mEc969(0qFXFOdogw=nGp%p#~eHNi#wb|fArU*P}d$AIJ+XPC$*HoRg>_+Vh? zTwq{i|E9)pfXp>J$bc15+m3llUbGa1c1o(1bm$a=l*h)j%}q#L-HeA`PO_0rie>XN z^7E!Uog3FnNi1#~?lhHe=%$PShU+TZz}-E&Vh0-qjyY7oV*vWtqEgjHtYf z&R)rcO7l?{D7|sau1cCoFTwqL3Jea1+#Fxw_$E+OYk;GMvVfWRq)$AbaR!o-?z{0n zqxwdVct@lv0{$eI8m=XV326#86nQWtTCgdbEo}y(s&q2Il5W|GuawhgF z%Ji*EX70)PA`B>&**su(cYthaT}(esCqL)|rc855MSqY;J3jJ7+L+c&{F=NpDi3{? z^BYs&-&W{!BjqEW5TwrUQL&Laf>UB{ASj|cYU;zI`2h%@;SyJ$V3_4Yu6b59tE-Uo z+K~wtUICgLlThWUp1U%;{U}LH2Ne{mqby8L4|3MHg?&f?BW+Mx18 z_IuqP#vyk-i0aCKHvCi=m(3E)#bAX?QbuPZ)-118iSkti^dJh5Nzim59G5EAIdlJb zY*m`6JAirkmu-@-HLT@zDcWVRkUL#KCbN3>B{Y`^*ejBd0!b}zXnsk<0kWQ)&AV2a zl$KL^>yeWCg^H6Y;y2!|nID|rIx|` zq#Ak}>5JzddM76ISG7dtu6_tc3{B-45akfcc(1IQ!D=2AI&GF=IE$SDS0;KoH4|pZ z-*F6=}ZX zP6B-3OXG{vDxgF3`Zn)AYj&fx7j#vweLGQVyv+W_>i`KE9K*7njhB>IZ>QXO0^kx{ zV%a?fkOVTg87TRG`LYG*cgTSK+O>E?LGr}Uz2ftgk_!2z2If8B$>W1bYpvrJ)r&}v zVzGKu8gFW5h<_Je%EaWR6;1t{2SI?3BN9-i9rqgW7ECN{1jV-YWN>8N@(#*vRUEEs z_CIp}wMNgG_VoU12?;GXnV^>6RTO>~hSH;z-wGl_l2mHP5Yz+N{uggx-)LRZYaZv# zo1WHp4|iq`6?=U~iSB6gr*>|QznFUUC}o{)Mdz2X90t$>&o?d5{LhtBNE}qB#}NPy z*{W5Gq}aE-wOS&Kz@LR_PysU3$c4L+z+p8vKV2(nz1d<11cY4_K7|9IuKS@wU59e) ze78&T$xe1i8JLtFeffouxJynw$xjV&M+tHD9aORVVg=$-6B20~Cj7oGus_gn`Viap z)BJboiUVY?sZ|;CZF5X>h30C0D-GbtCWUZ%J%w&Z?^op!FP)h$Ls6V%B%@JekO8?} z^=y8RlqXP;S0=nVz&j8p^Nq+m0FC4pjrEh&L1F}n%&Oc?Ut4~g`7O<%n^~ZAN^JeL z1;K`*A`&gX6}%ch`46Snl;>HyKD1zQPK+Lkn%#tn?YShg(axEUrjF>3r$qq2mGyH{ zgPLNi$x>XG%$Mq(8^0ye0^hqd0P(Q(nzCe>nnid8J!)~zlA##qbVPH%+IK&&nyz%N z8e?Uj0cBpA0nEX5Tj5pMsz1bJy?glNXFZ>Oy~}OyT!wkc{9j{72)sJYBGWQoJ=^uT zfv`e29xPVysxGuKKZIOgm`#8;GnNVrHly^D0SeyYz7I`4a^JIF6aa<&nEP-t@GvSC zeJL`DR5+;j9Lz%X(x=a#eDPUe$OpDkxnyU7v@kyqDoq3;%5fcT9WYSY_et}{@slyo zoA__|C&I9DAp^+i!Rw|MXYHI+=e#eU;k4iZP)ISNBl|`R*QIgzk^xZulD_Z`1u12B z!W2RCm4WT>Plb#fQ}}d8H>YN?Y?rp#?+`*G4oEiK3AuDK?Ym>fPJ0L|=jA1gCxkXX zk~wT7Cf}>{Y=;&-6AK;kN}kxIN5194o`zVl*}SW!nv*q(9A#8gGd^O3eR2;4;KM&- zlihXQ6p)f3e4#}Jqybt78Km+Q7*W(^FI$Avw?830Yzv$6wj&bx8$EG)O8ogQ>)4;% z2!}C8Z@FLh>eSOLV}89D()PQqWc*4Fi;bwZ8uJ00UJ18Va$fAw?j7EU@pY%xmXfJZ z-*=FysHrYlxO9ujZDFRfppwe>{U@Yxg;E&!RQ5$a{88cmvIdZR(S+Y+!|uz3g=Fb> zgPzP`z93MWr+BL3&%*l1S1Xf-tPb`Q6Dd$OLv~WGeQJ_OBk&yc=uyHnepLicpa!=B zO+yecFEQk)sF1r}OND+f z_dl$LF@jH>w69IA0i0VDelSLec6+kgNDFE6x1X)mR-*-3T*689khQfgVDmog{^DJve6UL2 zpfOM8K1XHARbU6)dj|++GHrZ7u5GY<#snaz{vA-^eADde6mfEOf^mdG{Q$??z0&H7 z>0^A&bc#XnHNcMy62wo-NYEoi%Ze6`_Me`VldMrKuU$C3a|tXoK^ST=JzQIr?5=MI zRfoDio}6ZzbhefigF*-0^N3{YfZ5vRH-cC<7V>X$%NRLMkb3#mn>wkaYYqe7#kJra zJOJ3^88~|`0d_|moIAg4rK#_>E?mRA#_?mp1b=c*UHG`vV>30d**CDcJ5KY3Qn!$D^yrsscj?Ipds93(`n$^ooqcrMHbC}4R^e~s* z@oN(QQoH7L?Us<@fA<;5AuAsHN;m%VvjVWl7im3Xvc45R`D_`)+v=h;Q0E&N)huiR44j%A9>2%J}tu^aE0C(5GJfwlc7CUD&YSH z7og~Gb}dX085-HWxBJWK0p-HG0t>_EZht}|{2Xf9Z@B#>w%Uqh+E;te2iveDe;V*$ zlk&YnP&kyvS?JZ93vDB6P!=<<->x!xrnsd$q16@f(UnlpR0zewfivoad0RBYRY0&b zw0_{;SJ3G&z6w&B&f|ti82U{&A&Lig+=%V4}>fRsih>I9rCuC~c8#CLutITP?(|K!XI#F^&^Q!n$&r<`H5kgFIH)fL4j^lqC% zDGfR6vE!rJregSe;df&_J&+{%iWc~mBgo*mJ9b1{i%%Xc;%c4e?OV_<;$SPMPBhIj z9w%}hr!w(v>4jJSp}&aM%uX}1=Vf%!3gGj<8KM<@*f=R|0@AB7Zh>5z3Eth0X6V7hwjBSz*NeBs(mee4F;T#Wh^5{VBx(@>%50I0zG0< z?Ge8|>d9J53NBU6VQmrdsN539WKQv!lImkfwTJHRQQDJ5Fm7S$M2JT5NPZ2NxI&zs zz*Bpf@WJN0ZqZ2I`i#SM#VuhLecRH(5W}(aE|@lioo}*a-51G;R_>4cPf{Sx@DmyW zZg7S!&OddG3S6p6C4MT)G7-Q~eL)l}Vn*C%9RuX`iiM7~UMMN10vW#u*N5+v z`Evxr9+O7SVr1tqe0tSo1Q8Gv94+D- zgdlPskSuN>0xSo7wRqx$)7)kiXBT=(fb(KL36qRPG&o3SfpKH8nhBuK;SNz!=5_?6 zIIm_RO^eNeqR4wR99DxL+RTqAUO7Toe&FADR{k{uM3_!~&B{3gVMVY2|`3xZnLaGl<1%Q3Z?Hrn7U$R!j3_EeY zh@o7%phu}7pj;P>T#ij8&uffc$p&odBoLdA~JY!NX3VK1=>$E-Ts;5ku zZp6iCT`jln?22p}!Do05z|{8K^1^NNo*Hv^VwqX*5nUeKBDV4sC}(wiWC~Y#+_RM? zuetB9Ydz^p!4MA0rFFg$l0uh3&c%Y{B-A|3`ODJ469JpA?1LVh;oj9PtiR)y?!(}i>(!_)`nF|-6$ z=H)stA;(hDEeJTa80sT}5pO^^;1t$$DKPG3_zOib470JDYWm3yH_g9W8>;5cHXpHf zoiM=^m%95W6O1$;UHl7c-cX(b}i%B@^N z(48q?hEh9s_zHZTiK#`byC0sf%dIlYi%88e<3v>Zp&9_{e>M(=+&2@$X(x+KIu3r( zL4)T~2oMF;g8K29qxwP^-NdMb|JAjHmMy5V1CYA=A#sgl=LSjd{z>RK=8#-D0ir1+ zqmaz9LC|BaV(G7B;5g>ETphw>bf}WYAyB$WLd>HQ!m>%wKJnQ+0iq*%l~ED{~uvln@+CJ20R#8EjAb!?f*%+ zQ+L*I0Y1i9N7!FVO*v~wsm9z?XmFjTKP|k-V^q=5j^He~w1M!P#yQH|spjTD;PkYs zb=|O*9qOqZ(^G5RB96X2c~QAMYD`_v^?UF2dwI)s0LR6&BaFh=>TAMt?@rgw^JVIn z&w~pX!>toOOY-eJno)Tn0!xNVLkJlPZPE<_VB4oGPCNX@7QaE&8P}+$5C;}}vL773 zL7f#B);9WH__I4-B=TkV?}rbh`VQVej<-L@b$7Ux6Y`#epm1M7TjUK2$(@zKdwc8eqGw!Ul?mCN02fgw_ z1sxrjMi+_dg-{jciw)MsB?$u+X+?)E0BiSMbxovt=oZHDwd@me1&r^z00X+vPxEO$rzdR_YR9ymou&{zu)K*!1TTRG9EJbU-s*MS=o_hC%b+vx%ubY~WHvf~kvu^k( z5pmgY2w27`=qy|49b6uyb7#+OJnQHsOt(0BjVOgw7~8a(Se~jJWZER><~%m{0M;5o zc6#qr?vfMz1t`DV8uFQE*&q<@*=6K_9fs0c*K~>rpyeR$fzF7o$>#L6a$T5)Ev43t zG=)!cA%nhN1c`IC*7WVAx}!}uuJgEBlZK4OW^o0;3eyISSh1N>zW?cF&azuQEW}fo zSb~#)2xg93dj0}q05G{CmynJXFj{CK+fLRwiJr7{`PBbO1xw|GQ|nHrK^>!}LB?{R zZeCnwR{}9l)XeTqW@cLwklzf4uRHEyn8Ua(CjAZA5prqYkalZ>UyyvO>-yF1=(j|< zWnIB|gRwvN^-aOt&^t(R4S$QT>*^yZ#UL^(j>VzGX1%l^{d{?qd8)|+pfE&NsC!`U zP?CtGHsDM~-7K6Z3V$!{e>0~>w|Hr z{igU10dQ2imGX}!2pl{96kq11c{C-Kmu=^llHW~cQ=@5mnE#j`t(2RnwUK$~(a>Y4 zESJ~mq1+tN@W=mQV)LVH+C9IlY(ER6Jr_@c-2+l*>+iJ1Q@!N^_~(Vi`JQ=~q_1fD zL+)s}FgR-8GNo&b%vG#m()Ugg?Ui`q@qrCczxDc%7!lF@K(wN=2eDBW(^L2% z`B5|}?3|R!2v=0Zvq_M~;KGvgIkqp?Oo{*XN<6g;PH?wten{#-W9 z_rNmg^|2;7o{))iC!W*!4!BmsBbye}a}YO# zcX;ps;ANN!1ZbY1~hv1vdNMKW4PuVRTmoAo2vMh?jDvQ6SwCzL6R=1Fh;lLRni zs4|%^F2D`JQwD3*-i*q(TV9}bt1%$EKMRPL5fQ`9PFJmRp22%Fga2?QLjE=65@vRL zU>%pr9eHCc=mK$X`X`D#zMPIT*2Y^HRb7V_5T8!R=>CMm=T~Ry^b6=!1oT4pp=A$` z&6}d0KBf-&HMQ2YxYnh3!Q}B&JiXmylVr6Y`KwW;-Lm5#o43pIl~XI%Kg>R6mz;<^ zmAJxQ3^JgB3~>X5`Y1m+n0EMvvfr7#-;0o8#&xvJg%!t@Iiz>-ho5MuCCo*rsP@kw zpgrL;)Cp@k4t;#kdIWe&w0EYCH{u4)W(KQZI+CSMZLk$rT>)2`9YS9sU;g`vlg2uO zl>Ol-Nk2?i%8Zb&r6*P};1x6X`%i^Gv%KL9)>hOI`u|k24S4iaxBXVs0{XMJYHH39iKO+wUILxLBh*iwb~6HP zr-J@!ayCPucsqKI`V0+_1SPgC-2tpu z20?po6xi5Ery?X5|1|Q@5Tf@m%DwmCehnz%HKbl&khnib{k#VcnGMy6MLCJzSB{mSru-M7YIf>C&TK{asy8rb%F zI0J2{ddgkg_P%$+U07>uEGhXiF>IfuY*B?>PFp<)8O#cFMIu9gxRzhM_L}3WRT{(! zvT|tI;t12!ldM-%E8S>_&bSt*Tav&3U>3F(GdoBbt{YJLcz(+}1Y;VCwPqn}(iVHf z53|_BuBEQ;iZwYadD~U5D^_qs=rnYt?Nd6s5K`OA@DnPsV>+8ZJEPbe4*AOef=KN@ zBm%x3kRkp5OocQz^sxW8sW27%1Sj>?1r6z+7vaC9G#Jh)buJJ)mB^JS74`%zRpOQa z95ogEmOeG=mKDOx^WQ;|)F2<&)SX*2qW>&VP+(xI|I7@513LtG>3`6<67&CD5z+tri~66YM#}#Y z6(QF8{)=7u$PE!b_#a#uLrxjR`|p0xJP|MOB delta 16170 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c747538fb3..8707e8b506 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip networkTimeout=10000 -validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index fcb6fca147..aeb74cbb43 100755 --- a/gradlew +++ b/gradlew @@ -130,13 +130,10 @@ location of your Java installation." fi else JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." - fi fi # Increase the maximum file descriptors if we can. From 46071f77d633019e12f2aaf286a9e982f63a7170 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 9 Aug 2023 11:38:53 +0100 Subject: [PATCH 257/805] [Java] Upgrade to JMH 1.27. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c19f043865..3fa15b8065 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.0' -def jmhVersion = '1.36' +def jmhVersion = '1.37' def agronaVersion = '1.19.0' def agronaVersionRange = '[1.19.0,2.0[' // allow any release >= 1.19.0 and < 2.0.0 From 8f480b9a239a1ac4b9122055852322cdc69df29c Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 9 Aug 2023 18:00:39 +0200 Subject: [PATCH 258/805] [Java] Upgrade to Agrona 1.19.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3fa15b8065..6865c71331 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.0' def jmhVersion = '1.37' -def agronaVersion = '1.19.0' +def agronaVersion = '1.19.1' def agronaVersionRange = '[1.19.0,2.0[' // allow any release >= 1.19.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' From 0aeb59ee5c80f3b64268f62a747df08341ac9112 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:00:41 +0200 Subject: [PATCH 259/805] [Java] Upgrade to Agrona 1.19.2. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 6865c71331..c9a218bb34 100644 --- a/build.gradle +++ b/build.gradle @@ -58,8 +58,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.0' def jmhVersion = '1.37' -def agronaVersion = '1.19.1' -def agronaVersionRange = '[1.19.0,2.0[' // allow any release >= 1.19.0 and < 2.0.0 +def agronaVersion = '1.19.2' +def agronaVersionRange = '[1.19.2,2.0[' // allow any release >= 1.19.2 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 432ccfc3bf7f24c05f6a46adcd096e69c082b93c Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 7 Sep 2023 15:23:06 +0200 Subject: [PATCH 260/805] Upgrade to Versions plugin 0.48.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c9a218bb34..b0015d32af 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '8.1.1' apply false - id 'com.github.ben-manes.versions' version '0.47.0' + id 'com.github.ben-manes.versions' version '0.48.0' } defaultTasks 'clean', 'build' From 3f6b6297446a4a4d65d1460bd0d66c0d69500a3f Mon Sep 17 00:00:00 2001 From: ratcash Date: Thu, 14 Sep 2023 15:42:03 +0200 Subject: [PATCH 261/805] [Java] Expose actingVersion (#953) * [Java] Expose actingVersion * ir codec update --- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 5 +++++ .../uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java | 5 +++++ .../uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index d44bf668b8..e40a02c6a1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -2716,6 +2716,11 @@ private CharSequence generateDecoderFlyweightCode(final String className, final " final int decodedLength = encodedLength();\n" + " limit(currentLimit);\n\n" + " return decodedLength;\n" + + " }\n\n" + + + " public int actingVersion()\n" + + " {\n" + + " return actingVersion;\n" + " }\n\n"; return generateFlyweightCode(DECODER, className, token, methods, readOnlyBuffer); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index 2bdd4647fc..8cbdc11954 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -120,6 +120,11 @@ public int sbeDecodedLength() return decodedLength; } + public int actingVersion() + { + return actingVersion; + } + public int encodedLength() { return limit - offset; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index 244fb30ec1..8c7a7a1ee6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -120,6 +120,11 @@ public int sbeDecodedLength() return decodedLength; } + public int actingVersion() + { + return actingVersion; + } + public int encodedLength() { return limit - offset; From 0dcf92266164ecc1e8428a07feda8f4351d576f6 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 20 Sep 2023 12:46:13 +0200 Subject: [PATCH 262/805] [CI] Use JDK 21 GA and drop JDK 11. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e89e54c175..d6a6ef95ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '8', '11', '17', '21-ea' ] + java: [ '8', '17', '21' ] os: [ 'ubuntu-22.04', 'windows-latest' ] steps: - name: Checkout code From 510d3e8929ef72cb71b5258afdada16f6f08d486 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:03:01 +0200 Subject: [PATCH 263/805] [Java] Fix javadoc link for JDK 21 GA. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b0015d32af..2761b537e4 100644 --- a/build.gradle +++ b/build.gradle @@ -202,7 +202,7 @@ subprojects { options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' options.links("https://www.javadoc.io/doc/org.agrona/agrona/${agronaVersion}/") - if (buildJavaVersion >= 19) { // early access JavaDoc location is different + if (buildJavaVersion > 21) { // early access JavaDoc location is different options.links("https://download.java.net/java/early_access/jdk${buildJavaVersion}/docs/api/") } else if (buildJavaVersion >= 11) { From 0a05d9a0e39f5ff5ac43c6a9eb57f1dcac0b81c3 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 29 Sep 2023 13:41:58 +0100 Subject: [PATCH 264/805] [C++] Rely on NAN from limits rather than pulling in cmath. Issue #956. --- .../sbe/generation/cpp/CppGenerator.java | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 482335b269..debb990d27 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1051,18 +1051,6 @@ private static CharSequence generateFileHeader( "#ifndef _%1$s_%2$s_CXX_H_\n" + "#define _%1$s_%2$s_CXX_H_\n\n" + - "#if defined(SBE_HAVE_CMATH)\n" + - "/* cmath needed for std::numeric_limits::quiet_NaN() */\n" + - "# include \n" + - "# define SBE_FLOAT_NAN std::numeric_limits::quiet_NaN()\n" + - "# define SBE_DOUBLE_NAN std::numeric_limits::quiet_NaN()\n" + - "#else\n" + - "/* math.h needed for NAN */\n" + - "# include \n" + - "# define SBE_FLOAT_NAN NAN\n" + - "# define SBE_DOUBLE_NAN NAN\n" + - "#endif\n\n" + - "#if __cplusplus >= 201103L\n" + "# define SBE_CONSTEXPR constexpr\n" + "# define SBE_NOEXCEPT noexcept\n" + @@ -1083,9 +1071,9 @@ private static CharSequence generateFileHeader( "#endif\n\n" + "#include \n" + + "#include \n" + "#include \n" + "#include \n" + - "#include \n" + "#include \n" + "#include \n" + "#include \n" + @@ -1130,6 +1118,8 @@ private static CharSequence generateFileHeader( "# endif\n\n" + "#endif\n\n" + + "#define SBE_FLOAT_NAN std::numeric_limits::quiet_NaN()\n" + + "#define SBE_DOUBLE_NAN std::numeric_limits::quiet_NaN()\n" + "#define SBE_NULLVALUE_INT8 (std::numeric_limits::min)()\n" + "#define SBE_NULLVALUE_INT16 (std::numeric_limits::min)()\n" + "#define SBE_NULLVALUE_INT32 (std::numeric_limits::min)()\n" + @@ -1141,7 +1131,7 @@ private static CharSequence generateFileHeader( String.join("_", namespaces).toUpperCase(), className.toUpperCase())); - if (typesToInclude != null && typesToInclude.size() != 0) + if (typesToInclude != null && !typesToInclude.isEmpty()) { sb.append("\n"); for (final String incName : typesToInclude) From 1aef658c474e72f78f6a56e48e98fe978ff33fc9 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 29 Sep 2023 13:53:40 +0100 Subject: [PATCH 265/805] [C++] Replace trivial String.format. --- .../java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index debb990d27..6448ce3e05 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1136,7 +1136,7 @@ private static CharSequence generateFileHeader( sb.append("\n"); for (final String incName : typesToInclude) { - sb.append(String.format("#include \"%1$s.h\"\n", toUpperFirstChar(incName))); + sb.append("#include \"").append(toUpperFirstChar(incName)).append(".h\"\n"); } } From 1467df86d8d81ee3ffb5683b952b1eb3c2bf03a2 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 1 Oct 2023 22:27:28 +0200 Subject: [PATCH 266/805] [Java] Upgrade to ASM 9.6. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 2761b537e4..a40ad4d16f 100644 --- a/build.gradle +++ b/build.gradle @@ -24,8 +24,8 @@ buildscript { mavenCentral() } dependencies { - classpath 'org.ow2.asm:asm:9.5' - classpath 'org.ow2.asm:asm-commons:9.5' + classpath 'org.ow2.asm:asm:9.6' + classpath 'org.ow2.asm:asm-commons:9.6' } } From 186b9aac0699c4b7bfd24deeb5945e7aaea671aa Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:56:18 +0300 Subject: [PATCH 267/805] [Java] Upgrade to Versions 0.49.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a40ad4d16f..04b981c43f 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '8.1.1' apply false - id 'com.github.ben-manes.versions' version '0.48.0' + id 'com.github.ben-manes.versions' version '0.49.0' } defaultTasks 'clean', 'build' From 060031c86165fe291f8bee3b0daf56efe5a539bd Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 1 Nov 2023 16:36:42 +0000 Subject: [PATCH 268/805] [C++] Fix comment typo. --- .../java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 6448ce3e05..f52d4695eb 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -53,7 +53,7 @@ public class CppGenerator implements CodeGenerator private final boolean shouldDecodeUnknownEnumValues; /** - * Create a new Go language {@link CodeGenerator}. + * Create a new Cpp language {@link CodeGenerator}. * * @param ir for the messages and types. * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. From c0dae9ef7126da4a8fd756f2065283eb9a837dfa Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Wed, 1 Nov 2023 11:39:45 -0500 Subject: [PATCH 269/805] [Rust] update how "use declarations" are generated, now deriving Defaults for enums (#952) * Fixed several issues: #1: LibRsDef explicitly us crate:: to disambiguate from built in mods like bool #2: Added acting_version field to Composite structs to fix compilation errors when using Composite structs. This is an incomplete implementation because the parent doesn't pass the acting_version to the composite because you need to change the signature of wrap(parent, offset) to include the acting_version, so this version just ensures that if the acting_version isn't set on the composite, it disregards the version check. #3: fixed primitiveArrayDecoder to return an empty array of the right size if less than version required. * [Rust] removed 'acting_version' field from SubGroup decoder * [Rust] updated RustGenerator::generateEnum() to support derive "Default" instead of generating impl * fixed formatting issue * [Rust] updated how 'use declarations' are generated to prevent "ambiguous glob re-exports" warnings from rust compiler --------- Co-authored-by: Adam Krieg Co-authored-by: Michael Ward --- rust/Cargo.toml | 2 +- rust/benches/car_benchmark.rs | 1 + rust/benches/md_benchmark.rs | 1 + rust/tests/baseline_test.rs | 1 + rust/tests/big_endian_test.rs | 1 + rust/tests/extension_test.rs | 1 + rust/tests/issue_895_test.rs | 14 ++-- .../sbe/generation/rust/LibRsDef.java | 2 +- .../sbe/generation/rust/RustGenerator.java | 74 +++++++++++-------- .../sbe/generation/rust/RustUtil.java | 4 +- .../sbe/generation/rust/SubGroup.java | 3 - .../sbe/generation/rust/RustUtilTest.java | 2 + 12 files changed, 64 insertions(+), 42 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 8b7c1e774d..020747c06d 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -17,7 +17,7 @@ baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } nested_composite_name = { path = "../generated/rust/nested-composite-name" } [dev-dependencies] -criterion = "0.3" +criterion = "0.5" [[bench]] name = "car_benchmark" diff --git a/rust/benches/car_benchmark.rs b/rust/benches/car_benchmark.rs index 7ca9c2e5c8..92b964147a 100644 --- a/rust/benches/car_benchmark.rs +++ b/rust/benches/car_benchmark.rs @@ -1,5 +1,6 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use examples_uk_co_real_logic_sbe_benchmarks::*; +use car_codec::encoder::*; const MANUFACTURER: &[u8] = b"MANUFACTURER"; const MODEL: &[u8] = b"MODEL"; diff --git a/rust/benches/md_benchmark.rs b/rust/benches/md_benchmark.rs index b429622f92..ab7f4bf367 100644 --- a/rust/benches/md_benchmark.rs +++ b/rust/benches/md_benchmark.rs @@ -1,5 +1,6 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use examples_uk_co_real_logic_sbe_benchmarks_fix::*; +use market_data_incremental_refresh_trades_codec::encoder::*; struct State { buffer: Vec, diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index ca45f14b43..c223c83989 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -2,6 +2,7 @@ use std::fs::File; use std::io::prelude::*; use examples_baseline::*; +use car_codec::encoder::*; fn read_sbe_file_generated_from_java_example() -> std::io::Result> { // Generated by the generateCarExampleDataFile gradle task. diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index d3a6952dec..a1e107bc8d 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -1,4 +1,5 @@ use baseline_bigendian::*; +use car_codec::encoder::*; #[test] fn big_endian_baseline_example() -> SbeResult<()> { diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index c189763c6f..ad813c056f 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -2,6 +2,7 @@ use std::fs::File; use std::io::prelude::*; use examples_extension::*; +use car_codec::encoder::*; fn read_sbe_file_generated_from_java_example() -> std::io::Result> { // Generated by the generateCarExampleDataFile gradle task. diff --git a/rust/tests/issue_895_test.rs b/rust/tests/issue_895_test.rs index 6c7090d2da..dd9b19fa04 100644 --- a/rust/tests/issue_895_test.rs +++ b/rust/tests/issue_895_test.rs @@ -1,10 +1,12 @@ -use ::issue_895::*; +use issue_895::{ + issue_895_codec::{decoder::Issue895Decoder, encoder::Issue895Encoder}, + MessageHeaderDecoder, ReadBuf, SbeResult, WriteBuf, ENCODED_LENGTH, SBE_BLOCK_LENGTH, + SBE_SCHEMA_ID, SBE_SCHEMA_VERSION, SBE_TEMPLATE_ID, +}; fn create_encoder(buffer: &mut Vec) -> Issue895Encoder { - let issue_895 = Issue895Encoder::default().wrap( - WriteBuf::new(buffer.as_mut_slice()), - ENCODED_LENGTH, - ); + let issue_895 = + Issue895Encoder::default().wrap(WriteBuf::new(buffer.as_mut_slice()), ENCODED_LENGTH); let mut header = issue_895.header(0); header.parent().unwrap() } @@ -72,4 +74,4 @@ fn issue_895_double_none() -> SbeResult<()> { assert_eq!(None, decoder.optional_double()); Ok(()) -} \ No newline at end of file +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 3d38b28aa2..67c949cbe0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -81,7 +81,7 @@ void generate() throws IOException // add re-export of modules for (final String module : modules) { - indent(libRs, 0, "pub use %s::*;\n", toLowerSnakeCase(module)); + indent(libRs, 0, "pub use crate::%s::*;\n", toLowerSnakeCase(module)); } indent(libRs, 0, "\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 25e200a268..cb06bbc96a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -15,6 +15,7 @@ */ package uk.co.real_logic.sbe.generation.rust; +import org.agrona.Strings; import org.agrona.Verify; import org.agrona.generation.OutputManager; import uk.co.real_logic.sbe.PrimitiveType; @@ -119,7 +120,7 @@ public void generate() throws IOException indent(writer, 0, "version = \"0.1.0\"\n"); indent(writer, 0, "authors = [\"sbetool\"]\n"); indent(writer, 0, "description = \"%s\"\n", ir.description()); - indent(writer, 0, "edition = \"2018\"\n\n"); + indent(writer, 0, "edition = \"2021\"\n\n"); indent(writer, 0, "[lib]\n"); indent(writer, 0, "name = \"%s\"\n", namespace); indent(writer, 0, "path = \"src/lib.rs\"\n"); @@ -151,8 +152,8 @@ public void generate() throws IOException try (Writer out = outputManager.createOutput(codecModName)) { indent(out, 0, "use crate::*;\n\n"); - indent(out, 0, "pub use encoder::*;\n"); - indent(out, 0, "pub use decoder::*;\n\n"); + indent(out, 0, "pub use encoder::%sEncoder;\n", formatStructName(msgToken.name())); + indent(out, 0, "pub use decoder::%sDecoder;\n\n", formatStructName(msgToken.name())); final String blockLengthType = blockLengthType(); final String templateIdType = rustTypeName(ir.headerStructure().templateIdType()); final String schemaIdType = rustTypeName(ir.headerStructure().schemaIdType()); @@ -274,7 +275,18 @@ static void generateEncoderGroups( final Token numInGroupToken = Generators.findFirst("numInGroup", tokens, index); final PrimitiveType numInGroupPrimitiveType = numInGroupToken.encoding().primitiveType(); - indent(sb, level, "/// GROUP ENCODER\n"); + final String description = groupToken.description(); + if (!Strings.isEmpty(description)) + { + indent(sb, level, "/// GROUP ENCODER (id=%s, description='%s')\n", + groupToken.id(), description); + } + else + { + indent(sb, level, "/// GROUP ENCODER (id=%s)\n", + groupToken.id()); + } + assert 4 == groupHeaderTokenCount; indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(self, count: %s, %1$s: %3$s) -> %3$s {\n", @@ -553,7 +565,7 @@ private static void generateCompositeDecoder( decoderName, decoderTypeName); - indent(sb, level + 1, "if self.acting_version < %d {\n", fieldToken.version()); + indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", fieldToken.version()); indent(sb, level + 2, "return Either::Left(self);\n"); indent(sb, level + 1, "}\n\n"); @@ -587,7 +599,7 @@ private static void generateBitSetDecoder( if (bitsetToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version < %d {\n", bitsetToken.version()); + indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", bitsetToken.version()); indent(sb, level + 2, "return %s::default();\n", structTypeName); indent(sb, level + 1, "}\n\n"); } @@ -647,7 +659,7 @@ private static void generatePrimitiveArrayDecoder( if (fieldToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version < %d {\n", fieldToken.version()); + indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", fieldToken.version()); indent(sb, level + 2, "return [%s; %d];\n", encoding.applicableNullValue(), arrayLength); indent(sb, level + 1, "}\n\n"); } @@ -756,7 +768,7 @@ private static void generatePrimitiveOptionalDecoder( if (fieldToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version < %d {\n", fieldToken.version()); + indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", fieldToken.version()); indent(sb, level + 2, "return None;\n"); indent(sb, level + 1, "}\n\n"); } @@ -809,7 +821,7 @@ private static void generatePrimitiveRequiredDecoder( if (fieldToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version < %d {\n", fieldToken.version()); + indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", fieldToken.version()); indent(sb, level + 2, "return %s;\n", generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString())); indent(sb, level + 1, "}\n\n"); @@ -897,9 +909,19 @@ static void generateDecoderGroups( i = collectVarData(tokens, i, varData); final String groupName = decoderName(formatStructName(groupToken.name())); - indent(sb, level, "/// GROUP DECODER\n"); - assert 4 == groupHeaderTokenCount; + final String description = groupToken.description(); + if (!Strings.isEmpty(description)) + { + indent(sb, level, "/// GROUP DECODER (id=%s, description='%s')\n", + groupToken.id(), description); + } + else + { + indent(sb, level, "/// GROUP DECODER (id=%s)\n", + groupToken.id()); + } + assert 4 == groupHeaderTokenCount; indent(sb, level, "#[inline]\n"); if (groupToken.version() > 0) { @@ -910,18 +932,14 @@ static void generateDecoderGroups( indent(sb, level + 2, "return None;\n"); indent(sb, level + 1, "}\n\n"); - indent(sb, level + 1, "let acting_version = self.acting_version;\n"); - indent(sb, level + 1, "Some(%s::default().wrap(self, acting_version as usize))\n", - groupName); + indent(sb, level + 1, "Some(%s::default().wrap(self))\n", groupName); } else { indent(sb, level, "pub fn %s(self) -> %2$s {\n", formatFunctionName(groupName), groupName); - indent(sb, level + 1, "let acting_version = self.acting_version;\n"); - indent(sb, level + 1, "%s::default().wrap(self, acting_version as usize)\n", - groupName); + indent(sb, level + 1, "%s::default().wrap(self)\n", groupName); } indent(sb, level, "}\n\n"); @@ -958,7 +976,8 @@ static void generateDecoderVarData( { if (varDataToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version < %d {\n", varDataToken.version()); + indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", + varDataToken.version()); indent(sb, level + 2, "return (self.parent.as_ref().unwrap().get_limit(), 0);\n"); indent(sb, level + 1, "}\n\n"); } @@ -973,7 +992,8 @@ static void generateDecoderVarData( { if (varDataToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version < %d {\n", varDataToken.version()); + indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", + varDataToken.version()); indent(sb, level + 2, "return (self.get_limit(), 0);\n"); indent(sb, level + 1, "}\n\n"); } @@ -992,7 +1012,8 @@ static void generateDecoderVarData( if (varDataToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version < %d {\n", varDataToken.version()); + indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", + varDataToken.version()); indent(sb, level + 2, "return &[] as &[u8];\n"); indent(sb, level + 1, "}\n\n"); } @@ -1199,7 +1220,7 @@ private static void generateEnum( throw new IllegalArgumentException("No valid values provided for enum " + originalEnumName); } - indent(writer, 0, "#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\n"); + indent(writer, 0, "#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]\n"); final String primitiveType = rustTypeName(messageBody.get(0).encoding().primitiveType()); indent(writer, 0, "#[repr(%s)]\n", primitiveType); indent(writer, 0, "pub enum %s {\n", enumRustName); @@ -1216,16 +1237,11 @@ private static void generateEnum( final Encoding encoding = messageBody.get(0).encoding(); final CharSequence nullVal = generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString()); + indent(writer, 1, "#[default]\n"); indent(writer, 1, "NullVal = %s, \n", nullVal); } indent(writer, 0, "}\n"); - // Default implementation to support Default in other structs - indent(writer, 0, "impl Default for %s {\n", enumRustName); - indent(writer, 1, "#[inline]\n"); - indent(writer, 1, "fn default() -> Self { %s::%s }\n", enumRustName, "NullVal"); - indent(writer, 0, "}\n"); - // From impl indent(writer, 0, "impl From<%s> for %s {\n", primitiveType, enumRustName); indent(writer, 1, "#[inline]\n"); @@ -1271,8 +1287,8 @@ private static void generateComposite( { indent(out, 0, "use crate::*;\n\n"); - indent(out, 0, "pub use encoder::*;\n"); - indent(out, 0, "pub use decoder::*;\n\n"); + indent(out, 0, "pub use encoder::%sEncoder;\n", formatStructName(compositeName)); + indent(out, 0, "pub use decoder::%sDecoder;\n\n", formatStructName(compositeName)); final int encodedLength = tokens.get(0).encodedLength(); if (encodedLength > 0) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 4f71f0de84..13fa241a40 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -260,7 +260,7 @@ private static String sanitizeMethodOrProperty(final String name) { if (shadowsKeyword(name)) { - return name + "_"; + return "r#" + name; } else { @@ -310,7 +310,7 @@ enum ReservedKeyword { for (final ReservedKeyword value : ReservedKeyword.values()) { - LOWER_CASE_NAMES.add(value.name()); + LOWER_CASE_NAMES.add(value.name().toLowerCase()); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 756e019fdf..d7fd2cc55d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -157,7 +157,6 @@ void generateDecoder( indent(sb, level - 1, "pub struct %s

    {\n", name); indent(sb, level, "parent: Option

    ,\n"); indent(sb, level, "block_length: usize,\n"); - indent(sb, level, "acting_version: usize,\n"); indent(sb, level, "count: %s,\n", rustTypeName(numInGroupPrimitiveType)); indent(sb, level, "index: usize,\n"); indent(sb, level, "offset: usize,\n"); @@ -174,7 +173,6 @@ void generateDecoder( indent(sb, level, "pub fn wrap(\n"); indent(sb, level + 1, "mut self,\n"); indent(sb, level + 1, "mut parent: P,\n"); - indent(sb, level + 1, "acting_version: usize,\n"); indent(sb, level, ") -> Self {\n"); indent(sb, level + 1, "let initial_offset = parent.get_limit();\n"); indent(sb, level + 1, "let block_length = parent.get_buf().get_%s_at(initial_offset) as usize;\n", @@ -186,7 +184,6 @@ void generateDecoder( indent(sb, level + 1, "self.parent = Some(parent);\n"); indent(sb, level + 1, "self.block_length = block_length;\n"); - indent(sb, level + 1, "self.acting_version = acting_version;\n"); indent(sb, level + 1, "self.count = count;\n"); indent(sb, level + 1, "self.index = usize::MAX;\n"); indent(sb, level + 1, "self.offset = 0;\n"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index 33f3a876d4..f7dcc14c28 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -136,6 +136,8 @@ void functionNameCasing() assertEquals("pricenull_9", formatFunctionName("PRICENULL9")); assertEquals("price_9_book", formatFunctionName("PRICE9Book")); assertEquals("issue_435", formatFunctionName("issue435")); + assertEquals("r#type", formatFunctionName("type")); + assertEquals("upper_case", formatFunctionName("UPPERCase")); assertEquals("no_md_entries", formatFunctionName("NoMDEntries")); assertEquals("md_entry_type_book", formatFunctionName("MD_EntryTYPEBook")); From 3b8101dffed86b4c76a30da4f2319036bcdf4b36 Mon Sep 17 00:00:00 2001 From: Wojciech Lukowicz Date: Thu, 2 Nov 2023 10:52:42 +0000 Subject: [PATCH 270/805] [Java] Upgrade to Agrona 1.20.0. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 04b981c43f..9e0286ff8c 100644 --- a/build.gradle +++ b/build.gradle @@ -58,8 +58,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.0' def jmhVersion = '1.37' -def agronaVersion = '1.19.2' -def agronaVersionRange = '[1.19.2,2.0[' // allow any release >= 1.19.2 and < 2.0.0 +def agronaVersion = '1.20.0' +def agronaVersionRange = '[1.20.0,2.0[' // allow any release >= 1.20.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 24ede47c74297b3db2d841df70c181736c7ac3df Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 6 Nov 2023 11:18:24 +0100 Subject: [PATCH 271/805] [Java] Upgrade to JUnit 5.10.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9e0286ff8c..143ef8c335 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' -def junitVersion = '5.10.0' +def junitVersion = '5.10.1' def jmhVersion = '1.37' def agronaVersion = '1.20.0' def agronaVersionRange = '[1.20.0,2.0[' // allow any release >= 1.20.0 and < 2.0.0 From 3a7d44595e054c377eb0044074b10bc2bb68f64e Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 17 Nov 2023 09:35:27 +0000 Subject: [PATCH 272/805] [Java] Upgrade to Versions 0.50.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 143ef8c335..3838d1a1ce 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '8.1.1' apply false - id 'com.github.ben-manes.versions' version '0.49.0' + id 'com.github.ben-manes.versions' version '0.50.0' } defaultTasks 'clean', 'build' From dd6063fe8bf2ab03ca6c3a51b462a6aba5f2be74 Mon Sep 17 00:00:00 2001 From: pliard Date: Tue, 28 Nov 2023 16:18:28 +0100 Subject: [PATCH 273/805] [Java] Support `valueRef` with camelCase enum type identifiers (#963) The type identifier was previously used as-is (e.g. `carFilterType`) in the generated code for uses of `valueRef` while generated Java enums always start with a capital letter (`CarFilterType`). See the added test in ValueRefWithLowerCaseEnum.java. --- .../sbe/generation/java/JavaGenerator.java | 3 +- .../java/ValueRefWithLowerCaseEnum.java | 69 +++++++++++++++++++ .../value-ref-with-lower-case-enum.xml | 24 +++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java create mode 100644 sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index e40a02c6a1..eb90237170 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -3074,7 +3074,8 @@ private void generateEnumDecoder( if (fieldToken.isConstantEncoding()) { - final String enumValueStr = fieldToken.encoding().constValue().toString(); + final String enumValueStr = formatClassName( + fieldToken.encoding().constValue().toString()); new Formatter(sb).format( "\n" + diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java new file mode 100644 index 0000000000..98cdf3852b --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java @@ -0,0 +1,69 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import org.agrona.DirectBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; +import uk.co.real_logic.sbe.xml.XmlSchemaParser; + +import java.io.InputStream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; + +class ValueRefWithLowerCaseEnum +{ + private static final Class BUFFER_CLASS = MutableDirectBuffer.class; + private static final String BUFFER_NAME = BUFFER_CLASS.getName(); + private static final Class READ_ONLY_BUFFER_CLASS = DirectBuffer.class; + private static final String READ_ONLY_BUFFER_NAME = READ_ONLY_BUFFER_CLASS.getName(); + + @Test + void shouldGenerateConstCharArrayMethods() throws Exception + { + try (InputStream in = Tests.getLocalResource("value-ref-with-lower-case-enum.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = XmlSchemaParser.parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); + + generator.generate(); + final String sources = outputManager.getSources().toString(); + + // Prior to the fix the generated body of the following method was + // `return engineType.gas;` + final String expected = + " public EngineType engineType()\n" + + " {\n" + + " return EngineType.gas;\n" + + " }"; + assertThat(sources, containsString(expected)); + } + } +} diff --git a/sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml b/sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml new file mode 100644 index 0000000000..c33b4133c8 --- /dev/null +++ b/sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + 0 + + + + + + + From a259c7d5f6389f240700b7801d842940621b6151 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 6 Dec 2023 11:32:28 +0000 Subject: [PATCH 274/805] [Java,C#,C++] Support field access order checking (#948) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a squashed merge of many commits. I've kept the original commit messages below for posterity; however, a better summary is available in the description of [PR #948](https://github.com/real-logic/simple-binary-encoding/pull/948). Squashing makes it easy to revert, but sadly, it loses the fine-grained history available through `git blame`. --- * [Java] Add disabled tests around checking field access order. SBE does not support arbitrary access to fields when encoding and decoding. In particular, accessing groups and variable length fields advances a `limit`, which marks where the start of the next group/variable length field is expected. We aim to introduce some checking (in debug mode - when bounds checks are enabled) that verifies field access order is consistent enough with the order defined in the schema to encode or decode a valid message. * [Java] Spike an approach for checking field encode order. Also, enable some tests around field order checking. Outline of the approach: - Using a FSM, model the states of an encoder during encoding. - Hopefully, this model will be language independent. - Generate code to perform state transitions upon field accesses. - And to throw when transitions are not in the model. Assumptions: - JIT compilation will remove `if (DEBUG_MODE) { ... }` blocks when the static boolean constant, `DEBUG_MODE`, is `false`. Questions: - Is the approach reasonable? - Is the newly disallowed behaviour reasonable? - For example, it prevents encoding block fields after a group or variable length field has been encoded. Further work: - Decode path - More tests (including tests for decoding old messages where some fields may not be present) * [Java] Support printing field order access state machine. Use `-Dsbe.print.state.machine=$NAME_OF_MSG`. * [Java] Add checking around decoding order. This change builds upon the work to check field encoding order. It is a slightly more-complex problem than with encoding, as when decoding it is necessary to deal with multiple versions of encoded data. To handle this, we fuse together the state machines for decoding each possible version and branch on "decoder.wrap(...)". Further work: - More tests - Better error messages * [Java] Test field order checks across versions. "New" decoders (in Java at least) read null-like values for fields that are not present in "old" messages. There are no restrictions on the order in which these "new" fields are accessed when decoding "old" data. In Java, a version check returns a null-like value when a field is not present in the acting version. This behaviour matches the wiki documentation. C#, currently, has different behaviour: the application code needs to interrogate a boolean property, e.g., `IsFooInActingVersion`, before accessing the data property, e.g., `Foo`. The property itself assumes that the field is present. It will attempt to read it from the buffer and possibly advance a `limit` field. In this commit, I have moved the state transition beneath the existing version check in Java decoders. This change allows these fields to be accessed when decoding "old" messages without changing the state of decoding, which seems appropriate as there are no side-effects on internal state, e.g., the `limit` field. Also, in this commit, I have expanded the test coverage to include the getter and setter variants for fixed-size arrays and variable-length data. * [Java] Generate better error messages. Also, use an enum to represent codec states rather than a state number and generate (dot-based) state machine diagram in Javadoc for states enum. * [Java] Test field order checks with fixed-length strings. Also, fix some spots where I had forgotten to move the state transition below the version check in decoders. * [Java] Test field checks do not affect toString. * [Java] Fix field order checks to work with `decodedLength()`. * [Java] Test content of field order error messages. There is still work to do in this area. In particular: 1. States should be more descriptive. 1. Errors should contain full field paths. 2. Group error messages should be more clear, e.g., "cannot write group element before calling next()". * [Java] Fix field access order in tests and re-enable. * [Java] Permit block field access whenever it is safe (and, unfortunately, in some cases where it is not). This commit makes the field order checks more-lenient. The aim is to allow the application code to access fields in the root/top-level block or blocks inside groups whenever it is safe. However, the approach is broken and does not work in general. To (try to) achieve this aim, we rely on the fact that once a block is positioned correctly, it is safe to access during the remainder of encoding/decoding. For example, the following code is safe: ``` encoder.wrap(...); encoder.blockField1(42); encoder.varData("abc"); encoder.blockField2(43); ``` As soon as `wrap(...)` is called, the top-level block will be positioned over a valid region for the remainder of encoding. Groups are slightly trickier. The following code is _safe_: ``` encoder.wrap(...); Foo.BarEncoder bar = encoder.groupBarCount(2); bar.next() .x(1).y(2) .next(); .x(3).y(4); ``` But the following code is _unsafe_: ``` encoder.wrap(...); Foo.BarEncoder bar = encoder.groupBarCount(2); bar.x(1).y(2) .next(); .x(3).y(4); ``` And the following code is _unsafe_ too: ``` encoder.wrap(...) Foo.BarEncoder bar = encoder.groupBarCount(0); encoder.baz("abc"); bar.x(1).y(2); ``` The `offset` for the group encoder is only set when `next()` is called. Therefore, calling `x(1)` and `y(2)` will likely overwrite some data elsewhere in the buffer (probably near offset 0). We can still rely on the fact that once `next()` has been called - even if it is called multiple times, or too many times (causing it to throw) - the group's block fields will be safe to encode/decode. Thinking about this in terms of our state machine that models codec state and field accesses, we can put this another way. There is at least one transition that represents the `next()` method call. The states (transitively) reachable from these transitions can safely access the associated group block. As already mentioned, despite the passing tests, the approach in this commit doesn't always work. I had thought it would be possible to assign a number to each state as we find them using DFS and use this number as a shortcut to determining whether a block access was safe. For example, in each block field we would check: ``` if (currentState.number() >= firstStateAfterNextIsCalled.number()) { // ALLOW } else { // DENY } ``` However, (even ignoring the cycles due to repeating groups and the use of DFS) this solution makes the following assumptions: 1. There is a single state: `firstStateAfterNextIsCalled`, such that all subsequent transitively reachable states are safe. 2. It is possible to number the states in such a way that `numberOfState(b) >= numberOfState(a)` implies `b` is (transitively) reachable from `a`. Let's consider the following psuedo-schema w.r.t. our assumptions above: ``` group a { x: int32 } group b { y: int32 } ``` Can we set `x` if we've called `BEncoder#next`? Sometimes. The following code is invalid. ``` AEncoder a = encoder.aCount(0); BEncoder b = encoder.bCount(1).next(); b.y(2); a.x(1); // Whoops! We overwrote some data somewhere. ``` But this code is valid. ``` AEncoder a = encoder.aCount(1).next(); BEncoder b = encoder.bCount(1).next(); b.y(2); a.x(1); ``` Therefore, multiple transitions must exist for the `BEncoder#next` call with different exit states, which breaks Assumption 1. Assumption 2 is also problematic. As alluded to above, we must have a bifurcation of states depending on whether a group has elements or is empty. With arbitrary bifurcations, it is not possible to number the states in such a way that Assumption 2 holds. Consider the following state diagram: ``` state N / \ empty non-empty / \ state X state Y ``` Depending on whether a group is empty, e.g., `aCount(0)`, or not, e.g., `aCount(1)`, we transition to either `state X` or `state Y` from `state N`. For Assumption 2 to hold, we need `numberOf(state X) >= numberOf(state N)` (reachable) and `numberOf(state Y) >= numberOf(state N)` (reachable) and `numberOf(state X) < numberOf(state Y)` (unreachable) and `numberOf(state Y) < numberOf(state X)` (unreachable). Clearly, this is impossible. Prior to this commit, we avoided such problems by enforcing a more-strict ordering of field accesses. With this more-strict ordering, setting fields in a group block in later states was not allowed. Therefore, the state machine didn't have to have to split into mutually exclusive subgraphs of reachable states depending on whether or not the group is empty. For example, let's consider a psuedo-schema with two groups. ``` group a { x: int32 } group b { y: int32 } ``` Once the application code calls `encoder.bCount(2).next()`, our state machine will enter the `V0_B_N_BLOCK` state regardless of whether previously the application code called `encoder.aCount(0)` or `encoder.aCount(1).next()`. In `V_B_N_BLOCK` the application code is not allowed to call `AEncoder#x`; therefore, it is safe, i.e., it has no false positives. However, it is also too-strict, i.e., it has false negatives, e.g., the `encoder.aCount(1).next()` case. How likely are these false negatives to come up in the "wild"? If we think false negatives will often come up, is it possible to remove them whilst still using a state machine? We could consider generating more states to represent the reachable states under each fork of group emptiness. The number of states would grow exponentially w.r.t. the number of top-level groups, but let's ignore that for the moment and just consider whether or not it is possible. Continuing the example above with two groups, when the application code calls `encoder.bCount(2).next()`, the state it enters would depend on whether it had previously called `encoder.aCount(0)` or `encoder.aCount(n)...next()` for some value `n > 0`. To safely model this example, we'd need at least the following states: 1. has no `a` elements 2. has no `a` elements, and has no `b` elements 3. has `a` elements, but has not called `AEncoder#next` 4. has `a` elements, and has called `AEncoder#next` 5. has `a` elements, has called `AEncoder#next`, has `b` elements, but has not called `BEncoder#next` 6. has `a` elements, has called `AEncoder#next`, has `b` elements, and has called `BEncoder#next` 7. has no `a` elements, has `b` elements, but has not called `BEncoder#next` 8. has no `a` elements, has `b` elements, and has called `BEncoder#next` A trickier case is with nested groups: ``` group foo { x: int32 group bar { y: int32 } r: string s: string } ``` When is `Bar#y` safe to call? I believe it is safe to call in states where `FooEncoder#next` and `BarEncoder#next` have been called in-order more recently than `BarEncoder#count(0)`. Note, as `bar` is a group within `foo`, the `BarEncoder#next` and `BarEncoder#count` methods may be called repeatedly during the encoding of a single message. Implementing a more-permissive safety check, using this model, would entail checking that the current state of the encoder/decoder is in a state where this condition holds. To safely model this example, we'd need (at least) the following states: 1. has no `foo` elements 2. has `foo` elements, but has not called `FooEncoder#next` 3. has `foo` elements, and has called `FooEncoder#next` 4. has `foo` elements, has called `FooEncoder#next`, and has no `bar` elements 5. has `foo` elements, has called `FooEncoder#next`, has no `bar` elements, and has encoded `r` 6. has `foo` elements, has called `FooEncoder#next`, has no `bar` elements, and has encoded `s` 7. has `foo` elements, has called `FooEncoder#next`, has `bar` elements, but has not called `BarEncoder#next` 8. has `foo` elements, has called `FooEncoder#next`, has `bar` elements, has not called `BarEncoder#next`, and has encoded `r` 9. has `foo` elements, has called `FooEncoder#next`, has `bar` elements, has not called `BarEncoder#next`, and has encoded `s` 10. has `foo` elements, has called `FooEncoder#next`, has `bar` elements, and has called `BarEncoder#next` 11. has `foo` elements, has called `FooEncoder#next`, has `bar` elements, and has called `BarEncoder#next`, and has encoded `r` 12. has `foo` elements, has called `FooEncoder#next`, has `bar` elements, and has called `BarEncoder#next`, and has encoded `s` ``` FooEncoder foo = encoder.fooCount(3); // State 2 foo.next(); // State 3 foo.barCount(0); // State 4 foo.r("abc"); // State 5 foo.s("def"); // State 6 foo.next(); // State 4 BarEncoder bar = foo.barCount(1); // State 7 foo.r("abc"); // State 8 bar.next(); // State 11 bar.y(42); // State 11 foo.s("def"); // State 12 foo.next(); // State X? bar.y(43); // Weird but allowed. foo.barCount(0); // State Y? State X cannot be State 10, as State 10 should not allow _re-encoding_ of the bar group count ``` OK. We didn't have enough states. In the case where we "wrap back around", we need to model whether `bar` block access is allowed (State 13 vs State 3): 13. has `foo` elements, has called `FooEncoder#next`, has called `BarEncoder#next` for last iteration, but hasn't set `bar` group size in this iteration. An even trickier case is with doubly-nested groups: ``` group foo { x: int32 group bar { y: int32 group baz { z: int32 } } } ``` When is `Baz#z` safe to call? I believe it is safe to call in states where `FooEncoder#next`, `BarEncoder#next` and `BazEncoder#next` have been called in-order more recently than `BarEncoder#count(0)` or `BazEncoder#count(0). Encoding this in states is likely to result in more cases like State 13 above. Generalising: a group block field may be accessed only when all outer groups' and its own `#next` methods have been called in-order more recently than any outer groups' or its own `#count` method with a `0` argument. Can model "more-recently" exactly, i.e., with no false positives and no false negatives, using a state machine? Another way of looking at the state machines we generate, is as parsers for a language. Where our language, based on an SBE schema, comprises valid "strings" of calls to an encoder/decoder. Is this language a regular language? If not, representing it using a FSM will not work. Cue Pumping Lemma? Next steps: - Add more tests to show where this approach breaks - Revert the changes and see if it is acceptable that some valid uses of codecs will be prevented when enabling field order checking. I.e., it will give false negatives when testing the hypothesis "this encoding/decoding is valid". - Personally, I think false negatives are better than false positives. (False positives are possible as of this commit.) Having said that, it will discourage use of these checks in existing systems where valid code already exists that does not pass the checks. * [Java] Add (disabled) failing tests for false positives. (When testing the hypothesis "this decoding/encoding code is valid".) These tests show that there are problems with the approach in the last commit. * Revert "[Java] Permit block field access whenever it is safe (and, unfortunately, in some cases where it is not)." This reverts commit d9eb33dc793d7f62e696e4f40a1b4cf36d50316f. * [Java] Treat top-level block fields as a special case. To reduce the number of false negatives the field access order checker generates, in this commit, we treat the top-level block fields differently. We know that once the top-level encoder is wrapped, these fields are always safe to access. As a result, we were able to enable several tests that previously failed. * [Java] Support turning on access checks independently of bounds checks. Introduces the system property: ``` sbe.enable.access.order.checks ``` * [Java] Attempt to optimise code with disabled access order checks. Some JIT compilers are able to eliminate dead code within branches of if-statements where the conditional is a static expression. Some JIT compilers perform inlining to some degree and use heuristics, e.g., method size. It isn't clear whether code size metrics will be calculated after dead code elimination is performed. In this commit, I've moved the code that performs state transitions when access order checks are enabled into separate methods that the encoders/decoders call upon field accesses, e.g., the getter for a field `xyz` might look like this: ``` int xyz() { if (ENABLED_ACCESS_ORDER_CHECKS) { onXyzAccessed(); } // ... } ``` This keeps the initial size of `xyz` smaller than when the code of `onXyzAccessed()` is "inlined" by the code generator. There is a lot of noise on my ThinkPad P14s, but benchmarks do show improvements after this change. Before: ``` $ java -jar -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ./sbe-benchmarks/build/libs/sbe-benchmarks.jar ".*Car.*" -bm thrpt -f 2 -i 3 -wi 2 \# JMH version: 1.36 \# VM version: JDK 1.8.0_302, OpenJDK 64-Bit Server VM, 25.302-b08 \# VM invoker: /home/zach/.asdf/installs/java/zulu-8.56.0.21/jre/bin/java \# VM options: -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ... Benchmark Mode Cnt Score Error Units CarBenchmark.testDecode thrpt 6 18051405.792 ± 444296.898 ops/s CarBenchmark.testEncode thrpt 6 11964827.418 ± 221996.747 ops/s ``` After: ``` $ java -jar -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ./sbe-benchmarks/build/libs/sbe-benchmarks.jar ".*Car.*" -bm thrpt -f 2 -i 3 -wi 2 \# JMH version: 1.36 \# VM version: JDK 1.8.0_302, OpenJDK 64-Bit Server VM, 25.302-b08 \# VM invoker: /home/zach/.asdf/installs/java/zulu-8.56.0.21/jre/bin/java \# VM options: -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ... Benchmark Mode Cnt Score Error Units CarBenchmark.testDecode thrpt 6 18132922.415 ± 1964596.044 ops/s CarBenchmark.testEncode thrpt 6 20018131.180 ± 671367.070 ops/s ``` Baseline (d2ec8f8a225808a1392872473f6e5e85b828056e): ``` $ java -jar -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ./sbe-benchmarks/build/libs/sbe-benchmarks.jar ".*Car.*" -bm thrpt -f 2 -i 3 -wi 2 \# JMH version: 1.36 \# VM version: JDK 1.8.0_302, OpenJDK 64-Bit Server VM, 25.302-b08 \# VM invoker: /home/zach/.asdf/installs/java/zulu-8.56.0.21/jre/bin/java \# VM options: -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ... Benchmark Mode Cnt Score Error Units CarBenchmark.testDecode thrpt 6 19270366.357 ± 2618336.027 ops/s CarBenchmark.testEncode thrpt 6 22519718.535 ± 794169.180 ops/s ``` * [Java] Add feature toggle for access order check generation. The code generator will omit checks when the `sbe.generate.access.order.checks` system property is set to `false`. Adding the feature toggle allowed me to run the following benchmarks on my ThinkPad P14s, where (unfortunately) there is some noise. Baseline (d2ec8f8a225808a1392872473f6e5e85b828056e): ``` $ java -jar -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ./sbe-benchmarks/build/libs/sbe-benchmarks.jar ".*Car.*" -bm thrpt -f 2 -i 3 -wi 2 \# JMH version: 1.36 \# JMH version: 1.36 \# JMH version: 1.36 \# JMH version: 1.36 \# VM version: JDK 1.8.0_302, OpenJDK 64-Bit Server VM, 25.302-b08 \# VM invoker: /home/zach/.asdf/installs/java/zulu-8.56.0.21/jre/bin/java \# VM options: -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ... Benchmark Mode Cnt Score Error Units CarBenchmark.testDecode thrpt 6 19270366.357 ± 2618336.027 ops/s CarBenchmark.testEncode thrpt 6 22519718.535 ± 794169.180 ops/s ``` This commit with new code generation disabled, i.e., `-Dsbe.generate.access.order.checks=false` at build time: ``` $ java -jar -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ./sbe-benchmarks/build/libs/sbe-benchmarks.jar ".*Car.*" -bm thrpt -f 2 -i 3 -wi 2 \# JMH version: 1.36 \# VM version: JDK 1.8.0_302, OpenJDK 64-Bit Server VM, 25.302-b08 \# VM invoker: /home/zach/.asdf/installs/java/zulu-8.56.0.21/jre/bin/java \# VM options: -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ... Benchmark Mode Cnt Score Error Units CarBenchmark.testDecode thrpt 6 19290928.253 ± 2226604.698 ops/s CarBenchmark.testEncode thrpt 6 21957767.395 ± 567000.570 ops/s ``` This commit with new code generation enabled, but disabled checks, i.e., `-Dsbe.enable.access.order.checks=false` at runtime. ``` $ java -jar -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ./sbe-benchmarks/build/libs/sbe-benchmarks.jar ".*Car.*" -bm thrpt -f 2 -i 3 -wi 2 \# JMH version: 1.36 \# VM version: JDK 1.8.0_302, OpenJDK 64-Bit Server VM, 25.302-b08 \# VM invoker: /home/zach/.asdf/installs/java/zulu-8.56.0.21/jre/bin/java \# VM options: -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=false ... Benchmark Mode Cnt Score Error Units CarBenchmark.testDecode thrpt 6 19238066.328 ± 2557533.640 ops/s CarBenchmark.testEncode thrpt 6 22284274.779 ± 520984.898 ops/s ``` Whilst it is hard to definitively conclude anything using my noisy machine to benchmark, it seems like there is no obvious performance regression when the runtime checks are disabled in comparison to omitting the checks at build time. * [Java] Improve performance of field access order checking. This commit switches the generated code to using an int to represent the state rather than a reference to an enum case. The change improves performance significantly, which I suspect is due to avoiding a write barrier that updates the card table. Relevant benchmark runs are below. Perhaps different JVM versions and GC options will yield different relative improvements. All benchmark runs use: - `-Dsbe.generate.access.order.checks=true` at build time - `-Dsbe.enable.access.order.checks=true` at runtime Using an enum: ``` $ java -jar -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=true ./sbe-benchmarks/build/libs/sbe-benchmarks.jar ".*Car.*" -bm thrpt -f 2 -i 3 -wi 2 \# JMH version: 1.36 \# VM version: JDK 1.8.0_302, OpenJDK 64-Bit Server VM, 25.302-b08 \# VM invoker: /home/zach/.asdf/installs/java/zulu-8.56.0.21/jre/bin/java \# VM options: -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=true ... Benchmark Mode Cnt Score Error Units CarBenchmark.testDecode thrpt 6 8075519.641 ± 363346.224 ops/s CarBenchmark.testEncode thrpt 6 7211523.145 ± 504174.913 ops/s ``` Using an int: ``` $ java -jar -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=true ./sbe-benchmarks/build/libs/sbe-benchmarks.jar ".*Car.*" -bm thrpt -f 2 -i 3 -wi 2 \# JMH version: 1.36 \# VM version: JDK 1.8.0_302, OpenJDK 64-Bit Server VM, 25.302-b08 \# VM invoker: /home/zach/.asdf/installs/java/zulu-8.56.0.21/jre/bin/java \# VM options: -Dagrona.disable.bounds.checks=true -Dsbe.enable.access.order.checks=true ... Benchmark Mode Cnt Score Error Units CarBenchmark.testDecode thrpt 6 13030684.127 ± 155782.171 ops/s CarBenchmark.testEncode thrpt 6 9781612.505 ± 1342559.378 ops/s ``` * [Java] Provide more context in error messages. In this commit, we associate field tokens with the "path" through the message to it. We can then use this to generate code with better error messages that include the path to the field rather than just the field name, which could have been ambiguous when there are groups. * [Java] Provide more context in error messages. In this commit, I've customised the error messages around group access to give a better indication of what was attempted. * [Java] Specify expected transitions in error messages. In this commit, I've improved the error messages around field access order checks so that it reports the legal transitions in the current state. Hopefully, this will make it easier for users to fix problems. * [Java] Use fewer states to model encoding. Encoders can only encode the latest version, unlike decoders. Therefore, we do not need to model field access patterns other than that of the latest version. * [Java] Refactor field access order checking. Overview: - `AccessOrderModel.CodecInteraction` models the possible interactions with an encoder or decoder: - Wrapping it around a buffer - Accessing its fields (block or var data) - Encoding/decoding the count of a repeating group - Moving to the next element in a repeating group - Moving to the last element in a repeating group - `AccessOrderModel` models the encoder/decoder state transitions w.r.t. these interactions * [Java] Address review comment. A disabled test had an incorrect assertion. Also, I've replaced the term "group length" with "group count" in the test names. * [Java] Add tests for variable-length data in nested group. These tests are based on Mike's review comments. * [Java] Generate check that encoding is complete. Previously, we checked the order of encoding was correct but not that the encoding reached a terminal state. In this commit, I've added code to generate a new method `checkEncodingIsComplete` on Java encoders. It verifies that a terminal state has been reached; otherwise, it throws an exception with information about the current state and transitions. * [Java] Initialise buffer bytes before encoding in tests. Check that null checks are actually working, rather than just returning 0s from the buffer. Also, fix usage of bitsets to always set all options. * [C#] Ignore personal Rider file. * [C#] Fix bug in string encoding method. Previously it would generate something like: ``` buffer.PutByte(someOffset, (ushort) someValue); // ^^^^^^^^ ``` Where the source value was too wide for the destination. * [C#] Port field access order tests. In this commit, I've ported most of the tests from the Java suite of tests for field access order checking to CSharp. To get the tests to compile, I had to generate an empty method stub for `CheckEncodingIsComplete()` on the codecs. Some generated APIs are different, e.g., around strings and arrays. Therefore, test cases and their numbers differ slightly in some places. * [Java] Fix indent. * [C#,Java] Port access order checking implementation to C#. Tests remain ignored due to two pre-existing problems in the C# codecs: 1. `ToString()` alters the codec state, e.g., `_limit`. 2. Some accessors do not check the field is present in the version being decoded. * [C#] Recover codec state after `ToString()`. Previously, the `ToString()` call would fail or complete but alter the state of the codec such that it was in a terminal state. Now, we treat `codecState` much like `limit` and recover the original value before returning control from `ToString()`. * [C#] Generate (more) presence checks in accessors. Previously, some accessors did not check that the acting version (being decoded) had the field/group/varData being accessed. Therefore, it might return garbage. But other accessors did check. In this commit, I've attempted to make more of the accessors (hopefully all) check the acting version before attempting to read data from the underlying buffer. This change should make the C# codecs closer to the Java decoders. * [C#] Enable access order checking tests. Having ported the implementation from Java and fixed some issues where the C# codecs were not checking the acting version when decoding data, the tests now pass. * [C++] Port access order checking tests and implementation to C++. In this commit, I also addressed these issues (1-3): --- 1. Tidy up string format usage. --- For convenience and readability, I had inlined some concatenation into `string.format(...)` templates; however, this makes it unclear whether the variable/method-output being concatenated uses template parameters. Therefore, I have adjusted to inject these strings via template parameters. FWIW I'd prefer to use `StringBuilder` everywhere, as I think it is hard to read large string format templates. --- 2. Explcitly delete copy constructors of flyweights. --- I found it easy to accidentally write sub-optimal code where I relied on copy constructors. For example: ``` MyMessage::MyGroup myGroup = myMessage.myGroup(10); ``` rather than: ``` MyMessage::MyGroup &myGroup = myMessage.myGroup(10); ``` Copying semantics are a bit strange when it comes to flyweights and trees of flyweights. Therefore, I think it is best to avoid entirely. This change is behind a feature flag. To re-enable implicit copy constructors specify the system property `-Dsbe.generate.implicit.copy.constructors=true`. --- 3. Adjust state machines to allow repeated decoding of variable-length --- data lengths, as accesses do not advance `limit`. * [C#] Improve indentation generation. Previously, some sections were not correctly aligned. * [Java, C#, C++] Model `resetCountToIndex()` state machine transition. Previously, the access order checks did not work with the `resetCountToIndex()` methods (generated on flyweights for repeating groups). Now, the valid transitions using these methods are modelled in the state machine and this is reflected in the code we generate for Java, C# and C++. Note that the `resetCountToIndex()` method does not change the `limit`/`position` of the message; therefore, it is only valid to use it when the `limit` aligns with a boundary between group elements. * [Java, C++, C#] Disable access order checking feature by default. We can deliver this new feature (and the C++ changes around copy constructors and copy assignment operators) without breaking any existing consumers by disabling the new code generation by default. Once released, and we've started to get feedback, we can decide whether we want to change the default and encourage our users to make use of the new feature. * [C++] Make access listener methods private. Also, fix some indentation issues. * [C++, C#] Tidy up. Removes superfluous space before SBE_NOEXCEPT specifier in C++. Tightens access modifiers in C#. * [Java, C++] Tidy up. Removes extraneous space in Java output when access order checks are disabled. Removes unnecessary access modifiers in C++ when access order checks are disabled. * [Java, C#, C++] Rename flags to enable field access order checking. The aim of this change is to avoid naming collisions with other flags, particularly in financial domains where "order" is used frequently. * [Java,C#,C++] Allow custom flag/properties to enable precedence checks. Some users would like the ability to enable precedence checks on some schemas but not others. Initially, I considered generating flags or system properties with the schema namespace; however, this forces the more-complex scheme on all users. It also might get unwieldly with long namespaces. It also assumes a one-to-one correspondence between namespaces and schemas. Instead, I have introduced two new system properties that can be applied at code generation time: - `sbe.precedence.checks.flagName`, which controls the symbol/macro used to enable precedence checks at build time in the generated C#/C++ code. It defaults to `"SBE_ENABLE_PRECEDENCE_CHECKS"`. - `sbe.precedence.checks.propName`, which controls the property name used to enable precedence checks at runtime in the generated Java code. It defaults to `"sbe.enable.precedence.checks"`. Now, users can run SbeTool with different values for these system properties to generate code with different enablement flags. Note above that the defaults are: - `SBE_ENABLE_PRECEDENCE_CHECKS` rather than `SBE_ENABLE_SEQUENCING_CHECKS`, and - `sbe.enable.precedence.checks` rather than `sbe.enable.sequencing.checks`. These changes and a change to another system property: - `sbe.generate.sequencing.checks` -> `sbe.generate.precedence.checks` address some feedback from Martin on the associated PR #948. * Address Mike's feedback around depending directly on system properties. Also, addresses Mike's feedback around the names of those system properties. In this commit, I've introduced a factory-like class: `PrecedenceChecks`. It creates models for message field access when the checks are enabled. It also provides a convenient place to group together some properties affecting the generation of field precedence checks. I have also renamed `AccessOrderModel` to `FieldPrecedenceModel` in this commit, as it aligns better with the system property names. * Address Mike's feedback: provide more specific diagram location. Previously, we only gave the (quite ambiguous) name of the inner class in the error message. Now, we give a qualified name that includes the codec/encoder/decoder class name (for C++, C#, and Java). * Validate PrecedenceChecks#Context in conclude. * Address Mike's feedback: move sys prop eval higher. In this commit, I've removed the `PrecedenceChecks#Configuration` class in favour of a static method within `TargetCodeGeneratorLoader`. Unfortunately, C# behaves differently to all the other code generators. To avoid duplicating the default configuration for precedence checks in the `CSharp` class, I've made the method publicly visible, which is a bit ugly. It has also introduced a cyclic dependency between the code generators, e.g., `JavaGenerator`, and `TargetCodeGeneratorLoader`, as in order to preserve the existing public signatures I have kept the old constructors around and supplied a default `PrecedenceChecks`. * Avoid cyclic dependency between classes. Move defaults out of property evaluation and into context. --- .gitignore | 5 + build.gradle | 26 +- csharp/sbe-generated/sbe-generated.csproj | 8 + .../sbe-tests/FieldAccessOrderCheckTests.cs | 3185 +++++++++++ .../java/uk/co/real_logic/sbe/SbeTool.java | 18 + .../generation/TargetCodeGeneratorLoader.java | 35 +- .../common/FieldPrecedenceModel.java | 1190 ++++ .../generation/common/PrecedenceChecks.java | 253 + .../sbe/generation/cpp/CppGenerator.java | 1264 ++++- .../sbe/generation/csharp/CSharp.java | 6 +- .../generation/csharp/CSharpGenerator.java | 933 +++- .../sbe/generation/java/JavaGenerator.java | 1109 +++- .../sbe/ir/generated/FrameCodecDecoder.java | 329 ++ .../sbe/ir/generated/FrameCodecEncoder.java | 237 + .../sbe/ir/generated/TokenCodecDecoder.java | 988 ++++ .../sbe/ir/generated/TokenCodecEncoder.java | 636 +++ sbe-tool/src/test/cpp/BoundsCheckTest.cpp | 61 +- sbe-tool/src/test/cpp/CMakeLists.txt | 9 + sbe-tool/src/test/cpp/CodeGenTest.cpp | 80 +- .../test/cpp/CompositeOffsetsCodeGenTest.cpp | 2 +- .../test/cpp/FieldAccessOrderCheckTest.cpp | 4937 +++++++++++++++++ .../sbe/FieldAccessOrderCheckTest.java | 3425 ++++++++++++ .../generation/java/JavaGeneratorTest.java | 93 +- .../sbe/generation/java/ReflectionUtil.java | 34 +- .../resources/field-order-check-schema.xml | 292 + 25 files changed, 18686 insertions(+), 469 deletions(-) create mode 100644 csharp/sbe-tests/FieldAccessOrderCheckTests.cs create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java create mode 100644 sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java create mode 100644 sbe-tool/src/test/resources/field-order-check-schema.xml diff --git a/.gitignore b/.gitignore index 117022a886..6769c8db69 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,9 @@ out # cmake cmake-build-debug codecs +.cmake +CMakeFiles +thirdparty # cpp build linux cppbuild/CMakeCache.txt @@ -101,10 +104,12 @@ csharp/sbe-generated/issue483 csharp/sbe-generated/issue560 csharp/sbe-generated/issue661 csharp/sbe-generated/since-deprecated +csharp/sbe-generated/order_check csharp/sbe-generated/mktdata/*.cs csharp/sbe-generated/uk_co_real_logic_sbe_benchmarks_fix csharp/sbe-tests/*.sbe csharp/nuget/ +csharp/csharp.sln.DotSettings.user # rust rust/target diff --git a/build.gradle b/build.gradle index 3838d1a1ce..3d08ca9f4a 100644 --- a/build.gradle +++ b/build.gradle @@ -229,6 +229,9 @@ subprojects { } javaLauncher.set(toolchainLauncher) + + systemProperty 'sbe.enable.ir.precedence.checks', 'true' + systemProperty 'sbe.enable.test.precedence.checks', 'true' } } @@ -279,9 +282,12 @@ project(':sbe-tool') { 'sbe.output.dir': generatedDir, 'sbe.target.language': 'Java', 'sbe.validation.stop.on.error': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.validation.xsd': validationXsdPath, + 'sbe.generate.precedence.checks': 'true', + 'sbe.java.precedence.checks.property.name': 'sbe.enable.test.precedence.checks') args = ['src/test/resources/json-printer-test-schema.xml', - 'src/test/resources/composite-elements-schema.xml'] + 'src/test/resources/composite-elements-schema.xml', + 'src/test/resources/field-order-check-schema.xml'] } jar { @@ -541,7 +547,8 @@ project(':sbe-benchmarks') { 'sbe.validation.stop.on.error': 'true', 'sbe.validation.xsd': validationXsdPath, 'sbe.java.encoding.buffer.type': 'org.agrona.concurrent.UnsafeBuffer', - 'sbe.java.decoding.buffer.type': 'org.agrona.concurrent.UnsafeBuffer') + 'sbe.java.decoding.buffer.type': 'org.agrona.concurrent.UnsafeBuffer', + 'sbe.generate.precedence.checks': 'false') args = ['src/main/resources/car.xml', 'src/main/resources/fix-message-samples.xml'] } @@ -730,13 +737,15 @@ tasks.register('generateCSharpCodecsTests', JavaExec) { 'sbe.output.dir': 'csharp/sbe-generated', 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', 'sbe.xinclude.aware': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.validation.xsd': validationXsdPath, + 'sbe.generate.precedence.checks': 'true') args = ['sbe-tool/src/test/resources/FixBinary.xml', 'sbe-tool/src/test/resources/issue435.xml', 'sbe-tool/src/test/resources/issue483.xml', 'sbe-tool/src/test/resources/issue560.xml', 'sbe-tool/src/test/resources/since-deprecated-test-schema.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', + 'sbe-tool/src/test/resources/field-order-check-schema.xml', 'sbe-benchmarks/src/main/resources/fix-message-samples.xml'] } @@ -753,7 +762,10 @@ tasks.register('generateJavaIrCodecs', JavaExec) { systemProperties( 'sbe.output.dir': 'sbe-tool/src/main/java', 'sbe.target.language': 'Java', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.validation.xsd': validationXsdPath, + 'sbe.generate.precedence.checks': 'true', + 'sbe.precedence.checks.flag.name': 'SBE_ENABLE_IR_PRECEDENCE_CHECKS', + 'sbe.java.precedence.checks.property.name': 'sbe.enable.ir.precedence.checks') args = ['sbe-tool/src/main/resources/sbe-ir.xml'] } @@ -763,7 +775,9 @@ tasks.register('generateCppIrCodecs', JavaExec) { systemProperties( 'sbe.output.dir': 'sbe-tool/src/main/cpp', 'sbe.target.language': 'cpp', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.validation.xsd': validationXsdPath, + 'sbe.generate.precedence.checks': 'true', + 'sbe.precedence.checks.flag.name': 'SBE_ENABLE_IR_PRECEDENCE_CHECKS') args = ['sbe-tool/src/main/resources/sbe-ir.xml'] } diff --git a/csharp/sbe-generated/sbe-generated.csproj b/csharp/sbe-generated/sbe-generated.csproj index 6b4fc7bdbc..806168d7d5 100644 --- a/csharp/sbe-generated/sbe-generated.csproj +++ b/csharp/sbe-generated/sbe-generated.csproj @@ -7,6 +7,14 @@ Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014. All rights reserved. + + TRACE,SBE_ENABLE_PRECEDENCE_CHECKS + + + + TRACE,SBE_ENABLE_PRECEDENCE_CHECKS + + diff --git a/csharp/sbe-tests/FieldAccessOrderCheckTests.cs b/csharp/sbe-tests/FieldAccessOrderCheckTests.cs new file mode 100644 index 0000000000..d0b7e16992 --- /dev/null +++ b/csharp/sbe-tests/FieldAccessOrderCheckTests.cs @@ -0,0 +1,3185 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Order.Check; +using Org.SbeTool.Sbe.Dll; + +namespace Org.SbeTool.Sbe.Tests +{ + [TestClass] + public class FieldAccessOrderCheckTests + { + private const int Offset = 0; + private readonly DirectBuffer _buffer = new DirectBuffer(); + private readonly MessageHeader _messageHeader = new MessageHeader(); + + [TestInitialize] + public void SetUp() + { + var byteArray = new byte[128]; + new Random().NextBytes(byteArray); + _buffer.Wrap(byteArray); + } + + [TestMethod] + public void AllowsEncodingAndDecodingVariableLengthFieldsInSchemaDefinedOrder() + { + var encoder = new MultipleVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.SetB("abc"); + encoder.SetC("def"); + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + Assert.AreEqual("abc", decoder.GetB()); + Assert.AreEqual("def", decoder.GetC()); + Assert.IsTrue(decoder.ToString().Contains("A=42|B='abc'|C='def'")); + } + + [TestMethod] + public void AllowsReEncodingTopLevelPrimitiveFields() + { + var encoder = new MultipleVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.SetB("abc"); + encoder.SetC("def"); + encoder.A = 43; + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(43, decoder.A); + Assert.AreEqual("abc", decoder.GetB()); + Assert.AreEqual("def", decoder.GetC()); + } + + [TestMethod] + public void DisallowsSkippingEncodingOfVariableLengthField1() + { + var encoder = new MultipleVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var exception = Assert.ThrowsException(() => encoder.SetC("def")); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"c\" in state: V0_BLOCK")); + } + + [TestMethod] + public void DisallowsSkippingEncodingOfVariableLengthField2() + { + var encoder = new MultipleVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var def = Encoding.ASCII.GetBytes("def"); + var exception = Assert.ThrowsException(() => encoder.SetC(def)); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"c\" in state: V0_BLOCK")); + } + + [TestMethod] + public void DisallowsReEncodingEarlierVariableLengthFields() + { + var encoder = new MultipleVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.SetB("abc"); + encoder.SetC("def"); + var exception = Assert.ThrowsException(() => encoder.SetB("ghi")); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b\" in state: V0_C_DONE")); + } + + [TestMethod] + public void DisallowsReEncodingLatestVariableLengthField() + { + var encoder = new MultipleVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.SetB("abc"); + encoder.SetC("def"); + var exception = Assert.ThrowsException(() => encoder.SetC("ghi")); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"c\" in state: V0_C_DONE")); + } + + [TestMethod] + public void DisallowsSkippingDecodingOfVariableLengthField1() + { + var decoder = DecodeUntilVarLengthFields(); + + var exception = Assert.ThrowsException(() => decoder.GetC()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"c\" in state: V0_BLOCK")); + } + + [TestMethod] + public void DisallowsSkippingDecodingOfVariableLengthField2() + { + var decoder = DecodeUntilVarLengthFields(); + + var exception = Assert.ThrowsException(() => decoder.GetCBytes()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"c\" in state: V0_BLOCK")); + } + + [TestMethod] + public void DisallowsSkippingDecodingOfVariableLengthField3() + { + var decoder = DecodeUntilVarLengthFields(); + + var exception = Assert.ThrowsException(() => decoder.GetC(new byte[8])); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"c\" in state: V0_BLOCK")); + } + + [TestMethod] + public void AllowsRepeatedDecodingOfVariableLengthDataLength() + { + var decoder = DecodeUntilVarLengthFields(); + Assert.AreEqual(3, decoder.BLength()); + Assert.AreEqual(3, decoder.BLength()); + Assert.AreEqual(3, decoder.BLength()); + Assert.AreEqual("abc", decoder.GetB()); + Assert.AreEqual(3, decoder.CLength()); + Assert.AreEqual(3, decoder.CLength()); + Assert.AreEqual(3, decoder.CLength()); + } + + [TestMethod] + public void DisallowsReDecodingEarlierVariableLengthField() + { + var decoder = DecodeUntilVarLengthFields(); + Assert.AreEqual("abc", decoder.GetB()); + Assert.AreEqual("def", decoder.GetC()); + + var exception = Assert.ThrowsException(() => decoder.GetB()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b\" in state: V0_C_DONE")); + } + + [TestMethod] + public void DisallowsReDecodingLatestVariableLengthField() + { + var decoder = DecodeUntilVarLengthFields(); + Assert.AreEqual("abc", decoder.GetB()); + Assert.AreEqual("def", decoder.GetC()); + + var exception = Assert.ThrowsException(() => decoder.GetC()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"c\" in state: V0_C_DONE")); + } + + private MultipleVarLength DecodeUntilVarLengthFields() + { + var encoder = new MultipleVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.SetB("abc"); + encoder.SetC("def"); + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + + return decoder; + } + + [TestMethod] + public void AllowsEncodingAndDecodingGroupAndVariableLengthFieldsInSchemaDefinedOrder() + { + var encoder = new GroupAndVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder.Next().C = 1; + bEncoder.Next().C = 2; + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(2, bDecoder.Count); + Assert.AreEqual(1, bDecoder.Next().C); + Assert.AreEqual(2, bDecoder.Next().C); + Assert.AreEqual("abc", decoder.GetD()); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=[(C=1),(C=2)]|D='abc'")); + } + + [TestMethod] + public void AllowsEncodingAndDecodingEmptyGroupAndVariableLengthFieldsInSchemaDefinedOrder() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.BCount(0); + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bs = decoder.B; + Assert.AreEqual(0, bs.Count); + Assert.AreEqual("abc", decoder.GetD()); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=[]|D='abc'")); + } + + [TestMethod] + public void AllowsEncoderToResetZeroGroupLengthToZero() + { + var encoder = new GroupAndVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.BCount(0).ResetCountToIndex(); + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(0, bDecoder.Count); + Assert.AreEqual("abc", decoder.GetD()); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=[]|D='abc'")); + } + + [TestMethod] + public void AllowsEncoderToResetNonZeroGroupLengthToZeroBeforeCallingNext() + { + var encoder = new GroupAndVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.BCount(2).ResetCountToIndex(); + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(0, bDecoder.Count); + Assert.AreEqual("abc", decoder.GetD()); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=[]|D='abc'")); + } + + [TestMethod] + public void AllowsEncoderToResetNonZeroGroupLengthToNonZero() + { + var encoder = new GroupAndVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder.Next().C = 43; + bEncoder.ResetCountToIndex(); + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(43, bDecoder.Next().C); + Assert.AreEqual("abc", decoder.GetD()); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=[(C=43)]|D='abc'")); + } + + [TestMethod] + public void DisallowsEncoderToResetGroupLengthMidGroupElement() + { + var encoder = new NestedGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2).Next(); + bEncoder.C = 43; + var exception = Assert.ThrowsException(() => bEncoder.ResetCountToIndex()); + Assert.IsTrue(exception.Message.Contains( + "Cannot reset count of repeating group \"b\" in state: V0_B_N_BLOCK")); + } + + [TestMethod] + public void DisallowsEncodingGroupElementBeforeCallingNext() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(1); + var exception = Assert.ThrowsException(() => bEncoder.C = 1); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsDecodingGroupElementBeforeCallingNext() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder + .Next() + .C = 1; + bEncoder.Next() + .C = 2; + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bs = decoder.B; + Assert.AreEqual(2, bs.Count); + var exception = Assert.ThrowsException(() => _ = bs.C); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsSkippingEncodingOfGroup() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var exception = Assert.ThrowsException(() => encoder.SetD("abc")); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"d\" in state: V0_BLOCK")); + } + + [TestMethod] + public void DisallowsReEncodingVariableLengthFieldAfterGroup() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder + .Next() + .C = 1; + bEncoder.Next() + .C = 2; + encoder.SetD("abc"); + var exception = Assert.ThrowsException(() => encoder.SetD("def")); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"d\" in state: V0_D_DONE")); + } + + [TestMethod] + public void DisallowsReEncodingGroupCount() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder + .Next() + .C = 1; + bEncoder.Next() + .C = 2; + encoder.SetD("abc"); + var exception = Assert.ThrowsException(() => encoder.BCount(1)); + Assert.IsTrue( + exception.Message.Contains("Cannot encode count of repeating group \"b\" in state: V0_D_DONE")); + } + + [TestMethod] + public void DisallowsMissedDecodingOfGroupBeforeVariableLengthField() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder + .Next() + .C = 1; + bEncoder + .Next() + .C = 2; + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var exception = Assert.ThrowsException(() => decoder.GetD()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"d\" in state: V0_BLOCK")); + } + + [TestMethod] + public void DisallowsReDecodingVariableLengthFieldAfterGroup() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder + .Next() + .C = 1; + bEncoder + .Next() + .C = 2; + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bs = decoder.B; + Assert.AreEqual(2, bs.Count); + Assert.AreEqual(1, bs.Next().C); + Assert.AreEqual(2, bs.Next().C); + Assert.AreEqual("abc", decoder.GetD()); + var exception = Assert.ThrowsException(() => decoder.GetD()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"d\" in state: V0_D_DONE")); + } + + [TestMethod] + public void DisallowsReDecodingGroupAfterVariableLengthField() + { + var encoder = new GroupAndVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder + .Next() + .C = 1; + bEncoder + .Next() + .C = 2; + encoder.SetD("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupAndVarLength() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bs = decoder.B; + Assert.AreEqual(2, bs.Count); + Assert.AreEqual(1, bs.Next().C); + Assert.AreEqual(2, bs.Next().C); + Assert.AreEqual("abc", decoder.GetD()); + var exception = Assert.ThrowsException(() => decoder.B); + Assert.IsTrue( + exception.Message.Contains("Cannot decode count of repeating group \"b\" in state: V0_D_DONE")); + } + + [TestMethod] + public void AllowsEncodingAndDecodingVariableLengthFieldInsideGroupInSchemaDefinedOrder() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder + .Next() + .C = 1; + bEncoder + .SetD("abc"); + bEncoder + .Next() + .C = 2; + bEncoder + .SetD("def"); + encoder.SetE("ghi"); + encoder.CheckEncodingIsComplete(); + + var decoder = new VarLengthInsideGroup() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bs = decoder.B; + Assert.AreEqual(2, bs.Count); + Assert.AreEqual(1, bs.Next().C); + Assert.AreEqual("abc", bs.GetD()); + Assert.AreEqual(2, bs.Next().C); + Assert.AreEqual("def", bs.GetD()); + Assert.AreEqual("ghi", decoder.GetE()); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=[(C=1|D='abc'),(C=2|D='def')]|E='ghi'")); + } + + [TestMethod] + public void DisallowsMissedGroupElementVariableLengthFieldToEncodeAtTopLevel() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.BCount(1).Next().C = 1; + var exception = Assert.ThrowsException(() => encoder.SetE("abc")); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"e\" in state: V0_B_1_BLOCK")); + } + + [TestMethod] + public void DisallowsMissedGroupElementVariableLengthFieldToEncodeNextElement() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2).Next(); + var exception = Assert.ThrowsException(() => bEncoder.Next()); + Assert.IsTrue( + exception.Message.Contains( + "Cannot access next element in repeating group \"b\" in state: V0_B_N_BLOCK")); + } + + [TestMethod] + public void DisallowsMissedGroupElementEncoding() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2); + bEncoder.Next().C = 1; + bEncoder.SetD("abc"); + var exception = Assert.ThrowsException(() => encoder.SetE("abc")); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"e\" in state: V0_B_N_D_DONE")); + } + + [TestMethod] + public void DisallowsReEncodingGroupElementVariableLengthField() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 1; + bEncoder.SetD("abc"); + encoder.SetE("def"); + var exception = Assert.ThrowsException(() => bEncoder.SetD("ghi")); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.d\" in state: V0_E_DONE")); + } + + [TestMethod] + public void DisallowsReDecodingGroupElementVariableLengthField() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2).Next(); + bEncoder.C = 1; + bEncoder.SetD("abc"); + bEncoder.Next().C = 2; + bEncoder.SetD("def"); + encoder.SetE("ghi"); + encoder.CheckEncodingIsComplete(); + + var decoder = new VarLengthInsideGroup() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(2, bDecoder.Count); + Assert.AreEqual(1, bDecoder.Next().C); + Assert.AreEqual("abc", bDecoder.GetD()); + var exception = Assert.ThrowsException(() => bDecoder.GetD()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.d\" in state: V0_B_N_D_DONE")); + } + + [TestMethod] + public void DisallowsMissedDecodingOfGroupElementVariableLengthFieldToNextElement() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2).Next(); + bEncoder.C = 1; + bEncoder.SetD("abc"); + bEncoder.Next().C = 2; + bEncoder.SetD("def"); + encoder.SetE("ghi"); + encoder.CheckEncodingIsComplete(); + + var decoder = new VarLengthInsideGroup() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(2, bDecoder.Count); + Assert.AreEqual(1, bDecoder.Next().C); + var exception = Assert.ThrowsException(() => bDecoder.Next()); + Assert.IsTrue( + exception.Message.Contains( + "Cannot access next element in repeating group \"b\" in state: V0_B_N_BLOCK")); + } + + [TestMethod] + public void DisallowsMissedDecodingOfGroupElementVariableLengthFieldToTopLevel() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 1; + bEncoder.SetD("abc"); + encoder.SetE("ghi"); + encoder.CheckEncodingIsComplete(); + + var decoder = new VarLengthInsideGroup() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(1, bDecoder.Next().C); + var exception = Assert.ThrowsException(() => decoder.GetE()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"e\" in state: V0_B_1_BLOCK")); + } + + [TestMethod] + public void DisallowsMissedDecodingOfGroupElement() + { + var encoder = new VarLengthInsideGroup() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2).Next(); + bEncoder.C = 1; + bEncoder.SetD("abc"); + bEncoder.Next().C = 2; + bEncoder.SetD("def"); + encoder.SetE("ghi"); + encoder.CheckEncodingIsComplete(); + + var decoder = new VarLengthInsideGroup() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(2, bDecoder.Count); + Assert.AreEqual(1, bDecoder.Next().C); + var exception = Assert.ThrowsException(() => decoder.GetE()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"e\" in state: V0_B_N_BLOCK")); + } + + [TestMethod] + public void AllowsEncodingNestedGroupsInSchemaDefinedOrder() + { + var encoder = new NestedGroups().WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(2).Next(); + bEncoder.C = 1; + var dEncoder = bEncoder.DCount(2).Next(); + dEncoder.E = 2; + dEncoder = dEncoder.Next(); + dEncoder.E = 3; + var fEncoder = bEncoder.FCount(1).Next(); + fEncoder.G = 4; + bEncoder = bEncoder.Next(); + bEncoder.C = 5; + dEncoder = bEncoder.DCount(1).Next(); + dEncoder.E = 6; + fEncoder = bEncoder.FCount(1).Next(); + fEncoder.G = 7; + var hEncoder = encoder.HCount(1).Next(); + hEncoder.I = 8; + encoder.CheckEncodingIsComplete(); + + var decoder = new NestedGroups().WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(2, bDecoder.Count); + var b0 = bDecoder.Next(); + Assert.AreEqual(1, b0.C); + var b0ds = b0.D; + Assert.AreEqual(2, b0ds.Count); + Assert.AreEqual(2, b0ds.Next().E); + Assert.AreEqual(3, b0ds.Next().E); + var b0Fs = b0.F; + Assert.AreEqual(1, b0Fs.Count); + Assert.AreEqual(4, b0Fs.Next().G); + var b1 = bDecoder.Next(); + Assert.AreEqual(5, b1.C); + var b1ds = b1.D; + Assert.AreEqual(1, b1ds.Count); + Assert.AreEqual(6, b1ds.Next().E); + var b1Fs = b1.F; + Assert.AreEqual(1, b1Fs.Count); + Assert.AreEqual(7, b1Fs.Next().G); + var hs = decoder.H; + Assert.AreEqual(1, hs.Count); + Assert.AreEqual(8, hs.Next().I); + Assert.IsTrue(decoder.ToString() + .Contains("A=42|B=[(C=1|D=[(E=2),(E=3)]|F=[(G=4)]),(C=5|D=[(E=6)]|F=[(G=7)])]|H=[(I=8)]")); + } + + [TestMethod] + public void AllowsEncodingEmptyNestedGroupsInSchemaDefinedOrder() + { + var encoder = new NestedGroups().WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.BCount(0); + encoder.HCount(0); + encoder.CheckEncodingIsComplete(); + + var decoder = new NestedGroups().WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(0, bDecoder.Count); + var hDecoder = decoder.H; + Assert.AreEqual(0, hDecoder.Count); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=[]|H=[]")); + } + + [TestMethod] + public void DisallowsMissedEncodingOfNestedGroup() + { + var encoder = new NestedGroups().WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 1; + Exception exception = Assert.ThrowsException(() => bEncoder.FCount(1)); + Assert.IsTrue( + exception.Message.Contains("Cannot encode count of repeating group \"b.f\" in state: V0_B_1_BLOCK")); + } + + [TestMethod] + public void AllowsEncodingAndDecodingCompositeInsideGroupInSchemaDefinedOrder() + { + var encoder = new CompositeInsideGroup().WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1).Next(); + var cEncoder = bEncoder.C; + cEncoder.X = 3; + cEncoder.Y = 4; + encoder.CheckEncodingIsComplete(); + + var decoder = new CompositeInsideGroup().WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aDecoder = decoder.A; + Assert.AreEqual(1, aDecoder.X); + Assert.AreEqual(2, aDecoder.Y); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + var cDecoder = bDecoder.Next().C; + Assert.AreEqual(3, cDecoder.X); + Assert.AreEqual(4, cDecoder.Y); + Assert.IsTrue(decoder.ToString().Contains("A=(X=1|Y=2)|B=[(C=(X=3|Y=4))]")); + } + + [TestMethod] + public void DisallowsEncodingCompositeInsideGroupBeforeCallingNext() + { + var encoder = new CompositeInsideGroup().WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1); + Exception exception = Assert.ThrowsException(() => bEncoder.C); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void AllowsReEncodingTopLevelCompositeViaReWrap() + { + var encoder = new CompositeInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C.X = 3; + bEncoder.C.Y = 4; + aEncoder = encoder.A; + aEncoder.X = 5; + aEncoder.Y = 6; + encoder.CheckEncodingIsComplete(); + + var decoder = new CompositeInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var a = decoder.A; + Assert.AreEqual(5, a.X); + Assert.AreEqual(6, a.Y); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + var c = b.Next().C; + Assert.AreEqual(3, c.X); + Assert.AreEqual(4, c.Y); + } + + [TestMethod] + public void AllowsReEncodingTopLevelCompositeViaEncoderReference() + { + var encoder = new CompositeInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C.X = 3; + bEncoder.C.Y = 4; + aEncoder.X = 5; + aEncoder.Y = 6; + encoder.CheckEncodingIsComplete(); + + var decoder = new CompositeInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var a = decoder.A; + Assert.AreEqual(5, a.X); + Assert.AreEqual(6, a.Y); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + var c = b.Next().C; + Assert.AreEqual(3, c.X); + Assert.AreEqual(4, c.Y); + } + + [TestMethod] + public void AllowsReEncodingGroupElementCompositeViaReWrap() + { + var encoder = new CompositeInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1).Next(); + var cEncoder = bEncoder.C; + cEncoder.X = 3; + cEncoder.Y = 4; + cEncoder = bEncoder.C; + cEncoder.X = 5; + cEncoder.Y = 6; + encoder.CheckEncodingIsComplete(); + + var decoder = new CompositeInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var a = decoder.A; + Assert.AreEqual(1, a.X); + Assert.AreEqual(2, a.Y); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + var c = b.Next().C; + Assert.AreEqual(5, c.X); + Assert.AreEqual(6, c.Y); + } + + [TestMethod] + public void AllowsReEncodingGroupElementCompositeViaEncoderReference() + { + var encoder = new CompositeInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1).Next(); + var cEncoder = bEncoder.C; + cEncoder.X = 3; + cEncoder.Y = 4; + cEncoder.X = 5; + cEncoder.Y = 6; + encoder.CheckEncodingIsComplete(); + + var decoder = new CompositeInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var a = decoder.A; + Assert.AreEqual(1, a.X); + Assert.AreEqual(2, a.Y); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + var c = b.Next().C; + Assert.AreEqual(5, c.X); + Assert.AreEqual(6, c.Y); + } + + [TestMethod] + public void AllowsReDecodingTopLevelCompositeViaReWrap() + { + var encoder = new CompositeInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1).Next(); + var cEncoder = bEncoder.C; + cEncoder.X = 3; + cEncoder.Y = 4; + encoder.CheckEncodingIsComplete(); + + var decoder = new CompositeInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var a1 = decoder.A; + Assert.AreEqual(1, a1.X); + Assert.AreEqual(2, a1.Y); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + var c = b.Next().C; + Assert.AreEqual(3, c.X); + Assert.AreEqual(4, c.Y); + var a2 = decoder.A; + Assert.AreEqual(1, a2.X); + Assert.AreEqual(2, a2.Y); + } + + [TestMethod] + public void AllowsReDecodingTopLevelCompositeViaEncoderReference() + { + var encoder = new CompositeInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1).Next(); + var cEncoder = bEncoder.C; + cEncoder.X = 3; + cEncoder.Y = 4; + encoder.CheckEncodingIsComplete(); + + var decoder = new CompositeInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var a = decoder.A; + Assert.AreEqual(1, a.X); + Assert.AreEqual(2, a.Y); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + var c = b.Next().C; + Assert.AreEqual(3, c.X); + Assert.AreEqual(4, c.Y); + Assert.AreEqual(1, a.X); + Assert.AreEqual(2, a.Y); + } + + [TestMethod] + public void AllowsReDecodingGroupElementCompositeViaEncoderReference() + { + var encoder = new CompositeInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.A; + aEncoder.X = 1; + aEncoder.Y = 2; + var bEncoder = encoder.BCount(1).Next(); + var cEncoder = bEncoder.C; + cEncoder.X = 3; + cEncoder.Y = 4; + encoder.CheckEncodingIsComplete(); + + var decoder = new CompositeInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var a = decoder.A; + Assert.AreEqual(1, a.X); + Assert.AreEqual(2, a.Y); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + var c = b.Next().C; + Assert.AreEqual(3, c.X); + Assert.AreEqual(4, c.Y); + Assert.AreEqual(3, c.X); + Assert.AreEqual(4, c.Y); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedPrimitiveField() + { + var encoder = new AddPrimitiveV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.B = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddPrimitiveV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(2, decoder.B); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingPrimitiveFieldAsNullValue() + { + var encoder = new AddPrimitiveV0() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddPrimitiveV1() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(AddPrimitiveV1.BNullValue, decoder.B); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedPrimitiveFieldBeforeGroup() + { + var encoder = new AddPrimitiveBeforeGroupV1() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = 3; + encoder.BCount(1).Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddPrimitiveBeforeGroupV1() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(3, decoder.D); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + Assert.AreEqual(2, b.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingPrimitiveFieldBeforeGroupAsNullValue() + { + var encoder = new AddPrimitiveBeforeGroupV0() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.BCount(1).Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddPrimitiveBeforeGroupV1() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(AddPrimitiveBeforeGroupV1.DNullValue, decoder.D); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + Assert.AreEqual(2, b.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToSkipPresentButAddedPrimitiveFieldBeforeGroup() + { + var encoder = new AddPrimitiveBeforeGroupV1() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = 3; + encoder.BCount(1).Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddPrimitiveBeforeGroupV1() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + Assert.AreEqual(2, b.Next().C); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedPrimitiveFieldBeforeGroup() + { + var encoder = new AddPrimitiveBeforeGroupV1() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = 3; + encoder.BCount(1).Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddPrimitiveBeforeGroupV0() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + Assert.AreEqual(2, b.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedPrimitiveFieldBeforeVarData() + { + var encoder = new AddPrimitiveBeforeVarDataV1() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.C = 3; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new AddPrimitiveBeforeVarDataV1() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(3, decoder.C); + Assert.AreEqual("abc", decoder.GetB()); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingPrimitiveFieldBeforeVarDataAsNullValue() + { + var encoder = new AddPrimitiveBeforeVarDataV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddPrimitiveBeforeVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(AddPrimitiveBeforeVarDataV1.CNullValue, decoder.C); + Assert.AreEqual("abc", decoder.GetB()); + } + + [TestMethod] + public void AllowsNewDecoderToSkipPresentButAddedPrimitiveFieldBeforeVarData() + { + var encoder = new AddPrimitiveBeforeVarDataV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.C = 3; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new AddPrimitiveBeforeVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual("abc", decoder.GetB()); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedPrimitiveFieldBeforeVarData() + { + var encoder = new AddPrimitiveBeforeVarDataV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.C = 3; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddPrimitiveBeforeVarDataV0(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual("abc", decoder.GetB()); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedPrimitiveFieldInsideGroup() + { + var encoder = new AddPrimitiveInsideGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var group1 = encoder.BCount(1); + group1.Next(); + group1.C = 2; + group1.D = 3; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddPrimitiveInsideGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var group2 = decoder.B; + Assert.AreEqual(1, group2.Count); + Assert.AreEqual(2, group2.Next().C); + Assert.AreEqual(3, group2.D); + } + + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingPrimitiveFieldInsideGroupAsNullValue() + { + var encoder = new AddPrimitiveInsideGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.BCount(1).Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddPrimitiveInsideGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + Assert.AreEqual(2, b.Next().C); + Assert.AreEqual(AddPrimitiveInsideGroupV1.BGroup.DNullValue, b.D); + } + + [TestMethod] + public void AllowsNewDecoderToSkipPresentButAddedPrimitiveFieldInsideGroup() + { + var encoder = new AddPrimitiveInsideGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var group = encoder.BCount(2); + group.Next().C = 2; + group.D = 3; + group.Next().C = 4; + group.D = 5; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddPrimitiveInsideGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var b = decoder.B; + Assert.AreEqual(2, b.Count); + Assert.AreEqual(2, b.Next().C); + Assert.AreEqual(4, b.Next().C); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedPrimitiveFieldInsideGroup() + { + var encoder = new AddPrimitiveInsideGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var group = encoder.BCount(2); + group.Next().C = 2; + group.D = 3; + group.Next().C = 4; + group.D = 5; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddPrimitiveInsideGroupV0(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var b = decoder.B; + Assert.AreEqual(2, b.Count); + Assert.AreEqual(2, b.Next().C); + Assert.AreEqual(4, b.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedGroupBeforeVarData() + { + var encoder = new AddGroupBeforeVarDataV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var groupEncoder = encoder.CCount(1); + groupEncoder.Next().D = 2; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new AddGroupBeforeVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var groupDecoder = decoder.C; + Assert.AreEqual(1, groupDecoder.Count); + Assert.AreEqual(2, groupDecoder.Next().D); + Assert.AreEqual("abc", decoder.GetB()); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingGroupBeforeVarDataAsNullValue() + { + var encoder = new AddGroupBeforeVarDataV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddGroupBeforeVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var groupDecoder = decoder.C; + Assert.AreEqual(0, groupDecoder.Count); + Assert.AreEqual("abc", decoder.GetB()); + Assert.IsTrue(decoder.ToString().Contains("A=1|C=[]|B='abc'")); + } + + [TestMethod] + public void AllowsNewDecoderToSkipMissingGroupBeforeVarData() + { + var encoder = new AddGroupBeforeVarDataV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddGroupBeforeVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual("abc", decoder.GetB()); + } + + [TestMethod] + public void DisallowsNewDecoderToSkipPresentButAddedGroupBeforeVarData() + { + var encoder = new AddGroupBeforeVarDataV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var groupEncoder = encoder.CCount(1); + groupEncoder.Next().D = 2; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new AddGroupBeforeVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + + var exception = Assert.ThrowsException(() => decoder.GetB()); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b\" in state: V1_BLOCK")); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedGroupBeforeVarData() + { + var encoder = new AddGroupBeforeVarDataV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + _messageHeader.NumGroups = 1; + encoder.A = 1; + var groupEncoder = encoder.CCount(1); + groupEncoder.Next().D = 2; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddGroupBeforeVarDataV0(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + + for (int i = 0; i < _messageHeader.NumGroups; i++) + { + SkipGroup(decoder); + } + + Assert.AreEqual("abc", decoder.GetB()); + } + + private void SkipGroup(AddGroupBeforeVarDataV0 decoder) + { + var groupSizeEncoding = new GroupSizeEncoding(); + groupSizeEncoding.Wrap(_buffer, decoder.Limit, MessageHeader.SbeSchemaVersion); + var bytesToSkip = GroupSizeEncoding.Size + + groupSizeEncoding.BlockLength * groupSizeEncoding.NumInGroup; + decoder.Limit += bytesToSkip; + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedEnumFieldBeforeGroup() + { + var encoder = new AddEnumBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = Direction.BUY; + var groupEncoder = encoder.BCount(1); + groupEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddEnumBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(Direction.BUY, decoder.D); + var groupDecoder = decoder.B; + Assert.AreEqual(1, groupDecoder.Count); + Assert.AreEqual(2, groupDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingEnumFieldBeforeGroupAsNullValue() + { + var encoder = new AddEnumBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var myGroup = encoder.BCount(1); + myGroup.Next(); + myGroup.C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddEnumBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(Direction.NULL_VALUE, decoder.D); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + Assert.AreEqual(2, b.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToSkipPresentButAddedEnumFieldBeforeGroup() + { + var encoder = new AddEnumBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = Direction.SELL; + encoder.BCount(1).Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddEnumBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + Assert.AreEqual(2, b.Next().C); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedEnumFieldBeforeGroup() + { + var encoder = new AddEnumBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = Direction.BUY; + encoder.BCount(1).Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddEnumBeforeGroupV0(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var b = decoder.B; + Assert.AreEqual(1, b.Count); + Assert.AreEqual(2, b.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedCompositeFieldBeforeGroup() + { + var encoder = new AddCompositeBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var dEncoder = encoder.D; + dEncoder.X = -1; + dEncoder.Y = -2; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddCompositeBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var d = decoder.D; + Assert.IsNotNull(d); + Assert.AreEqual(-1, d.X); + Assert.AreEqual(-2, d.Y); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingCompositeFieldBeforeGroupAsNullValue() + { + var encoder = new AddCompositeBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddCompositeBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.IsNull(decoder.D); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToSkipPresentButAddedCompositeFieldBeforeGroup() + { + var encoder = new AddCompositeBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var dEncoder = encoder.D; + dEncoder.X = -1; + dEncoder.Y = -2; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddCompositeBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedCompositeFieldBeforeGroup() + { + var encoder = new AddCompositeBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var dEncoder = encoder.D; + dEncoder.X = -1; + dEncoder.Y = -2; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddCompositeBeforeGroupV0(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedArrayFieldBeforeGroup1() + { + var encoder = new AddArrayBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var dEncoder = encoder.DAsSpan(); + dEncoder[0] = 1; + dEncoder[1] = 2; + dEncoder[2] = 3; + dEncoder[3] = 4; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddArrayBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual((short)1, decoder.GetD(0)); + Assert.AreEqual((short)2, decoder.GetD(1)); + Assert.AreEqual((short)3, decoder.GetD(2)); + Assert.AreEqual((short)4, decoder.GetD(3)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedArrayFieldBeforeGroup2() + { + var encoder = new AddArrayBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetD(0, 1); + encoder.SetD(1, 2); + encoder.SetD(2, 3); + encoder.SetD(3, 4); + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddArrayBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual((short)1, decoder.GetD(0)); + Assert.AreEqual((short)2, decoder.GetD(1)); + Assert.AreEqual((short)3, decoder.GetD(2)); + Assert.AreEqual((short)4, decoder.GetD(3)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue1() + { + var encoder = new AddArrayBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddArrayBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(AddArrayBeforeGroupV1.DNullValue, decoder.GetD(0)); + Assert.AreEqual(AddArrayBeforeGroupV1.DNullValue, decoder.GetD(1)); + Assert.AreEqual(AddArrayBeforeGroupV1.DNullValue, decoder.GetD(2)); + Assert.AreEqual(AddArrayBeforeGroupV1.DNullValue, decoder.GetD(3)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue2() + { + var encoder = new AddArrayBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddArrayBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(0, decoder.D.Length); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToSkipPresentButAddedArrayFieldBeforeGroup() + { + var encoder = new AddArrayBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetD(0, 1); + encoder.SetD(1, 2); + encoder.SetD(2, 3); + encoder.SetD(3, 4); + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddArrayBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedArrayFieldBeforeGroup() + { + var encoder = new AddArrayBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetD(0, 1); + encoder.SetD(1, 2); + encoder.SetD(2, 3); + encoder.SetD(3, 4); + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddArrayBeforeGroupV0(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedBitSetFieldBeforeGroup() + { + var encoder = new AddBitSetBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = Flags.Guacamole | Flags.Cheese; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddBitSetBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.IsNotNull(decoder.D); + Assert.AreEqual(true, decoder.D.HasFlag(Flags.Guacamole)); + Assert.AreEqual(true, decoder.D.HasFlag(Flags.Cheese)); + Assert.AreEqual(false, decoder.D.HasFlag(Flags.SourCream)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingBitSetFieldBeforeGroupAsNullValue() + { + var encoder = new AddBitSetBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddBitSetBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual((byte)decoder.D, 0); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToSkipPresentButAddedBitSetFieldBeforeGroup() + { + var encoder = new AddBitSetBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = Flags.Guacamole | Flags.Cheese; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddBitSetBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedBitSetFieldBeforeGroup() + { + var encoder = new AddBitSetBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.D = Flags.Guacamole | Flags.Cheese; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddBitSetBeforeGroupV0(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsEncodingAndDecodingEnumInsideGroupInSchemaDefinedOrder() + { + var encoder = new EnumInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = Direction.BUY; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = Direction.SELL; + encoder.CheckEncodingIsComplete(); + + var decoder = new EnumInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(Direction.BUY, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(Direction.SELL, bDecoder.Next().C); + Assert.IsTrue(decoder.ToString().Contains("A=BUY|B=[(C=SELL)]")); + } + + [TestMethod] + public void DisallowsEncodingEnumInsideGroupBeforeCallingNext() + { + var encoder = new EnumInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = Direction.BUY; + var bEncoder = encoder.BCount(1); + var exception = Assert.ThrowsException(() => bEncoder.C = Direction.SELL); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsDecodingEnumInsideGroupBeforeCallingNext() + { + var encoder = new EnumInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = Direction.BUY; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = Direction.SELL; + encoder.CheckEncodingIsComplete(); + + var decoder = new EnumInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(Direction.BUY, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + var exception = Assert.ThrowsException(() => + { + var _ = bDecoder.C; + }); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void AllowsReEncodingTopLevelEnum() + { + var encoder = new EnumInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = Direction.BUY; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = Direction.SELL; + + encoder.A = Direction.SELL; + encoder.CheckEncodingIsComplete(); + + var decoder = new EnumInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(Direction.SELL, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(Direction.SELL, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsEncodingAndDecodingBitSetInsideGroupInSchemaDefinedOrder() + { + var encoder = new BitSetInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = Flags.Cheese | Flags.Guacamole; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = Flags.SourCream; + encoder.CheckEncodingIsComplete(); + + var decoder = new BitSetInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(true, decoder.A.HasFlag((Flags.Guacamole))); + Assert.AreEqual(true, decoder.A.HasFlag(Flags.Cheese)); + Assert.AreEqual(false, decoder.A.HasFlag(Flags.SourCream)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + var cDecoder = bDecoder.Next().C; + Assert.AreEqual(false, cDecoder.HasFlag((Flags.Guacamole))); + Assert.AreEqual(false, cDecoder.HasFlag(Flags.Cheese)); + Assert.AreEqual(true, cDecoder.HasFlag(Flags.SourCream)); + Assert.IsTrue(decoder.ToString().Contains("A={Guacamole, Cheese}|B=[(C={SourCream})]")); + } + + [TestMethod] + public void DisallowsEncodingBitSetInsideGroupBeforeCallingNext() + { + var encoder = new BitSetInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = Flags.Cheese | Flags.Guacamole; + var bEncoder = encoder.BCount(1); + var exception = Assert.ThrowsException(() => + { + var _ = bEncoder.C; + }); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsDecodingBitSetInsideGroupBeforeCallingNext() + { + var encoder = new BitSetInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = Flags.Cheese | Flags.Guacamole; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = Flags.SourCream; + encoder.CheckEncodingIsComplete(); + + var decoder = new BitSetInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(true, decoder.A.HasFlag((Flags.Guacamole))); + Assert.AreEqual(true, decoder.A.HasFlag(Flags.Cheese)); + Assert.AreEqual(false, decoder.A.HasFlag(Flags.SourCream)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + var exception = Assert.ThrowsException(() => + { + var _ = bDecoder.C; + }); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void AllowsReEncodingTopLevelBitSetViaReWrap() + { + var encoder = new BitSetInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = Flags.Cheese | Flags.Guacamole; + var bEncoder = encoder.BCount(1); + bEncoder.Next().C = Flags.SourCream; + + encoder.A |= Flags.SourCream; + encoder.CheckEncodingIsComplete(); + + var decoder = new BitSetInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(true, decoder.A.HasFlag((Flags.Guacamole))); + Assert.AreEqual(true, decoder.A.HasFlag(Flags.Cheese)); + Assert.AreEqual(true, decoder.A.HasFlag(Flags.SourCream)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + var cDecoder = bDecoder.Next().C; + Assert.AreEqual(false, cDecoder.HasFlag((Flags.Guacamole))); + Assert.AreEqual(false, cDecoder.HasFlag(Flags.Cheese)); + Assert.AreEqual(true, cDecoder.HasFlag(Flags.SourCream)); + } + + [TestMethod] + public void AllowsEncodingAndDecodingArrayInsideGroupInSchemaDefinedOrder() + { + var encoder = new ArrayInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA(0, 1); + encoder.SetA(1, 2); + encoder.SetA(2, 3); + encoder.SetA(3, 4); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.SetC(0, 5); + bEncoder.SetC(1, 6); + bEncoder.SetC(2, 7); + bEncoder.SetC(3, 8); + encoder.CheckEncodingIsComplete(); + + var decoder = new ArrayInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A[0]); + Assert.AreEqual(2, decoder.A[1]); + Assert.AreEqual(3, decoder.A[2]); + Assert.AreEqual(4, decoder.A[3]); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + bDecoder.Next(); + Assert.AreEqual(5, bDecoder.C[0]); + Assert.AreEqual(6, bDecoder.C[1]); + Assert.AreEqual(7, bDecoder.C[2]); + Assert.AreEqual(8, bDecoder.C[3]); + StringAssert.Contains(decoder.ToString(), "A=[1,2,3,4]|B=[(C=[5,6,7,8])]"); + } + + [TestMethod] + public void DisallowsEncodingArrayInsideGroupBeforeCallingNext1() + { + var bEncoder = EncodeUntilGroupWithArrayInside(); + var exception = Assert.ThrowsException(() => { bEncoder.SetC(0, 5); }); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsEncodingArrayInsideGroupBeforeCallingNext2() + { + var bEncoder = EncodeUntilGroupWithArrayInside(); + var exception = Assert.ThrowsException(() => { bEncoder.CAsSpan()[0] = 1; }); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + private ArrayInsideGroup.BGroup EncodeUntilGroupWithArrayInside() + { + var encoder = new ArrayInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA(0, 1); + encoder.SetA(1, 2); + encoder.SetA(2, 3); + encoder.SetA(3, 4); + return encoder.BCount(1); + } + + [TestMethod] + public void DisallowsDecodingArrayInsideGroupBeforeCallingNext1() + { + var bDecoder = DecodeUntilGroupWithArrayInside(); + var exception = Assert.ThrowsException(() => bDecoder.C[0]); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsDecodingArrayInsideGroupBeforeCallingNext2() + { + var bDecoder = DecodeUntilGroupWithArrayInside(); + var exception = Assert.ThrowsException(() => bDecoder.GetC(0)); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + private ArrayInsideGroup.BGroup DecodeUntilGroupWithArrayInside() + { + var encoder = new ArrayInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA(0, 1); + encoder.SetA(1, 2); + encoder.SetA(2, 3); + encoder.SetA(3, 4); + var bEncoder = encoder.BCount(1).Next(); + bEncoder.SetC(0, 5); + bEncoder.SetC(1, 6); + bEncoder.SetC(2, 7); + bEncoder.SetC(3, 8); + + encoder.CheckEncodingIsComplete(); + + var decoder = new ArrayInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual((short)1, decoder.A[0]); + Assert.AreEqual((short)2, decoder.A[1]); + Assert.AreEqual((short)3, decoder.A[2]); + Assert.AreEqual((short)4, decoder.A[3]); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + return bDecoder; + } + + [TestMethod] + public void AllowsReEncodingTopLevelArrayViaReWrap() + { + var encoder = new ArrayInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA(0, 1); + encoder.SetA(1, 2); + encoder.SetA(2, 3); + encoder.SetA(3, 4); + var bEncoder = encoder.BCount(1).Next(); + bEncoder.SetC(0, 5); + bEncoder.SetC(1, 6); + bEncoder.SetC(2, 7); + bEncoder.SetC(3, 8); + + encoder.SetA(0, 9); + encoder.SetA(1, 10); + encoder.SetA(2, 11); + encoder.SetA(3, 12); + encoder.CheckEncodingIsComplete(); + + var decoder = new ArrayInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(9, decoder.A[0]); + Assert.AreEqual(10, decoder.A[1]); + Assert.AreEqual(11, decoder.A[2]); + Assert.AreEqual(12, decoder.A[3]); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + bDecoder.Next(); + Assert.AreEqual(5, bDecoder.C[0]); + Assert.AreEqual(6, bDecoder.C[1]); + Assert.AreEqual(7, bDecoder.C[2]); + Assert.AreEqual(8, bDecoder.C[3]); + } + + [TestMethod] + public void AllowsEncodingAndDecodingGroupFieldsInSchemaDefinedOrder1() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.BCount(0); + var dEncoder = encoder.DCount(1).Next(); + dEncoder.E = 43; + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleGroups(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + Assert.AreEqual(0, decoder.B.Count); + var dDecoder = decoder.D; + Assert.AreEqual(1, dDecoder.Count); + Assert.AreEqual(dDecoder.Next().E, 43); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=[]|D=[(E=43)]")); + } + + [TestMethod] + public void AllowsEncodingAndDecodingGroupFieldsInSchemaDefinedOrder2() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 41; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 42; + var dEncoder = encoder.DCount(1).Next(); + dEncoder.E = 43; + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleGroups(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(41, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(42, bDecoder.Next().C); + var dDecoder = decoder.D; + Assert.AreEqual(1, dDecoder.Count); + Assert.AreEqual(43, dDecoder.Next().E); + } + + [TestMethod] + public void AllowsReEncodingTopLevelPrimitiveFieldsAfterGroups() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 41; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 42; + var dEncoder = encoder.DCount(1).Next(); + dEncoder.E = 43; + encoder.A = 44; + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleGroups(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(44, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(42, bDecoder.Next().C); + var dDecoder = decoder.D; + Assert.AreEqual(1, dDecoder.Count); + Assert.AreEqual(43, dDecoder.Next().E); + } + + [TestMethod] + public void DisallowsMissedEncodingOfGroupField() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 41; + Assert.ThrowsException(() => encoder.DCount(0)); + } + + [TestMethod] + public void DisallowsReEncodingEarlierGroupFields() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 41; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 42; + var dEncoder = encoder.DCount(1).Next(); + dEncoder.E = 43; + Assert.ThrowsException(() => encoder.BCount(1)); + } + + [TestMethod] + public void DisallowsReEncodingLatestGroupField() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 41; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 42; + var dEncoder = encoder.DCount(1).Next(); + dEncoder.E = 43; + Assert.ThrowsException(() => encoder.DCount(1)); + } + + [TestMethod] + public void DisallowsMissedDecodingOfGroupField() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 41; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 42; + var dEncoder = encoder.DCount(1).Next(); + dEncoder.E = 43; + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleGroups(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(41, decoder.A); + Assert.ThrowsException(() => + { + // ReSharper disable once UnusedVariable + var ignored = decoder.D; + }); + } + + [TestMethod] + public void DisallowsReDecodingEarlierGroupField() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 41; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 42; + var dEncoder = encoder.DCount(1).Next(); + dEncoder.E = 43; + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleGroups(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(41, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(42, bDecoder.Next().C); + var dDecoder = decoder.D; + Assert.AreEqual(1, dDecoder.Count); + Assert.AreEqual(43, dDecoder.Next().E); + Assert.ThrowsException(() => + { + // ReSharper disable once UnusedVariable + var ignored = decoder.B; + }); + } + + [TestMethod] + public void DisallowsReDecodingLatestGroupField() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 41; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 42; + var dEncoder = encoder.DCount(1).Next(); + dEncoder.E = 43; + encoder.CheckEncodingIsComplete(); + + var decoder = new MultipleGroups(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(41, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(42, bDecoder.Next().C); + var dDecoder = decoder.D; + Assert.AreEqual(1, dDecoder.Count); + Assert.AreEqual(43, dDecoder.Next().E); + Assert.ThrowsException(() => + { + // ReSharper disable once UnusedVariable + var ignored = decoder.D; + }); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedVarData() + { + var encoder = new AddVarDataV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new AddVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + Assert.AreEqual("abc", decoder.GetB()); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingAddedVarDataAsNullValue1() + { + var encoder = new AddVarDataV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + Assert.AreEqual("", decoder.GetB()); + Assert.IsTrue(decoder.ToString().Contains("A=42|B=''")); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingAddedVarDataAsNullValue2() + { + var encoder = new AddVarDataV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + Assert.AreEqual(0, decoder.BLength()); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingAddedVarDataAsNullValue3() + { + var encoder = new AddVarDataV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + Assert.AreEqual(0, decoder.GetB(new byte[16])); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingAddedVarDataAsNullValue4() + { + var encoder = new AddVarDataV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddVarDataV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(42, decoder.A); + Assert.AreEqual(0, decoder.GetB(new byte[16], 0, 16)); + } + + [TestMethod] + public void AllowsEncodingAndDecodingAsciiInsideGroupInSchemaDefinedOrder1() + { + var encoder = new AsciiInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA("GBPUSD"); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.SetC("EURUSD"); + encoder.CheckEncodingIsComplete(); + + var decoder = new AsciiInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual("GBPUSD", decoder.GetA()); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + bDecoder.Next(); + Assert.AreEqual("EURUSD", bDecoder.GetC()); + Assert.IsTrue(decoder.ToString().Contains("A='GBPUSD'|B=[(C='EURUSD')]")); + } + + [TestMethod] + public void AllowsEncodingAndDecodingAsciiInsideGroupInSchemaDefinedOrder2() + { + var encoder = new AsciiInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var gbpUsdBytes = Encoding.ASCII.GetBytes("GBPUSD"); + encoder.SetA(gbpUsdBytes, 0); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.SetC(Encoding.ASCII.GetBytes("EURUSD"), 0); + encoder.CheckEncodingIsComplete(); + + var decoder = new AsciiInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aBytes = new byte[6]; + decoder.GetA(aBytes, 0); + Assert.IsTrue(gbpUsdBytes.SequenceEqual(aBytes)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + bDecoder.Next(); + Assert.AreEqual((byte)'E', bDecoder.GetC(0)); + Assert.AreEqual((byte)'U', bDecoder.GetC(1)); + Assert.AreEqual((byte)'R', bDecoder.GetC(2)); + Assert.AreEqual((byte)'U', bDecoder.GetC(3)); + Assert.AreEqual((byte)'S', bDecoder.GetC(4)); + Assert.AreEqual((byte)'D', bDecoder.GetC(5)); + } + + [TestMethod] + public void DisallowsEncodingAsciiInsideGroupBeforeCallingNext1() + { + var bEncoder = EncodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => bEncoder.SetC("EURUSD")); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsEncodingAsciiInsideGroupBeforeCallingNext2() + { + var bEncoder = EncodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => bEncoder.SetC(0, (byte)'E')); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsEncodingAsciiInsideGroupBeforeCallingNext3() + { + var bEncoder = EncodeUntilGroupWithAsciiInside(); + + Exception exception = + Assert.ThrowsException(() => bEncoder.CAsSpan()[0] = (byte)'E'); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsEncodingAsciiInsideGroupBeforeCallingNext4() + { + var bEncoder = EncodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => + { + bEncoder.SetC(Encoding.ASCII.GetBytes("EURUSD"), 0); + }); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsEncodingAsciiInsideGroupBeforeCallingNext5() + { + var bEncoder = EncodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => + bEncoder.SetC(Encoding.ASCII.GetBytes("EURUSD"), 0)); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsEncodingAsciiInsideGroupBeforeCallingNext6() + { + var bEncoder = EncodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => + bEncoder.SetC(Encoding.ASCII.GetBytes("EURUSD"))); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + private AsciiInsideGroup.BGroup EncodeUntilGroupWithAsciiInside() + { + var encoder = new AsciiInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA("GBPUSD"); + return encoder.BCount(1); + } + + [TestMethod] + public void DisallowsDecodingAsciiInsideGroupBeforeCallingNext1() + { + var b = DecodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => b.GetC(0)); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsDecodingAsciiInsideGroupBeforeCallingNext2() + { + var b = DecodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => b.GetC()); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsDecodingAsciiInsideGroupBeforeCallingNext3() + { + var b = DecodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => b.C[0]); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsDecodingAsciiInsideGroupBeforeCallingNext4() + { + var b = DecodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => b.GetC(new byte[16], 0)); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + [TestMethod] + public void DisallowsDecodingAsciiInsideGroupBeforeCallingNext5() + { + var b = DecodeUntilGroupWithAsciiInside(); + + Exception exception = Assert.ThrowsException(() => b.GetC(new byte[16])); + + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_B_N")); + } + + private AsciiInsideGroup.BGroup DecodeUntilGroupWithAsciiInside() + { + var encoder = new AsciiInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA("GBPUSD"); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.SetC("EURUSD"); + encoder.CheckEncodingIsComplete(); + + var decoder = new AsciiInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual("GBPUSD", decoder.GetA()); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + return bDecoder; + } + + [TestMethod] + public void AllowsReEncodingTopLevelAsciiViaReWrap() + { + var encoder = new AsciiInsideGroup(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA("GBPUSD"); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.SetC("EURUSD"); + + encoder.SetA("CADUSD"); + encoder.CheckEncodingIsComplete(); + + var decoder = new AsciiInsideGroup(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual("CADUSD", decoder.GetA()); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + bDecoder.Next(); + Assert.AreEqual("EURUSD", bDecoder.GetC()); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup1() + { + var encoder = new AddAsciiBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetD("EURUSD"); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddAsciiBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual("EURUSD", decoder.GetD()); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup2() + { + var encoder = new AddAsciiBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetD("EURUSD"); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddAsciiBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual((byte)'E', decoder.GetD(0)); + Assert.AreEqual((byte)'U', decoder.GetD(1)); + Assert.AreEqual((byte)'R', decoder.GetD(2)); + Assert.AreEqual((byte)'U', decoder.GetD(3)); + Assert.AreEqual((byte)'S', decoder.GetD(4)); + Assert.AreEqual((byte)'D', decoder.GetD(5)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup3() + { + var encoder = new AddAsciiBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetD("EURUSD"); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddAsciiBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual((byte)'E', decoder.D[0]); + Assert.AreEqual((byte)'U', decoder.D[1]); + Assert.AreEqual((byte)'R', decoder.D[2]); + Assert.AreEqual((byte)'U', decoder.D[3]); + Assert.AreEqual((byte)'S', decoder.D[4]); + Assert.AreEqual((byte)'D', decoder.D[5]); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue1() + { + var encoder = new AddAsciiBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddAsciiBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(AddAsciiBeforeGroupV1.DNullValue, decoder.GetD(0)); + Assert.AreEqual(AddAsciiBeforeGroupV1.DNullValue, decoder.GetD(1)); + Assert.AreEqual(AddAsciiBeforeGroupV1.DNullValue, decoder.GetD(2)); + Assert.AreEqual(AddAsciiBeforeGroupV1.DNullValue, decoder.GetD(3)); + Assert.AreEqual(AddAsciiBeforeGroupV1.DNullValue, decoder.GetD(4)); + Assert.AreEqual(AddAsciiBeforeGroupV1.DNullValue, decoder.GetD(5)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue2() + { + var encoder = new AddAsciiBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddAsciiBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(0, decoder.D.Length); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue3() + { + var encoder = new AddAsciiBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddAsciiBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(0, decoder.GetD(new byte[16])); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue4() + { + var encoder = new AddAsciiBeforeGroupV0(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion0(); + + var decoder = new AddAsciiBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + Assert.AreEqual(0, decoder.GetD(new byte[16], 0)); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsNewDecoderToSkipPresentButAddedAsciiFieldBeforeGroup() + { + var encoder = new AddAsciiBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetD("EURUSD"); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + var decoder = new AddAsciiBeforeGroupV1(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsOldDecoderToSkipAddedAsciiFieldBeforeGroup() + { + var encoder = new AddAsciiBeforeGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetD("EURUSD"); + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 2; + encoder.CheckEncodingIsComplete(); + + ModifyHeaderToLookLikeVersion1(); + + var decoder = new AddAsciiBeforeGroupV0(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + } + + [TestMethod] + public void AllowsEncodeAndDecodeOfMessagesWithNoABlock() + { + var encoder = new NoBlock(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.SetA("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new NoBlock(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual("abc", decoder.GetA()); + } + + [TestMethod] + public void AllowsEncodeAndDecodeOfGroupsWithNoBlock() + { + var encoder = new GroupWithNoBlock(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aEncoder = encoder.ACount(1); + aEncoder.Next(); + aEncoder.SetB("abc"); + encoder.CheckEncodingIsComplete(); + + var decoder = new GroupWithNoBlock(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + var aDecoder = decoder.A; + Assert.AreEqual(1, aDecoder.Count); + Assert.AreEqual("abc", aDecoder.Next().GetB()); + } + + [TestMethod] + public void DisallowsEncodingElementOfEmptyGroup1() + { + var encoder = new MultipleGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(0); + var dEncoder = encoder.DCount(1); + dEncoder.Next(); + dEncoder.E = 43; + + var ex = Assert.ThrowsException(() => bEncoder.C = 44); + Assert.IsTrue(ex.Message.Contains("Cannot access field \"b.c\" in state: V0_D_1_BLOCK")); + } + + [TestMethod] + public void DisallowsEncodingElementOfEmptyGroup2() + { + var encoder = new NestedGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 43; + var dEncoder = bEncoder.DCount(0); + bEncoder.FCount(0); + encoder.HCount(0); + + var ex = Assert.ThrowsException(() => dEncoder.E = 44); + Assert.IsTrue(ex.Message.Contains("Cannot access field \"b.d.e\" in state: V0_H_DONE")); + } + + [TestMethod] + public void DisallowsEncodingElementOfEmptyGroup3() + { + var encoder = new NestedGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 43; + var dEncoder = bEncoder.DCount(0); + bEncoder.FCount(0); + encoder.HCount(0); + + var ex = Assert.ThrowsException(() => dEncoder.E = 44); + Assert.IsTrue(ex.Message.Contains("Cannot access field \"b.d.e\" in state: V0_H_DONE")); + } + + [TestMethod] + public void DisallowsEncodingElementOfEmptyGroup4() + { + var encoder = new NestedGroups(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(1); + bEncoder.Next(); + bEncoder.C = 43; + var dEncoder = bEncoder.DCount(0); + bEncoder.FCount(0); + + var ex = Assert.ThrowsException(() => dEncoder.E = 44); + Assert.IsTrue(ex.Message.Contains("Cannot access field \"b.d.e\" in state: V0_B_1_F_DONE")); + } + + + [TestMethod] + public void DisallowsEncodingElementOfEmptyGroup5() + { + var encoder = new AddPrimitiveInsideGroupV1(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(0); + var exception = Assert.ThrowsException(() => bEncoder.C = 43); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V1_B_DONE")); + } + + [TestMethod] + public void DisallowsEncodingElementOfEmptyGroup6() + { + var encoder = new GroupAndVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 42; + var bEncoder = encoder.BCount(0); + encoder.SetD("abc"); + var exception = Assert.ThrowsException(() => bEncoder.C = 43); + Assert.IsTrue(exception.Message.Contains("Cannot access field \"b.c\" in state: V0_D_DONE")); + } + + [TestMethod] + public void AllowsEncodingAndDecodingNestedGroupWithVarDataInSchemaDefinedOrder() + { + var encoder = new NestedGroupWithVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(3); + var bNext = bEncoder.Next(); + bNext.C = 2; + bNext.DCount(0); + bNext = bEncoder.Next(); + bNext.C = 3; + var dEncoder = bNext.DCount(1); + var dNext = dEncoder.Next(); + dNext.E = 4; + dEncoder.SetF("abc"); + bNext = bEncoder.Next(); + bNext.C = 5; + dEncoder = bNext.DCount(2); + dNext = dEncoder.Next(); + dNext.E = 6; + dEncoder.SetF("def"); + dNext = dEncoder.Next(); + dNext.E = 7; + dEncoder.SetF("ghi"); + encoder.CheckEncodingIsComplete(); + + var decoder = new NestedGroupWithVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(3, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + Assert.AreEqual(0, bDecoder.D.Count); + Assert.AreEqual(3, bDecoder.Next().C); + var dDecoder = bDecoder.D; + Assert.AreEqual(1, dDecoder.Count); + Assert.AreEqual(4, dDecoder.Next().E); + Assert.AreEqual("abc", dDecoder.GetF()); + Assert.AreEqual(5, bDecoder.Next().C); + Assert.AreEqual(dDecoder, bDecoder.D); + Assert.AreEqual(2, dDecoder.Count); + Assert.AreEqual(6, dDecoder.Next().E); + Assert.AreEqual("def", dDecoder.GetF()); + Assert.AreEqual(7, dDecoder.Next().E); + Assert.AreEqual("ghi", dDecoder.GetF()); + } + + [DataTestMethod] + [DataRow(1, "V0_B_N_D_1_BLOCK")] + [DataRow(2, "V0_B_N_D_N_BLOCK")] + public void DisallowsMissedEncodingOfVarLengthFieldInNestedGroupToNextOuterElement(int dCount, + string expectedState) + { + var encoder = new NestedGroupWithVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(2); + var bNext = bEncoder.Next(); + bNext.C = 3; + var dEncoder = bNext.DCount(dCount); + dEncoder.Next().E = 4; + var exception = Assert.ThrowsException(bEncoder.Next); + Assert.IsTrue(exception.Message.Contains("Cannot access next element in repeating group \"b\" in state: " + + expectedState)); + Assert.IsTrue( + exception.Message.Contains( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + [TestMethod] + public void DisallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextInnerElement1() + { + var encoder = new NestedGroupWithVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1); + var bNext = bEncoder.Next(); + bNext.C = 2; + var dEncoder = bNext.DCount(2); + var dNext = dEncoder.Next(); + dNext.E = 3; + dEncoder.SetF("abc"); + dNext = dEncoder.Next(); + dNext.E = 4; + dEncoder.SetF("def"); + encoder.CheckEncodingIsComplete(); + + var decoder = new NestedGroupWithVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(1, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + var dDecoder = bDecoder.D; + Assert.AreEqual(2, dDecoder.Count); + Assert.AreEqual(3, dDecoder.Next().E); + var exception = Assert.ThrowsException(dDecoder.Next); + Assert.IsTrue( + exception.Message.Contains( + "Cannot access next element in repeating group \"b.d\" in state: V0_B_1_D_N_BLOCK.")); + Assert.IsTrue( + exception.Message.Contains( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + [TestMethod] + public void DisallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextInnerElement2() + { + var encoder = new NestedGroupWithVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(2); + var bNext = bEncoder.Next(); + bNext.C = 2; + var dEncoder = bNext.DCount(2); + var dNext = dEncoder.Next(); + dNext.E = 3; + dEncoder.SetF("abc"); + dNext = dEncoder.Next(); + dNext.E = 4; + dEncoder.SetF("def"); + bEncoder.Next().C = 5; + bEncoder.DCount(0); + encoder.CheckEncodingIsComplete(); + + var decoder = new NestedGroupWithVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(2, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + var dDecoder = bDecoder.D; + Assert.AreEqual(2, dDecoder.Count); + Assert.AreEqual(3, dDecoder.Next().E); + var exception = Assert.ThrowsException(dDecoder.Next); + Assert.IsTrue( + exception.Message.Contains( + "Cannot access next element in repeating group \"b.d\" in state: V0_B_N_D_N_BLOCK.")); + Assert.IsTrue( + exception.Message.Contains( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + [TestMethod] + public void DisallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextOuterElement1() + { + var encoder = new NestedGroupWithVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(2); + var bNext = bEncoder.Next(); + bNext.C = 2; + var dEncoder = bNext.DCount(2); + var dNext = dEncoder.Next(); + dNext.E = 3; + dEncoder.SetF("abc"); + dNext = dEncoder.Next(); + dNext.E = 4; + dEncoder.SetF("def"); + bEncoder.Next().C = 5; + bEncoder.DCount(0); + encoder.CheckEncodingIsComplete(); + + var decoder = new NestedGroupWithVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(2, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + var dDecoder = bDecoder.D; + Assert.AreEqual(2, dDecoder.Count); + Assert.AreEqual(3, dDecoder.Next().E); + var exception = Assert.ThrowsException(bDecoder.Next); + Assert.IsTrue( + exception.Message.Contains( + "Cannot access next element in repeating group \"b\" in state: V0_B_N_D_N_BLOCK.")); + Assert.IsTrue( + exception.Message.Contains( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + [TestMethod] + public void DisallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextOuterElement2() + { + var encoder = new NestedGroupWithVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(2); + var bNext = bEncoder.Next(); + bNext.C = 2; + var dEncoder = bNext.DCount(1); + var dNext = dEncoder.Next(); + dNext.E = 3; + dEncoder.SetF("abc"); + bEncoder.Next().C = 5; + bEncoder.DCount(0); + encoder.CheckEncodingIsComplete(); + + var decoder = new NestedGroupWithVarLength(); + decoder.WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + Assert.AreEqual(1, decoder.A); + var bDecoder = decoder.B; + Assert.AreEqual(2, bDecoder.Count); + Assert.AreEqual(2, bDecoder.Next().C); + var dDecoder = bDecoder.D; + Assert.AreEqual(1, dDecoder.Count); + Assert.AreEqual(3, dDecoder.Next().E); + var exception = Assert.ThrowsException(() => bDecoder.Next()); + Assert.IsTrue( + exception.Message.Contains( + "Cannot access next element in repeating group \"b\" in state: V0_B_N_D_1_BLOCK.")); + Assert.IsTrue( + exception.Message.Contains( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + [TestMethod] + public void DisallowsIncompleteMessagesDueToMissingVarLengthField1() + { + var encoder = new MultipleVarLength(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.SetB("abc"); + var exception = Assert.ThrowsException(() => encoder.CheckEncodingIsComplete()); + Assert.IsTrue( + exception.Message.Contains( + "Not fully encoded, current state: V0_B_DONE, allowed transitions: \"cLength()\", \"c(?)\"")); + } + + [TestMethod] + public void DisallowsIncompleteMessagesDueToMissingVarLengthField2() + { + var encoder = new NoBlock(); + encoder.WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + var exception = Assert.ThrowsException(() => encoder.CheckEncodingIsComplete()); + Assert.IsTrue( + exception.Message.Contains( + "Not fully encoded, current state: V0_BLOCK, allowed transitions: \"aLength()\", \"a(?)\"")); + } + + [TestMethod] + public void DisallowsIncompleteMessagesDueToMissingTopLevelGroup1() + { + var encoder = new MultipleGroups() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + encoder.BCount(0); + var exception = Assert.ThrowsException(encoder.CheckEncodingIsComplete); + StringAssert.Contains(exception.Message, + "Not fully encoded, current state: V0_B_DONE, allowed transitions: " + + "\"b.resetCountToIndex()\", \"dCount(0)\", \"dCount(>0)\""); + } + + [TestMethod] + public void DisallowsIncompleteMessagesDueToMissingTopLevelGroup2() + { + var encoder = new MultipleGroups() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(1).Next(); + bEncoder.C = 2; + var exception = Assert.ThrowsException(encoder.CheckEncodingIsComplete); + StringAssert.Contains(exception.Message, + "Not fully encoded, current state: V0_B_1_BLOCK, allowed transitions:" + + " \"b.c(?)\", \"b.resetCountToIndex()\", \"dCount(0)\", \"dCount(>0)\""); + } + + [TestMethod] + public void DisallowsIncompleteMessagesDueToMissingTopLevelGroup3() + { + var encoder = new MultipleGroups() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var exception = Assert.ThrowsException(encoder.CheckEncodingIsComplete); + StringAssert.Contains(exception.Message, + "Not fully encoded, current state: V0_BLOCK, allowed transitions: \"a(?)\", \"bCount(0)\", \"bCount(>0)\""); + } + + [DataTestMethod] + [DataRow(1, "V0_B_1_BLOCK")] + [DataRow(2, "V0_B_N_BLOCK")] + public void DisallowsIncompleteMessagesDueToMissingNestedGroup1(int bCount, string expectedState) + { + var encoder = new NestedGroupWithVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(bCount).Next(); + bEncoder.C = 2; + var exception = Assert.ThrowsException(encoder.CheckEncodingIsComplete); + StringAssert.Contains(exception.Message, $"Not fully encoded, current state: {expectedState}"); + } + + [DataTestMethod] + [DataRow(1, 1, "V0_B_1_D_N")] + [DataRow(1, 2, "V0_B_1_D_N")] + [DataRow(2, 0, "V0_B_N_D_DONE")] + [DataRow(2, 1, "V0_B_N_D_N")] + [DataRow(2, 2, "V0_B_N_D_N")] + public void DisallowsIncompleteMessagesDueToMissingNestedGroup2( + int bCount, + int dCount, + string expectedState) + { + var encoder = new NestedGroupWithVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(bCount).Next(); + bEncoder.C = 2; + bEncoder.DCount(dCount); + var exception = Assert.ThrowsException(encoder.CheckEncodingIsComplete); + StringAssert.Contains(exception.Message, $"Not fully encoded, current state: {expectedState}"); + } + + [DataTestMethod] + [DataRow(1, 1, "V0_B_1_D_1_BLOCK")] + [DataRow(1, 2, "V0_B_1_D_N_BLOCK")] + [DataRow(2, 1, "V0_B_N_D_1_BLOCK")] + [DataRow(2, 2, "V0_B_N_D_N_BLOCK")] + public void DisallowsIncompleteMessagesDueToMissingVarDataInNestedGroup( + int bCount, + int dCount, + string expectedState) + { + var encoder = new NestedGroupWithVarLength() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.A = 1; + var bEncoder = encoder.BCount(bCount).Next(); + bEncoder.C = 2; + bEncoder.DCount(dCount).Next().E = 10; + var exception = Assert.ThrowsException(encoder.CheckEncodingIsComplete); + StringAssert.Contains(exception.Message, $"Not fully encoded, current state: {expectedState}"); + } + + private void ModifyHeaderToLookLikeVersion0() + { + var messageHeaderDecoder = new MessageHeader(); + messageHeaderDecoder.Wrap(_buffer, Offset, MessageHeader.SbeSchemaVersion); + int v1TemplateId = messageHeaderDecoder.TemplateId + 1_000; + var messageHeaderEncoder = new MessageHeader(); + messageHeaderEncoder.Wrap(_buffer, Offset, MessageHeader.SbeSchemaVersion); + messageHeaderEncoder.TemplateId = (ushort)v1TemplateId; + messageHeaderEncoder.Version = 0; + } + + private void ModifyHeaderToLookLikeVersion1() + { + var messageHeaderDecoder = new MessageHeader(); + messageHeaderDecoder.Wrap(_buffer, Offset, MessageHeader.SbeSchemaVersion); + Debug.Assert(messageHeaderDecoder.Version == 1); + int v0TemplateId = messageHeaderDecoder.TemplateId - 1_000; + var messageHeaderEncoder = new MessageHeader(); + messageHeaderEncoder.Wrap(_buffer, Offset, MessageHeader.SbeSchemaVersion); + messageHeaderEncoder.TemplateId = (ushort)v0TemplateId; + } + } +} \ No newline at end of file diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index 1134e90c0e..7c5ec14a9f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -204,6 +204,24 @@ public class SbeTool */ public static final String SCHEMA_TRANSFORM_VERSION = "sbe.schema.transform.version"; + /** + * Whether to generate field precedence checks. For example, whether to check that repeating groups are encoded + * in schema order. + */ + public static final String GENERATE_PRECEDENCE_CHECKS = "sbe.generate.precedence.checks"; + + /** + * The name of the symbol or macro that enables access order checks when building + * generated C# or C++ code. + */ + public static final String PRECEDENCE_CHECKS_FLAG_NAME = "sbe.precedence.checks.flag.name"; + + /** + * The name of the system property that enables access order checks at runtime + * in generated Java code. + */ + public static final String JAVA_PRECEDENCE_CHECKS_PROPERTY_NAME = "sbe.java.precedence.checks.property.name"; + /** * Main entry point for the SBE Tool. * diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 5d81eb691b..6552a72c00 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -15,14 +15,15 @@ */ package uk.co.real_logic.sbe.generation; -import uk.co.real_logic.sbe.generation.java.JavaOutputManager; import uk.co.real_logic.sbe.generation.c.CGenerator; import uk.co.real_logic.sbe.generation.c.COutputManager; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; import uk.co.real_logic.sbe.generation.cpp.CppGenerator; import uk.co.real_logic.sbe.generation.cpp.NamespaceOutputManager; import uk.co.real_logic.sbe.generation.golang.GolangGenerator; import uk.co.real_logic.sbe.generation.golang.GolangOutputManager; import uk.co.real_logic.sbe.generation.java.JavaGenerator; +import uk.co.real_logic.sbe.generation.java.JavaOutputManager; import uk.co.real_logic.sbe.generation.rust.RustGenerator; import uk.co.real_logic.sbe.generation.rust.RustOutputManager; import uk.co.real_logic.sbe.ir.Ir; @@ -53,6 +54,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) "true".equals(System.getProperty(JAVA_GENERATE_INTERFACES)), "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)), "true".equals(System.getProperty(TYPES_PACKAGE_OVERRIDE)), + precedenceChecks(), new JavaOutputManager(outputDir, ir.applicableNamespace())); } }, @@ -84,6 +86,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) return new CppGenerator( ir, "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)), + precedenceChecks(), new NamespaceOutputManager(outputDir, ir.applicableNamespace())); } }, @@ -118,6 +121,36 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) } }; + /** + * Returns the precedence checks to run, configured from system properties. + * + * @return the precedence checks to run, configured from system properties. + */ + public static PrecedenceChecks precedenceChecks() + { + final PrecedenceChecks.Context context = new PrecedenceChecks.Context(); + + final String shouldGeneratePrecedenceChecks = System.getProperty(GENERATE_PRECEDENCE_CHECKS); + if (shouldGeneratePrecedenceChecks != null) + { + context.shouldGeneratePrecedenceChecks(Boolean.parseBoolean(shouldGeneratePrecedenceChecks)); + } + + final String precedenceChecksFlagName = System.getProperty(PRECEDENCE_CHECKS_FLAG_NAME); + if (precedenceChecksFlagName != null) + { + context.precedenceChecksFlagName(precedenceChecksFlagName); + } + + final String precedenceChecksPropName = System.getProperty(JAVA_PRECEDENCE_CHECKS_PROPERTY_NAME); + if (precedenceChecksPropName != null) + { + context.precedenceChecksPropName(precedenceChecksPropName); + } + + return PrecedenceChecks.newInstance(context); + } + /** * Do a case-insensitive lookup of a target language for code generation. * diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java new file mode 100644 index 0000000000..0e79f88568 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java @@ -0,0 +1,1190 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.common; + +import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Signal; +import uk.co.real_logic.sbe.ir.Token; +import org.agrona.collections.Int2ObjectHashMap; +import org.agrona.collections.IntHashSet; +import org.agrona.collections.IntObjConsumer; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.IntStream; + +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; + +/** + * A state machine that models whether codec interactions are safe. + */ +@SuppressWarnings("CodeBlock2Expr") +// Lambdas without braces tend to conflict with the indentation Checkstyle expects. +// Therefore, we allow lambdas with code blocks even when a lambda expression is possible. +public final class FieldPrecedenceModel +{ + private final Map groupPathsByField = new HashMap<>(); + private final Set topLevelBlockFields = new HashSet<>(); + private final CodecInteraction.CodecInteractionFactory interactionFactory = + new CodecInteraction.CodecInteractionFactory(groupPathsByField, topLevelBlockFields); + private final Map> transitionsByInteraction = new LinkedHashMap<>(); + private final Map> transitionsByState = new HashMap<>(); + private final Int2ObjectHashMap versionWrappedStates = new Int2ObjectHashMap<>(); + private final State notWrappedState = allocateState("NOT_WRAPPED"); + private final String generatedRepresentationClassName; + private State encoderWrappedState; + private Set terminalEncoderStates; + + private FieldPrecedenceModel(final String generatedRepresentationClassName) + { + this.generatedRepresentationClassName = generatedRepresentationClassName; + } + + /** + * Builds a state machine that models whether codec interactions are safe. + * + * @param stateClassName the qualified name of the class that models the state machine in generated code + * @param msgToken the message token + * @param fields the fields in the message + * @param groups the groups in the message + * @param varData the varData in the message + * @param versionsSelector a function that selects the versions to model in the state machine + * @return the access order model + */ + public static FieldPrecedenceModel newInstance( + final String stateClassName, + final Token msgToken, + final List fields, + final List groups, + final List varData, + final Function versionsSelector) + { + final FieldPrecedenceModel model = new FieldPrecedenceModel(stateClassName); + model.findTransitions(msgToken, fields, groups, varData, versionsSelector); + return model; + } + + /** + * The initial state before a codec is wrapped. + * @return the initial state before a codec is wrapped. + */ + public State notWrappedState() + { + return notWrappedState; + } + + /** + * The state after a codec is wrapped in the latest version. + * @return the state after a codec is wrapped in the latest version. + */ + public State latestVersionWrappedState() + { + return encoderWrappedState; + } + + /** + * Iterates over the states after a codec is wrapped over a particular version of data. + * @param consumer the consumer of the states. + */ + public void forEachWrappedStateByVersion(final IntObjConsumer consumer) + { + final Int2ObjectHashMap.EntryIterator iterator = versionWrappedStates.entrySet().iterator(); + while (iterator.hasNext()) + { + iterator.next(); + consumer.accept(iterator.getIntKey(), iterator.getValue()); + } + } + + /** + * Returns the number of schema versions. + * @return the number of schema versions. + */ + public int versionCount() + { + return versionWrappedStates.size(); + } + + /** + * Iterates over the states in which a codec is fully encoded. + * @param consumer the consumer of the states. + */ + public void forEachTerminalEncoderState(final Consumer consumer) + { + terminalEncoderStates.forEach(consumer); + } + + /** + * Iterates over the codec states in the order of their state numbers. + * @param consumer the consumer of the states. + */ + public void forEachStateOrderedByStateNumber(final Consumer consumer) + { + transitionsByState.keySet().stream() + .sorted(Comparator.comparingInt(s -> s.number)) + .forEach(consumer); + } + + /** + * Returns the number of states in the state machine. + * @return the number of states in the state machine. + */ + public int stateCount() + { + return transitionsByState.size(); + } + + /** + * Returns a hash-consing factory for codec interactions. + * These interactions are the transitions in the state machine. + * @see CodecInteraction + * @return a hash-consing factory for codec interactions. + */ + public CodecInteraction.CodecInteractionFactory interactionFactory() + { + return interactionFactory; + } + + /** + * Returns the name of the class that models the state machine in generated code. + * @return the name of the class that models the state machine in generated code. + */ + public String generatedRepresentationClassName() + { + return generatedRepresentationClassName; + } + + /** + * Iterates over the possible state machine transitions due to the supplied codec interaction. + * @param interaction a codec interaction. + * @param consumer the consumer of the transitions. + */ + public void forEachTransition( + final CodecInteraction interaction, + final Consumer consumer) + { + final List transitionsForContext = transitionsByInteraction.get(interaction); + if (null != transitionsForContext) + { + transitionsForContext.forEach(consumer); + } + } + + /** + * Finds the possible transitions from a given state. + * @param state the state to find transitions from. + * @param consumer the consumer of the transitions. + */ + public void forEachTransitionFrom(final State state, final Consumer consumer) + { + final List transitionGroups = transitionsByState.get(state); + if (null != transitionGroups) + { + transitionGroups.forEach(consumer); + } + } + + /** + * Encodes the state machine as a graphviz dot diagram. + * @param sb the string builder to append to. + * @param indent the indentation to use. + */ + @SuppressWarnings("SameParameterValue") + public void generateGraph(final StringBuilder sb, final String indent) + { + sb.append(indent).append("digraph G {\n"); + transitionsByInteraction.values().forEach(transitionsForContext -> + { + transitionsForContext.forEach(transition -> + { + transition.forEachStartState(startState -> + { + sb.append(indent).append(" ") + .append(startState.name) + .append(" -> ") + .append(transition.endState().name) + .append(" [label=\" ").append(transition.interaction.exampleCode()); + + if (!transition.interaction.exampleConditions().isEmpty()) + { + sb.append("\\n").append(" where ").append(transition.interaction.exampleConditions()); + } + + sb.append(" \"];\n"); + }); + }); + }); + sb.append(indent).append("}\n"); + } + + private void findTransitions( + final Token msgToken, + final List fields, + final List groups, + final List varData, + final Function versionsSelector) + { + final IntHashSet versions = new IntHashSet(); + versions.add(msgToken.version()); + walkSchemaLevel(new VersionCollector(versions), fields, groups, varData); + walkSchemaLevel(new PathCollector(topLevelBlockFields, groupPathsByField), fields, groups, varData); + + final IntStream selectedVersions = versionsSelector.apply(versions.stream().mapToInt(i -> i)); + selectedVersions.sorted().forEach(version -> + { + final State versionWrappedState = allocateState("V" + version + "_BLOCK"); + + versionWrappedStates.put(version, versionWrappedState); + + final CodecInteraction wrapInteraction = interactionFactory.wrap(version); + + allocateTransitions( + wrapInteraction, + Collections.singletonList(notWrappedState), + versionWrappedState + ); + + final TransitionCollector transitionCollector = new TransitionCollector( + "V" + version + "_", + Collections.singleton(versionWrappedState), + versionWrappedState, + token -> token.version() <= version + ); + + walkSchemaLevel(transitionCollector, fields, groups, varData); + + // Last writer (highest version) wins when there are multiple versions + encoderWrappedState = versionWrappedState; + terminalEncoderStates = transitionCollector.exitStates(); + }); + } + + private State allocateState(final String name) + { + final State state = new State(transitionsByState.size(), name); + transitionsByState.put(state, new ArrayList<>()); + return state; + } + + private void allocateTransitions( + final CodecInteraction interaction, + final Collection from, + final State to) + { + final TransitionGroup transitionGroup = new TransitionGroup(interaction, from, to); + final List transitionsForInteraction = + transitionsByInteraction.computeIfAbsent(interaction, ignored -> new ArrayList<>()); + + final boolean duplicateEndState = + transitionsForInteraction.stream().anyMatch(t -> t.to.number == transitionGroup.to.number); + + if (duplicateEndState) + { + throw new IllegalStateException("Duplicate end state: " + transitionGroup.to.name); + } + + final Optional conflictingTransition = transitionsForInteraction.stream() + .filter(t -> t.from.stream().anyMatch(transitionGroup.from::contains)) + .findAny(); + + if (conflictingTransition.isPresent()) + { + throw new IllegalStateException( + "Conflicting transition: " + transitionGroup + " conflicts with " + conflictingTransition.get()); + } + + transitionsForInteraction.add(transitionGroup); + + from.forEach(fromState -> transitionsByState.get(fromState).add(transitionGroup)); + } + + private static void walkSchemaLevel( + final SchemaConsumer consumer, + final List fields, + final List groups, + final List varData) + { + Generators.forEachField(fields, (token, ignored) -> consumer.onBlockField(token)); + + for (int i = 0; i < groups.size(); i++) + { + final Token token = groups.get(i); + if (token.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + token); + } + + ++i; + final int groupHeaderTokenCount = groups.get(i).componentTokenCount(); + i += groupHeaderTokenCount; + + final ArrayList groupFields = new ArrayList<>(); + i = collectFields(groups, i, groupFields); + final ArrayList groupGroups = new ArrayList<>(); + i = collectGroups(groups, i, groupGroups); + final ArrayList groupVarData = new ArrayList<>(); + i = collectVarData(groups, i, groupVarData); + + consumer.onEnterRepeatingGroup(token, groupFields, groupGroups, groupVarData); + } + + for (int i = 0; i < varData.size(); ) + { + final Token token = varData.get(i); + if (token.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + token); + } + i += token.componentTokenCount(); + + consumer.onVarData(token); + } + } + + private interface SchemaConsumer + { + void onBlockField(Token token); + + void onEnterRepeatingGroup( + Token token, + List groupFields, + List groupGroups, + List groupVarData); + + void onVarData(Token token); + } + + private static final class PathCollector implements SchemaConsumer + { + private final ArrayDeque groupPath = new ArrayDeque<>(); + private final Set topLevelBlockFields; + private final Map groupPathsByField; + + private PathCollector( + final Set topLevelBlockFields, + final Map groupPathsByField) + { + this.topLevelBlockFields = topLevelBlockFields; + this.groupPathsByField = groupPathsByField; + } + + @Override + public void onBlockField(final Token token) + { + if (groupPath.isEmpty()) + { + topLevelBlockFields.add(token); + } + + groupPathsByField.put(token, currentGroupPath()); + } + + @Override + public void onEnterRepeatingGroup( + final Token token, + final List groupFields, + final List groupGroups, + final List groupVarData) + { + groupPathsByField.put(token, currentGroupPath()); + groupPath.addLast(token); + walkSchemaLevel(this, groupFields, groupGroups, groupVarData); + groupPath.removeLast(); + } + + @Override + public void onVarData(final Token token) + { + groupPathsByField.put(token, currentGroupPath()); + } + + private String currentGroupPath() + { + final StringBuilder sb = new StringBuilder(); + groupPath.forEach(token -> + { + sb.append(token.name()).append('.'); + }); + return sb.toString(); + } + } + + @SuppressWarnings("ClassCanBeRecord") + private static final class VersionCollector implements SchemaConsumer + { + private final IntHashSet versions; + + VersionCollector(final IntHashSet versions) + { + this.versions = versions; + } + + @Override + public void onBlockField(final Token token) + { + versions.add(token.version()); + } + + @Override + public void onEnterRepeatingGroup( + final Token token, + final List groupFields, + final List groupGroups, + final List groupVarData) + { + versions.add(token.version()); + walkSchemaLevel(this, groupFields, groupGroups, groupVarData); + } + + @Override + public void onVarData(final Token token) + { + versions.add(token.version()); + } + } + + private final class TransitionCollector implements SchemaConsumer + { + private final String statePrefix; + private final HashSet currentStates; + private final State blockState; + private final Predicate filter; + + private TransitionCollector( + final String statePrefix, + final Set fromStates, + final State blockState, + final Predicate filter) + { + this.statePrefix = statePrefix; + this.currentStates = new HashSet<>(fromStates); + this.blockState = blockState; + this.filter = filter; + + currentStates.add(blockState); + } + + @Override + public void onBlockField(final Token token) + { + if (filter.test(token)) + { + final CodecInteraction codecInteraction = interactionFactory.accessField(token); + allocateTransitions(codecInteraction, currentStates, blockState); + } + } + + @Override + public void onEnterRepeatingGroup( + final Token token, + final List groupFields, + final List groupGroups, + final List groupVarData) + { + if (filter.test(token)) + { + final String groupName = token.name().toUpperCase(); + final String groupPrefix = statePrefix + groupName + "_"; + final State nRemainingGroup = allocateState(groupPrefix + "N"); + final State nRemainingGroupElement = allocateState(groupPrefix + "N_BLOCK"); + final State oneRemainingGroupElement = allocateState(groupPrefix + "1_BLOCK"); + final State doneGroup = allocateState(groupPrefix + "DONE"); + + final Set beginGroupStates = new HashSet<>(currentStates); + + // fooCount(0) + final CodecInteraction emptyGroupInteraction = interactionFactory.determineGroupIsEmpty(token); + allocateTransitions(emptyGroupInteraction, beginGroupStates, doneGroup); + + // fooCount(N) where N > 0 + final CodecInteraction nonEmptyGroupInteraction = interactionFactory.determineGroupHasElements(token); + allocateTransitions(nonEmptyGroupInteraction, beginGroupStates, nRemainingGroup); + + currentStates.clear(); + currentStates.add(nRemainingGroupElement); + final TransitionCollector nRemainingCollector = new TransitionCollector( + groupPrefix + "N_", + currentStates, + nRemainingGroupElement, + filter + ); + walkSchemaLevel(nRemainingCollector, groupFields, groupGroups, groupVarData); + + currentStates.clear(); + currentStates.add(nRemainingGroup); + currentStates.addAll(nRemainingCollector.exitStates()); + + // where more than one element remains in the group + final CodecInteraction nextGroupElementInteraction = interactionFactory.moveToNextElement(token); + allocateTransitions(nextGroupElementInteraction, currentStates, nRemainingGroupElement); + + currentStates.clear(); + currentStates.add(nRemainingGroup); + currentStates.addAll(nRemainingCollector.exitStates()); + + // where only one element remains in the group + final CodecInteraction lastGroupElementInteraction = interactionFactory.moveToLastElement(token); + allocateTransitions(lastGroupElementInteraction, currentStates, oneRemainingGroupElement); + + currentStates.clear(); + currentStates.add(oneRemainingGroupElement); + + final TransitionCollector oneRemainingCollector = new TransitionCollector( + groupPrefix + "1_", + currentStates, + oneRemainingGroupElement, + filter + ); + walkSchemaLevel(oneRemainingCollector, groupFields, groupGroups, groupVarData); + + final CodecInteraction resetCountToIndexInteraction = interactionFactory.resetCountToIndex(token); + currentStates.clear(); + currentStates.add(doneGroup); + currentStates.add(nRemainingGroup); + currentStates.addAll(nRemainingCollector.exitStates()); + currentStates.addAll(oneRemainingCollector.exitStates()); + allocateTransitions(resetCountToIndexInteraction, currentStates, doneGroup); + + currentStates.clear(); + currentStates.add(doneGroup); + currentStates.addAll(oneRemainingCollector.exitStates()); + } + } + + @Override + public void onVarData(final Token token) + { + if (filter.test(token)) + { + final CodecInteraction lengthAccessInteraction = interactionFactory.accessVarDataLength(token); + currentStates.forEach(state -> + { + allocateTransitions(lengthAccessInteraction, Collections.singleton(state), state); + }); + + final CodecInteraction codecInteraction = interactionFactory.accessField(token); + final State accessedState = allocateState(statePrefix + token.name().toUpperCase() + "_DONE"); + allocateTransitions(codecInteraction, currentStates, accessedState); + currentStates.clear(); + currentStates.add(accessedState); + } + } + + private Set exitStates() + { + return currentStates; + } + } + + /** + * A state in which a codec may reside. + */ + public static final class State + { + private final int number; + private final String name; + + private State(final int number, final String name) + { + this.number = number; + this.name = name; + } + + /** + * In the scope of an {@code FieldPrecedenceModel} instance, state numbers are contiguous + * and start at 0. This numbering scheme allows easy generation of lookup tables. + * @return the state number + */ + public int number() + { + return number; + } + + /** + * Returns the name of the state. + * @return the name of the state. + */ + public String name() + { + return name; + } + + @Override + public String toString() + { + return "State{" + + "number=" + number + + ", name='" + name + '\'' + + '}'; + } + } + + /** + * A group of transitions that share the same end state. + */ + public static final class TransitionGroup + { + private final CodecInteraction interaction; + private final Set from; + private final State to; + + private TransitionGroup( + final CodecInteraction interaction, + final Collection from, + final State to) + { + this.interaction = interaction; + this.from = new HashSet<>(from); + this.to = to; + } + + /** + * Iterate over the start states of the transitions in this group. + * @param consumer the consumer of the start states. + */ + public void forEachStartState(final Consumer consumer) + { + from.forEach(consumer); + } + + /** + * Returns the end state of the transitions in this group. + * @return the end state of the transitions in this group. + */ + public State endState() + { + return to; + } + + /** + * Returns {@code true} if the transitions in this group do not change state. + * @return {@code true} if the transitions in this group do not change state. + */ + public boolean alwaysEndsInStartState() + { + return from.size() == 1 && from.contains(to); + } + + /** + * Returns some example code for the codec interaction that the transitions in this group share. + * Useful for producing error messages. + * @return some example code for the codec interaction that the transitions in this group share. + */ + public String exampleCode() + { + return interaction.exampleCode(); + } + + @Override + public String toString() + { + return "Transition{" + + "interaction='" + exampleCode() + '\'' + + ", from=" + from + + ", to=" + to + + '}'; + } + } + + /** + * Represents an interaction against a codec, e.g., {@code encoder.wrap(...)} or {@code decoder.myVarData()}. + */ + public abstract static class CodecInteraction + { + /** + * Returns a name for the interaction qualified by any groups that it is nested within. + * @return a name for the interaction qualified by any groups that it is nested within. + */ + public abstract String groupQualifiedName(); + + abstract String exampleCode(); + + abstract String exampleConditions(); + + /** + * Returns {@code true} if this interaction is a top-level block field access; {@code false} otherwise. + * @return {@code true} if this interaction is a top-level block field access; {@code false} otherwise. + */ + public final boolean isTopLevelBlockFieldAccess() + { + if (this instanceof AccessField) + { + //noinspection PatternVariableCanBeUsed + final AccessField accessField = (AccessField)this; + return accessField.isTopLevelBlockField(); + } + + return false; + } + + /** + * When an encoder or decoder is wrapped around a buffer. + */ + private static final class Wrap extends CodecInteraction + { + private final int version; + + Wrap(final int version) + { + this.version = version; + } + + @Override + public String groupQualifiedName() + { + return "wrap"; + } + + @Override + public String exampleCode() + { + return "wrap(version=" + version + ")"; + } + + @Override + public String exampleConditions() + { + return ""; + } + } + + /** + * When a block or variable-length field is accessed. + */ + private static final class AccessField extends CodecInteraction + { + private final String groupPath; + private final Token token; + private final boolean isTopLevelBlockField; + + private AccessField(final String groupPath, final Token token, final boolean isTopLevelBlockField) + { + this.isTopLevelBlockField = isTopLevelBlockField; + assert groupPath != null; + assert token.signal() == Signal.BEGIN_FIELD || token.signal() == Signal.BEGIN_VAR_DATA; + this.groupPath = groupPath; + this.token = token; + } + + boolean isTopLevelBlockField() + { + return isTopLevelBlockField; + } + + @Override + public String groupQualifiedName() + { + return groupPath + token.name(); + } + + @Override + public String exampleCode() + { + return groupPath + token.name() + "(?)"; + } + + @Override + public String exampleConditions() + { + return ""; + } + } + + /** + * When a repeating group count is supplied as zero. + */ + private static final class DetermineGroupIsEmpty extends CodecInteraction + { + private final String groupPath; + private final Token token; + + private DetermineGroupIsEmpty(final String groupPath, final Token token) + { + assert groupPath != null; + assert token.signal() == Signal.BEGIN_GROUP; + this.groupPath = groupPath; + this.token = token; + } + + @Override + public String groupQualifiedName() + { + return groupPath + token.name(); + } + + @Override + String exampleCode() + { + return groupPath + token.name() + "Count(0)"; + } + + @Override + String exampleConditions() + { + return ""; + } + } + + /** + * When a repeating group count is supplied as greater than zero. + */ + private static final class DetermineGroupHasElements extends CodecInteraction + { + private final String groupPath; + private final Token token; + + private DetermineGroupHasElements(final String groupPath, final Token token) + { + assert groupPath != null; + assert token.signal() == Signal.BEGIN_GROUP; + this.groupPath = groupPath; + this.token = token; + } + + @Override + public String groupQualifiedName() + { + return groupPath + token.name(); + } + + @Override + String exampleCode() + { + return groupPath + token.name() + "Count(>0)"; + } + + @Override + String exampleConditions() + { + return ""; + } + } + + /** + * When the next element in a repeating group is accessed, + * and it is not the last element. + */ + private static final class MoveToNextElement extends CodecInteraction + { + private final String groupPath; + private final Token token; + + private MoveToNextElement(final String groupPath, final Token token) + { + assert groupPath != null; + assert token.signal() == Signal.BEGIN_GROUP; + this.groupPath = groupPath; + this.token = token; + } + + @Override + public String groupQualifiedName() + { + return groupPath + token.name(); + } + + @Override + String exampleCode() + { + return groupPath + token.name() + ".next()"; + } + + @Override + String exampleConditions() + { + return "count - newIndex > 1"; + } + } + + /** + * When the next element in a repeating group is accessed, + * and it is the last element. + */ + private static final class MoveToLastElement extends CodecInteraction + { + private final String groupPath; + private final Token token; + + private MoveToLastElement(final String groupPath, final Token token) + { + assert groupPath != null; + assert token.signal() == Signal.BEGIN_GROUP; + this.groupPath = groupPath; + this.token = token; + } + + @Override + public String groupQualifiedName() + { + return groupPath + token.name(); + } + + @Override + String exampleCode() + { + return groupPath + token.name() + ".next()"; + } + + @Override + String exampleConditions() + { + return "count - newIndex == 1"; + } + } + + /** + * When the number of elements in a repeating group is set to be its current extent. + */ + private static final class ResetCountToIndex extends CodecInteraction + { + private final String groupPath; + private final Token token; + + private ResetCountToIndex(final String groupPath, final Token token) + { + assert groupPath != null; + assert token.signal() == Signal.BEGIN_GROUP; + this.groupPath = groupPath; + this.token = token; + } + + @Override + public String groupQualifiedName() + { + return groupPath + token.name(); + } + + @Override + String exampleCode() + { + return groupPath + token.name() + ".resetCountToIndex()"; + } + + @Override + String exampleConditions() + { + return ""; + } + } + + /** + * When the length of a variable length field is accessed without adjusting the position. + */ + private static final class AccessVarDataLength extends CodecInteraction + { + private final String groupPath; + private final Token token; + + private AccessVarDataLength(final String groupPath, final Token token) + { + assert groupPath != null; + assert token.signal() == Signal.BEGIN_VAR_DATA; + this.groupPath = groupPath; + this.token = token; + } + + @Override + public String groupQualifiedName() + { + return groupPath + token.name(); + } + + @Override + String exampleCode() + { + return groupPath + token.name() + "Length()"; + } + + @Override + String exampleConditions() + { + return ""; + } + } + + + /** + * Factory for creating {@link CodecInteraction} instances. This factory + * is used to hash-cons the instances, so that they can be compared by + * reference. + */ + public static final class CodecInteractionFactory + { + private final Int2ObjectHashMap wrapInteractions = new Int2ObjectHashMap<>(); + private final Map accessFieldInteractions = new HashMap<>(); + private final Map determineGroupIsEmptyInteractions = new HashMap<>(); + private final Map determineGroupHasElementsInteractions = new HashMap<>(); + private final Map moveToNextElementInteractions = new HashMap<>(); + private final Map moveToLastElementInteractions = new HashMap<>(); + private final Map resetCountToIndexInteractions = new HashMap<>(); + private final Map accessVarDataLengthInteractions = new HashMap<>(); + private final Map groupPathsByField; + private final Set topLevelBlockFields; + + CodecInteractionFactory( + final Map groupPathsByField, + final Set topLevelBlockFields) + { + + this.groupPathsByField = groupPathsByField; + this.topLevelBlockFields = topLevelBlockFields; + } + + /** + * Find or create a {@link CodecInteraction} to represent wrapping a codec around + * the given version of data. + * @param version the version of data to wrap + * @return the {@link CodecInteraction} instance + */ + public CodecInteraction wrap(final int version) + { + return wrapInteractions.computeIfAbsent(version, Wrap::new); + } + + /** + * Find or create a {@link CodecInteraction} to represent accessing the field identified + * by the given token. + * + *

    The supplied token must carry a {@link Signal#BEGIN_FIELD} + * or {@link Signal#BEGIN_VAR_DATA} signal. + * + * @param token the token identifying the field + * @return the {@link CodecInteraction} instance + */ + public CodecInteraction accessField(final Token token) + { + return accessFieldInteractions.computeIfAbsent(token, + t -> new AccessField(groupPathsByField.get(t), t, topLevelBlockFields.contains(t))); + } + + /** + * Find or create a {@link CodecInteraction} to represent determining a + * repeating group is empty. + * + *

    For encoding, this will be when the group count is supplied, e.g., + * {@code encoder.myGroupCount(0)}. + * + *

    For decoding, this will be when the group is read, e.g., + * {@code decoder.myGroup()}. + * + *

    The supplied token must carry a {@link Signal#BEGIN_GROUP} signal. + * + * @param token the token identifying the group + * @return the {@link CodecInteraction} instance + */ + public CodecInteraction determineGroupIsEmpty(final Token token) + { + return determineGroupIsEmptyInteractions.computeIfAbsent(token, + t -> new DetermineGroupIsEmpty(groupPathsByField.get(t), t)); + } + + /** + * Find or create a {@link CodecInteraction} to represent determining a + * repeating group has elements. + * + *

    For encoding, this will be when the group count is supplied, e.g., + * {@code encoder.myGroupCount(1)}. + * + *

    For decoding, this will be when the group is read, e.g., + * {@code decoder.myGroup()}. + * + *

    The supplied token must carry a {@link Signal#BEGIN_GROUP} signal. + * + * @param token the token identifying the group + * @return the {@link CodecInteraction} instance + */ + public CodecInteraction determineGroupHasElements(final Token token) + { + return determineGroupHasElementsInteractions.computeIfAbsent(token, + t -> new DetermineGroupHasElements(groupPathsByField.get(t), t)); + } + + /** + * Find or create a {@link CodecInteraction} to represent moving to the next + * element in a repeating group. + * + *

    For encoders, decoders, and codecs, this will be when the next element + * is accessed, e.g., {@code myGroup.next()} when {@code myGroup.count - myGroup.index > 1}. + * + *

    The supplied token must carry a {@link Signal#BEGIN_GROUP} signal. + * + * @param token the token identifying the group + * @return the {@link CodecInteraction} instance + */ + public CodecInteraction moveToNextElement(final Token token) + { + return moveToNextElementInteractions.computeIfAbsent(token, + t -> new MoveToNextElement(groupPathsByField.get(t), t)); + } + + /** + * Find or create a {@link CodecInteraction} to represent moving to the last + * element in a repeating group. + * + *

    For encoders, decoders, and codecs, this will be when the last element + * is accessed, e.g., {@code myGroup.next()} when {@code myGroup.count - myGroup.index == 1}. + * + * @param token the token identifying the group + * @return the {@link CodecInteraction} instance + */ + public CodecInteraction moveToLastElement(final Token token) + { + return moveToLastElementInteractions.computeIfAbsent(token, + t -> new MoveToLastElement(groupPathsByField.get(t), t)); + } + + /** + * Find or create a {@link CodecInteraction} to represent resetting the count + * of a repeating group to the current index. + * + *

    For encoders, decoders, and codecs, this will be when the {@code resetCountToIndex} + * method is called, e.g., {@code myGroup.resetCountToIndex()}. + * + *

    The supplied token must carry a {@link Signal#BEGIN_GROUP} signal. + * + * @param token the token identifying the group + * @return the {@link CodecInteraction} instance + */ + public CodecInteraction resetCountToIndex(final Token token) + { + return resetCountToIndexInteractions.computeIfAbsent(token, + t -> new ResetCountToIndex(groupPathsByField.get(t), t)); + } + + /** + * Find or create a {@link CodecInteraction} to represent accessing the length + * of a variable-length data field without advancing the codec position. + * + *

    For decoders and codecs, this will be when the length is accessed, e.g., + * {@code decoder.myVarDataLength()}. + * + *

    The supplied token must carry a {@link Signal#BEGIN_VAR_DATA} signal. + * + * @param token the token identifying the field + * @return the {@link CodecInteraction} instance + */ + public CodecInteraction accessVarDataLength(final Token token) + { + return accessVarDataLengthInteractions.computeIfAbsent(token, + t -> new AccessVarDataLength(groupPathsByField.get(t), t)); + } + } + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java new file mode 100644 index 0000000000..9825a3e6b7 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java @@ -0,0 +1,253 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.common; + +import uk.co.real_logic.sbe.ir.Token; + +import java.util.ArrayList; +import java.util.List; +import java.util.OptionalInt; +import java.util.function.Function; +import java.util.stream.IntStream; + +import static java.util.Objects.requireNonNull; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; + +/** + * A factory for creating a {@link FieldPrecedenceModel} for a message from its IR tokens. + */ +public final class PrecedenceChecks +{ + private static final Function SELECT_LATEST_VERSION_ONLY = versions -> + { + final OptionalInt max = versions.max(); + return max.isPresent() ? IntStream.of(max.getAsInt()) : IntStream.empty(); + }; + + private final Context context; + + private PrecedenceChecks(final Context context) + { + context.conclude(); + this.context = context; + } + + /** + * Creates a {@link FieldPrecedenceModel} for the given message tokens, + * unless precedence checks are disabled, in which case {@code null} is returned. + *

    + * Only the latest version of the message is considered when creating the model. + *

    + * + * @param stateClassName the name of the generated class that models the state of the encoder. + * @param msgTokens the tokens of the message. + * @return a {@link FieldPrecedenceModel} for the given message tokens or {@code null} if precedence checks + * are disabled. + */ + public FieldPrecedenceModel createEncoderModel( + final String stateClassName, + final List msgTokens) + { + return createModel(stateClassName, msgTokens, SELECT_LATEST_VERSION_ONLY); + } + + /** + * Creates a {@link FieldPrecedenceModel} for the given message tokens, + * unless precedence checks are disabled, in which case {@code null} is returned. + *

    + * All versions of the message are considered when creating the model. + *

    + * + * @param stateClassName the name of the generated class that models the state of the decoder. + * @param msgTokens the tokens of the message. + * @return a {@link FieldPrecedenceModel} for the given message tokens or {@code null} if precedence checks + * are disabled. + */ + public FieldPrecedenceModel createDecoderModel( + final String stateClassName, + final List msgTokens) + { + return createModel(stateClassName, msgTokens, Function.identity()); + } + + /** + * Creates a {@link FieldPrecedenceModel} for the given message tokens, + * unless precedence checks are disabled, in which case {@code null} is returned. + *

    + * All versions of the message are considered when creating the model. + *

    + * + * @param stateClassName the name of the generated class that models the state of the codec. + * @param msgTokens the tokens of the message. + * @return a {@link FieldPrecedenceModel} for the given message tokens or {@code null} if precedence checks + * are disabled. + */ + public FieldPrecedenceModel createCodecModel( + final String stateClassName, + final List msgTokens + ) + { + return createModel(stateClassName, msgTokens, Function.identity()); + } + + /** + * Returns the {@link Context} describing how precedence checks should be generated. + * + * @return the {@link Context} describing how precedence checks should be generated. + */ + public Context context() + { + return context; + } + + /** + * Creates a new {@link PrecedenceChecks} instance. + * + * @param context the {@link Context} describing how precedence checks should be generated. + * @return a new {@link PrecedenceChecks} instance. + */ + public static PrecedenceChecks newInstance(final Context context) + { + return new PrecedenceChecks(context); + } + + private FieldPrecedenceModel createModel( + final String stateClassName, + final List tokens, + final Function versionsSelector + ) + { + if (context.shouldGeneratePrecedenceChecks()) + { + final Token msgToken = tokens.get(0); + + final List messageBody = tokens.subList(1, tokens.size() - 1); + int i = 0; + + final List fields = new ArrayList<>(); + i = collectFields(messageBody, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(messageBody, i, groups); + + final List varData = new ArrayList<>(); + collectVarData(messageBody, i, varData); + + return FieldPrecedenceModel.newInstance( + stateClassName, + msgToken, + fields, + groups, + varData, + versionsSelector); + } + + return null; + } + + /** + * The context describing how precedence checks should be generated. + */ + public static final class Context + { + private boolean shouldGeneratePrecedenceChecks; + private String precedenceChecksFlagName = "SBE_ENABLE_PRECEDENCE_CHECKS"; + private String precedenceChecksPropName = "sbe.enable.precedence.checks"; + + /** + * Returns {@code true} if precedence checks should be generated; {@code false} otherwise. + * + * @return {@code true} if precedence checks should be generated; {@code false} otherwise. + */ + public boolean shouldGeneratePrecedenceChecks() + { + return shouldGeneratePrecedenceChecks; + } + + /** + * Sets whether field precedence checks should be generated. + * + * @param shouldGeneratePrecedenceChecks {@code true} if precedence checks should be generated; + * {@code false} otherwise. + * @return this {@link Context} instance. + */ + public Context shouldGeneratePrecedenceChecks(final boolean shouldGeneratePrecedenceChecks) + { + this.shouldGeneratePrecedenceChecks = shouldGeneratePrecedenceChecks; + return this; + } + + /** + * Returns the name of the flag that can be used to enable precedence checks at runtime. + * + * @return the name of the flag that can be used to enable precedence checks at runtime. + */ + public String precedenceChecksFlagName() + { + return precedenceChecksFlagName; + } + + /** + * Sets the name of the flag that can be used to enable precedence checks at runtime. + * + * @param precedenceChecksFlagName the name of the flag that can be used to enable + * precedence checks at runtime. + * @return this {@link Context} instance. + */ + public Context precedenceChecksFlagName(final String precedenceChecksFlagName) + { + this.precedenceChecksFlagName = precedenceChecksFlagName; + return this; + } + + /** + * Returns the name of the system property that can be used to enable precedence checks + * at runtime. + * + * @return the name of the system property that can be used to enable precedence checks + * at runtime. + */ + public String precedenceChecksPropName() + { + return precedenceChecksPropName; + } + + /** + * Sets the name of the system property that can be used to enable precedence checks + * at runtime. + * + * @param precedenceChecksPropName the name of the system property that can be used to + * enable precedence checks at runtime. + * @return this {@link Context} instance. + */ + public Context precedenceChecksPropName(final String precedenceChecksPropName) + { + this.precedenceChecksPropName = precedenceChecksPropName; + return this; + } + + /** + * Validates this {@link Context} instance. + */ + public void conclude() + { + requireNonNull(precedenceChecksFlagName, "precedenceChecksFlagName"); + requireNonNull(precedenceChecksPropName, "precedenceChecksPropName"); + } + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index f52d4695eb..b47e1d2f4a 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -15,23 +15,24 @@ */ package uk.co.real_logic.sbe.generation.cpp; -import org.agrona.Strings; -import org.agrona.Verify; -import org.agrona.generation.OutputManager; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.generation.CodeGenerator; import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.generation.common.FieldPrecedenceModel; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; import uk.co.real_logic.sbe.ir.Encoding; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.ir.Signal; import uk.co.real_logic.sbe.ir.Token; +import org.agrona.Strings; +import org.agrona.Verify; +import org.agrona.collections.MutableBoolean; +import org.agrona.generation.OutputManager; import java.io.IOException; import java.io.Writer; import java.nio.ByteOrder; -import java.util.ArrayList; -import java.util.Formatter; -import java.util.List; +import java.util.*; import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; @@ -45,12 +46,18 @@ @SuppressWarnings("MethodLength") public class CppGenerator implements CodeGenerator { + private static final boolean DISABLE_IMPLICIT_COPYING = Boolean.parseBoolean( + System.getProperty("sbe.cpp.disable.implicit.copying", "false")); private static final String BASE_INDENT = ""; private static final String INDENT = " "; + private static final String TWO_INDENT = INDENT + INDENT; + private static final String THREE_INDENT = TWO_INDENT + INDENT; private final Ir ir; private final OutputManager outputManager; private final boolean shouldDecodeUnknownEnumValues; + private final PrecedenceChecks precedenceChecks; + private final String precedenceChecksFlagName; /** * Create a new Cpp language {@link CodeGenerator}. @@ -60,12 +67,36 @@ public class CppGenerator implements CodeGenerator * @param outputManager for generating the codecs to. */ public CppGenerator(final Ir ir, final boolean shouldDecodeUnknownEnumValues, final OutputManager outputManager) + { + this( + ir, + shouldDecodeUnknownEnumValues, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + outputManager + ); + } + + /** + * Create a new Go language {@link CodeGenerator}. + * + * @param ir for the messages and types. + * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. + * @param precedenceChecks whether and how to generate field precedence checks. + * @param outputManager for generating the codecs to. + */ + public CppGenerator( + final Ir ir, + final boolean shouldDecodeUnknownEnumValues, + final PrecedenceChecks precedenceChecks, + final OutputManager outputManager) { Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); this.ir = ir; this.shouldDecodeUnknownEnumValues = shouldDecodeUnknownEnumValues; + this.precedenceChecks = precedenceChecks; + this.precedenceChecksFlagName = precedenceChecks.context().precedenceChecksFlagName(); this.outputManager = outputManager; } @@ -143,12 +174,11 @@ public void generate() throws IOException { final Token msgToken = tokens.get(0); final String className = formatClassName(msgToken.name()); + final String stateClassName = className + "::CodecState"; + final FieldPrecedenceModel fieldPrecedenceModel = precedenceChecks.createCodecModel(stateClassName, tokens); try (Writer out = outputManager.createOutput(className)) { - out.append(generateFileHeader(ir.namespaces(), className, typesToInclude)); - out.append(generateClassDeclaration(className)); - out.append(generateMessageFlyweightCode(className, msgToken)); final List messageBody = tokens.subList(1, tokens.size() - 1); int i = 0; @@ -162,20 +192,393 @@ public void generate() throws IOException final List varData = new ArrayList<>(); collectVarData(messageBody, i, varData); + out.append(generateFileHeader(ir.namespaces(), className, typesToInclude)); + out.append(generateClassDeclaration(className)); + out.append(generateMessageFlyweightCode(className, msgToken, fieldPrecedenceModel)); + out.append(generateFullyEncodedCheck(fieldPrecedenceModel)); + final StringBuilder sb = new StringBuilder(); - generateFields(sb, className, fields, BASE_INDENT); - generateGroups(sb, groups, BASE_INDENT); - generateVarData(sb, className, varData, BASE_INDENT); + generateFields(sb, className, fields, fieldPrecedenceModel, BASE_INDENT); + generateGroups(sb, groups, fieldPrecedenceModel, BASE_INDENT); + generateVarData(sb, className, varData, fieldPrecedenceModel, BASE_INDENT); generateDisplay(sb, msgToken.name(), fields, groups, varData); sb.append(generateMessageLength(groups, varData, BASE_INDENT)); sb.append("};\n"); + generateLookupTableDefinitions(sb, className, fieldPrecedenceModel); sb.append(CppUtil.closingBraces(ir.namespaces().length)).append("#endif\n"); out.append(sb); } } } - private void generateGroups(final StringBuilder sb, final List tokens, final String indent) + private CharSequence generateFullyEncodedCheck(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final String indent = " "; + final StringBuilder sb = new StringBuilder(); + sb.append("\n"); + + sb.append(indent).append("void checkEncodingIsComplete()\n") + .append(indent).append("{\n") + .append("#if defined(").append(precedenceChecksFlagName).append(")\n") + .append(indent).append(INDENT).append("switch (m_codecState)\n") + .append(indent).append(INDENT).append("{\n"); + + fieldPrecedenceModel.forEachTerminalEncoderState(state -> + { + sb.append(indent).append(TWO_INDENT).append("case ").append(stateCaseForSwitchCase(state)).append(":\n") + .append(indent).append(THREE_INDENT).append("return;\n"); + }); + + sb.append(indent).append(TWO_INDENT).append("default:\n") + .append(indent).append(THREE_INDENT) + .append("throw AccessOrderError(std::string(\"Not fully encoded, current state: \") +\n") + .append(indent).append(THREE_INDENT) + .append(INDENT).append("codecStateName(m_codecState) + \", allowed transitions: \" +\n") + .append(indent).append(THREE_INDENT) + .append(INDENT).append("codecStateTransitions(m_codecState));\n") + .append(indent).append(INDENT).append("}\n") + .append("#endif\n"); + + sb.append(indent).append("}\n\n"); + + return sb; + } + + private static String accessOrderListenerMethodName(final Token token) + { + return "on" + Generators.toUpperFirstChar(token.name()) + "Accessed"; + } + + private static String accessOrderListenerMethodName(final Token token, final String suffix) + { + return "on" + Generators.toUpperFirstChar(token.name()) + suffix + "Accessed"; + } + + private static void generateAccessOrderListenerMethod( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + final FieldPrecedenceModel.CodecInteraction fieldAccess = + fieldPrecedenceModel.interactionFactory().accessField(token); + + final String constDeclaration = canChangeState(fieldPrecedenceModel, fieldAccess) ? "" : " const"; + + sb.append("\n") + .append(indent).append("private:\n") + .append(indent).append(INDENT).append("void ").append(accessOrderListenerMethodName(token)).append("()") + .append(constDeclaration).append("\n") + .append(indent).append(INDENT).append("{\n"); + + generateAccessOrderListener( + sb, + indent + TWO_INDENT, + "access field", + fieldPrecedenceModel, + fieldAccess); + + sb.append(indent).append(INDENT).append("}\n\n") + .append(indent).append("public:"); + } + + private static boolean canChangeState( + final FieldPrecedenceModel fieldPrecedenceModel, + final FieldPrecedenceModel.CodecInteraction fieldAccess) + { + if (fieldAccess.isTopLevelBlockFieldAccess()) + { + return false; + } + + final MutableBoolean canChangeState = new MutableBoolean(false); + fieldPrecedenceModel.forEachTransition(fieldAccess, transition -> + { + if (!transition.alwaysEndsInStartState()) + { + canChangeState.set(true); + } + }); + + return canChangeState.get(); + } + + private CharSequence generateAccessOrderListenerCall( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token, + final String... arguments) + { + return generateAccessOrderListenerCall( + fieldPrecedenceModel, + indent, + accessOrderListenerMethodName(token), + arguments); + } + + private CharSequence generateAccessOrderListenerCall( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final String methodName, + final String... arguments) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append("#if defined(").append(precedenceChecksFlagName).append(")\n") + .append(indent).append(methodName).append("("); + + for (int i = 0; i < arguments.length; i++) + { + if (i > 0) + { + sb.append(", "); + } + sb.append(arguments[i]); + } + sb.append(");\n"); + + sb.append("#endif\n"); + + return sb; + } + + private static void generateAccessOrderListenerMethodForGroupWrap( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append("private:\n") + .append(indent).append(INDENT).append("void ").append(accessOrderListenerMethodName(token)) + .append("(std::uint64_t remaining, std::string action)\n") + .append(indent).append(INDENT).append("{\n") + .append(indent).append(TWO_INDENT).append("if (0 == remaining)\n") + .append(indent).append(TWO_INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction selectEmptyGroup = + fieldPrecedenceModel.interactionFactory().determineGroupIsEmpty(token); + + generateAccessOrderListener( + sb, + indent + THREE_INDENT, + "\" + action + \" count of repeating group", + fieldPrecedenceModel, + selectEmptyGroup); + + sb.append(indent).append(TWO_INDENT).append("}\n") + .append(indent).append(TWO_INDENT).append("else\n") + .append(indent).append(TWO_INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction selectNonEmptyGroup = + fieldPrecedenceModel.interactionFactory().determineGroupHasElements(token); + + generateAccessOrderListener( + sb, + indent + THREE_INDENT, + "\" + action + \" count of repeating group", + fieldPrecedenceModel, + selectNonEmptyGroup); + + sb.append(indent).append(TWO_INDENT).append("}\n") + .append(indent).append(INDENT).append("}\n\n") + .append(indent).append("public:"); + } + + private static void generateAccessOrderListenerMethodForVarDataLength( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append("private:\n") + .append(indent).append(INDENT).append("void ").append(accessOrderListenerMethodName(token, "Length")) + .append("() const\n") + .append(indent).append(INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction accessLength = + fieldPrecedenceModel.interactionFactory().accessVarDataLength(token); + + generateAccessOrderListener( + sb, + indent + TWO_INDENT, + "decode length of var data", + fieldPrecedenceModel, + accessLength); + + sb.append(indent).append(INDENT).append("}\n\n") + .append(indent).append("public:"); + } + + private static void generateAccessOrderListener( + final StringBuilder sb, + final String indent, + final String action, + final FieldPrecedenceModel fieldPrecedenceModel, + final FieldPrecedenceModel.CodecInteraction interaction) + { + if (interaction.isTopLevelBlockFieldAccess()) + { + sb.append(indent).append("if (codecState() == ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())) + .append(")\n") + .append(indent).append("{\n"); + generateAccessOrderException(sb, indent + INDENT, action, fieldPrecedenceModel, interaction); + sb.append(indent).append("}\n"); + } + else + { + sb.append(indent).append("switch (codecState())\n") + .append(indent).append("{\n"); + + fieldPrecedenceModel.forEachTransition(interaction, transitionGroup -> + { + + transitionGroup.forEachStartState(startState -> + { + sb.append(indent).append(INDENT) + .append("case ").append(stateCaseForSwitchCase(startState)).append(":\n"); + }); + + if (!transitionGroup.alwaysEndsInStartState()) + { + sb.append(indent).append(TWO_INDENT).append("codecState(") + .append(qualifiedStateCase(transitionGroup.endState())).append(");\n"); + } + + sb.append(indent).append(TWO_INDENT).append("break;\n"); + }); + + sb.append(indent).append(INDENT).append("default:\n"); + generateAccessOrderException(sb, indent + TWO_INDENT, action, fieldPrecedenceModel, interaction); + sb.append(indent).append("}\n"); + } + } + + private static void generateAccessOrderException( + final StringBuilder sb, + final String indent, + final String action, + final FieldPrecedenceModel fieldPrecedenceModel, + final FieldPrecedenceModel.CodecInteraction interaction) + { + sb.append(indent).append("throw AccessOrderError(") + .append("std::string(\"Illegal field access order. \") +\n") + .append(indent).append(INDENT) + .append("\"Cannot ").append(action).append(" \\\"").append(interaction.groupQualifiedName()) + .append("\\\" in state: \" + codecStateName(codecState()) +\n") + .append(indent).append(INDENT) + .append("\". Expected one of these transitions: [\" + codecStateTransitions(codecState()) +\n") + .append(indent).append(INDENT) + .append("\"]. Please see the diagram in the docs of the enum ") + .append(fieldPrecedenceModel.generatedRepresentationClassName()).append(".\");\n"); + } + + private static void generateAccessOrderListenerMethodForNextGroupElement( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n"); + + sb.append(indent).append(INDENT).append("void onNextElementAccessed()\n") + .append(indent).append(INDENT).append("{\n") + .append(indent).append(TWO_INDENT).append("std::uint64_t remaining = m_count - m_index;\n") + .append(indent).append(TWO_INDENT).append("if (remaining > 1)\n") + .append(indent).append(TWO_INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction selectNextElementInGroup = + fieldPrecedenceModel.interactionFactory().moveToNextElement(token); + + generateAccessOrderListener( + sb, + indent + THREE_INDENT, + "access next element in repeating group", + fieldPrecedenceModel, + selectNextElementInGroup); + + sb.append(indent).append(TWO_INDENT).append("}\n") + .append(indent).append(TWO_INDENT).append("else if (1 == remaining)\n") + .append(indent).append(TWO_INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction selectLastElementInGroup = + fieldPrecedenceModel.interactionFactory().moveToLastElement(token); + + generateAccessOrderListener( + sb, + indent + THREE_INDENT, + "access next element in repeating group", + fieldPrecedenceModel, + selectLastElementInGroup); + + sb.append(indent).append(TWO_INDENT).append("}\n") + .append(indent).append(INDENT).append("}\n"); + } + + private static void generateAccessOrderListenerMethodForResetGroupCount( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append(INDENT).append("void onResetCountToIndex()\n") + .append(indent).append(INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction resetCountToIndex = + fieldPrecedenceModel.interactionFactory().resetCountToIndex(token); + + generateAccessOrderListener( + sb, + indent + TWO_INDENT, + "reset count of repeating group", + fieldPrecedenceModel, + resetCountToIndex); + + sb.append(indent).append(INDENT).append("}\n"); + } + + private void generateGroups( + final StringBuilder sb, + final List tokens, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) { for (int i = 0, size = tokens.size(); i < size; i++) { @@ -189,7 +592,7 @@ private void generateGroups(final StringBuilder sb, final List tokens, fi final Token numInGroupToken = Generators.findFirst("numInGroup", tokens, i); final String cppTypeForNumInGroup = cppTypeName(numInGroupToken.encoding().primitiveType()); - generateGroupClassHeader(sb, groupName, tokens, i, indent + INDENT); + generateGroupClassHeader(sb, groupName, groupToken, tokens, fieldPrecedenceModel, i, indent + INDENT); ++i; final int groupHeaderTokenCount = tokens.get(i).componentTokenCount(); @@ -197,26 +600,32 @@ private void generateGroups(final StringBuilder sb, final List tokens, fi final List fields = new ArrayList<>(); i = collectFields(tokens, i, fields); - generateFields(sb, formatClassName(groupName), fields, indent + INDENT); + generateFields(sb, formatClassName(groupName), fields, fieldPrecedenceModel, indent + INDENT); final List groups = new ArrayList<>(); i = collectGroups(tokens, i, groups); - generateGroups(sb, groups, indent + INDENT); + generateGroups(sb, groups, fieldPrecedenceModel, indent + INDENT); final List varData = new ArrayList<>(); i = collectVarData(tokens, i, varData); - generateVarData(sb, formatClassName(groupName), varData, indent + INDENT); + generateVarData(sb, formatClassName(groupName), varData, fieldPrecedenceModel, indent + INDENT); sb.append(generateGroupDisplay(groupName, fields, groups, varData, indent + INDENT + INDENT)); sb.append(generateMessageLength(groups, varData, indent + INDENT + INDENT)); sb.append(indent).append(" };\n"); - generateGroupProperty(sb, groupName, groupToken, cppTypeForNumInGroup, indent); + generateGroupProperty(sb, groupName, groupToken, cppTypeForNumInGroup, fieldPrecedenceModel, indent); } } - private static void generateGroupClassHeader( - final StringBuilder sb, final String groupName, final List tokens, final int index, final String indent) + private void generateGroupClassHeader( + final StringBuilder sb, + final String groupName, + final Token groupToken, + final List tokens, + final FieldPrecedenceModel fieldPrecedenceModel, + final int index, + final String indent) { final String dimensionsClassName = formatClassName(tokens.get(index + 1).name()); final int dimensionHeaderLength = tokens.get(index + 1).encodedLength(); @@ -226,6 +635,8 @@ private static void generateGroupClassHeader( final String cppTypeBlockLength = cppTypeName(blockLengthToken.encoding().primitiveType()); final String cppTypeNumInGroup = cppTypeName(numInGroupToken.encoding().primitiveType()); + final String groupClassName = formatClassName(groupName); + new Formatter(sb).format("\n" + indent + "class %1$s\n" + indent + "{\n" + @@ -243,17 +654,50 @@ private static void generateGroupClassHeader( indent + " SBE_NODISCARD std::uint64_t *sbePositionPtr() SBE_NOEXCEPT\n" + indent + " {\n" + indent + " return m_positionPtr;\n" + - indent + " }\n\n" + + indent + " }\n\n", + groupClassName); - indent + "public:\n", - formatClassName(groupName)); + if (null != fieldPrecedenceModel) + { + new Formatter(sb).format( + indent + " CodecState *m_codecStatePtr = nullptr;\n\n" + + + indent + " CodecState codecState() const SBE_NOEXCEPT\n" + + indent + " {\n" + + indent + " return *m_codecStatePtr;\n" + + indent + " }\n\n" + + + indent + " CodecState *codecStatePtr()\n" + + indent + " {\n" + + indent + " return m_codecStatePtr;\n" + + indent + " }\n\n" + + + indent + " void codecState(CodecState codecState)\n" + + indent + " {\n" + + indent + " *m_codecStatePtr = codecState;\n" + + indent + " }\n\n" + ); + } + + sb.append(generateHiddenCopyConstructor(indent + " ", groupClassName)); + + final String codecStateParameter = null == fieldPrecedenceModel ? + ")\n" : + ",\n " + indent + " CodecState *codecState)\n"; + + final String codecStateAssignment = null == fieldPrecedenceModel ? + "" : + indent + " m_codecStatePtr = codecState;\n"; new Formatter(sb).format( + indent + "public:\n" + + indent + " %5$s() = default;\n\n" + + indent + " inline void wrapForDecode(\n" + indent + " char *buffer,\n" + indent + " std::uint64_t *pos,\n" + indent + " const std::uint64_t actingVersion,\n" + - indent + " const std::uint64_t bufferLength)\n" + + indent + " const std::uint64_t bufferLength%3$s" + indent + " {\n" + indent + " %2$s dimensions(buffer, *pos, bufferLength, actingVersion);\n" + indent + " m_buffer = buffer;\n" + @@ -265,8 +709,13 @@ private static void generateGroupClassHeader( indent + " m_initialPosition = *pos;\n" + indent + " m_positionPtr = pos;\n" + indent + " *m_positionPtr = *m_positionPtr + %1$d;\n" + + "%4$s" + indent + " }\n", - dimensionHeaderLength, dimensionsClassName); + dimensionHeaderLength, + dimensionsClassName, + codecStateParameter, + codecStateAssignment, + groupClassName); final long minCount = numInGroupToken.encoding().applicableMinValue().longValue(); final String minCheck = minCount > 0 ? "count < " + minCount + " || " : ""; @@ -277,7 +726,7 @@ private static void generateGroupClassHeader( indent + " const %3$s count,\n" + indent + " std::uint64_t *pos,\n" + indent + " const std::uint64_t actingVersion,\n" + - indent + " const std::uint64_t bufferLength)\n" + + indent + " const std::uint64_t bufferLength%8$s" + indent + " {\n" + indent + "#if defined(__GNUG__) && !defined(__clang__)\n" + indent + "#pragma GCC diagnostic push\n" + @@ -302,6 +751,7 @@ private static void generateGroupClassHeader( indent + " m_initialPosition = *pos;\n" + indent + " m_positionPtr = pos;\n" + indent + " *m_positionPtr = *m_positionPtr + %4$d;\n" + + "%9$s" + indent + " }\n", cppTypeBlockLength, blockLength, @@ -309,7 +759,43 @@ private static void generateGroupClassHeader( dimensionHeaderLength, minCheck, numInGroupToken.encoding().applicableMaxValue().longValue(), - dimensionsClassName); + dimensionsClassName, + codecStateParameter, + codecStateAssignment); + + if (groupToken.version() > 0) + { + final String codecStateNullAssignment = null == fieldPrecedenceModel ? + "" : + indent + " m_codecStatePtr = nullptr;\n"; + + new Formatter(sb).format( + indent + " inline void notPresent(std::uint64_t actingVersion)\n" + + indent + " {\n" + + indent + " m_buffer = nullptr;\n" + + indent + " m_bufferLength = 0;\n" + + indent + " m_blockLength = 0;\n" + + indent + " m_count = 0;\n" + + indent + " m_index = 0;\n" + + indent + " m_actingVersion = actingVersion;\n" + + indent + " m_initialPosition = 0;\n" + + indent + " m_positionPtr = nullptr;\n" + + "%1$s" + + indent + " }\n", + codecStateNullAssignment); + } + + + if (null != fieldPrecedenceModel) + { + sb.append("\n").append(indent).append("private:"); + generateAccessOrderListenerMethodForNextGroupElement(sb, fieldPrecedenceModel, indent, groupToken); + generateAccessOrderListenerMethodForResetGroupCount(sb, fieldPrecedenceModel, indent, groupToken); + sb.append("\n").append(indent).append("public:"); + } + + final CharSequence onNextAccessOrderCall = null == fieldPrecedenceModel ? "" : + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, "onNextElementAccessed"); new Formatter(sb).format("\n" + indent + " static SBE_CONSTEXPR std::uint64_t sbeHeaderSize() SBE_NOEXCEPT\n" + @@ -358,6 +844,7 @@ private static void generateGroupClassHeader( indent + " {\n" + indent + " throw std::runtime_error(\"index >= count [E108]\");\n" + indent + " }\n" + + "%4$s" + indent + " m_offset = *m_positionPtr;\n" + indent + " if (SBE_BOUNDS_CHECK_EXPECT(((m_offset + m_blockLength) > m_bufferLength), false))\n" + indent + " {\n" + @@ -370,11 +857,13 @@ private static void generateGroupClassHeader( indent + " }\n", dimensionHeaderLength, blockLength, - formatClassName(groupName)); + groupClassName, + onNextAccessOrderCall); sb.append("\n") .append(indent).append(" inline std::uint64_t resetCountToIndex()\n") .append(indent).append(" {\n") + .append(generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, "onResetCountToIndex")) .append(indent).append(" m_count = m_index;\n") .append(indent).append(" ").append(dimensionsClassName) .append(" dimensions(m_buffer, m_initialPosition, m_bufferLength, m_actingVersion);\n") @@ -394,11 +883,12 @@ private static void generateGroupClassHeader( .append(indent).append(" }\n\n"); } - private static void generateGroupProperty( + private void generateGroupProperty( final StringBuilder sb, final String groupName, final Token token, final String cppTypeForNumInGroup, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final String className = formatClassName(groupName); @@ -420,25 +910,76 @@ private static void generateGroupProperty( groupName, token.id()); - new Formatter(sb).format("\n" + - indent + " SBE_NODISCARD inline %1$s &%2$s()\n" + - indent + " {\n" + - indent + " m_%2$s.wrapForDecode(m_buffer, sbePositionPtr(), m_actingVersion, m_bufferLength);\n" + - indent + " return m_%2$s;\n" + - indent + " }\n", - className, - propertyName); + if (null != fieldPrecedenceModel) + { + generateAccessOrderListenerMethodForGroupWrap( + sb, + fieldPrecedenceModel, + indent, + token + ); + } + + final String codecStateArgument = null == fieldPrecedenceModel ? "" : ", codecStatePtr()"; + + final CharSequence onDecodeAccessOrderCall = null == fieldPrecedenceModel ? "" : + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, token, + "m_" + propertyName + ".count()", "\"decode\""); + + if (token.version() > 0) + { + new Formatter(sb).format("\n" + + indent + " SBE_NODISCARD inline %1$s &%2$s()\n" + + indent + " {\n" + + indent + " if (m_actingVersion < %5$du)\n" + + indent + " {\n" + + indent + " m_%2$s.notPresent(m_actingVersion);\n" + + indent + " return m_%2$s;\n" + + indent + " }\n\n" + + + indent + " m_%2$s.wrapForDecode(" + + "m_buffer, sbePositionPtr(), m_actingVersion, m_bufferLength%3$s);\n" + + "%4$s" + + indent + " return m_%2$s;\n" + + indent + " }\n", + className, + propertyName, + codecStateArgument, + onDecodeAccessOrderCall, + token.version()); + } + else + { + new Formatter(sb).format("\n" + + indent + " SBE_NODISCARD inline %1$s &%2$s()\n" + + indent + " {\n" + + indent + " m_%2$s.wrapForDecode(" + + "m_buffer, sbePositionPtr(), m_actingVersion, m_bufferLength%3$s);\n" + + "%4$s" + + indent + " return m_%2$s;\n" + + indent + " }\n", + className, + propertyName, + codecStateArgument, + onDecodeAccessOrderCall); + } + + final CharSequence onEncodeAccessOrderCall = null == fieldPrecedenceModel ? "" : + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, token, "count", "\"encode\""); new Formatter(sb).format("\n" + indent + " %1$s &%2$sCount(const %3$s count)\n" + indent + " {\n" + indent + " m_%2$s.wrapForEncode(" + - "m_buffer, count, sbePositionPtr(), m_actingVersion, m_bufferLength);\n" + + "m_buffer, count, sbePositionPtr(), m_actingVersion, m_bufferLength%4$s);\n" + + "%5$s" + indent + " return m_%2$s;\n" + indent + " }\n", className, propertyName, - cppTypeForNumInGroup); + cppTypeForNumInGroup, + codecStateArgument, + onEncodeAccessOrderCall); final int version = token.version(); final String versionCheck = 0 == version ? @@ -458,7 +999,11 @@ private static void generateGroupProperty( } private void generateVarData( - final StringBuilder sb, final String className, final List tokens, final String indent) + final StringBuilder sb, + final String className, + final List tokens, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) { for (int i = 0, size = tokens.size(); i < size;) { @@ -480,12 +1025,39 @@ private void generateVarData( generateFieldMetaAttributeMethod(sb, token, indent); generateVarDataDescriptors( - sb, token, propertyName, characterEncoding, lengthToken, lengthOfLengthField, lengthCppType, indent); + sb, token, propertyName, characterEncoding, lengthOfLengthField, indent); + + generateAccessOrderListenerMethodForVarDataLength(sb, fieldPrecedenceModel, indent, token); + + final CharSequence lengthAccessListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + TWO_INDENT, + accessOrderListenerMethodName(token, "Length")); + + new Formatter(sb).format("\n" + + indent + " SBE_NODISCARD %4$s %1$sLength() const\n" + + indent + " {\n" + + "%2$s" + + "%5$s" + + indent + " %4$s length;\n" + + indent + " std::memcpy(&length, m_buffer + sbePosition(), sizeof(%4$s));\n" + + indent + " return %3$s(length);\n" + + indent + " }\n", + toLowerFirstChar(propertyName), + generateArrayFieldNotPresentCondition(token.version(), BASE_INDENT), + formatByteOrderEncoding(lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType()), + lengthCppType, + lengthAccessListenerCall); + + generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent, token); + + final CharSequence accessOrderListenerCall = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, token); new Formatter(sb).format("\n" + indent + " std::uint64_t skip%1$s()\n" + indent + " {\n" + "%2$s" + + "%6$s" + indent + " std::uint64_t lengthOfLengthField = %3$d;\n" + indent + " std::uint64_t lengthPosition = sbePosition();\n" + indent + " %5$s lengthFieldValue;\n" + @@ -498,12 +1070,14 @@ private void generateVarData( generateArrayFieldNotPresentCondition(token.version(), indent), lengthOfLengthField, lengthByteOrderStr, - lengthCppType); + lengthCppType, + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " SBE_NODISCARD const char *%1$s()\n" + indent + " {\n" + "%2$s" + + "%6$s" + indent + " %4$s lengthFieldValue;\n" + indent + " std::memcpy(&lengthFieldValue, m_buffer + sbePosition(), sizeof(%4$s));\n" + indent + " const char *fieldPtr = m_buffer + sbePosition() + %3$d;\n" + @@ -514,12 +1088,14 @@ private void generateVarData( generateTypeFieldNotPresentCondition(token.version(), indent), lengthOfLengthField, lengthCppType, - lengthByteOrderStr); + lengthByteOrderStr, + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " std::uint64_t get%1$s(char *dst, const std::uint64_t length)\n" + indent + " {\n" + "%2$s" + + "%6$s" + indent + " std::uint64_t lengthOfLengthField = %3$d;\n" + indent + " std::uint64_t lengthPosition = sbePosition();\n" + indent + " sbePosition(lengthPosition + lengthOfLengthField);\n" + @@ -536,11 +1112,13 @@ private void generateVarData( generateArrayFieldNotPresentCondition(token.version(), indent), lengthOfLengthField, lengthByteOrderStr, - lengthCppType); + lengthCppType, + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " %5$s &put%1$s(const char *src, const %3$s length)\n" + indent + " {\n" + + "%6$s" + indent + " std::uint64_t lengthOfLengthField = %2$d;\n" + indent + " std::uint64_t lengthPosition = sbePosition();\n" + indent + " %3$s lengthFieldValue = %4$s(length);\n" + @@ -558,12 +1136,14 @@ private void generateVarData( lengthOfLengthField, lengthCppType, lengthByteOrderStr, - className); + className, + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " std::string get%1$sAsString()\n" + indent + " {\n" + "%2$s" + + "%6$s" + indent + " std::uint64_t lengthOfLengthField = %3$d;\n" + indent + " std::uint64_t lengthPosition = sbePosition();\n" + indent + " sbePosition(lengthPosition + lengthOfLengthField);\n" + @@ -579,15 +1159,17 @@ private void generateVarData( generateStringNotPresentCondition(token.version(), indent), lengthOfLengthField, lengthByteOrderStr, - lengthCppType); + lengthCppType, + accessOrderListenerCall); - generateJsonEscapedStringGetter(sb, token, indent, propertyName); + generateJsonEscapedStringGetter(sb, token, indent, propertyName, accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " #if __cplusplus >= 201703L\n" + indent + " std::string_view get%1$sAsStringView()\n" + indent + " {\n" + "%2$s" + + "%6$s" + indent + " std::uint64_t lengthOfLengthField = %3$d;\n" + indent + " std::uint64_t lengthPosition = sbePosition();\n" + indent + " sbePosition(lengthPosition + lengthOfLengthField);\n" + @@ -604,7 +1186,8 @@ private void generateVarData( generateStringViewNotPresentCondition(token.version(), indent), lengthOfLengthField, lengthByteOrderStr, - lengthCppType); + lengthCppType, + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " %1$s &put%2$s(const std::string &str)\n" + @@ -645,9 +1228,7 @@ private void generateVarDataDescriptors( final Token token, final String propertyName, final String characterEncoding, - final Token lengthToken, final Integer sizeOfLengthField, - final String lengthCppType, final String indent) { new Formatter(sb).format("\n" + @@ -687,19 +1268,6 @@ private void generateVarDataDescriptors( indent + " }\n", toLowerFirstChar(propertyName), sizeOfLengthField); - - new Formatter(sb).format("\n" + - indent + " SBE_NODISCARD %4$s %1$sLength() const\n" + - indent + " {\n" + - "%2$s" + - indent + " %4$s length;\n" + - indent + " std::memcpy(&length, m_buffer + sbePosition(), sizeof(%4$s));\n" + - indent + " return %3$s(length);\n" + - indent + " }\n", - toLowerFirstChar(propertyName), - generateArrayFieldNotPresentCondition(version, BASE_INDENT), - formatByteOrderEncoding(lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType()), - lengthCppType); } private void generateChoiceSet(final List tokens) throws IOException @@ -1216,19 +1784,21 @@ private CharSequence generateCompositePropertyElements( switch (fieldToken.signal()) { case ENCODING: - generatePrimitiveProperty(sb, containingClassName, propertyName, fieldToken, fieldToken, indent); + generatePrimitiveProperty(sb, containingClassName, propertyName, fieldToken, fieldToken, + null, indent); break; case BEGIN_ENUM: - generateEnumProperty(sb, containingClassName, fieldToken, propertyName, fieldToken, indent); + generateEnumProperty(sb, containingClassName, fieldToken, propertyName, fieldToken, + null, indent); break; case BEGIN_SET: - generateBitsetProperty(sb, propertyName, fieldToken, indent); + generateBitsetProperty(sb, propertyName, fieldToken, fieldToken, null, indent); break; case BEGIN_COMPOSITE: - generateCompositeProperty(sb, propertyName, fieldToken, indent); + generateCompositeProperty(sb, propertyName, fieldToken, fieldToken, null, indent); break; default: @@ -1247,6 +1817,7 @@ private void generatePrimitiveProperty( final String propertyName, final Token propertyToken, final Token encodingToken, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { generatePrimitiveFieldMetaData(sb, propertyName, encodingToken, indent); @@ -1258,7 +1829,7 @@ private void generatePrimitiveProperty( else { generatePrimitivePropertyMethods( - sb, containingClassName, propertyName, propertyToken, encodingToken, indent); + sb, containingClassName, propertyName, propertyToken, encodingToken, fieldPrecedenceModel, indent); } } @@ -1268,16 +1839,19 @@ private void generatePrimitivePropertyMethods( final String propertyName, final Token propertyToken, final Token encodingToken, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final int arrayLength = encodingToken.arrayLength(); if (arrayLength == 1) { - generateSingleValueProperty(sb, containingClassName, propertyName, propertyToken, encodingToken, indent); + generateSingleValueProperty(sb, containingClassName, propertyName, propertyToken, encodingToken, + fieldPrecedenceModel, indent); } else if (arrayLength > 1) { - generateArrayProperty(sb, containingClassName, propertyName, propertyToken, encodingToken, indent); + generateArrayProperty(sb, containingClassName, propertyName, propertyToken, encodingToken, + fieldPrecedenceModel, indent); } } @@ -1405,42 +1979,59 @@ private CharSequence generateStoreValue( return sb; } + private static String noexceptDeclaration(final FieldPrecedenceModel fieldPrecedenceModel) + { + return fieldPrecedenceModel == null ? " SBE_NOEXCEPT" : ""; + } + private void generateSingleValueProperty( final StringBuilder sb, final String containingClassName, final String propertyName, final Token propertyToken, final Token encodingToken, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final PrimitiveType primitiveType = encodingToken.encoding().primitiveType(); final String cppTypeName = cppTypeName(primitiveType); final int offset = encodingToken.offset(); + final CharSequence accessOrderListenerCall = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, propertyToken); + + final String noexceptDeclaration = noexceptDeclaration(fieldPrecedenceModel); + new Formatter(sb).format("\n" + - indent + " SBE_NODISCARD %1$s %2$s() const SBE_NOEXCEPT\n" + + indent + " SBE_NODISCARD %1$s %2$s() const%6$s\n" + indent + " {\n" + "%3$s" + "%4$s" + + "%5$s" + indent + " }\n", cppTypeName, propertyName, generateFieldNotPresentCondition(propertyToken.version(), encodingToken.encoding(), indent), - generateLoadValue(primitiveType, Integer.toString(offset), encodingToken.encoding().byteOrder(), indent)); + accessOrderListenerCall, + generateLoadValue(primitiveType, Integer.toString(offset), encodingToken.encoding().byteOrder(), indent), + noexceptDeclaration); final CharSequence storeValue = generateStoreValue( primitiveType, "", Integer.toString(offset), encodingToken.encoding().byteOrder(), indent); new Formatter(sb).format("\n" + - indent + " %1$s &%2$s(const %3$s value) SBE_NOEXCEPT\n" + + indent + " %1$s &%2$s(const %3$s value)%6$s\n" + indent + " {\n" + "%4$s" + + "%5$s" + indent + " return *this;\n" + indent + " }\n", formatClassName(containingClassName), propertyName, cppTypeName, - storeValue); + storeValue, + accessOrderListenerCall, + noexceptDeclaration); } private void generateArrayProperty( @@ -1449,12 +2040,18 @@ private void generateArrayProperty( final String propertyName, final Token propertyToken, final Token encodingToken, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final PrimitiveType primitiveType = encodingToken.encoding().primitiveType(); final String cppTypeName = cppTypeName(primitiveType); final int offset = encodingToken.offset(); + final CharSequence accessOrderListenerCall = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, propertyToken); + + final String noexceptDeclaration = noexceptDeclaration(fieldPrecedenceModel); + final int arrayLength = encodingToken.arrayLength(); new Formatter(sb).format("\n" + indent + " static SBE_CONSTEXPR std::uint64_t %1$sLength() SBE_NOEXCEPT\n" + @@ -1465,24 +2062,30 @@ private void generateArrayProperty( arrayLength); new Formatter(sb).format("\n" + - indent + " SBE_NODISCARD const char *%1$s() const SBE_NOEXCEPT\n" + + indent + " SBE_NODISCARD const char *%1$s() const%5$s\n" + indent + " {\n" + "%2$s" + + "%4$s" + indent + " return m_buffer + m_offset + %3$d;\n" + indent + " }\n", propertyName, generateTypeFieldNotPresentCondition(propertyToken.version(), indent), - offset); + offset, + accessOrderListenerCall, + noexceptDeclaration); new Formatter(sb).format("\n" + - indent + " SBE_NODISCARD char *%1$s() SBE_NOEXCEPT\n" + + indent + " SBE_NODISCARD char *%1$s()%5$s\n" + indent + " {\n" + "%2$s" + + "%4$s" + indent + " return m_buffer + m_offset + %3$d;\n" + indent + " }\n", propertyName, generateTypeFieldNotPresentCondition(propertyToken.version(), indent), - offset); + offset, + accessOrderListenerCall, + noexceptDeclaration); final CharSequence loadValue = generateLoadValue( primitiveType, @@ -1498,13 +2101,15 @@ private void generateArrayProperty( indent + " throw std::runtime_error(\"index out of range for %2$s [E104]\");\n" + indent + " }\n\n" + "%4$s" + + "%6$s" + "%5$s" + indent + " }\n", cppTypeName, propertyName, arrayLength, generateFieldNotPresentCondition(propertyToken.version(), encodingToken.encoding(), indent), - loadValue); + loadValue, + accessOrderListenerCall); final CharSequence storeValue = generateStoreValue( primitiveType, @@ -1521,6 +2126,7 @@ private void generateArrayProperty( indent + " throw std::runtime_error(\"index out of range for %2$s [E105]\");\n" + indent + " }\n\n" + + "%6$s" + "%5$s" + indent + " return *this;\n" + indent + " }\n", @@ -1528,7 +2134,8 @@ private void generateArrayProperty( propertyName, cppTypeName, arrayLength, - storeValue); + storeValue, + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " std::uint64_t get%1$s(char *const dst, const std::uint64_t length) const\n" + @@ -1539,6 +2146,7 @@ private void generateArrayProperty( indent + " }\n\n" + "%3$s" + + "%6$s" + indent + " std::memcpy(dst, m_buffer + m_offset + %4$d, " + "sizeof(%5$s) * static_cast(length));\n" + indent + " return length;\n" + @@ -1547,11 +2155,13 @@ private void generateArrayProperty( arrayLength, generateArrayFieldNotPresentCondition(propertyToken.version(), indent), offset, - cppTypeName); + cppTypeName, + accessOrderListenerCall); new Formatter(sb).format("\n" + - indent + " %1$s &put%2$s(const char *const src) SBE_NOEXCEPT\n" + + indent + " %1$s &put%2$s(const char *const src)%7$s\n" + indent + " {\n" + + "%6$s" + indent + " std::memcpy(m_buffer + m_offset + %3$d, src, sizeof(%4$s) * %5$d);\n" + indent + " return *this;\n" + indent + " }\n", @@ -1559,7 +2169,9 @@ private void generateArrayProperty( toUpperFirstChar(propertyName), offset, cppTypeName, - arrayLength); + arrayLength, + accessOrderListenerCall, + noexceptDeclaration); if (arrayLength > 1 && arrayLength <= 4) { @@ -1578,8 +2190,9 @@ private void generateArrayProperty( } } - sb.append(") SBE_NOEXCEPT\n"); + sb.append(")").append(noexceptDeclaration).append("\n"); sb.append(indent).append(" {\n"); + sb.append(accessOrderListenerCall); for (int i = 0; i < arrayLength; i++) { @@ -1601,6 +2214,8 @@ private void generateArrayProperty( new Formatter(sb).format("\n" + indent + " SBE_NODISCARD std::string get%1$sAsString() const\n" + indent + " {\n" + + "%4$s" + + "%5$s" + indent + " const char *buffer = m_buffer + m_offset + %2$d;\n" + indent + " std::size_t length = 0;\n\n" + @@ -1611,14 +2226,18 @@ private void generateArrayProperty( indent + " }\n", toUpperFirstChar(propertyName), offset, - arrayLength); + arrayLength, + generateStringNotPresentCondition(propertyToken.version(), indent), + accessOrderListenerCall); - generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName); + generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName, accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " #if __cplusplus >= 201703L\n" + - indent + " SBE_NODISCARD std::string_view get%1$sAsStringView() const SBE_NOEXCEPT\n" + + indent + " SBE_NODISCARD std::string_view get%1$sAsStringView() const%6$s\n" + indent + " {\n" + + "%4$s" + + "%5$s" + indent + " const char *buffer = m_buffer + m_offset + %2$d;\n" + indent + " std::size_t length = 0;\n\n" + @@ -1630,7 +2249,10 @@ private void generateArrayProperty( indent + " #endif\n", toUpperFirstChar(propertyName), offset, - arrayLength); + arrayLength, + generateStringViewNotPresentCondition(propertyToken.version(), indent), + accessOrderListenerCall, + noexceptDeclaration); new Formatter(sb).format("\n" + indent + " #if __cplusplus >= 201703L\n" + @@ -1642,6 +2264,7 @@ private void generateArrayProperty( indent + " throw std::runtime_error(\"string too large for put%2$s [E106]\");\n" + indent + " }\n\n" + + "%5$s" + indent + " std::memcpy(m_buffer + m_offset + %3$d, str.data(), srcLength);\n" + indent + " for (std::size_t start = srcLength; start < %4$d; ++start)\n" + indent + " {\n" + @@ -1659,6 +2282,7 @@ private void generateArrayProperty( indent + " throw std::runtime_error(\"string too large for put%2$s [E106]\");\n" + indent + " }\n\n" + + "%5$s" + indent + " std::memcpy(m_buffer + m_offset + %3$d, str.c_str(), srcLength);\n" + indent + " for (std::size_t start = srcLength; start < %4$d; ++start)\n" + indent + " {\n" + @@ -1671,17 +2295,23 @@ private void generateArrayProperty( containingClassName, toUpperFirstChar(propertyName), offset, - arrayLength); + arrayLength, + accessOrderListenerCall); } } private void generateJsonEscapedStringGetter( - final StringBuilder sb, final Token token, final String indent, final String propertyName) + final StringBuilder sb, + final Token token, + final String indent, + final String propertyName, + final CharSequence accessOrderListenerCall) { new Formatter(sb).format("\n" + indent + " std::string get%1$sAsJsonEscapedString()\n" + indent + " {\n" + "%2$s" + + "%3$s" + indent + " std::ostringstream oss;\n" + indent + " std::string s = get%1$sAsString();\n\n" + indent + " for (const auto c : s)\n" + @@ -1710,7 +2340,8 @@ private void generateJsonEscapedStringGetter( indent + " return oss.str();\n" + indent + " }\n", toUpperFirstChar(propertyName), - generateStringNotPresentCondition(token.version(), indent)); + generateStringNotPresentCondition(token.version(), indent), + accessOrderListenerCall); } private void generateConstPropertyMethods( @@ -1797,7 +2428,7 @@ private void generateConstPropertyMethods( values, constantValue.length); - generateJsonEscapedStringGetter(sb, token, indent, propertyName); + generateJsonEscapedStringGetter(sb, token, indent, propertyName, ""); } private CharSequence generateFixedFlyweightCode(final String className, final int size) @@ -1811,6 +2442,7 @@ private CharSequence generateFixedFlyweightCode(final String className, final in " std::uint64_t m_bufferLength = 0;\n" + " std::uint64_t m_offset = 0;\n" + " std::uint64_t m_actingVersion = 0;\n\n" + + "%7$s" + "public:\n" + " enum MetaAttribute\n" + @@ -1869,7 +2501,17 @@ private CharSequence generateFixedFlyweightCode(final String className, final in " const std::uint64_t actingVersion,\n" + " const std::uint64_t bufferLength)\n" + " {\n" + - " return *this = %1$s(buffer, offset, bufferLength, actingVersion);\n" + + " m_buffer = buffer;\n" + + " m_bufferLength = bufferLength;\n" + + " m_offset = offset;\n" + + " m_actingVersion = actingVersion;\n\n" + + + " if (SBE_BOUNDS_CHECK_EXPECT(((m_offset + %2$s) > m_bufferLength), false))\n" + + " {\n" + + " throw std::runtime_error(\"buffer too short for flyweight [E107]\");\n" + + " }\n\n" + + + " return *this;\n" + " }\n\n" + " SBE_NODISCARD static SBE_CONSTEXPR std::uint64_t encodedLength() SBE_NOEXCEPT\n" + @@ -1916,14 +2558,53 @@ private CharSequence generateFixedFlyweightCode(final String className, final in schemaIdType, generateLiteral(ir.headerStructure().schemaIdType(), Integer.toString(ir.id())), schemaVersionType, - generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version()))); + generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), + generateHiddenCopyConstructor(" ", className)); + } + + private static String generateHiddenCopyConstructor(final String indent, final String className) + { + final String ctorAndCopyAssignmentDeletion = String.format( + "#if __cplusplus >= 201103L\n" + + "%1$s%2$s(const %2$s&) = delete;\n" + + "%1$s%2$s& operator=(const %2$s&) = delete;\n" + + "#else\n" + + "%1$s%2$s(const %2$s&);\n" + + "%1$s%2$s& operator=(const %2$s&);\n" + + "#endif\n\n", + indent, className); + + return DISABLE_IMPLICIT_COPYING ? ctorAndCopyAssignmentDeletion : ""; } - private static CharSequence generateConstructorsAndOperators(final String className) + private static CharSequence generateConstructorsAndOperators( + final String className, + final FieldPrecedenceModel fieldPrecedenceModel) { + final String constructorWithCodecState = null == fieldPrecedenceModel ? "" : String.format( + " %1$s(\n" + + " char *buffer,\n" + + " const std::uint64_t offset,\n" + + " const std::uint64_t bufferLength,\n" + + " const std::uint64_t actingBlockLength,\n" + + " const std::uint64_t actingVersion,\n" + + " CodecState codecState) :\n" + + " m_buffer(buffer),\n" + + " m_bufferLength(bufferLength),\n" + + " m_offset(offset),\n" + + " m_position(sbeCheckPosition(offset + actingBlockLength)),\n" + + " m_actingBlockLength(actingBlockLength),\n" + + " m_actingVersion(actingVersion),\n" + + " m_codecState(codecState)\n" + + " {\n" + + " }\n\n", + className); + return String.format( " %1$s() = default;\n\n" + + "%2$s" + + " %1$s(\n" + " char *buffer,\n" + " const std::uint64_t offset,\n" + @@ -1952,10 +2633,14 @@ private static CharSequence generateConstructorsAndOperators(final String classN " %1$s(buffer, 0, bufferLength, actingBlockLength, actingVersion)\n" + " {\n" + " }\n\n", - className); + className, + constructorWithCodecState); } - private CharSequence generateMessageFlyweightCode(final String className, final Token token) + private CharSequence generateMessageFlyweightCode( + final String className, + final Token token, + final FieldPrecedenceModel fieldPrecedenceModel) { final String blockLengthType = cppTypeName(ir.headerStructure().blockLengthType()); final String templateIdType = cppTypeName(ir.headerStructure().templateIdType()); @@ -1965,20 +2650,28 @@ private CharSequence generateMessageFlyweightCode(final String className, final final String headerType = ir.headerStructure().tokens().get(0).name(); final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); + + final String codecStateArgument = null == fieldPrecedenceModel ? "" : ", m_codecState"; + return String.format( "private:\n" + + "%15$s" + + "%16$s" + " char *m_buffer = nullptr;\n" + " std::uint64_t m_bufferLength = 0;\n" + " std::uint64_t m_offset = 0;\n" + " std::uint64_t m_position = 0;\n" + " std::uint64_t m_actingBlockLength = 0;\n" + - " std::uint64_t m_actingVersion = 0;\n\n" + + " std::uint64_t m_actingVersion = 0;\n" + + "%17$s" + " inline std::uint64_t *sbePositionPtr() SBE_NOEXCEPT\n" + " {\n" + " return &m_position;\n" + " }\n\n" + + "%22$s" + + "public:\n" + " static const %1$s SBE_BLOCK_LENGTH = %2$s;\n" + " static const %3$s SBE_TEMPLATE_ID = %4$s;\n" + @@ -2005,7 +2698,9 @@ private CharSequence generateMessageFlyweightCode(final String className, final " using messageHeader = %12$s;\n\n" + + "%18$s" + "%11$s" + + " SBE_NODISCARD static SBE_CONSTEXPR %1$s sbeBlockLength() SBE_NOEXCEPT\n" + " {\n" + " return %2$s;\n" + @@ -2048,7 +2743,14 @@ private CharSequence generateMessageFlyweightCode(final String className, final " %10$s &wrapForEncode(char *buffer, const std::uint64_t offset, const std::uint64_t bufferLength)\n" + " {\n" + - " return *this = %10$s(buffer, offset, bufferLength, sbeBlockLength(), sbeSchemaVersion());\n" + + " m_buffer = buffer;\n" + + " m_bufferLength = bufferLength;\n" + + " m_offset = offset;\n" + + " m_actingBlockLength = sbeBlockLength();\n" + + " m_actingVersion = sbeSchemaVersion();\n" + + " m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" + + "%19$s" + + " return *this;\n" + " }\n\n" + " %10$s &wrapAndApplyHeader(" + @@ -2062,14 +2764,18 @@ private CharSequence generateMessageFlyweightCode(final String className, final " .schemaId(sbeSchemaId())\n" + " .version(sbeSchemaVersion());\n\n" + - " return *this = %10$s(\n" + - " buffer,\n" + - " offset + messageHeader::encodedLength(),\n" + - " bufferLength,\n" + - " sbeBlockLength(),\n" + - " sbeSchemaVersion());\n" + + " m_buffer = buffer;\n" + + " m_bufferLength = bufferLength;\n" + + " m_offset = offset + messageHeader::encodedLength();\n" + + " m_actingBlockLength = sbeBlockLength();\n" + + " m_actingVersion = sbeSchemaVersion();\n" + + " m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" + + "%19$s" + + " return *this;\n" + " }\n\n" + + "%20$s" + + " %10$s &wrapForDecode(\n" + " char *buffer,\n" + " const std::uint64_t offset,\n" + @@ -2077,7 +2783,14 @@ private CharSequence generateMessageFlyweightCode(final String className, final " const std::uint64_t actingVersion,\n" + " const std::uint64_t bufferLength)\n" + " {\n" + - " return *this = %10$s(buffer, offset, bufferLength, actingBlockLength, actingVersion);\n" + + " m_buffer = buffer;\n" + + " m_bufferLength = bufferLength;\n" + + " m_offset = offset;\n" + + " m_actingBlockLength = actingBlockLength;\n" + + " m_actingVersion = actingVersion;\n" + + " m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" + + "%21$s" + + " return *this;\n" + " }\n\n" + " %10$s &sbeRewind()\n" + @@ -2113,7 +2826,7 @@ private CharSequence generateMessageFlyweightCode(final String className, final " SBE_NODISCARD std::uint64_t decodeLength() const\n" + " {\n" + - " %10$s skipper(m_buffer, m_offset, m_bufferLength, sbeBlockLength(), m_actingVersion);\n" + + " %10$s skipper(m_buffer, m_offset, m_bufferLength, sbeBlockLength(), m_actingVersion%14$s);\n" + " skipper.skip();\n" + " return skipper.encodedLength();\n" + " }\n\n" + @@ -2147,15 +2860,269 @@ private CharSequence generateMessageFlyweightCode(final String className, final generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), semanticType, className, - generateConstructorsAndOperators(className), + generateConstructorsAndOperators(className, fieldPrecedenceModel), formatClassName(headerType), - semanticVersion); + semanticVersion, + codecStateArgument, + generateFieldOrderStateEnum(fieldPrecedenceModel), + generateLookupTableDeclarations(fieldPrecedenceModel), + generateFieldOrderStateMember(fieldPrecedenceModel), + generateAccessOrderErrorType(fieldPrecedenceModel), + generateEncoderWrapListener(fieldPrecedenceModel), + generateDecoderWrapListener(fieldPrecedenceModel), + generateDecoderWrapListenerCall(fieldPrecedenceModel), + generateHiddenCopyConstructor(" ", className)); + } + + private CharSequence generateAccessOrderErrorType(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(INDENT).append("class AccessOrderError : public std::logic_error\n") + .append(INDENT).append("{\n") + .append(INDENT).append("public:\n") + .append(INDENT).append(" explicit AccessOrderError(const std::string &msg) : std::logic_error(msg) {}\n") + .append(INDENT).append("};\n\n"); + return sb; + } + + private static CharSequence generateLookupTableDeclarations(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(INDENT).append("static const std::string STATE_NAME_LOOKUP[") + .append(fieldPrecedenceModel.stateCount()) + .append("];\n"); + sb.append(INDENT).append("static const std::string STATE_TRANSITIONS_LOOKUP[") + .append(fieldPrecedenceModel.stateCount()) + .append("];\n\n"); + + sb.append(INDENT).append("static std::string codecStateName(CodecState state)\n") + .append(INDENT).append("{\n") + .append(TWO_INDENT).append("return STATE_NAME_LOOKUP[static_cast(state)];\n") + .append(INDENT).append("}\n\n"); + + sb.append(INDENT).append("static std::string codecStateTransitions(CodecState state)\n") + .append(INDENT).append("{\n") + .append(TWO_INDENT).append("return STATE_TRANSITIONS_LOOKUP[static_cast(state)];\n") + .append(INDENT).append("}\n\n"); + + return sb; + } + + private static void generateLookupTableDefinitions( + final StringBuilder sb, + final String className, + final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n").append("const std::string ").append(className).append("::STATE_NAME_LOOKUP[") + .append(fieldPrecedenceModel.stateCount()).append("] =\n") + .append("{\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(INDENT).append("\"").append(state.name()).append("\",\n"); + }); + sb.append("};\n\n"); + + sb.append("const std::string ").append(className).append("::STATE_TRANSITIONS_LOOKUP[") + .append(fieldPrecedenceModel.stateCount()).append("] =\n") + .append("{\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(INDENT).append("\""); + final MutableBoolean isFirst = new MutableBoolean(true); + final Set transitionDescriptions = new HashSet<>(); + fieldPrecedenceModel.forEachTransitionFrom(state, transitionGroup -> + { + if (transitionDescriptions.add(transitionGroup.exampleCode())) + { + if (isFirst.get()) + { + isFirst.set(false); + } + else + { + sb.append(", "); + } + + sb.append("\\\"").append(transitionGroup.exampleCode()).append("\\\""); + } + }); + sb.append("\",\n"); + }); + sb.append("};\n\n"); + } + + private static CharSequence qualifiedStateCase(final FieldPrecedenceModel.State state) + { + return "CodecState::" + state.name(); + } + + private static CharSequence stateCaseForSwitchCase(final FieldPrecedenceModel.State state) + { + return qualifiedStateCase(state); + } + + private static CharSequence unqualifiedStateCase(final FieldPrecedenceModel.State state) + { + return state.name(); + } + + private static CharSequence generateFieldOrderStateEnum(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + + sb.append(" /**\n"); + sb.append(" * The states in which a encoder/decoder/codec can live.\n"); + sb.append(" *\n"); + sb.append(" *

    The state machine diagram below, encoded in the dot language, describes\n"); + sb.append(" * the valid state transitions according to the order in which fields may be\n"); + sb.append(" * accessed safely. Tools such as PlantUML and Graphviz can render it.\n"); + sb.append(" *\n"); + sb.append(" *

    {@code\n");
    +        fieldPrecedenceModel.generateGraph(sb, "     *   ");
    +        sb.append("     * }
    \n"); + sb.append(" */\n"); + sb.append(INDENT).append("enum class CodecState\n") + .append(INDENT).append("{\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(INDENT).append(INDENT).append(unqualifiedStateCase(state)) + .append(" = ").append(state.number()) + .append(",\n"); + }); + sb.append(INDENT).append("};\n\n"); + + return sb; + } + + private static CharSequence generateFieldOrderStateMember(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return "\n"; + } + + final StringBuilder sb = new StringBuilder(); + + sb.append(INDENT).append("CodecState m_codecState = ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())) + .append(";\n\n"); + + sb.append(INDENT).append("CodecState codecState() const\n") + .append(INDENT).append("{\n") + .append(INDENT).append(INDENT).append("return m_codecState;\n") + .append(INDENT).append("}\n\n"); + + sb.append(INDENT).append("CodecState *codecStatePtr()\n") + .append(INDENT).append("{\n") + .append(INDENT).append(INDENT).append("return &m_codecState;\n") + .append(INDENT).append("}\n\n"); + + sb.append(INDENT).append("void codecState(CodecState newState)\n") + .append(INDENT).append("{\n") + .append(INDENT).append(INDENT).append("m_codecState = newState;\n") + .append(INDENT).append("}\n\n"); + + return sb; + } + + private static CharSequence generateDecoderWrapListener(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + if (fieldPrecedenceModel.versionCount() == 1) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(INDENT).append("void onWrapForDecode(std::uint64_t actingVersion)\n") + .append(INDENT).append("{\n") + .append(INDENT).append(INDENT).append("switch(actingVersion)\n") + .append(INDENT).append(INDENT).append("{\n"); + + fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> + { + sb.append(INDENT).append(TWO_INDENT).append("case ").append(version).append(":\n") + .append(INDENT).append(THREE_INDENT).append("codecState(") + .append(qualifiedStateCase(state)).append(");\n") + .append(INDENT).append(THREE_INDENT).append("break;\n"); + }); + + sb.append(INDENT).append(TWO_INDENT).append("default:\n") + .append(INDENT).append(THREE_INDENT).append("codecState(") + .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())).append(");\n") + .append(INDENT).append(THREE_INDENT).append("break;\n") + .append(INDENT).append(INDENT).append("}\n") + .append(INDENT).append("}\n\n"); + + return sb; + } + + + private CharSequence generateDecoderWrapListenerCall(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + if (fieldPrecedenceModel.versionCount() == 1) + { + final StringBuilder sb = new StringBuilder(); + sb.append("#if defined(").append(precedenceChecksFlagName).append(")\n") + .append(TWO_INDENT).append("codecState(") + .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())).append(");\n") + .append("#endif\n"); + return sb; + } + + return generateAccessOrderListenerCall(fieldPrecedenceModel, TWO_INDENT, "onWrapForDecode", "actingVersion"); + } + + private CharSequence generateEncoderWrapListener(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append("#if defined(").append(precedenceChecksFlagName).append(")\n") + .append(TWO_INDENT).append("codecState(") + .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())) + .append(");\n") + .append("#endif\n"); + return sb; } private void generateFields( final StringBuilder sb, final String containingClassName, final List tokens, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { for (int i = 0, size = tokens.size(); i < size; i++) @@ -2169,23 +3136,29 @@ private void generateFields( generateFieldMetaAttributeMethod(sb, signalToken, indent); generateFieldCommonMethods(indent, sb, signalToken, encodingToken, propertyName); + generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent, signalToken); + switch (encodingToken.signal()) { case ENCODING: generatePrimitiveProperty( - sb, containingClassName, propertyName, signalToken, encodingToken, indent); + sb, containingClassName, propertyName, signalToken, encodingToken, + fieldPrecedenceModel, indent); break; case BEGIN_ENUM: - generateEnumProperty(sb, containingClassName, signalToken, propertyName, encodingToken, indent); + generateEnumProperty(sb, containingClassName, signalToken, propertyName, encodingToken, + fieldPrecedenceModel, indent); break; case BEGIN_SET: - generateBitsetProperty(sb, propertyName, encodingToken, indent); + generateBitsetProperty(sb, propertyName, signalToken, encodingToken, + fieldPrecedenceModel, indent); break; case BEGIN_COMPOSITE: - generateCompositeProperty(sb, propertyName, encodingToken, indent); + generateCompositeProperty(sb, propertyName, signalToken, encodingToken, + fieldPrecedenceModel, indent); break; default: @@ -2300,6 +3273,7 @@ private void generateEnumProperty( final Token fieldToken, final String propertyName, final Token encodingToken, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final String enumName = formatClassName(encodingToken.applicableTypeName()); @@ -2352,21 +3326,31 @@ private void generateEnumProperty( else { final String offsetStr = Integer.toString(offset); + + final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + TWO_INDENT, fieldToken); + + final String noexceptDeclaration = noexceptDeclaration(fieldPrecedenceModel); + new Formatter(sb).format("\n" + - indent + " SBE_NODISCARD %1$s %2$sRaw() const SBE_NOEXCEPT\n" + + indent + " SBE_NODISCARD %1$s %2$sRaw() const%6$s\n" + indent + " {\n" + "%3$s" + "%4$s" + + "%5$s" + indent + " }\n", typeName, propertyName, generateFieldNotPresentCondition(fieldToken.version(), encodingToken.encoding(), indent), - generateLoadValue(primitiveType, offsetStr, encodingToken.encoding().byteOrder(), indent)); + accessOrderListenerCall, + generateLoadValue(primitiveType, offsetStr, encodingToken.encoding().byteOrder(), indent), + noexceptDeclaration); new Formatter(sb).format("\n" + indent + " SBE_NODISCARD %1$s::Value %2$s() const\n" + indent + " {\n" + "%3$s" + + "%7$s" + indent + " %5$s val;\n" + indent + " std::memcpy(&val, m_buffer + m_offset + %6$d, sizeof(%5$s));\n" + indent + " return %1$s::get(%4$s(val));\n" + @@ -2376,11 +3360,13 @@ private void generateEnumProperty( generateEnumFieldNotPresentCondition(fieldToken.version(), enumName, indent), formatByteOrderEncoding(encodingToken.encoding().byteOrder(), primitiveType), typeName, - offset); + offset, + accessOrderListenerCall); new Formatter(sb).format("\n" + - indent + " %1$s &%2$s(const %3$s::Value value) SBE_NOEXCEPT\n" + + indent + " %1$s &%2$s(const %3$s::Value value)%8$s\n" + indent + " {\n" + + "%7$s" + indent + " %4$s val = %6$s(value);\n" + indent + " std::memcpy(m_buffer + m_offset + %5$d, &val, sizeof(%4$s));\n" + indent + " return *this;\n" + @@ -2390,15 +3376,22 @@ private void generateEnumProperty( enumName, typeName, offset, - formatByteOrderEncoding(encodingToken.encoding().byteOrder(), primitiveType)); + formatByteOrderEncoding(encodingToken.encoding().byteOrder(), primitiveType), + accessOrderListenerCall, + noexceptDeclaration); } } - private static void generateBitsetProperty( - final StringBuilder sb, final String propertyName, final Token token, final String indent) + private void generateBitsetProperty( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token encodingToken, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) { - final String bitsetName = formatClassName(token.applicableTypeName()); - final int offset = token.offset(); + final String bitsetName = formatClassName(encodingToken.applicableTypeName()); + final int offset = encodingToken.offset(); new Formatter(sb).format("\n" + indent + "private:\n" + @@ -2408,15 +3401,20 @@ private static void generateBitsetProperty( bitsetName, propertyName); + final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + TWO_INDENT, fieldToken); + new Formatter(sb).format( indent + " SBE_NODISCARD %1$s &%2$s()\n" + indent + " {\n" + + "%4$s" + indent + " m_%2$s.wrap(m_buffer, m_offset + %3$d, m_actingVersion, m_bufferLength);\n" + indent + " return m_%2$s;\n" + indent + " }\n", bitsetName, propertyName, - offset); + offset, + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " static SBE_CONSTEXPR std::size_t %1$sEncodingLength() SBE_NOEXCEPT\n" + @@ -2424,13 +3422,18 @@ private static void generateBitsetProperty( indent + " return %2$d;\n" + indent + " }\n", propertyName, - token.encoding().primitiveType().size()); + encodingToken.encoding().primitiveType().size()); } - private static void generateCompositeProperty( - final StringBuilder sb, final String propertyName, final Token token, final String indent) + private void generateCompositeProperty( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token encodingToken, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) { - final String compositeName = formatClassName(token.applicableTypeName()); + final String compositeName = formatClassName(encodingToken.applicableTypeName()); new Formatter(sb).format("\n" + "private:\n" + @@ -2440,15 +3443,20 @@ private static void generateCompositeProperty( compositeName, propertyName); + final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + TWO_INDENT, fieldToken); + new Formatter(sb).format( indent + " SBE_NODISCARD %1$s &%2$s()\n" + indent + " {\n" + + "%4$s" + indent + " m_%2$s.wrap(m_buffer, m_offset + %3$d, m_actingVersion, m_bufferLength);\n" + indent + " return m_%2$s;\n" + indent + " }\n", compositeName, propertyName, - token.offset()); + encodingToken.offset(), + accessOrderListenerCall); } private CharSequence generateNullValueLiteral(final PrimitiveType primitiveType, final Encoding encoding) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java index 5b4870a321..ee55d214d5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java @@ -18,6 +18,7 @@ import uk.co.real_logic.sbe.generation.CodeGenerator; import uk.co.real_logic.sbe.generation.TargetCodeGenerator; +import uk.co.real_logic.sbe.generation.TargetCodeGeneratorLoader; import uk.co.real_logic.sbe.ir.Ir; /** @@ -30,6 +31,9 @@ public class CSharp implements TargetCodeGenerator */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new CSharpGenerator(ir, new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); + return new CSharpGenerator( + ir, + TargetCodeGeneratorLoader.precedenceChecks(), + new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 5a607a8414..8fe17df71a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -19,26 +19,30 @@ import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.PrimitiveValue; import uk.co.real_logic.sbe.generation.CodeGenerator; -import org.agrona.generation.OutputManager; import uk.co.real_logic.sbe.generation.Generators; -import uk.co.real_logic.sbe.ir.*; +import uk.co.real_logic.sbe.generation.common.FieldPrecedenceModel; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; +import uk.co.real_logic.sbe.ir.Encoding; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.Signal; +import uk.co.real_logic.sbe.ir.Token; import org.agrona.Verify; +import org.agrona.collections.MutableBoolean; +import org.agrona.generation.OutputManager; import java.io.IOException; import java.io.Writer; import java.nio.ByteOrder; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static java.lang.System.lineSeparator; - import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; import static uk.co.real_logic.sbe.generation.csharp.CSharpUtil.*; -import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; -import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; -import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; -import static uk.co.real_logic.sbe.ir.GenerationUtil.findEndSignal; +import static uk.co.real_logic.sbe.ir.GenerationUtil.*; /** * Codec generator for the CSharp programming language. @@ -54,6 +58,8 @@ public class CSharpGenerator implements CodeGenerator private final Ir ir; private final OutputManager outputManager; + private final PrecedenceChecks precedenceChecks; + private final String precedenceChecksFlagName; /** * Create a new C# language {@link CodeGenerator}. @@ -62,11 +68,32 @@ public class CSharpGenerator implements CodeGenerator * @param outputManager for generating the codecs to. */ public CSharpGenerator(final Ir ir, final OutputManager outputManager) + { + this( + ir, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + outputManager + ); + } + + /** + * Create a new C# language {@link CodeGenerator}. + * + * @param ir for the messages and types. + * @param precedenceChecks whether and how to perform field precedence checks. + * @param outputManager for generating the codecs to. + */ + public CSharpGenerator( + final Ir ir, + final PrecedenceChecks precedenceChecks, + final OutputManager outputManager) { Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); this.ir = ir; + this.precedenceChecks = precedenceChecks; + this.precedenceChecksFlagName = precedenceChecks.context().precedenceChecksFlagName(); this.outputManager = outputManager; } @@ -123,32 +150,38 @@ public void generate() throws IOException { final Token msgToken = tokens.get(0); final String className = formatClassName(msgToken.name()); + final String stateClassName = className + ".CodecState"; + final FieldPrecedenceModel fieldPrecedenceModel = precedenceChecks.createCodecModel(stateClassName, tokens); try (Writer out = outputManager.createOutput(className)) { - out.append(generateFileHeader(ir.applicableNamespace())); - out.append(generateDocumentation(BASE_INDENT, msgToken)); - out.append(generateClassDeclaration(className)); - out.append(generateMessageFlyweightCode(className, msgToken, BASE_INDENT)); - final List messageBody = tokens.subList(1, tokens.size() - 1); int offset = 0; - final List fields = new ArrayList<>(); offset = collectFields(messageBody, offset, fields); - out.append(generateFields(fields, BASE_INDENT)); - final List groups = new ArrayList<>(); offset = collectGroups(messageBody, offset, groups); + final List varData = new ArrayList<>(); + collectVarData(messageBody, offset, varData); + + out.append(generateFileHeader(ir.applicableNamespace())); + out.append(generateDocumentation(BASE_INDENT, msgToken)); + out.append(generateClassDeclaration(className)); + out.append(generateMessageFlyweightCode(className, msgToken, fieldPrecedenceModel, BASE_INDENT)); + + out.append(generateFieldOrderStates(BASE_INDENT + INDENT, fieldPrecedenceModel)); + out.append(generateFullyEncodedCheck(BASE_INDENT + INDENT, fieldPrecedenceModel)); + + out.append(generateFields(fieldPrecedenceModel, fields, BASE_INDENT)); + final StringBuilder sb = new StringBuilder(); - generateGroups(sb, className, groups, BASE_INDENT); + generateGroups(sb, className, groups, fieldPrecedenceModel, BASE_INDENT); out.append(sb); - final List varData = new ArrayList<>(); - collectVarData(messageBody, offset, varData); - out.append(generateVarData(varData, BASE_INDENT + INDENT)); + out.append(generateVarData(fieldPrecedenceModel, varData, BASE_INDENT + INDENT)); - out.append(generateDisplay(toUpperFirstChar(msgToken.name()), fields, groups, varData)); + out.append(generateDisplay(toUpperFirstChar(msgToken.name()), + fields, groups, varData, fieldPrecedenceModel)); out.append(INDENT + "}\n"); out.append("}\n"); @@ -160,6 +193,7 @@ private void generateGroups( final StringBuilder sb, final String parentMessageClassName, final List tokens, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { for (int i = 0, size = tokens.size(); i < size; i++) @@ -170,23 +204,24 @@ private void generateGroups( throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); } final String groupName = groupToken.name(); - sb.append(generateGroupProperty(groupName, groupToken, indent + INDENT)); + sb.append(generateGroupProperty(groupName, fieldPrecedenceModel, groupToken, indent + INDENT)); - generateGroupClassHeader(sb, groupName, parentMessageClassName, tokens, i, indent + INDENT); + generateGroupClassHeader(sb, groupName, parentMessageClassName, tokens, + fieldPrecedenceModel, i, indent + INDENT); i++; i += tokens.get(i).componentTokenCount(); final List fields = new ArrayList<>(); i = collectFields(tokens, i, fields); - sb.append(generateFields(fields, indent + INDENT)); + sb.append(generateFields(fieldPrecedenceModel, fields, indent + INDENT)); final List groups = new ArrayList<>(); i = collectGroups(tokens, i, groups); - generateGroups(sb, parentMessageClassName, groups, indent + INDENT); + generateGroups(sb, parentMessageClassName, groups, fieldPrecedenceModel, indent + INDENT); final List varData = new ArrayList<>(); i = collectVarData(tokens, i, varData); - sb.append(generateVarData(varData, indent + INDENT + INDENT)); + sb.append(generateVarData(fieldPrecedenceModel, varData, indent + INDENT + INDENT)); appendGroupInstanceDisplay(sb, fields, groups, varData, indent + TWO_INDENT); @@ -199,6 +234,7 @@ private void generateGroupClassHeader( final String groupName, final String parentMessageClassName, final List tokens, + final FieldPrecedenceModel fieldPrecedenceModel, final int index, final String indent) { @@ -232,6 +268,16 @@ private void generateGroupClassHeader( groupName)); } + sb.append("\n") + // The "file" access modifier is more suitable but only available from C# 11 onwards. + .append(indent).append(INDENT).append("internal void NotPresent()\n") + .append(indent).append(INDENT).append("{\n") + .append(indent).append(TWO_INDENT).append("_count = 0;\n") + .append(indent).append(TWO_INDENT).append("_index = 0;\n") + .append(indent).append(TWO_INDENT).append("_buffer = null;\n") + .append(indent).append(TWO_INDENT).append("_offset = 0;\n") + .append(indent).append(INDENT).append("}\n"); + sb.append(String.format("\n" + indent + INDENT + "public void WrapForDecode(%s parentMessage, DirectBuffer buffer, int actingVersion)\n" + indent + INDENT + "{\n" + @@ -284,27 +330,50 @@ private void generateGroupClassHeader( blockLength, dimensionHeaderLength)); - generateGroupEnumerator(sb, groupName, typeForNumInGroup, indent); + if (null != fieldPrecedenceModel) + { + sb.append("\n") + .append(indent).append(" private CodecState codecState()\n") + .append(indent).append(" {\n") + .append(indent).append(" return _parentMessage.codecState();\n") + .append(indent).append(" }\n"); + + sb.append("\n") + .append(indent).append(" private void codecState(CodecState newState)\n") + .append(indent).append(" {\n") + .append(indent).append(" _parentMessage.codecState(newState);\n") + .append(indent).append(" }\n"); + } + + final Token groupToken = tokens.get(index); + generateGroupEnumerator(sb, fieldPrecedenceModel, groupToken, groupName, typeForNumInGroup, indent); } private void generateGroupEnumerator( final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final Token groupToken, final String groupName, final String typeForNumInGroup, final String indent) { + generateAccessOrderListenerMethodForNextGroupElement(sb, fieldPrecedenceModel, indent + INDENT, groupToken); + generateAccessOrderListenerMethodForResetGroupCount(sb, fieldPrecedenceModel, indent + INDENT, groupToken); + sb.append( indent + INDENT + "public int ActingBlockLength { get { return _blockLength; } }\n\n" + indent + INDENT + "public int Count { get { return _count; } }\n\n" + - indent + INDENT + "public bool HasNext { get { return _index < _count; } }\n"); + indent + INDENT + "public bool HasNext { get { return _index < _count; } }\n\n"); sb.append(String.format("\n" + indent + INDENT + "public int ResetCountToIndex()\n" + indent + INDENT + "{\n" + + "%s" + indent + INDENT + INDENT + "_count = _index;\n" + indent + INDENT + INDENT + "_dimensions.NumInGroup = (%s) _count;\n\n" + indent + INDENT + INDENT + "return _count;\n" + indent + INDENT + "}\n", + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, "OnResetCountToIndex"), typeForNumInGroup)); sb.append(String.format("\n" + @@ -314,6 +383,7 @@ private void generateGroupEnumerator( indent + INDENT + INDENT + "{\n" + indent + INDENT + INDENT + INDENT + "ThrowHelper.ThrowInvalidOperationException();\n" + indent + INDENT + INDENT + "}\n\n" + + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, "OnNextElementAccessed") + indent + INDENT + INDENT + "_offset = _parentMessage.Limit;\n" + indent + INDENT + INDENT + "_parentMessage.Limit = _offset + _blockLength;\n" + indent + INDENT + INDENT + "++_index;\n\n" + @@ -338,7 +408,11 @@ private boolean isRepresentableByInt32(final Encoding encoding) encoding.applicableMaxValue().longValue() <= Integer.MAX_VALUE; } - private CharSequence generateGroupProperty(final String groupName, final Token token, final String indent) + private CharSequence generateGroupProperty( + final String groupName, + final FieldPrecedenceModel fieldPrecedenceModel, + final Token token, + final String indent) { final StringBuilder sb = new StringBuilder(); @@ -355,37 +429,65 @@ private CharSequence generateGroupProperty(final String groupName, final Token t toUpperFirstChar(groupName), token.id())); + generateAccessOrderListenerMethodForGroupWrap(sb, fieldPrecedenceModel, indent, token); + generateSinceActingDeprecated(sb, indent, toUpperFirstChar(groupName), token); + final String groupField = "_" + toLowerFirstChar(groupName); + + final CharSequence accessOrderListenerCallOnDecode = generateAccessOrderListenerCall( + fieldPrecedenceModel, + indent + TWO_INDENT, + token, + groupField + ".Count", + "\"decode\""); + sb.append(String.format("\n" + "%1$s" + indent + "public %2$sGroup %3$s\n" + indent + "{\n" + indent + INDENT + "get\n" + indent + INDENT + "{\n" + + "%5$s" + + indent + INDENT + INDENT + "_%4$s.WrapForDecode(_parentMessage, _buffer, _actingVersion);\n" + + "%6$s" + + indent + INDENT + INDENT + "return _%4$s;\n" + indent + INDENT + "}\n" + indent + "}\n", generateDocumentation(indent, token), className, toUpperFirstChar(groupName), - toLowerFirstChar(groupName))); - + toLowerFirstChar(groupName), + generateGroupNotPresentCondition(token.version(), indent + INDENT + INDENT, groupField), + accessOrderListenerCallOnDecode)); + + final CharSequence accessOrderListenerCallOnEncode = generateAccessOrderListenerCall( + fieldPrecedenceModel, + indent + INDENT, + token, + "count", + "\"encode\""); sb.append(String.format("\n" + indent + "public %1$sGroup %2$sCount(int count)\n" + indent + "{\n" + + "%4$s" + indent + INDENT + "_%3$s.WrapForEncode(_parentMessage, _buffer, count);\n" + indent + INDENT + "return _%3$s;\n" + indent + "}\n", className, toUpperFirstChar(groupName), - toLowerFirstChar(groupName))); + toLowerFirstChar(groupName), + accessOrderListenerCallOnEncode)); return sb; } - private CharSequence generateVarData(final List tokens, final String indent) + private CharSequence generateVarData( + final FieldPrecedenceModel fieldPrecedenceModel, + final List tokens, + final String indent) { final StringBuilder sb = new StringBuilder(); @@ -412,21 +514,34 @@ private CharSequence generateVarData(final List tokens, final String inde final ByteOrder byteOrder = lengthEncoding.byteOrder(); final String byteOrderStr = generateByteOrder(byteOrder, lengthEncoding.primitiveType().size()); + generateAccessOrderListenerMethodForVarDataLength(sb, fieldPrecedenceModel, indent, token); + generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent, token); + sb.append(String.format("\n" + indent + "public const int %sHeaderSize = %d;\n", propertyName, sizeOfLengthField)); + final CharSequence lengthAccessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + INDENT, accessOrderListenerMethodName(token, "Length")); + sb.append(String.format(indent + "\n" + indent + "public int %1$sLength()\n" + indent + "{\n" + + "%5$s" + + "%6$s" + indent + INDENT + "_buffer.CheckLimit(_parentMessage.Limit + %2$d);\n" + indent + INDENT + "return (int)_buffer.%3$sGet%4$s(_parentMessage.Limit);\n" + indent + "}\n", propertyName, sizeOfLengthField, lengthTypePrefix, - byteOrderStr)); + byteOrderStr, + generateArrayFieldNotPresentCondition(token.version(), indent, "0"), + lengthAccessOrderListenerCall)); + + final CharSequence accessOrderListenerCall = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + INDENT, token); sb.append(String.format("\n" + indent + "public int Get%1$s(byte[] dst, int dstOffset, int length) =>\n" + @@ -437,6 +552,7 @@ private CharSequence generateVarData(final List tokens, final String inde indent + "public int Get%1$s(Span dst)\n" + indent + "{\n" + "%2$s" + + "%6$s" + indent + INDENT + "const int sizeOfLengthField = %3$d;\n" + indent + INDENT + "int limit = _parentMessage.Limit;\n" + indent + INDENT + "_buffer.CheckLimit(limit + sizeOfLengthField);\n" + @@ -447,15 +563,18 @@ private CharSequence generateVarData(final List tokens, final String inde indent + INDENT + "return bytesCopied;\n" + indent + "}\n", propertyName, - generateArrayFieldNotPresentCondition(token.version(), indent), + generateArrayFieldNotPresentCondition(token.version(), indent, "0"), sizeOfLengthField, lengthTypePrefix, - byteOrderStr)); + byteOrderStr, + accessOrderListenerCall)); sb.append(String.format(indent + "\n" + indent + "// Allocates and returns a new byte array\n" + indent + "public byte[] Get%1$sBytes()\n" + indent + "{\n" + + "%5$s" + + "%6$s" + indent + INDENT + "const int sizeOfLengthField = %2$d;\n" + indent + INDENT + "int limit = _parentMessage.Limit;\n" + indent + INDENT + "_buffer.CheckLimit(limit + sizeOfLengthField);\n" + @@ -468,7 +587,9 @@ private CharSequence generateVarData(final List tokens, final String inde propertyName, sizeOfLengthField, lengthTypePrefix, - byteOrderStr)); + byteOrderStr, + generateArrayFieldNotPresentCondition(token.version(), indent, "new byte[0]"), + accessOrderListenerCall)); sb.append(String.format("\n" + indent + "public int Set%1$s(byte[] src, int srcOffset, int length) =>\n" + @@ -478,6 +599,7 @@ private CharSequence generateVarData(final List tokens, final String inde sb.append(String.format("\n" + indent + "public int Set%1$s(ReadOnlySpan src)\n" + indent + "{\n" + + "%6$s" + indent + INDENT + "const int sizeOfLengthField = %2$d;\n" + indent + INDENT + "int limit = _parentMessage.Limit;\n" + indent + INDENT + "_parentMessage.Limit = limit + sizeOfLengthField + src.Length;\n" + @@ -489,7 +611,8 @@ private CharSequence generateVarData(final List tokens, final String inde sizeOfLengthField, lengthTypePrefix, lengthCSharpType, - byteOrderStr)); + byteOrderStr, + accessOrderListenerCall)); if (characterEncoding != null) // only generate these string based methods if there is an encoding { @@ -497,6 +620,8 @@ private CharSequence generateVarData(final List tokens, final String inde .append(String.format( indent + "public string Get%1$s()\n" + indent + "{\n" + + "%6$s" + + "%7$s" + indent + INDENT + "const int sizeOfLengthField = %2$d;\n" + indent + INDENT + "int limit = _parentMessage.Limit;\n" + indent + INDENT + "_buffer.CheckLimit(limit + sizeOfLengthField);\n" + @@ -507,15 +632,22 @@ private CharSequence generateVarData(final List tokens, final String inde indent + "}\n\n" + indent + "public void Set%1$s(string value)\n" + indent + "{\n" + + "%7$s" + indent + INDENT + "var encoding = %1$sResolvedCharacterEncoding;\n" + indent + INDENT + "const int sizeOfLengthField = %2$d;\n" + indent + INDENT + "int limit = _parentMessage.Limit;\n" + indent + INDENT + "int byteCount = _buffer.SetBytesFromString(encoding, value, " + "limit + sizeOfLengthField);\n" + indent + INDENT + "_parentMessage.Limit = limit + sizeOfLengthField + byteCount;\n" + - indent + INDENT + "_buffer.%3$sPut%4$s(limit, (ushort)byteCount);\n" + + indent + INDENT + "_buffer.%3$sPut%4$s(limit, (%5$s)byteCount);\n" + indent + "}\n", - propertyName, sizeOfLengthField, lengthTypePrefix, byteOrderStr)); + propertyName, + sizeOfLengthField, + lengthTypePrefix, + byteOrderStr, + lengthCSharpType, + generateArrayFieldNotPresentCondition(token.version(), indent, "\"\""), + accessOrderListenerCall)); } } } @@ -588,23 +720,24 @@ private CharSequence generateCompositePropertyElements(final List tokens, { final Token token = tokens.get(i); final String propertyName = formatPropertyName(token.name()); + final FieldPrecedenceModel fieldPrecedenceModel = null; switch (token.signal()) { case ENCODING: - sb.append(generatePrimitiveProperty(propertyName, token, token, indent)); + sb.append(generatePrimitiveProperty(propertyName, token, token, fieldPrecedenceModel, indent)); break; case BEGIN_ENUM: - sb.append(generateEnumProperty(propertyName, token, token, indent)); + sb.append(generateEnumProperty(propertyName, token, token, fieldPrecedenceModel, indent)); break; case BEGIN_SET: - sb.append(generateBitSetProperty(propertyName, token, token, indent)); + sb.append(generateBitSetProperty(propertyName, token, token, fieldPrecedenceModel, indent)); break; case BEGIN_COMPOSITE: - sb.append(generateCompositeProperty(propertyName, token, token, indent)); + sb.append(generateCompositeProperty(propertyName, token, token, fieldPrecedenceModel, indent)); break; default: @@ -747,7 +880,11 @@ private CharSequence generateEnumDeclaration( } private CharSequence generatePrimitiveProperty( - final String propertyName, final Token fieldToken, final Token typeToken, final String indent) + final String propertyName, + final Token fieldToken, + final Token typeToken, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) { final StringBuilder sb = new StringBuilder(); @@ -759,7 +896,8 @@ private CharSequence generatePrimitiveProperty( } else { - sb.append(generatePrimitivePropertyMethods(propertyName, fieldToken, typeToken, indent)); + sb.append(generatePrimitivePropertyMethods(propertyName, fieldToken, typeToken, + fieldPrecedenceModel, indent)); } return sb; @@ -769,17 +907,20 @@ private CharSequence generatePrimitivePropertyMethods( final String propertyName, final Token fieldToken, final Token typeToken, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final int arrayLength = typeToken.arrayLength(); if (arrayLength == 1) { - return generateSingleValueProperty(propertyName, fieldToken, typeToken, indent + INDENT); + return generateSingleValueProperty(propertyName, fieldToken, typeToken, + fieldPrecedenceModel, indent + INDENT); } else if (arrayLength > 1) { - return generateArrayProperty(propertyName, fieldToken, typeToken, indent + INDENT); + return generateArrayProperty(propertyName, fieldToken, typeToken, + fieldPrecedenceModel, indent + INDENT); } return ""; @@ -809,6 +950,7 @@ private CharSequence generateSingleValueProperty( final String propertyName, final Token fieldToken, final Token typeToken, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); @@ -817,6 +959,9 @@ private CharSequence generateSingleValueProperty( final ByteOrder byteOrder = typeToken.encoding().byteOrder(); final String byteOrderStr = generateByteOrder(byteOrder, typeToken.encoding().primitiveType().size()); + final CharSequence accessOrderListenerCall = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, fieldToken); + return String.format("\n" + "%1$s" + indent + "public %2$s %3$s\n" + @@ -824,10 +969,12 @@ private CharSequence generateSingleValueProperty( indent + INDENT + "get\n" + indent + INDENT + "{\n" + "%4$s" + + "%8$s" + indent + INDENT + INDENT + "return _buffer.%5$sGet%7$s(_offset + %6$d);\n" + indent + INDENT + "}\n" + indent + INDENT + "set\n" + indent + INDENT + "{\n" + + "%8$s" + indent + INDENT + INDENT + "_buffer.%5$sPut%7$s(_offset + %6$d, value);\n" + indent + INDENT + "}\n" + indent + "}\n\n", @@ -837,7 +984,8 @@ private CharSequence generateSingleValueProperty( generateFieldNotPresentCondition(fieldToken.version(), typeToken.encoding(), indent), typePrefix, offset, - byteOrderStr); + byteOrderStr, + accessOrderListenerCall); } private CharSequence generateFieldNotPresentCondition( @@ -866,16 +1014,34 @@ private CharSequence generateFieldNotPresentCondition( literal); } - private CharSequence generateArrayFieldNotPresentCondition(final int sinceVersion, final String indent) + private CharSequence generateGroupNotPresentCondition( + final int sinceVersion, + final String indent, + final String groupInstanceField) { if (0 == sinceVersion) { return ""; } - return String.format( - indent + INDENT + INDENT + "if (_actingVersion < %d) return 0;\n\n", - sinceVersion); + return indent + "if (_actingVersion < " + sinceVersion + ")" + + indent + "{\n" + + indent + INDENT + groupInstanceField + ".NotPresent();\n" + + indent + INDENT + "return " + groupInstanceField + ";\n" + + indent + "}\n\n"; + } + + private CharSequence generateArrayFieldNotPresentCondition( + final int sinceVersion, + final String indent, + final String defaultValue) + { + if (0 == sinceVersion) + { + return ""; + } + + return indent + INDENT + "if (_actingVersion < " + sinceVersion + ") return " + defaultValue + ";\n\n"; } private CharSequence generateBitSetNotPresentCondition( @@ -912,7 +1078,7 @@ private CharSequence generateArrayProperty( final String propertyName, final Token fieldToken, final Token typeToken, - final String indent) + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); final String typePrefix = toUpperFirstChar(typeToken.encoding().primitiveType().primitiveName()); @@ -923,6 +1089,11 @@ private CharSequence generateArrayProperty( final int typeSize = typeToken.encoding().primitiveType().size(); final String propName = toUpperFirstChar(propertyName); + final CharSequence accessOrderListenerCall = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + INDENT, fieldToken); + final CharSequence accessOrderListenerCallDoubleIndent = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, fieldToken); + final StringBuilder sb = new StringBuilder(); sb.append(String.format("\n" + @@ -938,12 +1109,14 @@ private CharSequence generateArrayProperty( indent + INDENT + INDENT + "ThrowHelper.ThrowIndexOutOfRangeException(index);\n" + indent + INDENT + "}\n\n" + "%5$s" + + "%10$s" + indent + INDENT + "return _buffer.%6$sGet%9$s(_offset + %7$d + (index * %8$d));\n" + indent + "}\n", generateDocumentation(indent, fieldToken), typeName, propName, fieldLength, generateFieldNotPresentCondition(fieldToken.version(), typeToken.encoding(), indent), - typePrefix, offset, typeSize, byteOrderStr)); + typePrefix, offset, typeSize, byteOrderStr, + accessOrderListenerCall)); sb.append(String.format("\n" + "%1$s" + @@ -953,29 +1126,48 @@ private CharSequence generateArrayProperty( indent + INDENT + "{\n" + indent + INDENT + INDENT + "ThrowHelper.ThrowIndexOutOfRangeException(index);\n" + indent + INDENT + "}\n\n" + + "%9$s" + indent + INDENT + "_buffer.%5$sPut%8$s(_offset + %6$d + (index * %7$d), value);\n" + indent + "}\n", generateDocumentation(indent, fieldToken), - propName, typeName, fieldLength, typePrefix, offset, typeSize, byteOrderStr)); + propName, typeName, fieldLength, typePrefix, offset, typeSize, byteOrderStr, + accessOrderListenerCall)); sb.append(String.format("\n" + "%1$s" + indent + "public ReadOnlySpan<%2$s> %3$s\n" + indent + "{\n" + - indent + INDENT + "get => _buffer.AsReadOnlySpan<%2$s>(_offset + %4$s, %3$sLength);\n" + - indent + INDENT + "set => value.CopyTo(_buffer.AsSpan<%2$s>(_offset + %4$s, %3$sLength));\n" + + indent + INDENT + "get\n" + + indent + INDENT + "{\n" + + "%5$s" + + "%6$s" + + indent + INDENT + INDENT + "return _buffer.AsReadOnlySpan<%2$s>(_offset + %4$s, %3$sLength);\n" + + indent + INDENT + "}\n" + + indent + INDENT + "set\n" + + indent + INDENT + "{\n" + + "%6$s" + + indent + INDENT + INDENT + "value.CopyTo(_buffer.AsSpan<%2$s>(_offset + %4$s, %3$sLength));\n" + + indent + INDENT + "}\n" + indent + "}\n", generateDocumentation(indent, fieldToken), - typeName, propName, offset)); + typeName, propName, offset, + generateArrayFieldNotPresentCondition(fieldToken.version(), + indent + INDENT + INDENT, "new " + typeName + "[0]"), + accessOrderListenerCallDoubleIndent)); sb.append(String.format("\n" + "%1$s" + indent + "public Span<%2$s> %3$sAsSpan()\n" + indent + "{\n" + + "%5$s" + + "%6$s" + indent + INDENT + "return _buffer.AsSpan<%2$s>(_offset + %4$s, %3$sLength);\n" + indent + "}\n", generateDocumentation(indent, fieldToken), - typeName, propName, offset)); + typeName, propName, offset, + generateArrayFieldNotPresentCondition(fieldToken.version(), + indent + INDENT + INDENT, "new " + typeName + "[0]"), + accessOrderListenerCall)); if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { @@ -986,9 +1178,13 @@ private CharSequence generateArrayProperty( indent + "{\n" + indent + INDENT + "const int length = %2$d;\n" + "%3$s" + + "%4$s" + indent + INDENT + "return Get%1$s(new Span(dst, dstOffset, length));\n" + indent + "}\n", - propName, fieldLength, generateArrayFieldNotPresentCondition(fieldToken.version(), indent), offset)); + propName, + fieldLength, + generateArrayFieldNotPresentCondition(fieldToken.version(), indent, "0"), + accessOrderListenerCall)); sb.append(String.format("\n" + indent + "public int Get%1$s(Span dst)\n" + @@ -999,10 +1195,15 @@ private CharSequence generateArrayProperty( indent + INDENT + INDENT + "ThrowHelper.ThrowWhenSpanLengthTooSmall(dst.Length);\n" + indent + INDENT + "}\n\n" + "%3$s" + + "%5$s" + indent + INDENT + "_buffer.GetBytes(_offset + %4$d, dst);\n" + indent + INDENT + "return length;\n" + indent + "}\n", - propName, fieldLength, generateArrayFieldNotPresentCondition(fieldToken.version(), indent), offset)); + propName, + fieldLength, + generateArrayFieldNotPresentCondition(fieldToken.version(), indent, "0"), + offset, + accessOrderListenerCall)); sb.append(String.format("\n" + indent + "public void Set%1$s(byte[] src, int srcOffset)\n" + @@ -1019,22 +1220,28 @@ private CharSequence generateArrayProperty( indent + INDENT + "{\n" + indent + INDENT + INDENT + "ThrowHelper.ThrowWhenSpanLengthTooLarge(src.Length);\n" + indent + INDENT + "}\n\n" + + "%4$s" + indent + INDENT + "_buffer.SetBytes(_offset + %3$d, src);\n" + indent + "}\n", - propName, fieldLength, offset)); + propName, fieldLength, offset, + accessOrderListenerCall)); sb.append(String.format("\n" + indent + "public void Set%1$s(string value)\n" + indent + "{\n" + + "%3$s" + indent + INDENT + "_buffer.SetNullTerminatedBytesFromString(%1$sResolvedCharacterEncoding, " + "value, _offset + %2$s, %1$sLength, %1$sNullValue);\n" + indent + "}\n" + indent + "public string Get%1$s()\n" + indent + "{\n" + + "%3$s" + indent + INDENT + "return _buffer.GetStringFromNullTerminatedBytes(%1$sResolvedCharacterEncoding, " + "_offset + %2$s, %1$sLength, %1$sNullValue);\n" + indent + "}\n", - propName, offset)); + propName, + offset, + accessOrderListenerCall)); } return sb; @@ -1156,7 +1363,11 @@ private CharSequence generateFixedFlyweightCode(final int size) size); } - private CharSequence generateMessageFlyweightCode(final String className, final Token token, final String indent) + private CharSequence generateMessageFlyweightCode( + final String className, + final Token token, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) { final String blockLengthType = cSharpTypeName(ir.headerStructure().blockLengthType()); final String templateIdType = cSharpTypeName(ir.headerStructure().templateIdType()); @@ -1184,16 +1395,18 @@ private CharSequence generateMessageFlyweightCode(final String className, final indent + INDENT + "{\n" + indent + INDENT + INDENT + "_parentMessage = this;\n" + indent + INDENT + "}\n\n" + - indent + INDENT + "public void WrapForEncode(DirectBuffer buffer, int offset)\n" + + indent + INDENT + "public %10$s WrapForEncode(DirectBuffer buffer, int offset)\n" + indent + INDENT + "{\n" + + "%12$s" + indent + INDENT + INDENT + "_buffer = buffer;\n" + indent + INDENT + INDENT + "_offset = offset;\n" + indent + INDENT + INDENT + "_actingBlockLength = BlockLength;\n" + indent + INDENT + INDENT + "_actingVersion = SchemaVersion;\n" + indent + INDENT + INDENT + "Limit = offset + _actingBlockLength;\n" + + indent + INDENT + INDENT + "return this;\n" + indent + INDENT + "}\n\n" + - indent + INDENT + "public void WrapForEncodeAndApplyHeader(DirectBuffer buffer, int offset, " + - " MessageHeader headerEncoder)\n" + + indent + INDENT + "public %10$s WrapForEncodeAndApplyHeader(DirectBuffer buffer, int offset, " + + "MessageHeader headerEncoder)\n" + indent + INDENT + "{\n" + indent + INDENT + INDENT + "headerEncoder.Wrap(buffer, offset, SchemaVersion);\n" + indent + INDENT + INDENT + "headerEncoder.BlockLength = BlockLength;\n" + @@ -1201,16 +1414,27 @@ private CharSequence generateMessageFlyweightCode(final String className, final indent + INDENT + INDENT + "headerEncoder.SchemaId = SchemaId;\n" + indent + INDENT + INDENT + "headerEncoder.Version = SchemaVersion;\n" + indent + INDENT + INDENT + "\n" + - indent + INDENT + INDENT + "WrapForEncode(buffer, offset + MessageHeader.Size);\n" + + indent + INDENT + INDENT + "return WrapForEncode(buffer, offset + MessageHeader.Size);\n" + indent + INDENT + "}\n\n" + - indent + INDENT + "public void WrapForDecode(DirectBuffer buffer, int offset, " + + "%13$s" + + indent + INDENT + "public %10$s WrapForDecode(DirectBuffer buffer, int offset, " + "int actingBlockLength, int actingVersion)\n" + indent + INDENT + "{\n" + + "%14$s" + indent + INDENT + INDENT + "_buffer = buffer;\n" + indent + INDENT + INDENT + "_offset = offset;\n" + indent + INDENT + INDENT + "_actingBlockLength = actingBlockLength;\n" + indent + INDENT + INDENT + "_actingVersion = actingVersion;\n" + indent + INDENT + INDENT + "Limit = offset + _actingBlockLength;\n" + + indent + INDENT + INDENT + "return this;\n" + + indent + INDENT + "}\n\n" + + indent + INDENT + "public %10$s WrapForDecodeAndApplyHeader(DirectBuffer buffer, int offset, " + + "MessageHeader headerDecoder)\n" + + indent + INDENT + "{\n" + + indent + INDENT + INDENT + "headerDecoder.Wrap(buffer, offset, SchemaVersion);\n" + + indent + INDENT + INDENT + "\n" + + indent + INDENT + INDENT + "return WrapForDecode(buffer, offset + MessageHeader.Size, " + + " headerDecoder.BlockLength, headerDecoder.Version);\n" + indent + INDENT + "}\n\n" + indent + INDENT + "public int Size\n" + indent + INDENT + "{\n" + @@ -1241,10 +1465,507 @@ private CharSequence generateMessageFlyweightCode(final String className, final generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), semanticType, className, - semanticVersion); + semanticVersion, + generateEncoderWrapListener(fieldPrecedenceModel, indent + TWO_INDENT), + generateDecoderWrapListener(fieldPrecedenceModel, indent + INDENT), + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + TWO_INDENT, + "OnWrapForDecode", "actingVersion")); + } + + private static CharSequence qualifiedStateCase(final FieldPrecedenceModel.State state) + { + return "CodecState." + state.name(); + } + + private static CharSequence stateCaseForSwitchCase(final FieldPrecedenceModel.State state) + { + return qualifiedStateCase(state); + } + + private static CharSequence unqualifiedStateCase(final FieldPrecedenceModel.State state) + { + return state.name(); + } + + private static CharSequence generateFieldOrderStates( + final String indent, + final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + + sb.append(indent).append("///\n"); + + sb.append(indent).append("/// \n"); + sb.append(indent).append("/// \n"); + sb.append(indent).append("/// The states in which a encoder/decoder/codec can live.\n"); + sb.append(indent).append("/// \n"); + sb.append(indent).append("/// \n"); + sb.append(indent).append("/// The state machine diagram below, encoded in the dot language, describes\n"); + sb.append(indent).append("/// the valid state transitions according to the order in which fields may be\n"); + sb.append(indent).append("/// accessed safely. Tools such as PlantUML and Graphviz can render it.\n"); + sb.append(indent).append("/// \n"); + sb.append(indent).append("/// \n"); + fieldPrecedenceModel.generateGraph(sb, indent + "/// "); + sb.append(indent).append("/// \n"); + sb.append(indent).append("/// \n"); + sb.append(indent).append("private enum CodecState\n") + .append(indent).append("{\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(indent).append(INDENT).append(unqualifiedStateCase(state)) + .append(" = ").append(state.number()) + .append(",\n"); + }); + sb.append(indent).append("}\n\n"); + + sb.append("\n").append(indent).append("private static readonly string[] StateNameLookup = new []\n") + .append(indent).append("{\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(indent).append(INDENT).append("\"").append(state.name()).append("\",\n"); + }); + sb.append(indent).append("};\n\n"); + + sb.append(indent).append("private static readonly string[] StateTransitionsLookup = new []\n") + .append(indent).append("{\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(indent).append(INDENT).append("\""); + final MutableBoolean isFirst = new MutableBoolean(true); + final Set transitionDescriptions = new HashSet<>(); + fieldPrecedenceModel.forEachTransitionFrom(state, transitionGroup -> + { + if (transitionDescriptions.add(transitionGroup.exampleCode())) + { + if (isFirst.get()) + { + isFirst.set(false); + } + else + { + sb.append(", "); + } + + sb.append("\\\"").append(transitionGroup.exampleCode()).append("\\\""); + } + }); + sb.append("\",\n"); + }); + sb.append(indent).append("};\n\n"); + + sb.append(indent).append("private static string codecStateName(CodecState state)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return StateNameLookup[(int) state];\n") + .append(indent).append("}\n\n"); + + sb.append(indent).append("private static string codecStateTransitions(CodecState state)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return StateTransitionsLookup[(int) state];\n") + .append(indent).append("}\n\n"); + + sb.append(indent).append("private CodecState _codecState = ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())) + .append(";\n\n"); + + sb.append(indent).append("private CodecState codecState()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return _codecState;\n") + .append(indent).append("}\n\n"); + + sb.append(indent).append("private void codecState(CodecState newState)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("_codecState = newState;\n") + .append(indent).append("}\n"); + + return sb; + } + + private CharSequence generateFullyEncodedCheck( + final String indent, + final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append("\n"); + + sb.append(indent).append("public void CheckEncodingIsComplete()\n") + .append(indent).append("{\n") + .append("#if ").append(precedenceChecksFlagName).append("\n") + .append(indent).append(INDENT).append("switch (_codecState)\n") + .append(indent).append(INDENT).append("{\n"); + + fieldPrecedenceModel.forEachTerminalEncoderState(state -> + { + sb.append(indent).append(TWO_INDENT).append("case ").append(stateCaseForSwitchCase(state)).append(":\n") + .append(indent).append(THREE_INDENT).append("return;\n"); + }); + + sb.append(indent).append(TWO_INDENT).append("default:\n") + .append(indent).append(THREE_INDENT) + .append("throw new InvalidOperationException(\"Not fully encoded, current state: \" +\n") + .append(indent).append(THREE_INDENT) + .append(INDENT).append("codecStateName(_codecState) + \", allowed transitions: \" +\n") + .append(indent).append(THREE_INDENT) + .append(INDENT).append("codecStateTransitions(_codecState));\n") + .append(indent).append(INDENT).append("}\n") + .append("#endif\n") + .append(indent).append("}\n\n"); + + return sb; + } + + private static String accessOrderListenerMethodName(final Token token) + { + return "On" + Generators.toUpperFirstChar(token.name()) + "Accessed"; } - private CharSequence generateFields(final List tokens, final String indent) + private static String accessOrderListenerMethodName(final Token token, final String suffix) + { + return "On" + Generators.toUpperFirstChar(token.name()) + suffix + "Accessed"; + } + + private static void generateAccessOrderListenerMethod( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append("private void ").append(accessOrderListenerMethodName(token)).append("()\n") + .append(indent).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction fieldAccess = + fieldPrecedenceModel.interactionFactory().accessField(token); + + generateAccessOrderListener( + sb, + indent + INDENT, + "access field", + fieldPrecedenceModel, + fieldAccess); + + sb.append(indent).append("}\n"); + } + + private CharSequence generateAccessOrderListenerCall( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token, + final String... arguments) + { + return generateAccessOrderListenerCall( + fieldPrecedenceModel, + indent, + accessOrderListenerMethodName(token), + arguments); + } + + private CharSequence generateAccessOrderListenerCall( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final String methodName, + final String... arguments) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append("#if ").append(precedenceChecksFlagName).append("\n") + .append(indent).append(methodName).append("("); + + for (int i = 0; i < arguments.length; i++) + { + if (i > 0) + { + sb.append(", "); + } + sb.append(arguments[i]); + } + sb.append(");\n"); + + sb.append("#endif\n"); + + return sb; + } + + private static void generateAccessOrderListenerMethodForGroupWrap( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append("private void ").append(accessOrderListenerMethodName(token)) + .append("(int remaining, string action)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("if (remaining == 0)\n") + .append(indent).append(INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction selectEmptyGroup = + fieldPrecedenceModel.interactionFactory().determineGroupIsEmpty(token); + + generateAccessOrderListener( + sb, + indent + TWO_INDENT, + "\" + action + \" count of repeating group", + fieldPrecedenceModel, + selectEmptyGroup); + + sb.append(indent).append(INDENT).append("}\n") + .append(indent).append(INDENT).append("else\n") + .append(indent).append(INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction selectNonEmptyGroup = + fieldPrecedenceModel.interactionFactory().determineGroupHasElements(token); + + generateAccessOrderListener( + sb, + indent + TWO_INDENT, + "\" + action + \" count of repeating group", + fieldPrecedenceModel, + selectNonEmptyGroup); + + sb.append(indent).append(INDENT).append("}\n") + .append(indent).append("}\n"); + } + + private static void generateAccessOrderListener( + final StringBuilder sb, + final String indent, + final String action, + final FieldPrecedenceModel fieldPrecedenceModel, + final FieldPrecedenceModel.CodecInteraction interaction) + { + if (interaction.isTopLevelBlockFieldAccess()) + { + sb.append(indent).append("if (codecState() == ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())) + .append(")\n") + .append(indent).append("{\n"); + generateAccessOrderException(sb, indent + INDENT, action, fieldPrecedenceModel, interaction); + sb.append(indent).append("}\n"); + } + else + { + sb.append(indent).append("switch (codecState())\n") + .append(indent).append("{\n"); + + fieldPrecedenceModel.forEachTransition(interaction, transitionGroup -> + { + transitionGroup.forEachStartState(startState -> + { + sb.append(indent).append(INDENT) + .append("case ").append(stateCaseForSwitchCase(startState)).append(":\n"); + }); + sb.append(indent).append(TWO_INDENT).append("codecState(") + .append(qualifiedStateCase(transitionGroup.endState())).append(");\n") + .append(indent).append(TWO_INDENT).append("break;\n"); + }); + + sb.append(indent).append(INDENT).append("default:\n"); + generateAccessOrderException(sb, indent + TWO_INDENT, action, fieldPrecedenceModel, interaction); + sb.append(indent).append("}\n"); + } + } + + private static void generateAccessOrderException( + final StringBuilder sb, + final String indent, + final String action, + final FieldPrecedenceModel fieldPrecedenceModel, + final FieldPrecedenceModel.CodecInteraction interaction) + { + sb.append(indent).append("throw new InvalidOperationException(") + .append("\"Illegal field access order. \" +\n") + .append(indent).append(INDENT) + .append("\"Cannot ").append(action).append(" \\\"").append(interaction.groupQualifiedName()) + .append("\\\" in state: \" + codecStateName(codecState()) +\n") + .append(indent).append(INDENT) + .append("\". Expected one of these transitions: [\" + codecStateTransitions(codecState()) +\n") + .append(indent).append(INDENT) + .append("\"]. Please see the diagram in the docs of the enum ") + .append(fieldPrecedenceModel.generatedRepresentationClassName()).append(".\");\n"); + } + + private static void generateAccessOrderListenerMethodForNextGroupElement( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n"); + + sb.append(indent).append("private void OnNextElementAccessed()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("int remaining = ").append("_count - _index").append(";\n") + .append(indent).append(INDENT).append("if (remaining > 1)\n") + .append(indent).append(INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction selectNextElementInGroup = + fieldPrecedenceModel.interactionFactory().moveToNextElement(token); + + generateAccessOrderListener( + sb, + indent + TWO_INDENT, + "access next element in repeating group", + fieldPrecedenceModel, + selectNextElementInGroup); + + sb.append(indent).append(INDENT).append("}\n") + .append(indent).append(INDENT).append("else if (remaining == 1)\n") + .append(indent).append(INDENT).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction selectLastElementInGroup = + fieldPrecedenceModel.interactionFactory().moveToLastElement(token); + + generateAccessOrderListener( + sb, + indent + TWO_INDENT, + "access next element in repeating group", + fieldPrecedenceModel, + selectLastElementInGroup); + + sb.append(indent).append(INDENT).append("}\n") + .append(indent).append("}\n"); + } + + private static void generateAccessOrderListenerMethodForResetGroupCount( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append(indent).append("private void OnResetCountToIndex()\n") + .append(indent).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction resetCountToIndex = + fieldPrecedenceModel.interactionFactory().resetCountToIndex(token); + + generateAccessOrderListener( + sb, + indent + " ", + "reset count of repeating group", + fieldPrecedenceModel, + resetCountToIndex); + + sb.append(indent).append("}\n"); + } + + private static void generateAccessOrderListenerMethodForVarDataLength( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append("private void ") + .append(accessOrderListenerMethodName(token, "Length")).append("()\n") + .append(indent).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction accessLength = + fieldPrecedenceModel.interactionFactory().accessVarDataLength(token); + + generateAccessOrderListener( + sb, + indent + INDENT, + "decode length of var data", + fieldPrecedenceModel, + accessLength); + + sb.append(indent).append("}\n"); + } + + private static CharSequence generateDecoderWrapListener( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(indent).append("private void OnWrapForDecode(int actingVersion)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("switch(actingVersion)\n") + .append(indent).append(INDENT).append("{\n"); + + fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> + { + sb.append(indent).append(TWO_INDENT).append("case ").append(version).append(":\n") + .append(indent).append(THREE_INDENT).append("codecState(") + .append(qualifiedStateCase(state)).append(");\n") + .append(indent).append(THREE_INDENT).append("break;\n"); + }); + + sb.append(indent).append(TWO_INDENT).append("default:\n") + .append(indent).append(THREE_INDENT).append("codecState(") + .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())).append(");\n") + .append(indent).append(THREE_INDENT).append("break;\n") + .append(indent).append(INDENT).append("}\n") + .append(indent).append("}\n\n"); + + return sb; + } + + private CharSequence generateEncoderWrapListener( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append("#if ").append(precedenceChecksFlagName).append("\n") + .append(indent).append("codecState(") + .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())) + .append(");\n") + .append("#endif\n"); + return sb; + } + + private CharSequence generateFields( + final FieldPrecedenceModel fieldPrecedenceModel, + final List tokens, + final String indent) { final StringBuilder sb = new StringBuilder(); @@ -1258,26 +1979,32 @@ private CharSequence generateFields(final List tokens, final String inden generateFieldIdMethod(sb, signalToken, indent + INDENT); generateSinceActingDeprecated( - sb, indent, CSharpUtil.formatPropertyName(signalToken.name()), signalToken); + sb, indent + INDENT, CSharpUtil.formatPropertyName(signalToken.name()), signalToken); generateOffsetMethod(sb, signalToken, indent + INDENT); generateFieldMetaAttributeMethod(sb, signalToken, indent + INDENT); + generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent + INDENT, signalToken); + switch (encodingToken.signal()) { case ENCODING: - sb.append(generatePrimitiveProperty(propertyName, signalToken, encodingToken, indent)); + sb.append(generatePrimitiveProperty(propertyName, signalToken, encodingToken, + fieldPrecedenceModel, indent)); break; case BEGIN_ENUM: - sb.append(generateEnumProperty(propertyName, signalToken, encodingToken, indent)); + sb.append(generateEnumProperty(propertyName, signalToken, encodingToken, + fieldPrecedenceModel, indent)); break; case BEGIN_SET: - sb.append(generateBitSetProperty(propertyName, signalToken, encodingToken, indent)); + sb.append(generateBitSetProperty(propertyName, signalToken, encodingToken, + fieldPrecedenceModel, indent)); break; case BEGIN_COMPOSITE: - sb.append(generateCompositeProperty(propertyName, signalToken, encodingToken, indent)); + sb.append(generateCompositeProperty(propertyName, signalToken, encodingToken, + fieldPrecedenceModel, indent)); break; default: @@ -1352,6 +2079,7 @@ private CharSequence generateEnumProperty( final String propertyName, final Token fieldToken, final Token typeToken, + final FieldPrecedenceModel fieldPrecedenceModel, final String indent) { final String enumName = formatClassName(typeToken.applicableTypeName()); @@ -1381,6 +2109,9 @@ private CharSequence generateEnumProperty( } else { + final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + TWO_INDENT, fieldToken); + return String.format("\n" + "%1$s" + indent + INDENT + "public %2$s %3$s\n" + @@ -1388,10 +2119,12 @@ private CharSequence generateEnumProperty( indent + INDENT + INDENT + "get\n" + indent + INDENT + INDENT + "{\n" + "%4$s" + + "%10$s" + indent + INDENT + INDENT + INDENT + "return (%5$s)_buffer.%6$sGet%8$s(_offset + %7$d);\n" + indent + INDENT + INDENT + "}\n" + indent + INDENT + INDENT + "set\n" + indent + INDENT + INDENT + "{\n" + + "%10$s" + indent + INDENT + INDENT + INDENT + "_buffer.%6$sPut%8$s(_offset + %7$d, (%9$s)value);\n" + indent + INDENT + INDENT + "}\n" + indent + INDENT + "}\n\n", @@ -1403,12 +2136,17 @@ private CharSequence generateEnumProperty( typePrefix, offset, byteOrderStr, - enumUnderlyingType); + enumUnderlyingType, + accessOrderListenerCall); } } private String generateBitSetProperty( - final String propertyName, final Token fieldToken, final Token typeToken, final String indent) + final String propertyName, + final Token fieldToken, + final Token typeToken, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) { final String bitSetName = formatClassName(typeToken.applicableTypeName()); final int offset = typeToken.offset(); @@ -1416,6 +2154,8 @@ private String generateBitSetProperty( final ByteOrder byteOrder = typeToken.encoding().byteOrder(); final String byteOrderStr = generateByteOrder(byteOrder, typeToken.encoding().primitiveType().size()); final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); + final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + TWO_INDENT, fieldToken); return String.format("\n" + "%1$s" + @@ -1424,10 +2164,12 @@ private String generateBitSetProperty( indent + INDENT + INDENT + "get\n" + indent + INDENT + INDENT + "{\n" + "%4$s" + + "%10$s" + indent + INDENT + INDENT + INDENT + "return (%5$s)_buffer.%6$sGet%8$s(_offset + %7$d);\n" + indent + INDENT + INDENT + "}\n" + indent + INDENT + INDENT + "set\n" + indent + INDENT + INDENT + "{\n" + + "%10$s" + indent + INDENT + INDENT + INDENT + "_buffer.%6$sPut%8$s(_offset + %7$d, (%9$s)value);\n" + indent + INDENT + INDENT + "}\n" + indent + INDENT + "}\n", @@ -1439,14 +2181,21 @@ private String generateBitSetProperty( typePrefix, offset, byteOrderStr, - typeName); + typeName, + accessOrderListenerCall); } private Object generateCompositeProperty( - final String propertyName, final Token fieldToken, final Token typeToken, final String indent) + final String propertyName, + final Token fieldToken, + final Token typeToken, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) { final String compositeName = CSharpUtil.formatClassName(typeToken.applicableTypeName()); final int offset = typeToken.offset(); + final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + THREE_INDENT, fieldToken); final StringBuilder sb = new StringBuilder(); sb.append(String.format("\n" + @@ -1462,6 +2211,7 @@ private Object generateCompositeProperty( indent + INDENT + INDENT + "get\n" + indent + INDENT + INDENT + "{\n" + "%4$s" + + "%7$s" + indent + INDENT + INDENT + INDENT + "_%5$s.Wrap(_buffer, _offset + %6$d, _actingVersion);\n" + indent + INDENT + INDENT + INDENT + "return _%5$s;\n" + indent + INDENT + INDENT + "}\n" + @@ -1471,7 +2221,8 @@ private Object generateCompositeProperty( toUpperFirstChar(propertyName), generateTypeFieldNotPresentCondition(fieldToken.version(), indent), toLowerFirstChar(propertyName), - offset)); + offset, + accessOrderListenerCall)); return sb; } @@ -1715,11 +2466,13 @@ private int writeTokenDisplay( { if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { + append(sb, indent, "builder.Append(\"'\");"); append(sb, indent, "for (int i = 0; i < " + fieldName + "Length && this.Get" + fieldName + "(i) > 0; ++i)"); append(sb, indent, "{"); append(sb, indent, " builder.Append((char)this.Get" + fieldName + "(i));"); append(sb, indent, "}"); + append(sb, indent, "builder.Append(\"'\");"); } else { @@ -1804,7 +2557,8 @@ private CharSequence generateDisplay( final String name, final List tokens, final List groups, - final List varData) + final List varData, + final FieldPrecedenceModel fieldPrecedenceModel) { final StringBuilder sb = new StringBuilder(100); @@ -1818,6 +2572,15 @@ private CharSequence generateDisplay( append(sb, TWO_INDENT, " }"); sb.append('\n'); append(sb, TWO_INDENT, " int originalLimit = this.Limit;"); + if (null != fieldPrecedenceModel) + { + sb.append("#if ").append(precedenceChecksFlagName).append("\n"); + append(sb, TWO_INDENT, " CodecState originalState = _codecState;"); + sb.append(THREE_INDENT).append("_codecState = ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())).append(";\n"); + append(sb, TWO_INDENT, " OnWrapForDecode(_actingVersion);"); + sb.append("#endif\n"); + } append(sb, TWO_INDENT, " this.Limit = _offset + _actingBlockLength;"); append(sb, TWO_INDENT, " builder.Append(\"[" + name + "](sbeTemplateId=\");"); append(sb, TWO_INDENT, " builder.Append(" + name + ".TemplateId);"); @@ -1841,6 +2604,12 @@ private CharSequence generateDisplay( sb.append('\n'); appendDisplay(sb, tokens, groups, varData, THREE_INDENT); sb.append('\n'); + if (null != fieldPrecedenceModel) + { + sb.append("#if ").append(precedenceChecksFlagName).append("\n"); + append(sb, TWO_INDENT, " _codecState = originalState;"); + sb.append("#endif\n"); + } append(sb, TWO_INDENT, " this.Limit = originalLimit;"); sb.append('\n'); append(sb, TWO_INDENT, "}"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index eb90237170..3e6dd222eb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -15,25 +15,23 @@ */ package uk.co.real_logic.sbe.generation.java; +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.generation.common.FieldPrecedenceModel; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; +import uk.co.real_logic.sbe.ir.*; import org.agrona.DirectBuffer; import org.agrona.MutableDirectBuffer; import org.agrona.Strings; import org.agrona.Verify; +import org.agrona.collections.MutableBoolean; import org.agrona.generation.DynamicPackageOutputManager; import org.agrona.sbe.*; -import uk.co.real_logic.sbe.PrimitiveType; -import uk.co.real_logic.sbe.generation.CodeGenerator; -import uk.co.real_logic.sbe.generation.Generators; -import uk.co.real_logic.sbe.ir.*; import java.io.IOException; import java.io.Writer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Formatter; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.function.Function; import static uk.co.real_logic.sbe.SbeTool.JAVA_INTERFACE_PACKAGE; @@ -73,6 +71,9 @@ enum CodecType private final boolean shouldGenerateInterfaces; private final boolean shouldDecodeUnknownEnumValues; private final boolean shouldSupportTypesPackageNames; + private final PrecedenceChecks precedenceChecks; + private final String precedenceChecksFlagName; + private final String precedenceChecksPropName; private final Set packageNameByTypes = new HashSet<>(); /** @@ -120,6 +121,43 @@ public JavaGenerator( final boolean shouldDecodeUnknownEnumValues, final boolean shouldSupportTypesPackageNames, final DynamicPackageOutputManager outputManager) + { + this( + ir, + mutableBuffer, + readOnlyBuffer, + shouldGenerateGroupOrderAnnotation, + shouldGenerateInterfaces, + shouldDecodeUnknownEnumValues, + shouldSupportTypesPackageNames, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + outputManager + ); + } + + /** + * Create a new Java language {@link CodeGenerator}. + * + * @param ir for the messages and types. + * @param mutableBuffer implementation used for mutating underlying buffers. + * @param readOnlyBuffer implementation used for reading underlying buffers. + * @param shouldGenerateGroupOrderAnnotation in the codecs. + * @param shouldGenerateInterfaces for common methods. + * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. + * @param shouldSupportTypesPackageNames generator support for types in their own package. + * @param precedenceChecks whether and how to generate field precedence checks. + * @param outputManager for generating the codecs to. + */ + public JavaGenerator( + final Ir ir, + final String mutableBuffer, + final String readOnlyBuffer, + final boolean shouldGenerateGroupOrderAnnotation, + final boolean shouldGenerateInterfaces, + final boolean shouldDecodeUnknownEnumValues, + final boolean shouldSupportTypesPackageNames, + final PrecedenceChecks precedenceChecks, + final DynamicPackageOutputManager outputManager) { Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); @@ -137,6 +175,10 @@ public JavaGenerator( this.shouldGenerateGroupOrderAnnotation = shouldGenerateGroupOrderAnnotation; this.shouldGenerateInterfaces = shouldGenerateInterfaces; this.shouldDecodeUnknownEnumValues = shouldDecodeUnknownEnumValues; + + this.precedenceChecks = precedenceChecks; + this.precedenceChecksFlagName = precedenceChecks.context().precedenceChecksFlagName(); + this.precedenceChecksPropName = precedenceChecks.context().precedenceChecksPropName(); } /** @@ -230,20 +272,30 @@ public void generate() throws IOException final List varData = new ArrayList<>(); collectVarData(messageBody, i, varData); - generateDecoder(msgToken, fields, groups, varData, hasVarData); - generateEncoder(msgToken, fields, groups, varData, hasVarData); + final String decoderClassName = formatClassName(decoderName(msgToken.name())); + final String decoderStateClassName = decoderClassName + "#CodecStates"; + final FieldPrecedenceModel decoderPrecedenceModel = + precedenceChecks.createDecoderModel(decoderStateClassName, tokens); + generateDecoder(decoderClassName, msgToken, fields, groups, varData, hasVarData, decoderPrecedenceModel); + + final String encoderClassName = formatClassName(encoderName(msgToken.name())); + final String encoderStateClassName = encoderClassName + "#CodecStates"; + final FieldPrecedenceModel encoderPrecedenceModel = + precedenceChecks.createEncoderModel(encoderStateClassName, tokens); + generateEncoder(encoderClassName, msgToken, fields, groups, varData, hasVarData, encoderPrecedenceModel); } } private void generateEncoder( + final String className, final Token msgToken, final List fields, final List groups, final List varData, - final boolean hasVarData) + final boolean hasVarData, + final FieldPrecedenceModel fieldPrecedenceModel) throws IOException { - final String className = formatClassName(encoderName(msgToken.name())); final String implementsString = implementsInterface(MessageEncoderFlyweight.class.getSimpleName()); try (Writer out = outputManager.createOutput(className)) @@ -255,29 +307,519 @@ private void generateEncoder( generateAnnotations(BASE_INDENT, className, groups, out, this::encoderName); } out.append(generateDeclaration(className, implementsString, msgToken)); - out.append(generateEncoderFlyweightCode(className, msgToken)); + + out.append(generateFieldOrderStates(fieldPrecedenceModel)); + out.append(generateEncoderFlyweightCode(className, fieldPrecedenceModel, msgToken)); final StringBuilder sb = new StringBuilder(); - generateEncoderFields(sb, className, fields, BASE_INDENT); - generateEncoderGroups(sb, className, groups, BASE_INDENT, false); - generateEncoderVarData(sb, className, varData, BASE_INDENT); + generateEncoderFields(sb, className, fieldPrecedenceModel, fields, BASE_INDENT); + generateEncoderGroups(sb, className, fieldPrecedenceModel, groups, BASE_INDENT, false); + generateEncoderVarData(sb, className, fieldPrecedenceModel, varData, BASE_INDENT); generateEncoderDisplay(sb, decoderName(msgToken.name())); + generateFullyEncodedCheck(sb, fieldPrecedenceModel); out.append(sb); out.append("}\n"); } } + private static CharSequence qualifiedStateCase(final FieldPrecedenceModel.State state) + { + return "CodecStates." + state.name(); + } + + private static CharSequence stateCaseForSwitchCase(final FieldPrecedenceModel.State state) + { + return qualifiedStateCase(state); + } + + private static CharSequence unqualifiedStateCase(final FieldPrecedenceModel.State state) + { + return state.name(); + } + + private CharSequence generateFieldOrderStates(final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + + sb.append(" private static final boolean ENABLE_BOUNDS_CHECKS = ") + .append("!Boolean.getBoolean(\"agrona.disable.bounds.checks\");\n\n"); + sb.append(" private static final boolean ") + .append(precedenceChecksFlagName).append(" = ") + .append("Boolean.parseBoolean(System.getProperty(\n") + .append(" \"").append(precedenceChecksPropName).append("\",\n") + .append(" Boolean.toString(ENABLE_BOUNDS_CHECKS)));\n\n"); + + sb.append(" /**\n"); + sb.append(" * The states in which a encoder/decoder/codec can live.\n"); + sb.append(" *\n"); + sb.append(" *

    The state machine diagram below, encoded in the dot language, describes\n"); + sb.append(" * the valid state transitions according to the order in which fields may be\n"); + sb.append(" * accessed safely. Tools such as PlantUML and Graphviz can render it.\n"); + sb.append(" *\n"); + sb.append(" *

    {@code\n");
    +        fieldPrecedenceModel.generateGraph(sb, "     *   ");
    +        sb.append("     * }
    \n"); + sb.append(" */\n"); + sb.append(" private static class CodecStates\n") + .append(" {\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(" private static final int ") + .append(unqualifiedStateCase(state)) + .append(" = ").append(state.number()) + .append(";\n"); + }); + + sb.append("\n").append(" private static final String[] STATE_NAME_LOOKUP =\n") + .append(" {\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(" \"").append(state.name()).append("\",\n"); + }); + sb.append(" };\n\n"); + + sb.append(" private static final String[] STATE_TRANSITIONS_LOOKUP =\n") + .append(" {\n"); + fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + { + sb.append(" \""); + final MutableBoolean isFirst = new MutableBoolean(true); + final Set transitionDescriptions = new HashSet<>(); + fieldPrecedenceModel.forEachTransitionFrom(state, transitionGroup -> + { + if (transitionDescriptions.add(transitionGroup.exampleCode())) + { + if (isFirst.get()) + { + isFirst.set(false); + } + else + { + sb.append(", "); + } + + sb.append("\\\"").append(transitionGroup.exampleCode()).append("\\\""); + } + }); + sb.append("\",\n"); + }); + sb.append(" };\n\n"); + + sb.append(" private static String name(final int state)\n") + .append(" {\n") + .append(" return STATE_NAME_LOOKUP[state];\n") + .append(" }\n\n"); + + sb.append(" private static String transitions(final int state)\n") + .append(" {\n") + .append(" return STATE_TRANSITIONS_LOOKUP[state];\n") + .append(" }\n"); + + sb.append(" }\n\n"); + + sb.append(" private int codecState = ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())) + .append(";\n\n"); + + sb.append(" private int codecState()\n") + .append(" {\n") + .append(" return codecState;\n") + .append(" }\n\n"); + + sb.append(" private void codecState(int newState)\n") + .append(" {\n") + .append(" codecState = newState;\n") + .append(" }\n\n"); + + return sb; + } + + private void generateFullyEncodedCheck( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n"); + + sb.append(" public void checkEncodingIsComplete()\n") + .append(" {\n") + .append(" if (").append(precedenceChecksFlagName).append(")\n") + .append(" {\n") + .append(" switch (codecState)\n") + .append(" {\n"); + + fieldPrecedenceModel.forEachTerminalEncoderState(state -> + { + sb.append(" case ").append(stateCaseForSwitchCase(state)).append(":\n") + .append(" return;\n"); + }); + + sb.append(" default:\n") + .append(" throw new IllegalStateException(\"Not fully encoded, current state: \" +\n") + .append(" CodecStates.name(codecState) + \", allowed transitions: \" +\n") + .append(" CodecStates.transitions(codecState));\n") + .append(" }\n") + .append(" }\n") + .append(" }\n\n"); + } + + private static String accessOrderListenerMethodName(final Token token) + { + return "on" + Generators.toUpperFirstChar(token.name()) + "Accessed"; + } + + private static String accessOrderListenerMethodName(final Token token, final String suffix) + { + return "on" + Generators.toUpperFirstChar(token.name()) + suffix + "Accessed"; + } + + private static void generateAccessOrderListenerMethod( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append("private void ").append(accessOrderListenerMethodName(token)).append("()\n") + .append(indent).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction fieldAccess = + fieldPrecedenceModel.interactionFactory().accessField(token); + + generateAccessOrderListener( + sb, + indent + " ", + "access field", + fieldPrecedenceModel, + fieldAccess); + + sb.append(indent).append("}\n"); + } + + private CharSequence generateAccessOrderListenerCall( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token, + final String... arguments) + { + return generateAccessOrderListenerCall( + fieldPrecedenceModel, + indent, + accessOrderListenerMethodName(token), + arguments); + } + + private CharSequence generateAccessOrderListenerCall( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final String methodName, + final String... arguments) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(indent).append("if (").append(precedenceChecksFlagName).append(")\n") + .append(indent).append("{\n") + .append(indent).append(" ").append(methodName).append("("); + + for (int i = 0; i < arguments.length; i++) + { + if (i > 0) + { + sb.append(", "); + } + sb.append(arguments[i]); + } + sb.append(");\n"); + + sb.append(indent).append("}\n\n"); + + return sb; + } + + private static void generateAccessOrderListenerMethodForGroupWrap( + final StringBuilder sb, + final String action, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append("private void ").append(accessOrderListenerMethodName(token)) + .append("(final int count)\n") + .append(indent).append("{\n") + .append(indent).append(" if (count == 0)\n") + .append(indent).append(" {\n"); + + final FieldPrecedenceModel.CodecInteraction selectEmptyGroup = + fieldPrecedenceModel.interactionFactory().determineGroupIsEmpty(token); + + generateAccessOrderListener( + sb, + indent + " ", + action + " count of repeating group", + fieldPrecedenceModel, + selectEmptyGroup); + + sb.append(indent).append(" }\n") + .append(indent).append(" else\n") + .append(indent).append(" {\n"); + + final FieldPrecedenceModel.CodecInteraction selectNonEmptyGroup = + fieldPrecedenceModel.interactionFactory().determineGroupHasElements(token); + + generateAccessOrderListener( + sb, + indent + " ", + action + " count of repeating group", + fieldPrecedenceModel, + selectNonEmptyGroup); + + sb.append(indent).append(" }\n") + .append(indent).append("}\n"); + } + + private static void generateAccessOrderListener( + final StringBuilder sb, + final String indent, + final String action, + final FieldPrecedenceModel fieldPrecedenceModel, + final FieldPrecedenceModel.CodecInteraction interaction) + { + if (interaction.isTopLevelBlockFieldAccess()) + { + sb.append(indent).append("if (codecState() == ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())) + .append(")\n") + .append(indent).append("{\n"); + generateAccessOrderException(sb, indent + " ", action, fieldPrecedenceModel, interaction); + sb.append(indent).append("}\n"); + } + else + { + sb.append(indent).append("switch (codecState())\n") + .append(indent).append("{\n"); + + fieldPrecedenceModel.forEachTransition(interaction, transitionGroup -> + { + transitionGroup.forEachStartState(startState -> + sb.append(indent).append(" case ").append(stateCaseForSwitchCase(startState)).append(":\n")); + sb.append(indent).append(" codecState(") + .append(qualifiedStateCase(transitionGroup.endState())).append(");\n") + .append(indent).append(" break;\n"); + }); + + sb.append(indent).append(" default:\n"); + generateAccessOrderException(sb, indent + " ", action, fieldPrecedenceModel, interaction); + sb.append(indent).append("}\n"); + } + } + + private static void generateAccessOrderException( + final StringBuilder sb, + final String indent, + final String action, + final FieldPrecedenceModel fieldPrecedenceModel, + final FieldPrecedenceModel.CodecInteraction interaction) + { + sb.append(indent).append("throw new IllegalStateException(") + .append("\"Illegal field access order. \" +\n") + .append(indent) + .append(" \"Cannot ").append(action).append(" \\\"").append(interaction.groupQualifiedName()) + .append("\\\" in state: \" + CodecStates.name(codecState()) +\n") + .append(indent) + .append(" \". Expected one of these transitions: [\" + CodecStates.transitions(codecState()) +\n") + .append(indent) + .append(" \"]. Please see the diagram in the Javadoc of the class ") + .append(fieldPrecedenceModel.generatedRepresentationClassName()).append(".\");\n"); + } + + private static void generateAccessOrderListenerMethodForNextGroupElement( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append(indent).append("private void onNextElementAccessed()\n") + .append(indent).append("{\n") + .append(indent).append(" final int remaining = ").append("count - index").append(";\n") + .append(indent).append(" if (remaining > 1)\n") + .append(indent).append(" {\n"); + + final FieldPrecedenceModel.CodecInteraction selectNextElementInGroup = + fieldPrecedenceModel.interactionFactory().moveToNextElement(token); + + generateAccessOrderListener( + sb, + indent + " ", + "access next element in repeating group", + fieldPrecedenceModel, + selectNextElementInGroup); + + sb.append(indent).append(" }\n") + .append(indent).append(" else if (remaining == 1)\n") + .append(indent).append(" {\n"); + + final FieldPrecedenceModel.CodecInteraction selectLastElementInGroup = + fieldPrecedenceModel.interactionFactory().moveToLastElement(token); + + generateAccessOrderListener( + sb, + indent + " ", + "access next element in repeating group", + fieldPrecedenceModel, + selectLastElementInGroup); + + sb.append(indent).append(" }\n") + .append(indent).append("}\n\n"); + } + + private static void generateAccessOrderListenerMethodForResetGroupCount( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append(indent).append("private void onResetCountToIndex()\n") + .append(indent).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction resetCountToIndex = + fieldPrecedenceModel.interactionFactory().resetCountToIndex(token); + + generateAccessOrderListener( + sb, + indent + " ", + "reset count of repeating group", + fieldPrecedenceModel, + resetCountToIndex); + + sb.append(indent).append("}\n\n"); + } + + private static void generateAccessOrderListenerMethodForVarDataLength( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent, + final Token token) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb.append("\n") + .append(indent).append("void ").append(accessOrderListenerMethodName(token, "Length")).append("()\n") + .append(indent).append("{\n"); + + final FieldPrecedenceModel.CodecInteraction accessLength = + fieldPrecedenceModel.interactionFactory().accessVarDataLength(token); + + generateAccessOrderListener( + sb, + indent + INDENT, + "decode length of var data", + fieldPrecedenceModel, + accessLength); + + sb.append(indent).append("}\n"); + } + + private static CharSequence generateDecoderWrapListener( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(indent).append("private void onWrap(final int actingVersion)\n") + .append(indent).append("{\n") + .append(indent).append(" switch(actingVersion)\n") + .append(indent).append(" {\n"); + + fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> + { + sb.append(indent).append(" case ").append(version).append(":\n") + .append(indent).append(" codecState(") + .append(qualifiedStateCase(state)).append(");\n") + .append(indent).append(" break;\n"); + }); + + sb.append(indent).append(" default:\n") + .append(indent).append(" codecState(") + .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())).append(");\n") + .append(indent).append(" break;\n") + .append(indent).append(" }\n") + .append(indent).append("}\n\n"); + + return sb; + } + + private CharSequence generateEncoderWrapListener( + final FieldPrecedenceModel fieldPrecedenceModel, + final String indent) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(indent).append("if (").append(precedenceChecksFlagName).append(")") + .append("\n").append(indent).append("{\n") + .append(indent).append(" codecState(") + .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())) + .append(");\n") + .append(indent).append("}\n\n"); + return sb; + } + private void generateDecoder( + final String className, final Token msgToken, final List fields, final List groups, final List varData, - final boolean hasVarData) + final boolean hasVarData, + final FieldPrecedenceModel fieldPrecedenceModel) throws IOException { - final String className = formatClassName(decoderName(msgToken.name())); final String implementsString = implementsInterface(MessageDecoderFlyweight.class.getSimpleName()); try (Writer out = outputManager.createOutput(className)) @@ -288,13 +830,15 @@ private void generateDecoder( { generateAnnotations(BASE_INDENT, className, groups, out, this::decoderName); } + out.append(generateDeclaration(className, implementsString, msgToken)); - out.append(generateDecoderFlyweightCode(className, msgToken)); + out.append(generateFieldOrderStates(fieldPrecedenceModel)); + out.append(generateDecoderFlyweightCode(fieldPrecedenceModel, className, msgToken)); final StringBuilder sb = new StringBuilder(); - generateDecoderFields(sb, fields, BASE_INDENT); - generateDecoderGroups(sb, className, groups, BASE_INDENT, false); - generateDecoderVarData(sb, varData, BASE_INDENT); + generateDecoderFields(sb, fieldPrecedenceModel, fields, BASE_INDENT); + generateDecoderGroups(sb, fieldPrecedenceModel, className, groups, BASE_INDENT, false); + generateDecoderVarData(sb, fieldPrecedenceModel, varData, BASE_INDENT); generateDecoderDisplay(sb, msgToken.name(), fields, groups, varData); generateMessageLength(sb, className, true, groups, varData, BASE_INDENT); @@ -306,7 +850,7 @@ private void generateDecoder( private void generateDecoderGroups( final StringBuilder sb, - final String outerClassName, + final FieldPrecedenceModel fieldPrecedenceModel, final String outerClassName, final List tokens, final String indent, final boolean isSubGroup) throws IOException @@ -335,18 +879,19 @@ private void generateDecoderGroups( final List varData = new ArrayList<>(); i = collectVarData(tokens, i, varData); - generateGroupDecoderProperty(sb, groupName, groupToken, indent, isSubGroup); + generateGroupDecoderProperty(sb, groupName, fieldPrecedenceModel, groupToken, indent, isSubGroup); generateTypeJavadoc(sb, indent + INDENT, groupToken); if (shouldGenerateGroupOrderAnnotation) { generateAnnotations(indent + INDENT, groupName, groups, sb, this::decoderName); } - generateGroupDecoderClassHeader(sb, groupName, outerClassName, tokens, groups, index, indent + INDENT); + generateGroupDecoderClassHeader(sb, groupName, outerClassName, fieldPrecedenceModel, groupToken, + tokens, groups, index, indent + INDENT); - generateDecoderFields(sb, fields, indent + INDENT); - generateDecoderGroups(sb, outerClassName, groups, indent + INDENT, true); - generateDecoderVarData(sb, varData, indent + INDENT); + generateDecoderFields(sb, fieldPrecedenceModel, fields, indent + INDENT); + generateDecoderGroups(sb, fieldPrecedenceModel, outerClassName, groups, indent + INDENT, true); + generateDecoderVarData(sb, fieldPrecedenceModel, varData, indent + INDENT); appendGroupInstanceDecoderDisplay(sb, fields, groups, varData, indent + INDENT); generateMessageLength(sb, groupName, false, groups, varData, indent + INDENT); @@ -358,6 +903,7 @@ private void generateDecoderGroups( private void generateEncoderGroups( final StringBuilder sb, final String outerClassName, + final FieldPrecedenceModel fieldPrecedenceModel, final List tokens, final String indent, final boolean isSubGroup) throws IOException @@ -387,18 +933,20 @@ private void generateEncoderGroups( final List varData = new ArrayList<>(); i = collectVarData(tokens, i, varData); - generateGroupEncoderProperty(sb, groupName, groupToken, indent, isSubGroup); + generateGroupEncoderProperty(sb, groupName, fieldPrecedenceModel, groupToken, indent, isSubGroup); generateTypeJavadoc(sb, indent + INDENT, groupToken); if (shouldGenerateGroupOrderAnnotation) { generateAnnotations(indent + INDENT, groupClassName, groups, sb, this::encoderName); } - generateGroupEncoderClassHeader(sb, groupName, outerClassName, tokens, groups, index, indent + INDENT); + generateGroupEncoderClassHeader( + sb, groupName, outerClassName, fieldPrecedenceModel, groupToken, + tokens, groups, index, indent + INDENT); - generateEncoderFields(sb, groupClassName, fields, indent + INDENT); - generateEncoderGroups(sb, outerClassName, groups, indent + INDENT, true); - generateEncoderVarData(sb, groupClassName, varData, indent + INDENT); + generateEncoderFields(sb, groupClassName, fieldPrecedenceModel, fields, indent + INDENT); + generateEncoderGroups(sb, outerClassName, fieldPrecedenceModel, groups, indent + INDENT, true); + generateEncoderVarData(sb, groupClassName, fieldPrecedenceModel, varData, indent + INDENT); sb.append(indent).append(" }\n"); } @@ -408,6 +956,8 @@ private void generateGroupDecoderClassHeader( final StringBuilder sb, final String groupName, final String parentMessageClassName, + final FieldPrecedenceModel fieldPrecedenceModel, + final Token groupToken, final List tokens, final List subGroupTokens, final int index, @@ -452,15 +1002,18 @@ private void generateGroupDecoderClassHeader( .append(indent).append(" parentMessage.limit(limit + HEADER_SIZE);\n") .append(indent).append(" blockLength = ").append(blockLenCast).append(blockLengthGet).append(";\n") .append(indent).append(" count = ").append(numInGroupCast).append(numInGroupGet).append(";\n") - .append(indent).append(" }\n"); + .append(indent).append(" }\n\n"); - sb.append("\n") - .append(indent).append(" public ").append(className).append(" next()\n") + + generateAccessOrderListenerMethodForNextGroupElement(sb, fieldPrecedenceModel, indent + " ", groupToken); + + sb.append(indent).append(" public ").append(className).append(" next()\n") .append(indent).append(" {\n") .append(indent).append(" if (index >= count)\n") .append(indent).append(" {\n") .append(indent).append(" throw new java.util.NoSuchElementException();\n") .append(indent).append(" }\n\n") + .append(generateAccessOrderListenerCall(fieldPrecedenceModel, indent + " ", "onNextElementAccessed")) .append(indent).append(" offset = parentMessage.limit();\n") .append(indent).append(" parentMessage.limit(offset + blockLength);\n") .append(indent).append(" ++index;\n\n") @@ -508,12 +1061,29 @@ private void generateGroupDecoderClassHeader( .append(indent).append(" {\n") .append(indent).append(" return index < count;\n") .append(indent).append(" }\n"); + + if (null != fieldPrecedenceModel) + { + sb.append("\n") + .append(indent).append(" private int codecState()\n") + .append(indent).append(" {\n") + .append(indent).append(" return parentMessage.codecState();\n") + .append(indent).append(" }\n"); + + sb.append("\n") + .append(indent).append(" private void codecState(final int newState)\n") + .append(indent).append(" {\n") + .append(indent).append(" parentMessage.codecState(newState);\n") + .append(indent).append(" }\n"); + } } private void generateGroupEncoderClassHeader( final StringBuilder sb, final String groupName, final String parentMessageClassName, + final FieldPrecedenceModel fieldPrecedenceModel, + final Token groupToken, final List tokens, final List subGroupTokens, final int index, @@ -566,7 +1136,7 @@ private void generateGroupEncoderClassHeader( ind + " parentMessage.limit(limit + HEADER_SIZE);\n" + ind + " %5$s;\n" + ind + " %6$s;\n" + - ind + " }\n", + ind + " }\n\n", parentMessageClassName, mutableBuffer, numInGroupToken.encoding().applicableMinValue().longValue(), @@ -574,9 +1144,12 @@ private void generateGroupEncoderClassHeader( blockLengthPut, numInGroupPut); - sb.append("\n") - .append(ind).append(" public ").append(encoderName(groupName)).append(" next()\n") + generateAccessOrderListenerMethodForNextGroupElement(sb, fieldPrecedenceModel, ind + " ", groupToken); + generateAccessOrderListenerMethodForResetGroupCount(sb, fieldPrecedenceModel, ind + " ", groupToken); + + sb.append(ind).append(" public ").append(encoderName(groupName)).append(" next()\n") .append(ind).append(" {\n") + .append(generateAccessOrderListenerCall(fieldPrecedenceModel, ind + " ", "onNextElementAccessed")) .append(ind).append(" if (index >= count)\n") .append(ind).append(" {\n") .append(ind).append(" throw new java.util.NoSuchElementException();\n") @@ -585,15 +1158,15 @@ private void generateGroupEncoderClassHeader( .append(ind).append(" parentMessage.limit(offset + sbeBlockLength());\n") .append(ind).append(" ++index;\n\n") .append(ind).append(" return this;\n") - .append(ind).append(" }\n"); + .append(ind).append(" }\n\n"); final String countOffset = "initialLimit + " + numInGroupToken.offset(); final String resetCountPut = generatePut( numInGroupTypeCast, countOffset, numInGroupValue, byteOrderString(numInGroupToken.encoding())); - sb.append("\n") - .append(ind).append(" public int resetCountToIndex()\n") + sb.append(ind).append(" public int resetCountToIndex()\n") .append(ind).append(" {\n") + .append(generateAccessOrderListenerCall(fieldPrecedenceModel, ind + " ", "onResetCountToIndex")) .append(ind).append(" count = index;\n") .append(ind).append(" ").append(resetCountPut).append(";\n\n") .append(ind).append(" return count;\n") @@ -618,6 +1191,21 @@ private void generateGroupEncoderClassHeader( .append(ind).append(" {\n") .append(ind).append(" return ").append(blockLength).append(";\n") .append(ind).append(" }\n"); + + if (null != fieldPrecedenceModel) + { + sb.append("\n") + .append(ind).append(" private int codecState()\n") + .append(ind).append(" {\n") + .append(ind).append(" return parentMessage.codecState();\n") + .append(ind).append(" }\n"); + + sb.append("\n") + .append(ind).append(" private void codecState(final int newState)\n") + .append(ind).append(" {\n") + .append(ind).append(" parentMessage.codecState(newState);\n") + .append(ind).append(" }\n"); + } } private static String primitiveTypeName(final Token token) @@ -728,9 +1316,10 @@ private void generateGroupEncoderClassDeclaration( sb.append(indent).append(" }\n"); } - private static void generateGroupDecoderProperty( + private void generateGroupDecoderProperty( final StringBuilder sb, final String groupName, + final FieldPrecedenceModel fieldPrecedenceModel, final Token token, final String indent, final boolean isSubGroup) @@ -772,22 +1361,27 @@ private static void generateGroupDecoderProperty( indent + " return " + propertyName + ";\n" + indent + " }\n\n"; + generateAccessOrderListenerMethodForGroupWrap(sb, "decode", fieldPrecedenceModel, indent + " ", token); + generateFlyweightPropertyJavadoc(sb, indent + INDENT, token, className); new Formatter(sb).format("\n" + indent + " public %1$s %2$s()\n" + indent + " {\n" + "%3$s" + indent + " %2$s.wrap(buffer);\n" + + "%4$s" + indent + " return %2$s;\n" + indent + " }\n", className, propertyName, - actingVersionGuard); + actingVersionGuard, + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + " ", token, propertyName + ".count")); } private void generateGroupEncoderProperty( final StringBuilder sb, final String groupName, + final FieldPrecedenceModel fieldPrecedenceModel, final Token token, final String indent, final boolean isSubGroup) @@ -812,19 +1406,26 @@ private void generateGroupEncoderProperty( formatPropertyName(groupName), token.id()); + generateAccessOrderListenerMethodForGroupWrap(sb, "encode", fieldPrecedenceModel, indent + " ", token); + generateGroupEncodePropertyJavadoc(sb, indent + INDENT, token, className); new Formatter(sb).format("\n" + indent + " public %1$s %2$sCount(final int count)\n" + indent + " {\n" + + "%3$s" + indent + " %2$s.wrap(buffer, count);\n" + indent + " return %2$s;\n" + indent + " }\n", className, - propertyName); + propertyName, + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + " ", token, "count")); } private void generateDecoderVarData( - final StringBuilder sb, final List tokens, final String indent) + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final List tokens, + final String indent) { for (int i = 0, size = tokens.size(); i < size;) { @@ -855,24 +1456,39 @@ private void generateDecoderVarData( .append(indent).append(" return ").append(sizeOfLengthField).append(";\n") .append(indent).append(" }\n"); + generateAccessOrderListenerMethodForVarDataLength(sb, fieldPrecedenceModel, indent + " ", token); + + final CharSequence lengthAccessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + " ", accessOrderListenerMethodName(token, "Length")); + + generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent + " ", token); + sb.append("\n") .append(indent).append(" public int ").append(methodPropName).append("Length()\n") .append(indent).append(" {\n") .append(generateArrayFieldNotPresentCondition(token.version(), indent)) + .append(lengthAccessOrderListenerCall) .append(indent).append(" final int limit = parentMessage.limit();\n") .append(indent).append(" return ").append(PrimitiveType.UINT32 == lengthType ? "(int)" : "") .append(generateGet(lengthType, "limit", byteOrderStr)).append(";\n") .append(indent).append(" }\n"); - generateDataDecodeMethods( - sb, token, propertyName, sizeOfLengthField, lengthType, byteOrderStr, characterEncoding, indent); + final CharSequence accessOrderListenerCall = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + " ", token); + + generateDataDecodeMethods(sb, token, propertyName, sizeOfLengthField, lengthType, + byteOrderStr, characterEncoding, accessOrderListenerCall, indent); i += token.componentTokenCount(); } } private void generateEncoderVarData( - final StringBuilder sb, final String className, final List tokens, final String indent) + final StringBuilder sb, + final String className, + final FieldPrecedenceModel fieldPrecedenceModel, + final List tokens, + final String indent) { for (int i = 0, size = tokens.size(); i < size;) { @@ -903,9 +1519,14 @@ private void generateEncoderVarData( .append(sizeOfLengthField).append(";\n") .append(indent).append(" }\n"); + generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent + " ", token); + final CharSequence accessOrderListenerCall = + generateAccessOrderListenerCall(fieldPrecedenceModel, indent + " ", token); + generateDataEncodeMethods( sb, propertyName, + accessOrderListenerCall, sizeOfLengthField, maxLengthValue, lengthEncoding.primitiveType(), @@ -926,12 +1547,14 @@ private void generateDataDecodeMethods( final PrimitiveType lengthType, final String byteOrderStr, final String characterEncoding, + final CharSequence accessOrderListenerCall, final String indent) { new Formatter(sb).format("\n" + indent + " public int skip%1$s()\n" + indent + " {\n" + "%2$s" + + "%6$s" + indent + " final int headerLength = %3$d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " final int dataLength = %4$s%5$s;\n" + @@ -943,7 +1566,8 @@ private void generateDataDecodeMethods( generateStringNotPresentConditionForAppendable(token.version(), indent), sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", - generateGet(lengthType, "limit", byteOrderStr)); + generateGet(lengthType, "limit", byteOrderStr), + accessOrderListenerCall); generateVarDataTypedDecoder( sb, @@ -953,6 +1577,7 @@ private void generateDataDecodeMethods( mutableBuffer, lengthType, byteOrderStr, + accessOrderListenerCall, indent); generateVarDataTypedDecoder( @@ -963,9 +1588,18 @@ private void generateDataDecodeMethods( "byte[]", lengthType, byteOrderStr, + accessOrderListenerCall, indent); - generateVarDataWrapDecoder(sb, token, propertyName, sizeOfLengthField, lengthType, byteOrderStr, indent); + generateVarDataWrapDecoder( + sb, + token, + propertyName, + sizeOfLengthField, + lengthType, + byteOrderStr, + accessOrderListenerCall, + indent); if (null != characterEncoding) { @@ -973,6 +1607,7 @@ private void generateDataDecodeMethods( indent + " public String %1$s()\n" + indent + " {\n" + "%2$s" + + "%7$s" + indent + " final int headerLength = %3$d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " final int dataLength = %4$s%5$s;\n" + @@ -990,7 +1625,8 @@ private void generateDataDecodeMethods( sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", generateGet(lengthType, "limit", byteOrderStr), - charset(characterEncoding)); + charset(characterEncoding), + accessOrderListenerCall); if (isAsciiEncoding(characterEncoding)) { @@ -998,6 +1634,7 @@ private void generateDataDecodeMethods( indent + " public int get%1$s(final Appendable appendable)\n" + indent + " {\n" + "%2$s" + + "%6$s" + indent + " final int headerLength = %3$d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " final int dataLength = %4$s%5$s;\n" + @@ -1010,7 +1647,8 @@ private void generateDataDecodeMethods( generateStringNotPresentConditionForAppendable(token.version(), indent), sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", - generateGet(lengthType, "limit", byteOrderStr)); + generateGet(lengthType, "limit", byteOrderStr), + accessOrderListenerCall); } } } @@ -1022,12 +1660,14 @@ private void generateVarDataWrapDecoder( final int sizeOfLengthField, final PrimitiveType lengthType, final String byteOrderStr, + final CharSequence accessOrderListenerCall, final String indent) { new Formatter(sb).format("\n" + indent + " public void wrap%s(final %s wrapBuffer)\n" + indent + " {\n" + "%s" + + "%s" + indent + " final int headerLength = %d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " final int dataLength = %s%s;\n" + @@ -1037,6 +1677,7 @@ private void generateVarDataWrapDecoder( propertyName, readOnlyBuffer, generateWrapFieldNotPresentCondition(token.version(), indent), + accessOrderListenerCall, sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", generateGet(lengthType, "limit", byteOrderStr)); @@ -1045,6 +1686,7 @@ private void generateVarDataWrapDecoder( private void generateDataEncodeMethods( final StringBuilder sb, final String propertyName, + final CharSequence accessOrderListenerCall, final int sizeOfLengthField, final int maxLengthValue, final PrimitiveType lengthType, @@ -1057,6 +1699,7 @@ private void generateDataEncodeMethods( sb, className, propertyName, + accessOrderListenerCall, sizeOfLengthField, maxLengthValue, readOnlyBuffer, @@ -1068,6 +1711,7 @@ private void generateDataEncodeMethods( sb, className, propertyName, + accessOrderListenerCall, sizeOfLengthField, maxLengthValue, "byte[]", @@ -1080,6 +1724,7 @@ private void generateDataEncodeMethods( generateCharArrayEncodeMethods( sb, propertyName, + accessOrderListenerCall, sizeOfLengthField, maxLengthValue, lengthType, @@ -1093,6 +1738,7 @@ private void generateDataEncodeMethods( private void generateCharArrayEncodeMethods( final StringBuilder sb, final String propertyName, + final CharSequence accessOrderListenerCall, final int sizeOfLengthField, final int maxLengthValue, final PrimitiveType lengthType, @@ -1113,6 +1759,7 @@ private void generateCharArrayEncodeMethods( indent + " {\n" + indent + " throw new IllegalStateException(\"length > maxValue for type: \" + length);\n" + indent + " }\n\n" + + "%6$s" + indent + " final int headerLength = %4$d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " parentMessage.limit(limit + headerLength + length);\n" + @@ -1124,7 +1771,8 @@ private void generateCharArrayEncodeMethods( formatPropertyName(propertyName), maxLengthValue, sizeOfLengthField, - generatePut(lengthPutType, "limit", "length", byteOrderStr)); + generatePut(lengthPutType, "limit", "length", byteOrderStr), + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " public %1$s %2$s(final CharSequence value)\n" + @@ -1134,6 +1782,7 @@ private void generateCharArrayEncodeMethods( indent + " {\n" + indent + " throw new IllegalStateException(\"length > maxValue for type: \" + length);\n" + indent + " }\n\n" + + "%6$s" + indent + " final int headerLength = %4$d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " parentMessage.limit(limit + headerLength + length);\n" + @@ -1145,7 +1794,8 @@ private void generateCharArrayEncodeMethods( formatPropertyName(propertyName), maxLengthValue, sizeOfLengthField, - generatePut(lengthPutType, "limit", "length", byteOrderStr)); + generatePut(lengthPutType, "limit", "length", byteOrderStr), + accessOrderListenerCall); } else { @@ -1159,6 +1809,7 @@ private void generateCharArrayEncodeMethods( indent + " {\n" + indent + " throw new IllegalStateException(\"length > maxValue for type: \" + length);\n" + indent + " }\n\n" + + "%7$s" + indent + " final int headerLength = %5$d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " parentMessage.limit(limit + headerLength + length);\n" + @@ -1171,7 +1822,8 @@ private void generateCharArrayEncodeMethods( charset(characterEncoding), maxLengthValue, sizeOfLengthField, - generatePut(lengthPutType, "limit", "length", byteOrderStr)); + generatePut(lengthPutType, "limit", "length", byteOrderStr), + accessOrderListenerCall); } } @@ -1183,12 +1835,14 @@ private void generateVarDataTypedDecoder( final String exchangeType, final PrimitiveType lengthType, final String byteOrderStr, + final CharSequence accessOrderListenerCall, final String indent) { new Formatter(sb).format("\n" + indent + " public int get%s(final %s dst, final int dstOffset, final int length)\n" + indent + " {\n" + "%s" + + "%s" + indent + " final int headerLength = %d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " final int dataLength = %s%s;\n" + @@ -1200,6 +1854,7 @@ private void generateVarDataTypedDecoder( propertyName, exchangeType, generateArrayFieldNotPresentCondition(token.version(), indent), + accessOrderListenerCall, sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", generateGet(lengthType, "limit", byteOrderStr)); @@ -1209,6 +1864,7 @@ private void generateDataTypedEncoder( final StringBuilder sb, final String className, final String propertyName, + final CharSequence accessOrderListenerCall, final int sizeOfLengthField, final int maxLengthValue, final String exchangeType, @@ -1225,6 +1881,7 @@ private void generateDataTypedEncoder( indent + " {\n" + indent + " throw new IllegalStateException(\"length > maxValue for type: \" + length);\n" + indent + " }\n\n" + + "%7$s" + indent + " final int headerLength = %5$d;\n" + indent + " final int limit = parentMessage.limit();\n" + indent + " parentMessage.limit(limit + headerLength + length);\n" + @@ -1237,7 +1894,8 @@ private void generateDataTypedEncoder( exchangeType, maxLengthValue, sizeOfLengthField, - generatePut(lengthPutType, "limit", "length", byteOrderStr)); + generatePut(lengthPutType, "limit", "length", byteOrderStr), + accessOrderListenerCall); } private void generateBitSet(final List tokens) throws IOException @@ -1359,26 +2017,29 @@ private void generateComposite(final List tokens) throws IOException generateEncodingOffsetMethod(sb, propertyName, encodingToken.offset(), BASE_INDENT); generateEncodingLengthMethod(sb, propertyName, encodingToken.encodedLength(), BASE_INDENT); generateFieldSinceVersionMethod(sb, encodingToken, BASE_INDENT); + final String accessOrderListenerCall = ""; switch (encodingToken.signal()) { case ENCODING: generatePrimitiveDecoder( - sb, true, encodingToken.name(), encodingToken, encodingToken, BASE_INDENT); + sb, true, encodingToken.name(), "", encodingToken, encodingToken, BASE_INDENT); break; case BEGIN_ENUM: - generateEnumDecoder(sb, true, encodingToken, propertyName, encodingToken, BASE_INDENT); + generateEnumDecoder(sb, true, "", encodingToken, propertyName, encodingToken, BASE_INDENT); break; case BEGIN_SET: generateBitSetProperty( - sb, true, DECODER, propertyName, encodingToken, encodingToken, BASE_INDENT, typeName); + sb, true, DECODER, propertyName, accessOrderListenerCall, + encodingToken, encodingToken, BASE_INDENT, typeName); break; case BEGIN_COMPOSITE: generateCompositeProperty( - sb, true, DECODER, propertyName, encodingToken, encodingToken, BASE_INDENT, typeName); + sb, true, DECODER, propertyName, accessOrderListenerCall, + encodingToken, encodingToken, BASE_INDENT, typeName); break; default: @@ -1410,25 +2071,30 @@ private void generateComposite(final List tokens) throws IOException final StringBuilder sb = new StringBuilder(); generateEncodingOffsetMethod(sb, propertyName, encodingToken.offset(), BASE_INDENT); generateEncodingLengthMethod(sb, propertyName, encodingToken.encodedLength(), BASE_INDENT); + final String accessOrderListenerCall = ""; switch (encodingToken.signal()) { case ENCODING: - generatePrimitiveEncoder(sb, encoderName, encodingToken.name(), encodingToken, BASE_INDENT); + generatePrimitiveEncoder(sb, encoderName, encodingToken.name(), + accessOrderListenerCall, encodingToken, BASE_INDENT); break; case BEGIN_ENUM: - generateEnumEncoder(sb, encoderName, encodingToken, propertyName, encodingToken, BASE_INDENT); + generateEnumEncoder(sb, encoderName, accessOrderListenerCall, + encodingToken, propertyName, encodingToken, BASE_INDENT); break; case BEGIN_SET: generateBitSetProperty( - sb, true, ENCODER, propertyName, encodingToken, encodingToken, BASE_INDENT, typeName); + sb, true, ENCODER, propertyName, accessOrderListenerCall, + encodingToken, encodingToken, BASE_INDENT, typeName); break; case BEGIN_COMPOSITE: generateCompositeProperty( - sb, true, ENCODER, propertyName, encodingToken, encodingToken, BASE_INDENT, typeName); + sb, true, ENCODER, propertyName, accessOrderListenerCall, + encodingToken, encodingToken, BASE_INDENT, typeName); break; default: @@ -1855,6 +2521,7 @@ private void generatePrimitiveDecoder( final StringBuilder sb, final boolean inComposite, final String propertyName, + final CharSequence accessOrderListenerCall, final Token propertyToken, final Token encodingToken, final String indent) @@ -1870,7 +2537,7 @@ private void generatePrimitiveDecoder( else { sb.append(generatePrimitivePropertyDecodeMethods( - inComposite, formattedPropertyName, propertyToken, encodingToken, indent)); + inComposite, formattedPropertyName, accessOrderListenerCall, propertyToken, encodingToken, indent)); } } @@ -1878,43 +2545,52 @@ private void generatePrimitiveEncoder( final StringBuilder sb, final String containingClassName, final String propertyName, - final Token token, + final CharSequence accessOrderListenerCall, + final Token typeToken, final String indent) { final String formattedPropertyName = formatPropertyName(propertyName); - generatePrimitiveFieldMetaMethod(sb, formattedPropertyName, token, indent); + generatePrimitiveFieldMetaMethod(sb, formattedPropertyName, typeToken, indent); - if (!token.isConstantEncoding()) + if (!typeToken.isConstantEncoding()) { sb.append(generatePrimitivePropertyEncodeMethods( - containingClassName, formattedPropertyName, token, indent)); + containingClassName, formattedPropertyName, accessOrderListenerCall, typeToken, indent)); } else { - generateConstPropertyMethods(sb, formattedPropertyName, token, indent); + generateConstPropertyMethods(sb, formattedPropertyName, typeToken, indent); } } private CharSequence generatePrimitivePropertyDecodeMethods( final boolean inComposite, final String propertyName, + final CharSequence accessOrderListenerCall, final Token propertyToken, final Token encodingToken, final String indent) { return encodingToken.matchOnLength( - () -> generatePrimitivePropertyDecode(inComposite, propertyName, propertyToken, encodingToken, indent), + () -> generatePrimitivePropertyDecode( + inComposite, propertyName, accessOrderListenerCall, propertyToken, encodingToken, indent), () -> generatePrimitiveArrayPropertyDecode( - inComposite, propertyName, propertyToken, encodingToken, indent)); + inComposite, propertyName, accessOrderListenerCall, propertyToken, encodingToken, indent)); } private CharSequence generatePrimitivePropertyEncodeMethods( - final String containingClassName, final String propertyName, final Token token, final String indent) + final String containingClassName, + final String propertyName, + final CharSequence accessOrderListenerCall, + final Token typeToken, + final String indent) { - return token.matchOnLength( - () -> generatePrimitivePropertyEncode(containingClassName, propertyName, token, indent), - () -> generatePrimitiveArrayPropertyEncode(containingClassName, propertyName, token, indent)); + return typeToken.matchOnLength( + () -> generatePrimitivePropertyEncode( + containingClassName, propertyName, accessOrderListenerCall, typeToken, indent), + () -> generatePrimitiveArrayPropertyEncode( + containingClassName, propertyName, accessOrderListenerCall, typeToken, indent)); } private void generatePrimitiveFieldMetaMethod( @@ -1953,6 +2629,7 @@ private void generatePrimitiveFieldMetaMethod( private CharSequence generatePrimitivePropertyDecode( final boolean inComposite, final String propertyName, + final CharSequence accessOrderListenerCall, final Token propertyToken, final Token encodingToken, final String indent) @@ -1968,32 +2645,40 @@ private CharSequence generatePrimitivePropertyDecode( indent + " public %s %s()\n" + indent + " {\n" + "%s" + + "%s" + indent + " return %s;\n" + indent + " }\n\n", javaTypeName, formatPropertyName(propertyName), generateFieldNotPresentCondition(inComposite, propertyToken.version(), encoding, indent), + accessOrderListenerCall, generateGet(encoding.primitiveType(), "offset + " + offset, byteOrderStr)); } private CharSequence generatePrimitivePropertyEncode( - final String containingClassName, final String propertyName, final Token token, final String indent) + final String containingClassName, + final String propertyName, + final CharSequence accessOrderListenerCall, + final Token typeToken, + final String indent) { - final Encoding encoding = token.encoding(); + final Encoding encoding = typeToken.encoding(); final String javaTypeName = javaTypeName(encoding.primitiveType()); - final int offset = token.offset(); + final int offset = typeToken.offset(); final String byteOrderStr = byteOrderString(encoding); return String.format( "\n" + indent + " public %s %s(final %s value)\n" + indent + " {\n" + + "%s" + indent + " %s;\n" + indent + " return this;\n" + indent + " }\n\n", formatClassName(containingClassName), formatPropertyName(propertyName), javaTypeName, + accessOrderListenerCall, generatePut(encoding.primitiveType(), "offset + " + offset, "value", byteOrderStr)); } @@ -2094,6 +2779,7 @@ private static CharSequence generatePropertyNotPresentCondition( private CharSequence generatePrimitiveArrayPropertyDecode( final boolean inComposite, final String propertyName, + final CharSequence accessOrderListenerCall, final Token propertyToken, final Token encodingToken, final String indent) @@ -2117,6 +2803,7 @@ private CharSequence generatePrimitiveArrayPropertyDecode( indent + " throw new IndexOutOfBoundsException(\"index out of range: index=\" + index);\n" + indent + " }\n\n" + "%s" + + "%s" + indent + " final int pos = offset + %d + (index * %d);\n\n" + indent + " return %s;\n" + indent + " }\n\n", @@ -2124,6 +2811,7 @@ private CharSequence generatePrimitiveArrayPropertyDecode( propertyName, fieldLength, generateFieldNotPresentCondition(inComposite, propertyToken.version(), encoding, indent), + accessOrderListenerCall, offset, typeSize, generateGet(encoding.primitiveType(), "pos", byteOrderStr)); @@ -2142,18 +2830,21 @@ private CharSequence generatePrimitiveArrayPropertyDecode( "\"Copy will go out of range: offset=\" + dstOffset);\n" + indent + " }\n\n" + "%s" + + "%s" + indent + " buffer.getBytes(offset + %d, dst, dstOffset, length);\n\n" + indent + " return length;\n" + indent + " }\n", Generators.toUpperFirstChar(propertyName), fieldLength, generateArrayFieldNotPresentCondition(propertyToken.version(), indent), + accessOrderListenerCall, offset); new Formatter(sb).format("\n" + indent + " public String %s()\n" + indent + " {\n" + "%s" + + "%s" + indent + " final byte[] dst = new byte[%d];\n" + indent + " buffer.getBytes(offset + %d, dst, 0, %d);\n\n" + indent + " int end = 0;\n" + @@ -2162,6 +2853,7 @@ private CharSequence generatePrimitiveArrayPropertyDecode( indent + " }\n\n", propertyName, generateStringNotPresentCondition(propertyToken.version(), indent), + accessOrderListenerCall, fieldLength, offset, fieldLength, @@ -2174,6 +2866,7 @@ private CharSequence generatePrimitiveArrayPropertyDecode( indent + " public int get%1$s(final Appendable value)\n" + indent + " {\n" + "%2$s" + + "%5$s" + indent + " for (int i = 0; i < %3$d; ++i)\n" + indent + " {\n" + indent + " final int c = buffer.getByte(offset + %4$d + i) & 0xFF;\n" + @@ -2195,7 +2888,8 @@ private CharSequence generatePrimitiveArrayPropertyDecode( Generators.toUpperFirstChar(propertyName), generateStringNotPresentConditionForAppendable(propertyToken.version(), indent), fieldLength, - offset); + offset, + accessOrderListenerCall); } } else if (encoding.primitiveType() == PrimitiveType.UINT8) @@ -2204,12 +2898,14 @@ else if (encoding.primitiveType() == PrimitiveType.UINT8) indent + " public int get%s(final byte[] dst, final int dstOffset, final int length)\n" + indent + " {\n" + "%s" + + "%s" + indent + " final int bytesCopied = Math.min(length, %d);\n" + indent + " buffer.getBytes(offset + %d, dst, dstOffset, bytesCopied);\n\n" + indent + " return bytesCopied;\n" + indent + " }\n", Generators.toUpperFirstChar(propertyName), generateArrayFieldNotPresentCondition(propertyToken.version(), indent), + accessOrderListenerCall, fieldLength, offset); @@ -2217,6 +2913,7 @@ else if (encoding.primitiveType() == PrimitiveType.UINT8) indent + " public int get%s(final %s dst, final int dstOffset, final int length)\n" + indent + " {\n" + "%s" + + "%s" + indent + " final int bytesCopied = Math.min(length, %d);\n" + indent + " buffer.getBytes(offset + %d, dst, dstOffset, bytesCopied);\n\n" + indent + " return bytesCopied;\n" + @@ -2224,6 +2921,7 @@ else if (encoding.primitiveType() == PrimitiveType.UINT8) Generators.toUpperFirstChar(propertyName), fqMutableBuffer, generateArrayFieldNotPresentCondition(propertyToken.version(), indent), + accessOrderListenerCall, fieldLength, offset); @@ -2231,11 +2929,13 @@ else if (encoding.primitiveType() == PrimitiveType.UINT8) indent + " public void wrap%s(final %s wrapBuffer)\n" + indent + " {\n" + "%s" + + "%s" + indent + " wrapBuffer.wrap(buffer, offset + %d, %d);\n" + indent + " }\n", Generators.toUpperFirstChar(propertyName), readOnlyBuffer, generateWrapFieldNotPresentCondition(propertyToken.version(), indent), + accessOrderListenerCall, offset, fieldLength); } @@ -2260,14 +2960,18 @@ private String byteOrderString(final Encoding encoding) } private CharSequence generatePrimitiveArrayPropertyEncode( - final String containingClassName, final String propertyName, final Token token, final String indent) + final String containingClassName, + final String propertyName, + final CharSequence accessOrderListenerCall, + final Token typeToken, + final String indent) { - final Encoding encoding = token.encoding(); + final Encoding encoding = typeToken.encoding(); final PrimitiveType primitiveType = encoding.primitiveType(); final String javaTypeName = javaTypeName(primitiveType); - final int offset = token.offset(); + final int offset = typeToken.offset(); final String byteOrderStr = byteOrderString(encoding); - final int arrayLength = token.arrayLength(); + final int arrayLength = typeToken.arrayLength(); final int typeSize = sizeOfPrimitive(encoding); final StringBuilder sb = new StringBuilder(); @@ -2282,6 +2986,7 @@ private CharSequence generatePrimitiveArrayPropertyEncode( indent + " {\n" + indent + " throw new IndexOutOfBoundsException(\"index out of range: index=\" + index);\n" + indent + " }\n\n" + + "%s" + indent + " final int pos = offset + %d + (index * %d);\n" + indent + " %s;\n\n" + indent + " return this;\n" + @@ -2290,6 +2995,7 @@ private CharSequence generatePrimitiveArrayPropertyEncode( propertyName, javaTypeName, arrayLength, + accessOrderListenerCall, offset, typeSize, generatePut(primitiveType, "pos", "value", byteOrderStr)); @@ -2310,6 +3016,8 @@ private CharSequence generatePrimitiveArrayPropertyEncode( sb.append(")\n"); sb.append(indent).append(" {\n"); + sb.append(accessOrderListenerCall); + for (int i = 0; i < arrayLength; i++) { final String indexStr = "offset + " + (offset + (typeSize * i)); @@ -2327,12 +3035,25 @@ private CharSequence generatePrimitiveArrayPropertyEncode( if (primitiveType == PrimitiveType.CHAR) { generateCharArrayEncodeMethods( - containingClassName, propertyName, indent, encoding, offset, arrayLength, sb); + containingClassName, + propertyName, + indent, + accessOrderListenerCall, + encoding, + offset, + arrayLength, + sb); } else if (primitiveType == PrimitiveType.UINT8) { generateByteArrayEncodeMethods( - containingClassName, propertyName, indent, offset, arrayLength, sb); + containingClassName, + propertyName, + indent, + accessOrderListenerCall, + offset, + arrayLength, + sb); } return sb; @@ -2342,6 +3063,7 @@ private void generateCharArrayEncodeMethods( final String containingClassName, final String propertyName, final String indent, + final CharSequence accessOrderListenerCall, final Encoding encoding, final int offset, final int fieldLength, @@ -2358,12 +3080,14 @@ private void generateCharArrayEncodeMethods( indent + " throw new IndexOutOfBoundsException(" + "\"Copy will go out of range: offset=\" + srcOffset);\n" + indent + " }\n\n" + + "%s" + indent + " buffer.putBytes(offset + %d, src, srcOffset, length);\n\n" + indent + " return this;\n" + indent + " }\n", formatClassName(containingClassName), Generators.toUpperFirstChar(propertyName), fieldLength, + accessOrderListenerCall, offset); if (isAsciiEncoding(encoding.characterEncoding())) @@ -2378,6 +3102,7 @@ private void generateCharArrayEncodeMethods( indent + " throw new IndexOutOfBoundsException(" + "\"String too large for copy: byte length=\" + srcLength);\n" + indent + " }\n\n" + + "%5$s" + indent + " buffer.putStringWithoutLengthAscii(offset + %4$d, src);\n\n" + indent + " for (int start = srcLength; start < length; ++start)\n" + indent + " {\n" + @@ -2388,7 +3113,8 @@ private void generateCharArrayEncodeMethods( formatClassName(containingClassName), propertyName, fieldLength, - offset); + offset, + accessOrderListenerCall); new Formatter(sb).format("\n" + indent + " public %1$s %2$s(final CharSequence src)\n" + @@ -2400,6 +3126,7 @@ private void generateCharArrayEncodeMethods( indent + " throw new IndexOutOfBoundsException(" + "\"CharSequence too large for copy: byte length=\" + srcLength);\n" + indent + " }\n\n" + + "%5$s" + indent + " buffer.putStringWithoutLengthAscii(offset + %4$d, src);\n\n" + indent + " for (int start = srcLength; start < length; ++start)\n" + indent + " {\n" + @@ -2410,7 +3137,8 @@ private void generateCharArrayEncodeMethods( formatClassName(containingClassName), propertyName, fieldLength, - offset); + offset, + accessOrderListenerCall); } else { @@ -2425,6 +3153,7 @@ private void generateCharArrayEncodeMethods( indent + " throw new IndexOutOfBoundsException(" + "\"String too large for copy: byte length=\" + bytes.length);\n" + indent + " }\n\n" + + "%s" + indent + " buffer.putBytes(offset + %d, bytes, 0, bytes.length);\n\n" + indent + " for (int start = bytes.length; start < length; ++start)\n" + indent + " {\n" + @@ -2436,6 +3165,7 @@ private void generateCharArrayEncodeMethods( propertyName, fieldLength, charset(encoding.characterEncoding()), + accessOrderListenerCall, offset, offset); } @@ -2445,6 +3175,7 @@ private void generateByteArrayEncodeMethods( final String containingClassName, final String propertyName, final String indent, + final CharSequence accessOrderListenerCall, final int offset, final int fieldLength, final StringBuilder sb) @@ -2457,6 +3188,7 @@ private void generateByteArrayEncodeMethods( indent + " throw new IllegalStateException(" + "\"length > maxValue for type: \" + length);\n" + indent + " }\n\n" + + "%s" + indent + " buffer.putBytes(offset + %d, src, srcOffset, length);\n" + indent + " for (int i = length; i < %d; i++)\n" + indent + " {\n" + @@ -2467,6 +3199,7 @@ private void generateByteArrayEncodeMethods( formatClassName(containingClassName), Generators.toUpperFirstChar(propertyName), fieldLength, + accessOrderListenerCall, offset, fieldLength, offset); @@ -2479,6 +3212,7 @@ private void generateByteArrayEncodeMethods( indent + " throw new IllegalStateException(" + "\"length > maxValue for type: \" + length);\n" + indent + " }\n\n" + + "%s" + indent + " buffer.putBytes(offset + %d, src, srcOffset, length);\n" + indent + " for (int i = length; i < %d; i++)\n" + indent + " {\n" + @@ -2490,6 +3224,7 @@ private void generateByteArrayEncodeMethods( Generators.toUpperFirstChar(propertyName), fqReadOnlyBuffer, fieldLength, + accessOrderListenerCall, offset, fieldLength, offset); @@ -2663,67 +3398,90 @@ private CharSequence generateFixedFlyweightCode( semanticVersion); } - private CharSequence generateDecoderFlyweightCode(final String className, final Token token) + private CharSequence generateDecoderFlyweightCode( + final FieldPrecedenceModel fieldPrecedenceModel, + final String className, + final Token token) { final String headerClassName = formatClassName(ir.headerStructure().tokens().get(0).applicableTypeName()); - final String methods = - " public " + className + " wrap(\n" + - " final " + readOnlyBuffer + " buffer,\n" + - " final int offset,\n" + - " final int actingBlockLength,\n" + - " final int actingVersion)\n" + - " {\n" + - " if (buffer != this.buffer)\n" + - " {\n" + - " this.buffer = buffer;\n" + - " }\n" + - " this.initialOffset = offset;\n" + - " this.offset = offset;\n" + - " this.actingBlockLength = actingBlockLength;\n" + - " this.actingVersion = actingVersion;\n" + - " limit(offset + actingBlockLength);\n\n" + - " return this;\n" + - " }\n\n" + + final StringBuilder methods = new StringBuilder(); - " public " + className + " wrapAndApplyHeader(\n" + - " final " + readOnlyBuffer + " buffer,\n" + - " final int offset,\n" + - " final " + headerClassName + "Decoder headerDecoder)\n" + - " {\n" + - " headerDecoder.wrap(buffer, offset);\n\n" + - " final int templateId = headerDecoder.templateId();\n" + - " if (TEMPLATE_ID != templateId)\n" + - " {\n" + - " throw new IllegalStateException(\"Invalid TEMPLATE_ID: \" + templateId);\n" + - " }\n\n" + - " return wrap(\n" + - " buffer,\n" + - " offset + " + headerClassName + "Decoder.ENCODED_LENGTH,\n" + - " headerDecoder.blockLength(),\n" + - " headerDecoder.version());\n" + - " }\n\n" + + methods.append(generateDecoderWrapListener(fieldPrecedenceModel, " ")); - " public " + className + " sbeRewind()\n" + - " {\n" + - " return wrap(buffer, initialOffset, actingBlockLength, actingVersion);\n" + - " }\n\n" + + methods.append(" public ").append(className).append(" wrap(\n") + .append(" final ").append(readOnlyBuffer).append(" buffer,\n") + .append(" final int offset,\n") + .append(" final int actingBlockLength,\n") + .append(" final int actingVersion)\n") + .append(" {\n") + .append(" if (buffer != this.buffer)\n") + .append(" {\n") + .append(" this.buffer = buffer;\n") + .append(" }\n") + .append(" this.initialOffset = offset;\n") + .append(" this.offset = offset;\n") + .append(" this.actingBlockLength = actingBlockLength;\n") + .append(" this.actingVersion = actingVersion;\n") + .append(" limit(offset + actingBlockLength);\n\n") + .append(generateAccessOrderListenerCall(fieldPrecedenceModel, " ", "onWrap", "actingVersion")) + .append(" return this;\n") + .append(" }\n\n"); - " public int sbeDecodedLength()\n" + - " {\n" + - " final int currentLimit = limit();\n" + - " sbeSkip();\n" + - " final int decodedLength = encodedLength();\n" + - " limit(currentLimit);\n\n" + - " return decodedLength;\n" + - " }\n\n" + + methods.append(" public ").append(className).append(" wrapAndApplyHeader(\n") + .append(" final ").append(readOnlyBuffer).append(" buffer,\n") + .append(" final int offset,\n") + .append(" final ").append(headerClassName).append("Decoder headerDecoder)\n") + .append(" {\n") + .append(" headerDecoder.wrap(buffer, offset);\n\n") + .append(" final int templateId = headerDecoder.templateId();\n") + .append(" if (TEMPLATE_ID != templateId)\n") + .append(" {\n") + .append(" throw new IllegalStateException(\"Invalid TEMPLATE_ID: \" + templateId);\n") + .append(" }\n\n") + .append(" return wrap(\n") + .append(" buffer,\n") + .append(" offset + ").append(headerClassName).append("Decoder.ENCODED_LENGTH,\n") + .append(" headerDecoder.blockLength(),\n") + .append(" headerDecoder.version());\n") + .append(" }\n\n"); + + methods.append(" public ").append(className).append(" sbeRewind()\n") + .append(" {\n") + .append(" return wrap(buffer, initialOffset, actingBlockLength, actingVersion);\n") + .append(" }\n\n"); - " public int actingVersion()\n" + - " {\n" + - " return actingVersion;\n" + - " }\n\n"; + methods.append(" public int sbeDecodedLength()\n") + .append(" {\n") + .append(" final int currentLimit = limit();\n"); - return generateFlyweightCode(DECODER, className, token, methods, readOnlyBuffer); + if (null != fieldPrecedenceModel) + { + methods.append(" final int currentCodecState = codecState();\n"); + } + + methods + .append(" sbeSkip();\n") + .append(" final int decodedLength = encodedLength();\n") + .append(" limit(currentLimit);\n\n"); + + if (null != fieldPrecedenceModel) + { + methods.append(" if (").append(precedenceChecksFlagName).append(")\n") + .append(" {\n") + .append(" codecState(currentCodecState);\n") + .append(" }\n\n"); + } + + methods.append(" return decodedLength;\n") + .append(" }\n\n"); + + methods.append(" public int actingVersion()\n") + .append(" {\n") + .append(" return actingVersion;\n") + .append(" }\n\n"); + + return generateFlyweightCode(DECODER, className, token, methods.toString(), readOnlyBuffer); } private CharSequence generateFlyweightCode( @@ -2829,7 +3587,10 @@ private CharSequence generateFlyweightCode( semanticVersion); } - private CharSequence generateEncoderFlyweightCode(final String className, final Token token) + private CharSequence generateEncoderFlyweightCode( + final String className, + final FieldPrecedenceModel fieldPrecedenceModel, + final Token token) { final String wrapMethod = " public " + className + " wrap(final " + mutableBuffer + " buffer, final int offset)\n" + @@ -2841,6 +3602,7 @@ private CharSequence generateEncoderFlyweightCode(final String className, final " this.initialOffset = offset;\n" + " this.offset = offset;\n" + " limit(offset + BLOCK_LENGTH);\n\n" + + generateEncoderWrapListener(fieldPrecedenceModel, " ") + " return this;\n" + " }\n\n"; @@ -2889,7 +3651,11 @@ private CharSequence generateEncoderFlyweightCode(final String className, final } private void generateEncoderFields( - final StringBuilder sb, final String containingClassName, final List tokens, final String indent) + final StringBuilder sb, + final String containingClassName, + final FieldPrecedenceModel fieldPrecedenceModel, + final List tokens, + final String indent) { Generators.forEachField( tokens, @@ -2903,25 +3669,32 @@ private void generateEncoderFields( generateEncodingOffsetMethod(sb, propertyName, fieldToken.offset(), indent); generateEncodingLengthMethod(sb, propertyName, typeToken.encodedLength(), indent); generateFieldMetaAttributeMethod(sb, fieldToken, indent); + generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent + " ", fieldToken); + final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + " ", fieldToken); switch (typeToken.signal()) { case ENCODING: - generatePrimitiveEncoder(sb, containingClassName, propertyName, typeToken, indent); + generatePrimitiveEncoder(sb, containingClassName, propertyName, + accessOrderListenerCall, typeToken, indent); break; case BEGIN_ENUM: - generateEnumEncoder(sb, containingClassName, fieldToken, propertyName, typeToken, indent); + generateEnumEncoder(sb, containingClassName, + accessOrderListenerCall, fieldToken, propertyName, typeToken, indent); break; case BEGIN_SET: generateBitSetProperty( - sb, false, ENCODER, propertyName, fieldToken, typeToken, indent, typeName); + sb, false, ENCODER, propertyName, accessOrderListenerCall, + fieldToken, typeToken, indent, typeName); break; case BEGIN_COMPOSITE: generateCompositeProperty( - sb, false, ENCODER, propertyName, fieldToken, typeToken, indent, typeName); + sb, false, ENCODER, propertyName, accessOrderListenerCall, + fieldToken, typeToken, indent, typeName); break; default: @@ -2930,7 +3703,11 @@ private void generateEncoderFields( }); } - private void generateDecoderFields(final StringBuilder sb, final List tokens, final String indent) + private void generateDecoderFields( + final StringBuilder sb, + final FieldPrecedenceModel fieldPrecedenceModel, + final List tokens, + final String indent) { Generators.forEachField( tokens, @@ -2945,24 +3722,32 @@ private void generateDecoderFields(final StringBuilder sb, final List tok generateEncodingLengthMethod(sb, propertyName, typeToken.encodedLength(), indent); generateFieldMetaAttributeMethod(sb, fieldToken, indent); + generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent + " ", fieldToken); + final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( + fieldPrecedenceModel, indent + " ", fieldToken); + switch (typeToken.signal()) { case ENCODING: - generatePrimitiveDecoder(sb, false, propertyName, fieldToken, typeToken, indent); + generatePrimitiveDecoder( + sb, false, propertyName, accessOrderListenerCall, fieldToken, typeToken, indent); break; case BEGIN_ENUM: - generateEnumDecoder(sb, false, fieldToken, propertyName, typeToken, indent); + generateEnumDecoder( + sb, false, accessOrderListenerCall, fieldToken, propertyName, typeToken, indent); break; case BEGIN_SET: generateBitSetProperty( - sb, false, DECODER, propertyName, fieldToken, typeToken, indent, typeName); + sb, false, DECODER, propertyName, accessOrderListenerCall, + fieldToken, typeToken, indent, typeName); break; case BEGIN_COMPOSITE: generateCompositeProperty( - sb, false, DECODER, propertyName, fieldToken, typeToken, indent, typeName); + sb, false, DECODER, propertyName, accessOrderListenerCall, + fieldToken, typeToken, indent, typeName); break; default: @@ -3063,6 +3848,7 @@ private static void generateFieldMetaAttributeMethod(final StringBuilder sb, fin private void generateEnumDecoder( final StringBuilder sb, final boolean inComposite, + final CharSequence accessOrderListenerCall, final Token fieldToken, final String propertyName, final Token typeToken, @@ -3107,11 +3893,13 @@ private void generateEnumDecoder( indent + " public %s %sRaw()\n" + indent + " {\n" + "%s" + + "%s" + indent + " return %s;\n" + indent + " }\n", javaTypeName, formatPropertyName(propertyName), generateFieldNotPresentCondition(inComposite, fieldToken.version(), encoding, indent), + accessOrderListenerCall, rawGetStr); new Formatter(sb).format( @@ -3119,11 +3907,13 @@ private void generateEnumDecoder( indent + " public %s %s()\n" + indent + " {\n" + "%s" + + "%s" + indent + " return %s.get(%s);\n" + indent + " }\n\n", enumName, propertyName, generatePropertyNotPresentCondition(inComposite, DECODER, fieldToken, enumName, indent), + accessOrderListenerCall, enumName, rawGetStr); } @@ -3132,6 +3922,7 @@ private void generateEnumDecoder( private void generateEnumEncoder( final StringBuilder sb, final String containingClassName, + final CharSequence accessOrderListenerCall, final Token fieldToken, final String propertyName, final Token typeToken, @@ -3147,12 +3938,14 @@ private void generateEnumEncoder( new Formatter(sb).format("\n" + indent + " public %s %s(final %s value)\n" + indent + " {\n" + + "%s" + indent + " %s;\n" + indent + " return this;\n" + indent + " }\n", formatClassName(containingClassName), propertyName, enumName, + accessOrderListenerCall, generatePut(encoding.primitiveType(), "offset + " + offset, "value.value()", byteOrderString)); } } @@ -3162,6 +3955,7 @@ private void generateBitSetProperty( final boolean inComposite, final CodecType codecType, final String propertyName, + final CharSequence accessOrderListenerCall, final Token propertyToken, final Token bitsetToken, final String indent, @@ -3178,12 +3972,14 @@ private void generateBitSetProperty( indent + " public %s %s()\n" + indent + " {\n" + "%s" + + "%s" + indent + " %s.wrap(buffer, offset + %d);\n" + indent + " return %s;\n" + indent + " }\n", bitSetName, propertyName, generatePropertyNotPresentCondition(inComposite, codecType, propertyToken, null, indent), + accessOrderListenerCall, propertyName, bitsetToken.offset(), propertyName); @@ -3194,6 +3990,7 @@ private void generateCompositeProperty( final boolean inComposite, final CodecType codecType, final String propertyName, + final CharSequence accessOrderListenerCall, final Token propertyToken, final Token compositeToken, final String indent, @@ -3210,12 +4007,14 @@ private void generateCompositeProperty( indent + " public %s %s()\n" + indent + " {\n" + "%s" + + "%s" + indent + " %s.wrap(buffer, offset + %d);\n" + indent + " return %s;\n" + indent + " }\n", compositeName, propertyName, generatePropertyNotPresentCondition(inComposite, codecType, propertyToken, null, indent), + accessOrderListenerCall, propertyName, compositeToken.offset(), propertyName); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index 8cbdc11954..89962bd61f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -11,6 +11,83 @@ @SuppressWarnings("all") public final class FrameCodecDecoder { + private static final boolean ENABLE_BOUNDS_CHECKS = !Boolean.getBoolean("agrona.disable.bounds.checks"); + + private static final boolean SBE_ENABLE_IR_PRECEDENCE_CHECKS = Boolean.parseBoolean(System.getProperty( + "sbe.enable.ir.precedence.checks", + Boolean.toString(ENABLE_BOUNDS_CHECKS))); + + /** + * The states in which a encoder/decoder/codec can live. + * + *

    The state machine diagram below, encoded in the dot language, describes + * the valid state transitions according to the order in which fields may be + * accessed safely. Tools such as PlantUML and Graphviz can render it. + * + *

    {@code
    +     *   digraph G {
    +     *       NOT_WRAPPED -> V0_BLOCK [label="  wrap(version=0)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  irId(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  irVersion(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  schemaVersion(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  packageNameLength()  "];
    +     *       V0_BLOCK -> V0_PACKAGENAME_DONE [label="  packageName(?)  "];
    +     *       V0_PACKAGENAME_DONE -> V0_PACKAGENAME_DONE [label="  namespaceNameLength()  "];
    +     *       V0_PACKAGENAME_DONE -> V0_NAMESPACENAME_DONE [label="  namespaceName(?)  "];
    +     *       V0_NAMESPACENAME_DONE -> V0_NAMESPACENAME_DONE [label="  semanticVersionLength()  "];
    +     *       V0_NAMESPACENAME_DONE -> V0_SEMANTICVERSION_DONE [label="  semanticVersion(?)  "];
    +     *   }
    +     * }
    + */ + private static class CodecStates + { + private static final int NOT_WRAPPED = 0; + private static final int V0_BLOCK = 1; + private static final int V0_PACKAGENAME_DONE = 2; + private static final int V0_NAMESPACENAME_DONE = 3; + private static final int V0_SEMANTICVERSION_DONE = 4; + + private static final String[] STATE_NAME_LOOKUP = + { + "NOT_WRAPPED", + "V0_BLOCK", + "V0_PACKAGENAME_DONE", + "V0_NAMESPACENAME_DONE", + "V0_SEMANTICVERSION_DONE", + }; + + private static final String[] STATE_TRANSITIONS_LOOKUP = + { + "\"wrap(version=0)\"", + "\"irId(?)\", \"irVersion(?)\", \"schemaVersion(?)\", \"packageNameLength()\", \"packageName(?)\"", + "\"namespaceNameLength()\", \"namespaceName(?)\"", + "\"semanticVersionLength()\", \"semanticVersion(?)\"", + "", + }; + + private static String name(final int state) + { + return STATE_NAME_LOOKUP[state]; + } + + private static String transitions(final int state) + { + return STATE_TRANSITIONS_LOOKUP[state]; + } + } + + private int codecState = CodecStates.NOT_WRAPPED; + + private int codecState() + { + return codecState; + } + + private void codecState(int newState) + { + codecState = newState; + } + public static final int BLOCK_LENGTH = 12; public static final int TEMPLATE_ID = 1; public static final int SCHEMA_ID = 1; @@ -66,6 +143,19 @@ public int offset() return offset; } + private void onWrap(final int actingVersion) + { + switch(actingVersion) + { + case 0: + codecState(CodecStates.V0_BLOCK); + break; + default: + codecState(CodecStates.V0_BLOCK); + break; + } + } + public FrameCodecDecoder wrap( final DirectBuffer buffer, final int offset, @@ -82,6 +172,11 @@ public FrameCodecDecoder wrap( this.actingVersion = actingVersion; limit(offset + actingBlockLength); + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onWrap(actingVersion); + } + return this; } @@ -113,10 +208,16 @@ public FrameCodecDecoder sbeRewind() public int sbeDecodedLength() { final int currentLimit = limit(); + final int currentCodecState = codecState(); sbeSkip(); final int decodedLength = encodedLength(); limit(currentLimit); + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + codecState(currentCodecState); + } + return decodedLength; } @@ -170,6 +271,17 @@ public static String irIdMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onIrIdAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"irId\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + public static int irIdNullValue() { return -2147483648; @@ -187,6 +299,11 @@ public static int irIdMaxValue() public int irId() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onIrIdAccessed(); + } + return buffer.getInt(offset + 0, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -221,6 +338,17 @@ public static String irVersionMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onIrVersionAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"irVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + public static int irVersionNullValue() { return -2147483648; @@ -238,6 +366,11 @@ public static int irVersionMaxValue() public int irVersion() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onIrVersionAccessed(); + } + return buffer.getInt(offset + 4, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -272,6 +405,17 @@ public static String schemaVersionMetaAttribute(final MetaAttribute metaAttribut return ""; } + private void onSchemaVersionAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"schemaVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + public static int schemaVersionNullValue() { return -2147483648; @@ -289,6 +433,11 @@ public static int schemaVersionMaxValue() public int schemaVersion() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSchemaVersionAccessed(); + } + return buffer.getInt(offset + 8, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -323,14 +472,54 @@ public static int packageNameHeaderLength() return 2; } + void onPackageNameLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_BLOCK: + codecState(CodecStates.V0_BLOCK); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"packageName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + + private void onPackageNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_BLOCK: + codecState(CodecStates.V0_PACKAGENAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"packageName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + public int packageNameLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipPackageName() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -342,6 +531,11 @@ public int skipPackageName() public int getPackageName(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -354,6 +548,11 @@ public int getPackageName(final MutableDirectBuffer dst, final int dstOffset, fi public int getPackageName(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -366,6 +565,11 @@ public int getPackageName(final byte[] dst, final int dstOffset, final int lengt public void wrapPackageName(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -375,6 +579,11 @@ public void wrapPackageName(final DirectBuffer wrapBuffer) public String packageName() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -421,14 +630,54 @@ public static int namespaceNameHeaderLength() return 2; } + void onNamespaceNameLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_PACKAGENAME_DONE: + codecState(CodecStates.V0_PACKAGENAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"namespaceName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + + private void onNamespaceNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_PACKAGENAME_DONE: + codecState(CodecStates.V0_NAMESPACENAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"namespaceName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + public int namespaceNameLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipNamespaceName() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -440,6 +689,11 @@ public int skipNamespaceName() public int getNamespaceName(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -452,6 +706,11 @@ public int getNamespaceName(final MutableDirectBuffer dst, final int dstOffset, public int getNamespaceName(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -464,6 +723,11 @@ public int getNamespaceName(final byte[] dst, final int dstOffset, final int len public void wrapNamespaceName(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -473,6 +737,11 @@ public void wrapNamespaceName(final DirectBuffer wrapBuffer) public String namespaceName() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -519,14 +788,54 @@ public static int semanticVersionHeaderLength() return 2; } + void onSemanticVersionLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NAMESPACENAME_DONE: + codecState(CodecStates.V0_NAMESPACENAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"semanticVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + + private void onSemanticVersionAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NAMESPACENAME_DONE: + codecState(CodecStates.V0_SEMANTICVERSION_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"semanticVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecDecoder#CodecStates."); + } + } + public int semanticVersionLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipSemanticVersion() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -538,6 +847,11 @@ public int skipSemanticVersion() public int getSemanticVersion(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -550,6 +864,11 @@ public int getSemanticVersion(final MutableDirectBuffer dst, final int dstOffset public int getSemanticVersion(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -562,6 +881,11 @@ public int getSemanticVersion(final byte[] dst, final int dstOffset, final int l public void wrapSemanticVersion(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -571,6 +895,11 @@ public void wrapSemanticVersion(final DirectBuffer wrapBuffer) public String semanticVersion() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java index 0fd115d556..a5524033fc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java @@ -11,6 +11,83 @@ @SuppressWarnings("all") public final class FrameCodecEncoder { + private static final boolean ENABLE_BOUNDS_CHECKS = !Boolean.getBoolean("agrona.disable.bounds.checks"); + + private static final boolean SBE_ENABLE_IR_PRECEDENCE_CHECKS = Boolean.parseBoolean(System.getProperty( + "sbe.enable.ir.precedence.checks", + Boolean.toString(ENABLE_BOUNDS_CHECKS))); + + /** + * The states in which a encoder/decoder/codec can live. + * + *

    The state machine diagram below, encoded in the dot language, describes + * the valid state transitions according to the order in which fields may be + * accessed safely. Tools such as PlantUML and Graphviz can render it. + * + *

    {@code
    +     *   digraph G {
    +     *       NOT_WRAPPED -> V0_BLOCK [label="  wrap(version=0)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  irId(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  irVersion(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  schemaVersion(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  packageNameLength()  "];
    +     *       V0_BLOCK -> V0_PACKAGENAME_DONE [label="  packageName(?)  "];
    +     *       V0_PACKAGENAME_DONE -> V0_PACKAGENAME_DONE [label="  namespaceNameLength()  "];
    +     *       V0_PACKAGENAME_DONE -> V0_NAMESPACENAME_DONE [label="  namespaceName(?)  "];
    +     *       V0_NAMESPACENAME_DONE -> V0_NAMESPACENAME_DONE [label="  semanticVersionLength()  "];
    +     *       V0_NAMESPACENAME_DONE -> V0_SEMANTICVERSION_DONE [label="  semanticVersion(?)  "];
    +     *   }
    +     * }
    + */ + private static class CodecStates + { + private static final int NOT_WRAPPED = 0; + private static final int V0_BLOCK = 1; + private static final int V0_PACKAGENAME_DONE = 2; + private static final int V0_NAMESPACENAME_DONE = 3; + private static final int V0_SEMANTICVERSION_DONE = 4; + + private static final String[] STATE_NAME_LOOKUP = + { + "NOT_WRAPPED", + "V0_BLOCK", + "V0_PACKAGENAME_DONE", + "V0_NAMESPACENAME_DONE", + "V0_SEMANTICVERSION_DONE", + }; + + private static final String[] STATE_TRANSITIONS_LOOKUP = + { + "\"wrap(version=0)\"", + "\"irId(?)\", \"irVersion(?)\", \"schemaVersion(?)\", \"packageNameLength()\", \"packageName(?)\"", + "\"namespaceNameLength()\", \"namespaceName(?)\"", + "\"semanticVersionLength()\", \"semanticVersion(?)\"", + "", + }; + + private static String name(final int state) + { + return STATE_NAME_LOOKUP[state]; + } + + private static String transitions(final int state) + { + return STATE_TRANSITIONS_LOOKUP[state]; + } + } + + private int codecState = CodecStates.NOT_WRAPPED; + + private int codecState() + { + return codecState; + } + + private void codecState(int newState) + { + codecState = newState; + } + public static final int BLOCK_LENGTH = 12; public static final int TEMPLATE_ID = 1; public static final int SCHEMA_ID = 1; @@ -74,6 +151,11 @@ public FrameCodecEncoder wrap(final MutableDirectBuffer buffer, final int offset this.offset = offset; limit(offset + BLOCK_LENGTH); + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + codecState(CodecStates.V0_BLOCK); + } + return this; } @@ -135,6 +217,17 @@ public static String irIdMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onIrIdAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"irId\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecEncoder#CodecStates."); + } + } + public static int irIdNullValue() { return -2147483648; @@ -152,6 +245,11 @@ public static int irIdMaxValue() public FrameCodecEncoder irId(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onIrIdAccessed(); + } + buffer.putInt(offset + 0, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -187,6 +285,17 @@ public static String irVersionMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onIrVersionAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"irVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecEncoder#CodecStates."); + } + } + public static int irVersionNullValue() { return -2147483648; @@ -204,6 +313,11 @@ public static int irVersionMaxValue() public FrameCodecEncoder irVersion(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onIrVersionAccessed(); + } + buffer.putInt(offset + 4, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -239,6 +353,17 @@ public static String schemaVersionMetaAttribute(final MetaAttribute metaAttribut return ""; } + private void onSchemaVersionAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"schemaVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecEncoder#CodecStates."); + } + } + public static int schemaVersionNullValue() { return -2147483648; @@ -256,6 +381,11 @@ public static int schemaVersionMaxValue() public FrameCodecEncoder schemaVersion(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSchemaVersionAccessed(); + } + buffer.putInt(offset + 8, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -286,6 +416,21 @@ public static int packageNameHeaderLength() return 2; } + private void onPackageNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_BLOCK: + codecState(CodecStates.V0_PACKAGENAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"packageName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecEncoder#CodecStates."); + } + } + public FrameCodecEncoder putPackageName(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -293,6 +438,11 @@ public FrameCodecEncoder putPackageName(final DirectBuffer src, final int srcOff throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -309,6 +459,11 @@ public FrameCodecEncoder putPackageName(final byte[] src, final int srcOffset, f throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -328,6 +483,11 @@ public FrameCodecEncoder packageName(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -362,6 +522,21 @@ public static int namespaceNameHeaderLength() return 2; } + private void onNamespaceNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_PACKAGENAME_DONE: + codecState(CodecStates.V0_NAMESPACENAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"namespaceName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecEncoder#CodecStates."); + } + } + public FrameCodecEncoder putNamespaceName(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -369,6 +544,11 @@ public FrameCodecEncoder putNamespaceName(final DirectBuffer src, final int srcO throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -385,6 +565,11 @@ public FrameCodecEncoder putNamespaceName(final byte[] src, final int srcOffset, throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -404,6 +589,11 @@ public FrameCodecEncoder namespaceName(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNamespaceNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -438,6 +628,21 @@ public static int semanticVersionHeaderLength() return 2; } + private void onSemanticVersionAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NAMESPACENAME_DONE: + codecState(CodecStates.V0_SEMANTICVERSION_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"semanticVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class FrameCodecEncoder#CodecStates."); + } + } + public FrameCodecEncoder putSemanticVersion(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -445,6 +650,11 @@ public FrameCodecEncoder putSemanticVersion(final DirectBuffer src, final int sr throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -461,6 +671,11 @@ public FrameCodecEncoder putSemanticVersion(final byte[] src, final int srcOffse throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -480,6 +695,11 @@ public FrameCodecEncoder semanticVersion(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticVersionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -511,4 +731,21 @@ public StringBuilder appendTo(final StringBuilder builder) return decoder.appendTo(builder); } + + public void checkEncodingIsComplete() + { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + switch (codecState) + { + case CodecStates.V0_SEMANTICVERSION_DONE: + return; + default: + throw new IllegalStateException("Not fully encoded, current state: " + + CodecStates.name(codecState) + ", allowed transitions: " + + CodecStates.transitions(codecState)); + } + } + } + } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index 8c7a7a1ee6..6a48488936 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -11,6 +11,130 @@ @SuppressWarnings("all") public final class TokenCodecDecoder { + private static final boolean ENABLE_BOUNDS_CHECKS = !Boolean.getBoolean("agrona.disable.bounds.checks"); + + private static final boolean SBE_ENABLE_IR_PRECEDENCE_CHECKS = Boolean.parseBoolean(System.getProperty( + "sbe.enable.ir.precedence.checks", + Boolean.toString(ENABLE_BOUNDS_CHECKS))); + + /** + * The states in which a encoder/decoder/codec can live. + * + *

    The state machine diagram below, encoded in the dot language, describes + * the valid state transitions according to the order in which fields may be + * accessed safely. Tools such as PlantUML and Graphviz can render it. + * + *

    {@code
    +     *   digraph G {
    +     *       NOT_WRAPPED -> V0_BLOCK [label="  wrap(version=0)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  tokenOffset(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  tokenSize(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  fieldId(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  tokenVersion(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  componentTokenCount(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  signal(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  primitiveType(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  byteOrder(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  presence(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  deprecated(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  nameLength()  "];
    +     *       V0_BLOCK -> V0_NAME_DONE [label="  name(?)  "];
    +     *       V0_NAME_DONE -> V0_NAME_DONE [label="  constValueLength()  "];
    +     *       V0_NAME_DONE -> V0_CONSTVALUE_DONE [label="  constValue(?)  "];
    +     *       V0_CONSTVALUE_DONE -> V0_CONSTVALUE_DONE [label="  minValueLength()  "];
    +     *       V0_CONSTVALUE_DONE -> V0_MINVALUE_DONE [label="  minValue(?)  "];
    +     *       V0_MINVALUE_DONE -> V0_MINVALUE_DONE [label="  maxValueLength()  "];
    +     *       V0_MINVALUE_DONE -> V0_MAXVALUE_DONE [label="  maxValue(?)  "];
    +     *       V0_MAXVALUE_DONE -> V0_MAXVALUE_DONE [label="  nullValueLength()  "];
    +     *       V0_MAXVALUE_DONE -> V0_NULLVALUE_DONE [label="  nullValue(?)  "];
    +     *       V0_NULLVALUE_DONE -> V0_NULLVALUE_DONE [label="  characterEncodingLength()  "];
    +     *       V0_NULLVALUE_DONE -> V0_CHARACTERENCODING_DONE [label="  characterEncoding(?)  "];
    +     *       V0_CHARACTERENCODING_DONE -> V0_CHARACTERENCODING_DONE [label="  epochLength()  "];
    +     *       V0_CHARACTERENCODING_DONE -> V0_EPOCH_DONE [label="  epoch(?)  "];
    +     *       V0_EPOCH_DONE -> V0_EPOCH_DONE [label="  timeUnitLength()  "];
    +     *       V0_EPOCH_DONE -> V0_TIMEUNIT_DONE [label="  timeUnit(?)  "];
    +     *       V0_TIMEUNIT_DONE -> V0_TIMEUNIT_DONE [label="  semanticTypeLength()  "];
    +     *       V0_TIMEUNIT_DONE -> V0_SEMANTICTYPE_DONE [label="  semanticType(?)  "];
    +     *       V0_SEMANTICTYPE_DONE -> V0_SEMANTICTYPE_DONE [label="  descriptionLength()  "];
    +     *       V0_SEMANTICTYPE_DONE -> V0_DESCRIPTION_DONE [label="  description(?)  "];
    +     *       V0_DESCRIPTION_DONE -> V0_DESCRIPTION_DONE [label="  referencedNameLength()  "];
    +     *       V0_DESCRIPTION_DONE -> V0_REFERENCEDNAME_DONE [label="  referencedName(?)  "];
    +     *   }
    +     * }
    + */ + private static class CodecStates + { + private static final int NOT_WRAPPED = 0; + private static final int V0_BLOCK = 1; + private static final int V0_NAME_DONE = 2; + private static final int V0_CONSTVALUE_DONE = 3; + private static final int V0_MINVALUE_DONE = 4; + private static final int V0_MAXVALUE_DONE = 5; + private static final int V0_NULLVALUE_DONE = 6; + private static final int V0_CHARACTERENCODING_DONE = 7; + private static final int V0_EPOCH_DONE = 8; + private static final int V0_TIMEUNIT_DONE = 9; + private static final int V0_SEMANTICTYPE_DONE = 10; + private static final int V0_DESCRIPTION_DONE = 11; + private static final int V0_REFERENCEDNAME_DONE = 12; + + private static final String[] STATE_NAME_LOOKUP = + { + "NOT_WRAPPED", + "V0_BLOCK", + "V0_NAME_DONE", + "V0_CONSTVALUE_DONE", + "V0_MINVALUE_DONE", + "V0_MAXVALUE_DONE", + "V0_NULLVALUE_DONE", + "V0_CHARACTERENCODING_DONE", + "V0_EPOCH_DONE", + "V0_TIMEUNIT_DONE", + "V0_SEMANTICTYPE_DONE", + "V0_DESCRIPTION_DONE", + "V0_REFERENCEDNAME_DONE", + }; + + private static final String[] STATE_TRANSITIONS_LOOKUP = + { + "\"wrap(version=0)\"", + "\"tokenOffset(?)\", \"tokenSize(?)\", \"fieldId(?)\", \"tokenVersion(?)\", \"componentTokenCount(?)\", \"signal(?)\", \"primitiveType(?)\", \"byteOrder(?)\", \"presence(?)\", \"deprecated(?)\", \"nameLength()\", \"name(?)\"", + "\"constValueLength()\", \"constValue(?)\"", + "\"minValueLength()\", \"minValue(?)\"", + "\"maxValueLength()\", \"maxValue(?)\"", + "\"nullValueLength()\", \"nullValue(?)\"", + "\"characterEncodingLength()\", \"characterEncoding(?)\"", + "\"epochLength()\", \"epoch(?)\"", + "\"timeUnitLength()\", \"timeUnit(?)\"", + "\"semanticTypeLength()\", \"semanticType(?)\"", + "\"descriptionLength()\", \"description(?)\"", + "\"referencedNameLength()\", \"referencedName(?)\"", + "", + }; + + private static String name(final int state) + { + return STATE_NAME_LOOKUP[state]; + } + + private static String transitions(final int state) + { + return STATE_TRANSITIONS_LOOKUP[state]; + } + } + + private int codecState = CodecStates.NOT_WRAPPED; + + private int codecState() + { + return codecState; + } + + private void codecState(int newState) + { + codecState = newState; + } + public static final int BLOCK_LENGTH = 28; public static final int TEMPLATE_ID = 2; public static final int SCHEMA_ID = 1; @@ -66,6 +190,19 @@ public int offset() return offset; } + private void onWrap(final int actingVersion) + { + switch(actingVersion) + { + case 0: + codecState(CodecStates.V0_BLOCK); + break; + default: + codecState(CodecStates.V0_BLOCK); + break; + } + } + public TokenCodecDecoder wrap( final DirectBuffer buffer, final int offset, @@ -82,6 +219,11 @@ public TokenCodecDecoder wrap( this.actingVersion = actingVersion; limit(offset + actingBlockLength); + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onWrap(actingVersion); + } + return this; } @@ -113,10 +255,16 @@ public TokenCodecDecoder sbeRewind() public int sbeDecodedLength() { final int currentLimit = limit(); + final int currentCodecState = codecState(); sbeSkip(); final int decodedLength = encodedLength(); limit(currentLimit); + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + codecState(currentCodecState); + } + return decodedLength; } @@ -170,6 +318,17 @@ public static String tokenOffsetMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onTokenOffsetAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"tokenOffset\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public static int tokenOffsetNullValue() { return -2147483648; @@ -187,6 +346,11 @@ public static int tokenOffsetMaxValue() public int tokenOffset() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTokenOffsetAccessed(); + } + return buffer.getInt(offset + 0, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -221,6 +385,17 @@ public static String tokenSizeMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onTokenSizeAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"tokenSize\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public static int tokenSizeNullValue() { return -2147483648; @@ -238,6 +413,11 @@ public static int tokenSizeMaxValue() public int tokenSize() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTokenSizeAccessed(); + } + return buffer.getInt(offset + 4, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -272,6 +452,17 @@ public static String fieldIdMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onFieldIdAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"fieldId\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public static int fieldIdNullValue() { return -2147483648; @@ -289,6 +480,11 @@ public static int fieldIdMaxValue() public int fieldId() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onFieldIdAccessed(); + } + return buffer.getInt(offset + 8, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -323,6 +519,17 @@ public static String tokenVersionMetaAttribute(final MetaAttribute metaAttribute return ""; } + private void onTokenVersionAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"tokenVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public static int tokenVersionNullValue() { return -2147483648; @@ -340,6 +547,11 @@ public static int tokenVersionMaxValue() public int tokenVersion() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTokenVersionAccessed(); + } + return buffer.getInt(offset + 12, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -374,6 +586,17 @@ public static String componentTokenCountMetaAttribute(final MetaAttribute metaAt return ""; } + private void onComponentTokenCountAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"componentTokenCount\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public static int componentTokenCountNullValue() { return -2147483648; @@ -391,6 +614,11 @@ public static int componentTokenCountMaxValue() public int componentTokenCount() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onComponentTokenCountAccessed(); + } + return buffer.getInt(offset + 16, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -425,13 +653,34 @@ public static String signalMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onSignalAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"signal\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public short signalRaw() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSignalAccessed(); + } + return ((short)(buffer.getByte(offset + 20) & 0xFF)); } public SignalCodec signal() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSignalAccessed(); + } + return SignalCodec.get(((short)(buffer.getByte(offset + 20) & 0xFF))); } @@ -466,13 +715,34 @@ public static String primitiveTypeMetaAttribute(final MetaAttribute metaAttribut return ""; } + private void onPrimitiveTypeAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"primitiveType\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public short primitiveTypeRaw() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPrimitiveTypeAccessed(); + } + return ((short)(buffer.getByte(offset + 21) & 0xFF)); } public PrimitiveTypeCodec primitiveType() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPrimitiveTypeAccessed(); + } + return PrimitiveTypeCodec.get(((short)(buffer.getByte(offset + 21) & 0xFF))); } @@ -507,13 +777,34 @@ public static String byteOrderMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onByteOrderAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"byteOrder\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public short byteOrderRaw() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onByteOrderAccessed(); + } + return ((short)(buffer.getByte(offset + 22) & 0xFF)); } public ByteOrderCodec byteOrder() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onByteOrderAccessed(); + } + return ByteOrderCodec.get(((short)(buffer.getByte(offset + 22) & 0xFF))); } @@ -548,13 +839,34 @@ public static String presenceMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onPresenceAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"presence\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public short presenceRaw() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPresenceAccessed(); + } + return ((short)(buffer.getByte(offset + 23) & 0xFF)); } public PresenceCodec presence() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPresenceAccessed(); + } + return PresenceCodec.get(((short)(buffer.getByte(offset + 23) & 0xFF))); } @@ -589,6 +901,17 @@ public static String deprecatedMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onDeprecatedAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"deprecated\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public static int deprecatedNullValue() { return 0; @@ -606,6 +929,11 @@ public static int deprecatedMaxValue() public int deprecated() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDeprecatedAccessed(); + } + return buffer.getInt(offset + 24, java.nio.ByteOrder.LITTLE_ENDIAN); } @@ -640,14 +968,54 @@ public static int nameHeaderLength() return 2; } + void onNameLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_BLOCK: + codecState(CodecStates.V0_BLOCK); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"name\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_BLOCK: + codecState(CodecStates.V0_NAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"name\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int nameLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipName() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -659,6 +1027,11 @@ public int skipName() public int getName(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -671,6 +1044,11 @@ public int getName(final MutableDirectBuffer dst, final int dstOffset, final int public int getName(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -683,6 +1061,11 @@ public int getName(final byte[] dst, final int dstOffset, final int length) public void wrapName(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -692,6 +1075,11 @@ public void wrapName(final DirectBuffer wrapBuffer) public String name() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -738,14 +1126,54 @@ public static int constValueHeaderLength() return 2; } + void onConstValueLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NAME_DONE: + codecState(CodecStates.V0_NAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"constValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onConstValueAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NAME_DONE: + codecState(CodecStates.V0_CONSTVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"constValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int constValueLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipConstValue() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -757,6 +1185,11 @@ public int skipConstValue() public int getConstValue(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -769,6 +1202,11 @@ public int getConstValue(final MutableDirectBuffer dst, final int dstOffset, fin public int getConstValue(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -781,6 +1219,11 @@ public int getConstValue(final byte[] dst, final int dstOffset, final int length public void wrapConstValue(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -790,6 +1233,11 @@ public void wrapConstValue(final DirectBuffer wrapBuffer) public String constValue() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -836,14 +1284,54 @@ public static int minValueHeaderLength() return 2; } + void onMinValueLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_CONSTVALUE_DONE: + codecState(CodecStates.V0_CONSTVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"minValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onMinValueAccessed() + { + switch (codecState()) + { + case CodecStates.V0_CONSTVALUE_DONE: + codecState(CodecStates.V0_MINVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"minValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int minValueLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipMinValue() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -855,6 +1343,11 @@ public int skipMinValue() public int getMinValue(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -867,6 +1360,11 @@ public int getMinValue(final MutableDirectBuffer dst, final int dstOffset, final public int getMinValue(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -879,6 +1377,11 @@ public int getMinValue(final byte[] dst, final int dstOffset, final int length) public void wrapMinValue(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -888,6 +1391,11 @@ public void wrapMinValue(final DirectBuffer wrapBuffer) public String minValue() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -934,14 +1442,54 @@ public static int maxValueHeaderLength() return 2; } + void onMaxValueLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_MINVALUE_DONE: + codecState(CodecStates.V0_MINVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"maxValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onMaxValueAccessed() + { + switch (codecState()) + { + case CodecStates.V0_MINVALUE_DONE: + codecState(CodecStates.V0_MAXVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"maxValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int maxValueLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipMaxValue() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -953,6 +1501,11 @@ public int skipMaxValue() public int getMaxValue(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -965,6 +1518,11 @@ public int getMaxValue(final MutableDirectBuffer dst, final int dstOffset, final public int getMaxValue(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -977,6 +1535,11 @@ public int getMaxValue(final byte[] dst, final int dstOffset, final int length) public void wrapMaxValue(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -986,6 +1549,11 @@ public void wrapMaxValue(final DirectBuffer wrapBuffer) public String maxValue() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1032,14 +1600,54 @@ public static int nullValueHeaderLength() return 2; } + void onNullValueLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_MAXVALUE_DONE: + codecState(CodecStates.V0_MAXVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"nullValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onNullValueAccessed() + { + switch (codecState()) + { + case CodecStates.V0_MAXVALUE_DONE: + codecState(CodecStates.V0_NULLVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"nullValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int nullValueLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipNullValue() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1051,6 +1659,11 @@ public int skipNullValue() public int getNullValue(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1063,6 +1676,11 @@ public int getNullValue(final MutableDirectBuffer dst, final int dstOffset, fina public int getNullValue(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1075,6 +1693,11 @@ public int getNullValue(final byte[] dst, final int dstOffset, final int length) public void wrapNullValue(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1084,6 +1707,11 @@ public void wrapNullValue(final DirectBuffer wrapBuffer) public String nullValue() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1130,14 +1758,54 @@ public static int characterEncodingHeaderLength() return 2; } + void onCharacterEncodingLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NULLVALUE_DONE: + codecState(CodecStates.V0_NULLVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"characterEncoding\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onCharacterEncodingAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NULLVALUE_DONE: + codecState(CodecStates.V0_CHARACTERENCODING_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"characterEncoding\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int characterEncodingLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipCharacterEncoding() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1149,6 +1817,11 @@ public int skipCharacterEncoding() public int getCharacterEncoding(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1161,6 +1834,11 @@ public int getCharacterEncoding(final MutableDirectBuffer dst, final int dstOffs public int getCharacterEncoding(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1173,6 +1851,11 @@ public int getCharacterEncoding(final byte[] dst, final int dstOffset, final int public void wrapCharacterEncoding(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1182,6 +1865,11 @@ public void wrapCharacterEncoding(final DirectBuffer wrapBuffer) public String characterEncoding() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1228,14 +1916,54 @@ public static int epochHeaderLength() return 2; } + void onEpochLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_CHARACTERENCODING_DONE: + codecState(CodecStates.V0_CHARACTERENCODING_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"epoch\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onEpochAccessed() + { + switch (codecState()) + { + case CodecStates.V0_CHARACTERENCODING_DONE: + codecState(CodecStates.V0_EPOCH_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"epoch\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int epochLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipEpoch() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1247,6 +1975,11 @@ public int skipEpoch() public int getEpoch(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1259,6 +1992,11 @@ public int getEpoch(final MutableDirectBuffer dst, final int dstOffset, final in public int getEpoch(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1271,6 +2009,11 @@ public int getEpoch(final byte[] dst, final int dstOffset, final int length) public void wrapEpoch(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1280,6 +2023,11 @@ public void wrapEpoch(final DirectBuffer wrapBuffer) public String epoch() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1326,14 +2074,54 @@ public static int timeUnitHeaderLength() return 2; } + void onTimeUnitLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_EPOCH_DONE: + codecState(CodecStates.V0_EPOCH_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"timeUnit\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onTimeUnitAccessed() + { + switch (codecState()) + { + case CodecStates.V0_EPOCH_DONE: + codecState(CodecStates.V0_TIMEUNIT_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"timeUnit\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int timeUnitLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipTimeUnit() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1345,6 +2133,11 @@ public int skipTimeUnit() public int getTimeUnit(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1357,6 +2150,11 @@ public int getTimeUnit(final MutableDirectBuffer dst, final int dstOffset, final public int getTimeUnit(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1369,6 +2167,11 @@ public int getTimeUnit(final byte[] dst, final int dstOffset, final int length) public void wrapTimeUnit(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1378,6 +2181,11 @@ public void wrapTimeUnit(final DirectBuffer wrapBuffer) public String timeUnit() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1424,14 +2232,54 @@ public static int semanticTypeHeaderLength() return 2; } + void onSemanticTypeLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_TIMEUNIT_DONE: + codecState(CodecStates.V0_TIMEUNIT_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"semanticType\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onSemanticTypeAccessed() + { + switch (codecState()) + { + case CodecStates.V0_TIMEUNIT_DONE: + codecState(CodecStates.V0_SEMANTICTYPE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"semanticType\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int semanticTypeLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipSemanticType() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1443,6 +2291,11 @@ public int skipSemanticType() public int getSemanticType(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1455,6 +2308,11 @@ public int getSemanticType(final MutableDirectBuffer dst, final int dstOffset, f public int getSemanticType(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1467,6 +2325,11 @@ public int getSemanticType(final byte[] dst, final int dstOffset, final int leng public void wrapSemanticType(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1476,6 +2339,11 @@ public void wrapSemanticType(final DirectBuffer wrapBuffer) public String semanticType() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1522,14 +2390,54 @@ public static int descriptionHeaderLength() return 2; } + void onDescriptionLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_SEMANTICTYPE_DONE: + codecState(CodecStates.V0_SEMANTICTYPE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"description\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onDescriptionAccessed() + { + switch (codecState()) + { + case CodecStates.V0_SEMANTICTYPE_DONE: + codecState(CodecStates.V0_DESCRIPTION_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"description\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int descriptionLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipDescription() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1541,6 +2449,11 @@ public int skipDescription() public int getDescription(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1553,6 +2466,11 @@ public int getDescription(final MutableDirectBuffer dst, final int dstOffset, fi public int getDescription(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1565,6 +2483,11 @@ public int getDescription(final byte[] dst, final int dstOffset, final int lengt public void wrapDescription(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1574,6 +2497,11 @@ public void wrapDescription(final DirectBuffer wrapBuffer) public String description() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1620,14 +2548,54 @@ public static int referencedNameHeaderLength() return 2; } + void onReferencedNameLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_DESCRIPTION_DONE: + codecState(CodecStates.V0_DESCRIPTION_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"referencedName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onReferencedNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_DESCRIPTION_DONE: + codecState(CodecStates.V0_REFERENCEDNAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"referencedName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + public int referencedNameLength() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameLengthAccessed(); + } + final int limit = parentMessage.limit(); return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); } public int skipReferencedName() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1639,6 +2607,11 @@ public int skipReferencedName() public int getReferencedName(final MutableDirectBuffer dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1651,6 +2624,11 @@ public int getReferencedName(final MutableDirectBuffer dst, final int dstOffset, public int getReferencedName(final byte[] dst, final int dstOffset, final int length) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1663,6 +2641,11 @@ public int getReferencedName(final byte[] dst, final int dstOffset, final int le public void wrapReferencedName(final DirectBuffer wrapBuffer) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); @@ -1672,6 +2655,11 @@ public void wrapReferencedName(final DirectBuffer wrapBuffer) public String referencedName() { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java index 793f10756f..a0ece1099d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java @@ -11,6 +11,130 @@ @SuppressWarnings("all") public final class TokenCodecEncoder { + private static final boolean ENABLE_BOUNDS_CHECKS = !Boolean.getBoolean("agrona.disable.bounds.checks"); + + private static final boolean SBE_ENABLE_IR_PRECEDENCE_CHECKS = Boolean.parseBoolean(System.getProperty( + "sbe.enable.ir.precedence.checks", + Boolean.toString(ENABLE_BOUNDS_CHECKS))); + + /** + * The states in which a encoder/decoder/codec can live. + * + *

    The state machine diagram below, encoded in the dot language, describes + * the valid state transitions according to the order in which fields may be + * accessed safely. Tools such as PlantUML and Graphviz can render it. + * + *

    {@code
    +     *   digraph G {
    +     *       NOT_WRAPPED -> V0_BLOCK [label="  wrap(version=0)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  tokenOffset(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  tokenSize(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  fieldId(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  tokenVersion(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  componentTokenCount(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  signal(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  primitiveType(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  byteOrder(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  presence(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  deprecated(?)  "];
    +     *       V0_BLOCK -> V0_BLOCK [label="  nameLength()  "];
    +     *       V0_BLOCK -> V0_NAME_DONE [label="  name(?)  "];
    +     *       V0_NAME_DONE -> V0_NAME_DONE [label="  constValueLength()  "];
    +     *       V0_NAME_DONE -> V0_CONSTVALUE_DONE [label="  constValue(?)  "];
    +     *       V0_CONSTVALUE_DONE -> V0_CONSTVALUE_DONE [label="  minValueLength()  "];
    +     *       V0_CONSTVALUE_DONE -> V0_MINVALUE_DONE [label="  minValue(?)  "];
    +     *       V0_MINVALUE_DONE -> V0_MINVALUE_DONE [label="  maxValueLength()  "];
    +     *       V0_MINVALUE_DONE -> V0_MAXVALUE_DONE [label="  maxValue(?)  "];
    +     *       V0_MAXVALUE_DONE -> V0_MAXVALUE_DONE [label="  nullValueLength()  "];
    +     *       V0_MAXVALUE_DONE -> V0_NULLVALUE_DONE [label="  nullValue(?)  "];
    +     *       V0_NULLVALUE_DONE -> V0_NULLVALUE_DONE [label="  characterEncodingLength()  "];
    +     *       V0_NULLVALUE_DONE -> V0_CHARACTERENCODING_DONE [label="  characterEncoding(?)  "];
    +     *       V0_CHARACTERENCODING_DONE -> V0_CHARACTERENCODING_DONE [label="  epochLength()  "];
    +     *       V0_CHARACTERENCODING_DONE -> V0_EPOCH_DONE [label="  epoch(?)  "];
    +     *       V0_EPOCH_DONE -> V0_EPOCH_DONE [label="  timeUnitLength()  "];
    +     *       V0_EPOCH_DONE -> V0_TIMEUNIT_DONE [label="  timeUnit(?)  "];
    +     *       V0_TIMEUNIT_DONE -> V0_TIMEUNIT_DONE [label="  semanticTypeLength()  "];
    +     *       V0_TIMEUNIT_DONE -> V0_SEMANTICTYPE_DONE [label="  semanticType(?)  "];
    +     *       V0_SEMANTICTYPE_DONE -> V0_SEMANTICTYPE_DONE [label="  descriptionLength()  "];
    +     *       V0_SEMANTICTYPE_DONE -> V0_DESCRIPTION_DONE [label="  description(?)  "];
    +     *       V0_DESCRIPTION_DONE -> V0_DESCRIPTION_DONE [label="  referencedNameLength()  "];
    +     *       V0_DESCRIPTION_DONE -> V0_REFERENCEDNAME_DONE [label="  referencedName(?)  "];
    +     *   }
    +     * }
    + */ + private static class CodecStates + { + private static final int NOT_WRAPPED = 0; + private static final int V0_BLOCK = 1; + private static final int V0_NAME_DONE = 2; + private static final int V0_CONSTVALUE_DONE = 3; + private static final int V0_MINVALUE_DONE = 4; + private static final int V0_MAXVALUE_DONE = 5; + private static final int V0_NULLVALUE_DONE = 6; + private static final int V0_CHARACTERENCODING_DONE = 7; + private static final int V0_EPOCH_DONE = 8; + private static final int V0_TIMEUNIT_DONE = 9; + private static final int V0_SEMANTICTYPE_DONE = 10; + private static final int V0_DESCRIPTION_DONE = 11; + private static final int V0_REFERENCEDNAME_DONE = 12; + + private static final String[] STATE_NAME_LOOKUP = + { + "NOT_WRAPPED", + "V0_BLOCK", + "V0_NAME_DONE", + "V0_CONSTVALUE_DONE", + "V0_MINVALUE_DONE", + "V0_MAXVALUE_DONE", + "V0_NULLVALUE_DONE", + "V0_CHARACTERENCODING_DONE", + "V0_EPOCH_DONE", + "V0_TIMEUNIT_DONE", + "V0_SEMANTICTYPE_DONE", + "V0_DESCRIPTION_DONE", + "V0_REFERENCEDNAME_DONE", + }; + + private static final String[] STATE_TRANSITIONS_LOOKUP = + { + "\"wrap(version=0)\"", + "\"tokenOffset(?)\", \"tokenSize(?)\", \"fieldId(?)\", \"tokenVersion(?)\", \"componentTokenCount(?)\", \"signal(?)\", \"primitiveType(?)\", \"byteOrder(?)\", \"presence(?)\", \"deprecated(?)\", \"nameLength()\", \"name(?)\"", + "\"constValueLength()\", \"constValue(?)\"", + "\"minValueLength()\", \"minValue(?)\"", + "\"maxValueLength()\", \"maxValue(?)\"", + "\"nullValueLength()\", \"nullValue(?)\"", + "\"characterEncodingLength()\", \"characterEncoding(?)\"", + "\"epochLength()\", \"epoch(?)\"", + "\"timeUnitLength()\", \"timeUnit(?)\"", + "\"semanticTypeLength()\", \"semanticType(?)\"", + "\"descriptionLength()\", \"description(?)\"", + "\"referencedNameLength()\", \"referencedName(?)\"", + "", + }; + + private static String name(final int state) + { + return STATE_NAME_LOOKUP[state]; + } + + private static String transitions(final int state) + { + return STATE_TRANSITIONS_LOOKUP[state]; + } + } + + private int codecState = CodecStates.NOT_WRAPPED; + + private int codecState() + { + return codecState; + } + + private void codecState(int newState) + { + codecState = newState; + } + public static final int BLOCK_LENGTH = 28; public static final int TEMPLATE_ID = 2; public static final int SCHEMA_ID = 1; @@ -74,6 +198,11 @@ public TokenCodecEncoder wrap(final MutableDirectBuffer buffer, final int offset this.offset = offset; limit(offset + BLOCK_LENGTH); + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + codecState(CodecStates.V0_BLOCK); + } + return this; } @@ -135,6 +264,17 @@ public static String tokenOffsetMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onTokenOffsetAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"tokenOffset\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public static int tokenOffsetNullValue() { return -2147483648; @@ -152,6 +292,11 @@ public static int tokenOffsetMaxValue() public TokenCodecEncoder tokenOffset(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTokenOffsetAccessed(); + } + buffer.putInt(offset + 0, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -187,6 +332,17 @@ public static String tokenSizeMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onTokenSizeAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"tokenSize\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public static int tokenSizeNullValue() { return -2147483648; @@ -204,6 +360,11 @@ public static int tokenSizeMaxValue() public TokenCodecEncoder tokenSize(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTokenSizeAccessed(); + } + buffer.putInt(offset + 4, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -239,6 +400,17 @@ public static String fieldIdMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onFieldIdAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"fieldId\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public static int fieldIdNullValue() { return -2147483648; @@ -256,6 +428,11 @@ public static int fieldIdMaxValue() public TokenCodecEncoder fieldId(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onFieldIdAccessed(); + } + buffer.putInt(offset + 8, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -291,6 +468,17 @@ public static String tokenVersionMetaAttribute(final MetaAttribute metaAttribute return ""; } + private void onTokenVersionAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"tokenVersion\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public static int tokenVersionNullValue() { return -2147483648; @@ -308,6 +496,11 @@ public static int tokenVersionMaxValue() public TokenCodecEncoder tokenVersion(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTokenVersionAccessed(); + } + buffer.putInt(offset + 12, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -343,6 +536,17 @@ public static String componentTokenCountMetaAttribute(final MetaAttribute metaAt return ""; } + private void onComponentTokenCountAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"componentTokenCount\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public static int componentTokenCountNullValue() { return -2147483648; @@ -360,6 +564,11 @@ public static int componentTokenCountMaxValue() public TokenCodecEncoder componentTokenCount(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onComponentTokenCountAccessed(); + } + buffer.putInt(offset + 16, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -395,8 +604,24 @@ public static String signalMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onSignalAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"signal\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder signal(final SignalCodec value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSignalAccessed(); + } + buffer.putByte(offset + 20, (byte)value.value()); return this; } @@ -431,8 +656,24 @@ public static String primitiveTypeMetaAttribute(final MetaAttribute metaAttribut return ""; } + private void onPrimitiveTypeAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"primitiveType\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder primitiveType(final PrimitiveTypeCodec value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPrimitiveTypeAccessed(); + } + buffer.putByte(offset + 21, (byte)value.value()); return this; } @@ -467,8 +708,24 @@ public static String byteOrderMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onByteOrderAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"byteOrder\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder byteOrder(final ByteOrderCodec value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onByteOrderAccessed(); + } + buffer.putByte(offset + 22, (byte)value.value()); return this; } @@ -503,8 +760,24 @@ public static String presenceMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onPresenceAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"presence\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder presence(final PresenceCodec value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPresenceAccessed(); + } + buffer.putByte(offset + 23, (byte)value.value()); return this; } @@ -539,6 +812,17 @@ public static String deprecatedMetaAttribute(final MetaAttribute metaAttribute) return ""; } + private void onDeprecatedAccessed() + { + if (codecState() == CodecStates.NOT_WRAPPED) + { + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"deprecated\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public static int deprecatedNullValue() { return 0; @@ -556,6 +840,11 @@ public static int deprecatedMaxValue() public TokenCodecEncoder deprecated(final int value) { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDeprecatedAccessed(); + } + buffer.putInt(offset + 24, value, java.nio.ByteOrder.LITTLE_ENDIAN); return this; } @@ -586,6 +875,21 @@ public static int nameHeaderLength() return 2; } + private void onNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_BLOCK: + codecState(CodecStates.V0_NAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"name\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putName(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -593,6 +897,11 @@ public TokenCodecEncoder putName(final DirectBuffer src, final int srcOffset, fi throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -609,6 +918,11 @@ public TokenCodecEncoder putName(final byte[] src, final int srcOffset, final in throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -628,6 +942,11 @@ public TokenCodecEncoder name(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -662,6 +981,21 @@ public static int constValueHeaderLength() return 2; } + private void onConstValueAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NAME_DONE: + codecState(CodecStates.V0_CONSTVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"constValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putConstValue(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -669,6 +1003,11 @@ public TokenCodecEncoder putConstValue(final DirectBuffer src, final int srcOffs throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -685,6 +1024,11 @@ public TokenCodecEncoder putConstValue(final byte[] src, final int srcOffset, fi throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -704,6 +1048,11 @@ public TokenCodecEncoder constValue(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onConstValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -738,6 +1087,21 @@ public static int minValueHeaderLength() return 2; } + private void onMinValueAccessed() + { + switch (codecState()) + { + case CodecStates.V0_CONSTVALUE_DONE: + codecState(CodecStates.V0_MINVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"minValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putMinValue(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -745,6 +1109,11 @@ public TokenCodecEncoder putMinValue(final DirectBuffer src, final int srcOffset throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -761,6 +1130,11 @@ public TokenCodecEncoder putMinValue(final byte[] src, final int srcOffset, fina throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -780,6 +1154,11 @@ public TokenCodecEncoder minValue(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMinValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -814,6 +1193,21 @@ public static int maxValueHeaderLength() return 2; } + private void onMaxValueAccessed() + { + switch (codecState()) + { + case CodecStates.V0_MINVALUE_DONE: + codecState(CodecStates.V0_MAXVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"maxValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putMaxValue(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -821,6 +1215,11 @@ public TokenCodecEncoder putMaxValue(final DirectBuffer src, final int srcOffset throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -837,6 +1236,11 @@ public TokenCodecEncoder putMaxValue(final byte[] src, final int srcOffset, fina throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -856,6 +1260,11 @@ public TokenCodecEncoder maxValue(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onMaxValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -890,6 +1299,21 @@ public static int nullValueHeaderLength() return 2; } + private void onNullValueAccessed() + { + switch (codecState()) + { + case CodecStates.V0_MAXVALUE_DONE: + codecState(CodecStates.V0_NULLVALUE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"nullValue\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putNullValue(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -897,6 +1321,11 @@ public TokenCodecEncoder putNullValue(final DirectBuffer src, final int srcOffse throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -913,6 +1342,11 @@ public TokenCodecEncoder putNullValue(final byte[] src, final int srcOffset, fin throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -932,6 +1366,11 @@ public TokenCodecEncoder nullValue(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onNullValueAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -966,6 +1405,21 @@ public static int characterEncodingHeaderLength() return 2; } + private void onCharacterEncodingAccessed() + { + switch (codecState()) + { + case CodecStates.V0_NULLVALUE_DONE: + codecState(CodecStates.V0_CHARACTERENCODING_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"characterEncoding\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putCharacterEncoding(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -973,6 +1427,11 @@ public TokenCodecEncoder putCharacterEncoding(final DirectBuffer src, final int throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -989,6 +1448,11 @@ public TokenCodecEncoder putCharacterEncoding(final byte[] src, final int srcOff throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1008,6 +1472,11 @@ public TokenCodecEncoder characterEncoding(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onCharacterEncodingAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1042,6 +1511,21 @@ public static int epochHeaderLength() return 2; } + private void onEpochAccessed() + { + switch (codecState()) + { + case CodecStates.V0_CHARACTERENCODING_DONE: + codecState(CodecStates.V0_EPOCH_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"epoch\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putEpoch(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -1049,6 +1533,11 @@ public TokenCodecEncoder putEpoch(final DirectBuffer src, final int srcOffset, f throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1065,6 +1554,11 @@ public TokenCodecEncoder putEpoch(final byte[] src, final int srcOffset, final i throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1084,6 +1578,11 @@ public TokenCodecEncoder epoch(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onEpochAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1118,6 +1617,21 @@ public static int timeUnitHeaderLength() return 2; } + private void onTimeUnitAccessed() + { + switch (codecState()) + { + case CodecStates.V0_EPOCH_DONE: + codecState(CodecStates.V0_TIMEUNIT_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"timeUnit\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putTimeUnit(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -1125,6 +1639,11 @@ public TokenCodecEncoder putTimeUnit(final DirectBuffer src, final int srcOffset throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1141,6 +1660,11 @@ public TokenCodecEncoder putTimeUnit(final byte[] src, final int srcOffset, fina throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1160,6 +1684,11 @@ public TokenCodecEncoder timeUnit(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onTimeUnitAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1194,6 +1723,21 @@ public static int semanticTypeHeaderLength() return 2; } + private void onSemanticTypeAccessed() + { + switch (codecState()) + { + case CodecStates.V0_TIMEUNIT_DONE: + codecState(CodecStates.V0_SEMANTICTYPE_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"semanticType\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putSemanticType(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -1201,6 +1745,11 @@ public TokenCodecEncoder putSemanticType(final DirectBuffer src, final int srcOf throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1217,6 +1766,11 @@ public TokenCodecEncoder putSemanticType(final byte[] src, final int srcOffset, throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1236,6 +1790,11 @@ public TokenCodecEncoder semanticType(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onSemanticTypeAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1270,6 +1829,21 @@ public static int descriptionHeaderLength() return 2; } + private void onDescriptionAccessed() + { + switch (codecState()) + { + case CodecStates.V0_SEMANTICTYPE_DONE: + codecState(CodecStates.V0_DESCRIPTION_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"description\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putDescription(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -1277,6 +1851,11 @@ public TokenCodecEncoder putDescription(final DirectBuffer src, final int srcOff throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1293,6 +1872,11 @@ public TokenCodecEncoder putDescription(final byte[] src, final int srcOffset, f throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1312,6 +1896,11 @@ public TokenCodecEncoder description(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onDescriptionAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1346,6 +1935,21 @@ public static int referencedNameHeaderLength() return 2; } + private void onReferencedNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_DESCRIPTION_DONE: + codecState(CodecStates.V0_REFERENCEDNAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"referencedName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + public TokenCodecEncoder putReferencedName(final DirectBuffer src, final int srcOffset, final int length) { if (length > 65534) @@ -1353,6 +1957,11 @@ public TokenCodecEncoder putReferencedName(final DirectBuffer src, final int src throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1369,6 +1978,11 @@ public TokenCodecEncoder putReferencedName(final byte[] src, final int srcOffset throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1388,6 +2002,11 @@ public TokenCodecEncoder referencedName(final String value) throw new IllegalStateException("length > maxValue for type: " + length); } + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onReferencedNameAccessed(); + } + final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); @@ -1419,4 +2038,21 @@ public StringBuilder appendTo(final StringBuilder builder) return decoder.appendTo(builder); } + + public void checkEncodingIsComplete() + { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + switch (codecState) + { + case CodecStates.V0_REFERENCEDNAME_DONE: + return; + default: + throw new IllegalStateException("Not fully encoded, current state: " + + CodecStates.name(codecState) + ", allowed transitions: " + + CodecStates.transitions(codecState)); + } + } + } + } diff --git a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp index e3b81677dc..2adf48f06c 100644 --- a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include #include @@ -217,43 +216,43 @@ class BoundsCheckTest : public testing::Test performanceFigures.next(); EXPECT_EQ(performanceFigures.octaneRating(), 95); - Car::PerformanceFigures::Acceleration &acceleration = performanceFigures.acceleration(); - EXPECT_EQ(acceleration.count(), 3u); - EXPECT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), 30); - EXPECT_EQ(acceleration.seconds(), 4.0f); + Car::PerformanceFigures::Acceleration &acceleration1 = performanceFigures.acceleration(); + EXPECT_EQ(acceleration1.count(), 3u); + EXPECT_TRUE(acceleration1.hasNext()); + acceleration1.next(); + EXPECT_EQ(acceleration1.mph(), 30); + EXPECT_EQ(acceleration1.seconds(), 4.0f); - EXPECT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), 60); - EXPECT_EQ(acceleration.seconds(), 7.5f); + EXPECT_TRUE(acceleration1.hasNext()); + acceleration1.next(); + EXPECT_EQ(acceleration1.mph(), 60); + EXPECT_EQ(acceleration1.seconds(), 7.5f); - EXPECT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), 100); - EXPECT_EQ(acceleration.seconds(), 12.2f); + EXPECT_TRUE(acceleration1.hasNext()); + acceleration1.next(); + EXPECT_EQ(acceleration1.mph(), 100); + EXPECT_EQ(acceleration1.seconds(), 12.2f); EXPECT_TRUE(performanceFigures.hasNext()); performanceFigures.next(); EXPECT_EQ(performanceFigures.octaneRating(), 99); - acceleration = performanceFigures.acceleration(); - EXPECT_EQ(acceleration.count(), 3u); - EXPECT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), 30); - EXPECT_EQ(acceleration.seconds(), 3.8f); - - EXPECT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), 60); - EXPECT_EQ(acceleration.seconds(), 7.1f); - - EXPECT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), 100); - EXPECT_EQ(acceleration.seconds(), 11.8f); + Car::PerformanceFigures::Acceleration &acceleration2 = performanceFigures.acceleration(); + EXPECT_EQ(acceleration2.count(), 3u); + EXPECT_TRUE(acceleration2.hasNext()); + acceleration2.next(); + EXPECT_EQ(acceleration2.mph(), 30); + EXPECT_EQ(acceleration2.seconds(), 3.8f); + + EXPECT_TRUE(acceleration2.hasNext()); + acceleration2.next(); + EXPECT_EQ(acceleration2.mph(), 60); + EXPECT_EQ(acceleration2.seconds(), 7.1f); + + EXPECT_TRUE(acceleration2.hasNext()); + acceleration2.next(); + EXPECT_EQ(acceleration2.mph(), 100); + EXPECT_EQ(acceleration2.seconds(), 11.8f); return m_carDecoder.encodedLength(); } diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 03d1ab1cfb..8c698c83c3 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -18,6 +18,7 @@ function(sbe_test name) add_executable("${name}" "${name}.cpp") target_include_directories("${name}" PRIVATE ${GTEST_SOURCE_DIR}/googletest/include + PRIVATE ${GTEST_SOURCE_DIR}/googlemock/include PRIVATE ${CXX_CODEC_TARGET_DIR} ) target_compile_options("${name}" PRIVATE $<$:-Werror>) @@ -40,6 +41,7 @@ set(MESSAGE_BLOCK_LENGTH_TEST ${CODEC_SCHEMA_DIR}/message-block-length-test.xml) set(GROUP_WITH_DATA_SCHEMA ${CODEC_SCHEMA_DIR}/group-with-data-schema.xml) set(ISSUE835_SCHEMA ${CODEC_SCHEMA_DIR}/issue835.xml) set(ISSUE889_SCHEMA ${CODEC_SCHEMA_DIR}/issue889.xml) +set(ACCESS_ORDER_SCHEMA ${CODEC_SCHEMA_DIR}/field-order-check-schema.xml) set(GENERATED_CODECS ${CXX_CODEC_TARGET_DIR} @@ -54,12 +56,16 @@ add_custom_command( ${GROUP_WITH_DATA_SCHEMA} ${ISSUE835_SCHEMA} ${ISSUE889_SCHEMA} + ${ACCESS_ORDER_SCHEMA} sbe-jar ${SBE_JAR} COMMAND ${Java_JAVA_EXECUTABLE} -Dsbe.output.dir=${CXX_CODEC_TARGET_DIR} -Dsbe.generate.ir="true" -Dsbe.target.language="cpp" + -Dsbe.generate.precedence.checks="true" + -Dsbe.precedence.checks.flag.name="SBE_ENABLE_PRECEDENCE_CHECKS_IN_TESTS" + -Dsbe.cpp.disable.implicit.copying="true" -jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${COMPOSITE_OFFSETS_SCHEMA} @@ -68,6 +74,7 @@ add_custom_command( ${COMPOSITE_ELEMENTS_SCHEMA} ${ISSUE835_SCHEMA} ${ISSUE889_SCHEMA} + ${ACCESS_ORDER_SCHEMA} ) add_custom_target(codecs DEPENDS ${GENERATED_CODECS}) @@ -83,3 +90,5 @@ sbe_test(Rc3OtfFullIrTest codecs) sbe_test(CompositeElementsTest codecs) sbe_test(Issue835Test codecs) sbe_test(Issue889Test codecs) +sbe_test(FieldAccessOrderCheckTest codecs) +target_compile_definitions(FieldAccessOrderCheckTest PRIVATE SBE_ENABLE_PRECEDENCE_CHECKS_IN_TESTS) diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index 698d7ec849..6675172c8d 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -680,43 +680,43 @@ TEST_F(CodeGenTest, shouldBeAbleToEncodeAndDecodeHeaderPlusCarCorrectly) performanceFigures.next(); EXPECT_EQ(performanceFigures.octaneRating(), perf1Octane); - Car::PerformanceFigures::Acceleration &acceleration = performanceFigures.acceleration(); - EXPECT_EQ(acceleration.count(), ACCELERATION_COUNT); - ASSERT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), perf1aMph); - EXPECT_EQ(acceleration.seconds(), perf1aSeconds); - - ASSERT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), perf1bMph); - EXPECT_EQ(acceleration.seconds(), perf1bSeconds); - - ASSERT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), perf1cMph); - EXPECT_EQ(acceleration.seconds(), perf1cSeconds); + Car::PerformanceFigures::Acceleration &acceleration1 = performanceFigures.acceleration(); + EXPECT_EQ(acceleration1.count(), ACCELERATION_COUNT); + ASSERT_TRUE(acceleration1.hasNext()); + acceleration1.next(); + EXPECT_EQ(acceleration1.mph(), perf1aMph); + EXPECT_EQ(acceleration1.seconds(), perf1aSeconds); + + ASSERT_TRUE(acceleration1.hasNext()); + acceleration1.next(); + EXPECT_EQ(acceleration1.mph(), perf1bMph); + EXPECT_EQ(acceleration1.seconds(), perf1bSeconds); + + ASSERT_TRUE(acceleration1.hasNext()); + acceleration1.next(); + EXPECT_EQ(acceleration1.mph(), perf1cMph); + EXPECT_EQ(acceleration1.seconds(), perf1cSeconds); ASSERT_TRUE(performanceFigures.hasNext()); performanceFigures.next(); EXPECT_EQ(performanceFigures.octaneRating(), perf2Octane); - acceleration = performanceFigures.acceleration(); - EXPECT_EQ(acceleration.count(), ACCELERATION_COUNT); - ASSERT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), perf2aMph); - EXPECT_EQ(acceleration.seconds(), perf2aSeconds); + Car::PerformanceFigures::Acceleration &acceleration2 = performanceFigures.acceleration(); + EXPECT_EQ(acceleration2.count(), ACCELERATION_COUNT); + ASSERT_TRUE(acceleration2.hasNext()); + acceleration2.next(); + EXPECT_EQ(acceleration2.mph(), perf2aMph); + EXPECT_EQ(acceleration2.seconds(), perf2aSeconds); - ASSERT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), perf2bMph); - EXPECT_EQ(acceleration.seconds(), perf2bSeconds); + ASSERT_TRUE(acceleration2.hasNext()); + acceleration2.next(); + EXPECT_EQ(acceleration2.mph(), perf2bMph); + EXPECT_EQ(acceleration2.seconds(), perf2bSeconds); - ASSERT_TRUE(acceleration.hasNext()); - acceleration.next(); - EXPECT_EQ(acceleration.mph(), perf2cMph); - EXPECT_EQ(acceleration.seconds(), perf2cSeconds); + ASSERT_TRUE(acceleration2.hasNext()); + acceleration2.next(); + EXPECT_EQ(acceleration2.mph(), perf2cMph); + EXPECT_EQ(acceleration2.seconds(), perf2cSeconds); EXPECT_EQ(m_carDecoder.manufacturerLength(), MANUFACTURER_LENGTH); EXPECT_EQ(std::string(m_carDecoder.manufacturer(), MANUFACTURER_LENGTH), MANUFACTURER); @@ -748,7 +748,7 @@ struct CallbacksForEach void operator()(Car::PerformanceFigures &performanceFigures) { - Car::PerformanceFigures::Acceleration acceleration = performanceFigures.acceleration(); + Car::PerformanceFigures::Acceleration &acceleration = performanceFigures.acceleration(); countOfPerformanceFigures++; acceleration.forEach(*this); @@ -806,7 +806,7 @@ TEST_F(CodeGenTest, shouldBeAbleUseOnStackCodecsAndGroupForEach) #if __cplusplus >= 201103L performanceFigures.forEach([&](Car::PerformanceFigures &figures) { - Car::PerformanceFigures::Acceleration acceleration = figures.acceleration(); + Car::PerformanceFigures::Acceleration &acceleration = figures.acceleration(); cbs.countOfPerformanceFigures++; acceleration.forEach( @@ -964,13 +964,13 @@ TEST_F(CodeGenTest, shouldBeAbleToUseStdStringMethodsForDecode) Car::PerformanceFigures &perfFigures = carDecoder.performanceFigures(); perfFigures.next(); - Car::PerformanceFigures::Acceleration &acceleration = perfFigures.acceleration(); + Car::PerformanceFigures::Acceleration &acceleration1 = perfFigures.acceleration(); - acceleration.next().next().next(); + acceleration1.next().next().next(); perfFigures.next(); - acceleration = perfFigures.acceleration(); - acceleration.next().next().next(); + Car::PerformanceFigures::Acceleration &acceleration2 = perfFigures.acceleration(); + acceleration2.next().next().next(); EXPECT_EQ(carDecoder.getManufacturerAsString(), manufacturer); EXPECT_EQ(carDecoder.getModelAsString(), model); @@ -1037,15 +1037,15 @@ TEST_F(CodeGenTest, shouldPrintFullDecodedFlyweightRegardlessOfReadPosition) Car::PerformanceFigures &perfFigures = carDecoder.performanceFigures(); perfFigures.next(); - Car::PerformanceFigures::Acceleration &acceleration = perfFigures.acceleration(); + Car::PerformanceFigures::Acceleration &acceleration1 = perfFigures.acceleration(); - acceleration.next().next().next(); + acceleration1.next().next().next(); expectDisplayString(expectedDisplayString, carDecoder); perfFigures.next(); - acceleration = perfFigures.acceleration(); - acceleration.next().next().next(); + Car::PerformanceFigures::Acceleration &acceleration2 = perfFigures.acceleration(); + acceleration2.next().next().next(); EXPECT_EQ(carDecoder.getManufacturerAsString(), manufacturer); EXPECT_EQ(carDecoder.getModelAsString(), model); diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp index 28bcbb1880..39759c1d50 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp @@ -141,7 +141,7 @@ TEST_F(CompositeOffsetsCodeGenTest, shouldBeAbleToDecodeHeaderAndMsgCorrectly) m_msgDecoder.wrapForDecode( buffer, hdrSz, TestMessage1::sbeBlockLength(), TestMessage1::sbeSchemaVersion(), hdrSz + sz); - TestMessage1::Entries entries = m_msgDecoder.entries(); + TestMessage1::Entries &entries = m_msgDecoder.entries(); EXPECT_EQ(entries.count(), 2u); ASSERT_TRUE(entries.hasNext()); diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp new file mode 100644 index 0000000000..89aeeca267 --- /dev/null +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -0,0 +1,4937 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "order_check/MultipleVarLength.h" +#include "order_check/GroupAndVarLength.h" +#include "order_check/VarLengthInsideGroup.h" +#include "order_check/NestedGroups.h" +#include "order_check/CompositeInsideGroup.h" +#include "order_check/AddPrimitiveV1.h" +#include "order_check/AddPrimitiveV0.h" +#include "order_check/AddPrimitiveBeforeGroupV1.h" +#include "order_check/AddPrimitiveBeforeGroupV0.h" +#include "order_check/AddPrimitiveBeforeVarDataV1.h" +#include "order_check/AddPrimitiveBeforeVarDataV0.h" +#include "order_check/AddPrimitiveInsideGroupV1.h" +#include "order_check/AddPrimitiveInsideGroupV0.h" +#include "order_check/AddGroupBeforeVarDataV1.h" +#include "order_check/AddGroupBeforeVarDataV0.h" +#include "order_check/AddEnumBeforeGroupV1.h" +#include "order_check/AddEnumBeforeGroupV0.h" +#include "order_check/AddCompositeBeforeGroupV1.h" +#include "order_check/AddCompositeBeforeGroupV0.h" +#include "order_check/AddArrayBeforeGroupV1.h" +#include "order_check/AddArrayBeforeGroupV0.h" +#include "order_check/AddBitSetBeforeGroupV1.h" +#include "order_check/AddBitSetBeforeGroupV0.h" +#include "order_check/EnumInsideGroup.h" +#include "order_check/BitSetInsideGroup.h" +#include "order_check/ArrayInsideGroup.h" +#include "order_check/MultipleGroups.h" +#include "order_check/AddVarDataV1.h" +#include "order_check/AddVarDataV0.h" +#include "order_check/AsciiInsideGroup.h" +#include "order_check/AddAsciiBeforeGroupV1.h" +#include "order_check/AddAsciiBeforeGroupV0.h" +#include "order_check/NoBlock.h" +#include "order_check/GroupWithNoBlock.h" +#include "order_check/NestedGroupWithVarLength.h" + +using namespace order::check; +using ::testing::HasSubstr; + +class FieldAccessOrderCheckTest : public testing::Test +{ +public: + static const std::size_t BUFFER_LEN = 2048u; + static const std::size_t OFFSET = 0; + + char m_buffer[BUFFER_LEN] = {}; + +}; + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingVariableLengthFieldsInSchemaDefinedOrder1) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingVariableLengthFieldsInSchemaDefinedOrder2) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + auto bLength = decoder.bLength(); + auto *b = decoder.b(); + const std::string bStr(b, bLength); + EXPECT_EQ(bStr, "abc"); + auto cLength = decoder.cLength(); + auto *c = decoder.c(); + const std::string cStr(c, cLength); + EXPECT_EQ(cStr, "def"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingVariableLengthFieldsInSchemaDefinedOrder3) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + auto *bIn = "abc"; + encoder.putB(bIn, strlen(bIn)); + auto *cIn = "def"; + encoder.putC(cIn, strlen(cIn)); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + + const auto bLength = decoder.bLength(); + auto *bOut = new char[bLength]; + decoder.getB(bOut, bLength); + EXPECT_EQ(std::strncmp(bOut, "abc", bLength), 0); + delete[] bOut; + + auto cLength = decoder.cLength(); + auto *cOut = new char[cLength]; + decoder.getC(cOut, cLength); + EXPECT_EQ(std::strncmp(cOut, "def", cLength), 0); + delete[] cOut; +} + +TEST_F(FieldAccessOrderCheckTest, allowsDecodingVariableLengthFieldsAfterRewind) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); + + decoder.sbeRewind(); + + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsDecodingToSkipVariableLengthFields) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.skipB(), 3ul); + EXPECT_EQ(decoder.getCAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingTopLevelPrimitiveFields) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.a(43); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 43); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsSkippingEncodingOfVariableLengthField1) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + EXPECT_THROW( + { + try + { + encoder.putC("def"); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"c\" in state: V0_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsSkippingEncodingOfVariableLengthField2) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + EXPECT_THROW( + { + try + { + auto *cIn = "cIn"; + encoder.putC(cIn, std::strlen(cIn)); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"c\" in state: V0_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReEncodingEarlierVariableLengthFields) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + EXPECT_THROW( + { + try + { + encoder.putB("ghi"); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b\" in state: V0_C_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReEncodingLatestVariableLengthField) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + EXPECT_THROW( + { + try + { + encoder.putC("ghi"); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"c\" in state: V0_C_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsSkippingDecodingOfVariableLengthField1) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + + EXPECT_THROW( + { + try + { + decoder.getCAsString(); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"c\" in state: V0_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsSkippingDecodingOfVariableLengthField2) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + + EXPECT_THROW( + { + try + { + decoder.cLength(); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot decode length of var data \"c\" in state: V0_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsSkippingDecodingOfVariableLengthField3) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + + EXPECT_THROW( + { + try + { + char cOut[3]; + decoder.getC(cOut, 3); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"c\" in state: V0_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReDecodingEarlierVariableLengthField) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); + + EXPECT_THROW( + { + try + { + decoder.getBAsString(); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b\" in state: V0_C_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReDecodingLatestVariableLengthField) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); + + EXPECT_THROW( + { + try + { + decoder.getCAsString(); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"c\" in state: V0_C_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingGroupAndVariableLengthFieldsInSchemaDefinedOrder) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &b = encoder.bCount(2); + b.next().c(1); + b.next().c(2); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(decoder.getDAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsDecodingGroupAndVariableLengthFieldsAfterRewind) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &b = encoder.bCount(2); + b.next().c(1); + b.next().c(2); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(decoder.getDAsString(), "abc"); + + decoder.sbeRewind(); + + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder2 = decoder.b(); + EXPECT_EQ(bDecoder2.count(), 2u); + EXPECT_EQ(bDecoder2.next().c(), 1); + EXPECT_EQ(bDecoder2.next().c(), 2); + EXPECT_EQ(decoder.getDAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsDecodingToSkipMessage) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &b = encoder.bCount(2); + b.next().c(1); + b.next().c(2); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + const std::uint64_t nextEncodeOffset = encoder.sbePosition(); + encoder.wrapForEncode(m_buffer, nextEncodeOffset, BUFFER_LEN); + encoder.a(43); + GroupAndVarLength::B &b2 = encoder.bCount(2); + b2.next().c(3); + b2.next().c(4); + encoder.putD("def"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + decoder.skip(); + const std::uint64_t nextDecodeOffset = decoder.sbePosition(); + EXPECT_EQ(nextDecodeOffset, nextEncodeOffset); + + decoder.wrapForDecode( + m_buffer, + nextDecodeOffset, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 43); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 3); + EXPECT_EQ(bDecoder.next().c(), 4); + EXPECT_EQ(decoder.getDAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsDecodingToDetermineMessageLengthBeforeReadingFields) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(43); + GroupAndVarLength::B &b = encoder.bCount(2); + b.next().c(3); + b.next().c(4); + encoder.putD("def"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + EXPECT_EQ(decoder.decodeLength(), 18u); + EXPECT_EQ(decoder.a(), 43); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 3); + EXPECT_EQ(bDecoder.next().c(), 4); + EXPECT_EQ(decoder.getDAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingEmptyGroupAndVariableLengthFieldsInSchemaDefinedOrder) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.bCount(0); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 0u); + EXPECT_EQ(decoder.getDAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncoderToResetZeroGroupLengthToNonZero) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.bCount(0).resetCountToIndex(); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 0u); + EXPECT_EQ(decoder.getDAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncoderToResetNonZeroGroupLengthToNonZeroBeforeCallingNext) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.bCount(2).resetCountToIndex(); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 0u); + EXPECT_EQ(decoder.getDAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncoderToResetNonZeroGroupLengthToNonZero) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bEncoder = encoder.bCount(2).next(); + bEncoder.c(43); + bEncoder.resetCountToIndex(); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 43); + EXPECT_EQ(decoder.getDAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncoderToResetGroupLengthMidGroupElement) +{ + NestedGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + NestedGroups::B &bEncoder = encoder.bCount(2).next(); + bEncoder.c(43); + EXPECT_THROW( + { + try + { + bEncoder.resetCountToIndex(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot reset count of repeating group \"b\" in state: V0_B_N_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingGroupElementBeforeCallingNext) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bEncoder = encoder.bCount(1); + EXPECT_THROW( + { + try + { + bEncoder.c(1); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingGroupElementBeforeCallingNext) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1); + bEncoder.next().c(2); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + + EXPECT_THROW( + { + try + { + bDecoder.c(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsSkippingEncodingOfGroup) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + EXPECT_THROW( + { + try + { + encoder.putD("abc"); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"d\" in state: V0_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReEncodingVariableLengthFieldAfterGroup) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1); + bEncoder.next().c(2); + encoder.putD("abc"); + EXPECT_THROW( + { + try + { + encoder.putD("def"); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"d\" in state: V0_D_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReEncodingGroupCount) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1); + bEncoder.next().c(2); + encoder.putD("abc"); + EXPECT_THROW( + { + try + { + encoder.bCount(1); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot encode count of repeating group \"b\" in state: V0_D_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfGroupBeforeVariableLengthField) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1); + bEncoder.next().c(2); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + EXPECT_THROW( + { + try + { + decoder.getDAsString(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"d\" in state: V0_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReDecodingVariableLengthFieldAfterGroup) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1); + bEncoder.next().c(2); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(decoder.getDAsString(), "abc"); + EXPECT_THROW( + { + try + { + decoder.getDAsString(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"d\" in state: V0_D_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReDecodingGroupAfterVariableLengthField) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1); + bEncoder.next().c(2); + encoder.putD("abc"); + encoder.checkEncodingIsComplete(); + + GroupAndVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupAndVarLength::sbeBlockLength(), + GroupAndVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + GroupAndVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(decoder.getDAsString(), "abc"); + EXPECT_THROW( + { + try + { + decoder.b(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot decode count of repeating group \"b\" in state: V0_D_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingVariableLengthFieldInsideGroupInSchemaDefinedOrder) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1).putD("abc"); + bEncoder.next().c(2).putD("def"); + encoder.putE("ghi"); + encoder.checkEncodingIsComplete(); + + VarLengthInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + VarLengthInsideGroup::sbeBlockLength(), + VarLengthInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + VarLengthInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_EQ(bDecoder.getDAsString(), "abc"); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(bDecoder.getDAsString(), "def"); + EXPECT_EQ(decoder.getEAsString(), "ghi"); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedGroupElementVariableLengthFieldToEncodeAtTopLevel) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(1); + bEncoder.next().c(1); + EXPECT_THROW( + { + try + { + encoder.putE("abc"); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"e\" in state: V0_B_1_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedGroupElementVariableLengthFieldToEncodeNextElement) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(2); + bEncoder.next(); + EXPECT_THROW( + { + try + { + bEncoder.next(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access next element in repeating group \"b\" in state: V0_B_N_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedGroupElementEncoding) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1).putD("abc"); + EXPECT_THROW( + { + try + { + encoder.putE("abc"); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"e\" in state: V0_B_N_D_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReEncodingGroupElementVariableLengthField) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(1); + bEncoder.next().c(1).putD("abc"); + encoder.putE("def"); + EXPECT_THROW( + { + try + { + bEncoder.putD("ghi"); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.d\" in state: V0_E_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReDecodingGroupElementVariableLengthField) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1).putD("abc"); + bEncoder.next().c(2).putD("def"); + encoder.putE("ghi"); + encoder.checkEncodingIsComplete(); + + VarLengthInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + VarLengthInsideGroup::sbeBlockLength(), + VarLengthInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + VarLengthInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_EQ(bDecoder.getDAsString(), "abc"); + EXPECT_THROW( + { + try + { + bDecoder.getDAsString(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.d\" in state: V0_B_N_D_DONE") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfGroupElementVariableLengthFieldToNextElement) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1).putD("abc"); + bEncoder.next().c(2).putD("def"); + encoder.putE("ghi"); + encoder.checkEncodingIsComplete(); + + VarLengthInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + VarLengthInsideGroup::sbeBlockLength(), + VarLengthInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + VarLengthInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_THROW( + { + try + { + bDecoder.next(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access next element in repeating group \"b\" in state: V0_B_N_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfGroupElementVariableLengthFieldToTopLevel) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(1); + bEncoder.next().c(1).putD("abc"); + encoder.putE("ghi"); + encoder.checkEncodingIsComplete(); + + VarLengthInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + VarLengthInsideGroup::sbeBlockLength(), + VarLengthInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + VarLengthInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_THROW( + { + try + { + decoder.getEAsString(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"e\" in state: V0_B_1_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfGroupElement) +{ + VarLengthInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + VarLengthInsideGroup::B &bEncoder = encoder.bCount(2); + bEncoder.next().c(1).putD("abc"); + bEncoder.next().c(2).putD("def"); + encoder.putE("ghi"); + encoder.checkEncodingIsComplete(); + + VarLengthInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + VarLengthInsideGroup::sbeBlockLength(), + VarLengthInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + VarLengthInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 1); + EXPECT_THROW( + { + try + { + decoder.getEAsString(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"e\" in state: V0_B_N_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingNestedGroupsInSchemaDefinedOrder) +{ + NestedGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + NestedGroups::B &bEncoder = encoder.bCount(2); + bEncoder.next(); + bEncoder.c(1); + NestedGroups::B::D &b0dEncoder = bEncoder.dCount(2); + b0dEncoder.next().e(2); + b0dEncoder.next().e(3); + NestedGroups::B::F &b0fEncoder = bEncoder.fCount(1); + b0fEncoder.next().g(4); + bEncoder.next(); + bEncoder.c(5); + NestedGroups::B::D &b1dEncoder = bEncoder.dCount(1); + b1dEncoder.next().e(6); + NestedGroups::B::F &b1fEncoder = bEncoder.fCount(1); + b1fEncoder.next().g(7); + NestedGroups::H &hEncoder = encoder.hCount(1); + hEncoder.next().i(8); + encoder.checkEncodingIsComplete(); + + NestedGroups decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + NestedGroups::sbeBlockLength(), + NestedGroups::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + NestedGroups::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + NestedGroups::B &b0Decoder = bDecoder.next(); + EXPECT_EQ(b0Decoder.c(), 1); + NestedGroups::B::D &b0dDecoder = b0Decoder.d(); + EXPECT_EQ(b0dDecoder.count(), 2u); + EXPECT_EQ(b0dDecoder.next().e(), 2); + EXPECT_EQ(b0dDecoder.next().e(), 3); + NestedGroups::B::F &b0fDecoder = b0Decoder.f(); + EXPECT_EQ(b0fDecoder.count(), 1u); + EXPECT_EQ(b0fDecoder.next().g(), 4); + NestedGroups::B &b1Decoder = bDecoder.next(); + EXPECT_EQ(b1Decoder.c(), 5); + NestedGroups::B::D &b1dDecoder = b1Decoder.d(); + EXPECT_EQ(b1dDecoder.count(), 1u); + EXPECT_EQ(b1dDecoder.next().e(), 6); + NestedGroups::B::F &b1fDecoder = b1Decoder.f(); + EXPECT_EQ(b1fDecoder.count(), 1u); + EXPECT_EQ(b1fDecoder.next().g(), 7); + NestedGroups::H &hDecoder = decoder.h(); + EXPECT_EQ(hDecoder.count(), 1u); + EXPECT_EQ(hDecoder.next().i(), 8); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingEmptyNestedGroupsInSchemaDefinedOrder) +{ + NestedGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.bCount(0); + encoder.hCount(0); + encoder.checkEncodingIsComplete(); + + NestedGroups decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + NestedGroups::sbeBlockLength(), + NestedGroups::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + NestedGroups::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 0u); + NestedGroups::H &hDecoder = decoder.h(); + EXPECT_EQ(hDecoder.count(), 0u); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedEncodingOfNestedGroup) +{ + NestedGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + NestedGroups::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c(1); + EXPECT_THROW( + { + try + { + bEncoder.fCount(1); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot encode count of repeating group \"b.f\" in state: V0_B_1_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingCompositeInsideGroupInSchemaDefinedOrder) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + Point &cEncoder = bEncoder.c(); + cEncoder.x(3); + cEncoder.y(4); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 1); + EXPECT_EQ(aDecoder.y(), 2); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &cDecoder = bDecoder.next().c(); + EXPECT_EQ(cDecoder.x(), 3); + EXPECT_EQ(cDecoder.y(), 4); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingCompositeInsideGroupBeforeCallingNext) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1); + EXPECT_THROW( + { + try + { + bEncoder.c(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingCompositeInsideGroupBeforeCallingNext) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + Point &cEncoder = bEncoder.c(); + cEncoder.x(3); + cEncoder.y(4); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 1); + EXPECT_EQ(aDecoder.y(), 2); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_THROW( + { + try + { + bDecoder.c(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingTopLevelCompositeViaReWrap) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + Point &cEncoder = bEncoder.c(); + cEncoder.x(3); + cEncoder.y(4); + encoder.a().x(5); + encoder.a().y(6); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 5); + EXPECT_EQ(aDecoder.y(), 6); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &cDecoder = bDecoder.next().c(); + EXPECT_EQ(cDecoder.x(), 3); + EXPECT_EQ(cDecoder.y(), 4); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingTopLevelCompositeViaEncoderReference) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + Point &cEncoder = bEncoder.c(); + cEncoder.x(3); + cEncoder.y(4); + aEncoder.x(5); + aEncoder.y(6); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 5); + EXPECT_EQ(aDecoder.y(), 6); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &cDecoder = bDecoder.next().c(); + EXPECT_EQ(cDecoder.x(), 3); + EXPECT_EQ(cDecoder.y(), 4); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingGroupElementCompositeViaReWrap) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c().x(3).y(4); + bEncoder.c().x(5).y(6); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 1); + EXPECT_EQ(aDecoder.y(), 2); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &cDecoder = bDecoder.next().c(); + EXPECT_EQ(cDecoder.x(), 5); + EXPECT_EQ(cDecoder.y(), 6); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingGroupElementCompositeViaEncoderReference) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + Point &cEncoder = bEncoder.c(); + cEncoder.x(3); + cEncoder.y(4); + cEncoder.x(5); + cEncoder.y(6); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 1); + EXPECT_EQ(aDecoder.y(), 2); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &cDecoder = bDecoder.next().c(); + EXPECT_EQ(cDecoder.x(), 5); + EXPECT_EQ(cDecoder.y(), 6); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReDecodingTopLevelCompositeViaReWrap) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &a1Decoder = decoder.a(); + EXPECT_EQ(a1Decoder.x(), 1); + EXPECT_EQ(a1Decoder.y(), 2); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &cDecoder = bDecoder.next().c(); + EXPECT_EQ(cDecoder.x(), 3); + EXPECT_EQ(cDecoder.y(), 4); + Point &a2Decoder = decoder.a(); + EXPECT_EQ(a2Decoder.x(), 1); + EXPECT_EQ(a2Decoder.y(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReDecodingTopLevelCompositeViaEncoderReference) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 1); + EXPECT_EQ(aDecoder.y(), 2); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &cDecoder = bDecoder.next().c(); + EXPECT_EQ(cDecoder.x(), 3); + EXPECT_EQ(cDecoder.y(), 4); + EXPECT_EQ(aDecoder.x(), 1); + EXPECT_EQ(aDecoder.y(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReDecodingGroupElementCompositeViaReWrap) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 1); + EXPECT_EQ(aDecoder.y(), 2); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &c1Decoder = bDecoder.next().c(); + EXPECT_EQ(c1Decoder.x(), 3); + EXPECT_EQ(c1Decoder.y(), 4); + Point &c2Decoder = bDecoder.c(); + EXPECT_EQ(c2Decoder.x(), 3); + EXPECT_EQ(c2Decoder.y(), 4); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReDecodingGroupElementCompositeViaEncoderReference) +{ + CompositeInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Point &aEncoder = encoder.a(); + aEncoder.x(1); + aEncoder.y(2); + CompositeInsideGroup::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + CompositeInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + CompositeInsideGroup::sbeBlockLength(), + CompositeInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Point &aDecoder = decoder.a(); + EXPECT_EQ(aDecoder.x(), 1); + EXPECT_EQ(aDecoder.y(), 2); + CompositeInsideGroup::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + Point &cDecoder = bDecoder.next().c(); + EXPECT_EQ(cDecoder.x(), 3); + EXPECT_EQ(cDecoder.y(), 4); + EXPECT_EQ(cDecoder.x(), 3); + EXPECT_EQ(cDecoder.y(), 4); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedPrimitiveField) +{ + AddPrimitiveV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.b(2); + encoder.checkEncodingIsComplete(); + + AddPrimitiveV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveV1::sbeBlockLength(), + AddPrimitiveV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.b(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingPrimitiveFieldAsNullValue) +{ + AddPrimitiveV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.checkEncodingIsComplete(); + + AddPrimitiveV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.b(), AddPrimitiveV1::bNullValue()); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedPrimitiveFieldBeforeGroup) +{ + AddPrimitiveBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.d(3); + AddPrimitiveBeforeGroupV1::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c(2); + encoder.checkEncodingIsComplete(); + + AddPrimitiveBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveBeforeGroupV1::sbeBlockLength(), + AddPrimitiveBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.d(), 3); + AddPrimitiveBeforeGroupV1::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingPrimitiveFieldBeforeGroupAsNullValue) +{ + AddPrimitiveBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + AddPrimitiveBeforeGroupV0::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c(2); + encoder.checkEncodingIsComplete(); + + AddPrimitiveBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.d(), AddPrimitiveBeforeGroupV1::dNullValue()); + AddPrimitiveBeforeGroupV1::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipPresentButAddedPrimitiveFieldBeforeGroup) +{ + AddPrimitiveBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.d(3); + AddPrimitiveBeforeGroupV1::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c(2); + encoder.checkEncodingIsComplete(); + + AddPrimitiveBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveBeforeGroupV1::sbeBlockLength(), + AddPrimitiveBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddPrimitiveBeforeGroupV1::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedPrimitiveFieldBeforeGroup) +{ + AddPrimitiveBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.d(3); + AddPrimitiveBeforeGroupV1::B &bEncoder = encoder.bCount(1).next(); + bEncoder.c(2); + encoder.checkEncodingIsComplete(); + + AddPrimitiveBeforeGroupV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddPrimitiveBeforeGroupV0::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedPrimitiveFieldBeforeVarData) +{ + AddPrimitiveBeforeVarDataV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.c(3); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddPrimitiveBeforeVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveBeforeVarDataV1::sbeBlockLength(), + AddPrimitiveBeforeVarDataV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.c(), 3); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingPrimitiveFieldBeforeVarDataAsNullValue) +{ + AddPrimitiveBeforeVarDataV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddPrimitiveBeforeVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveBeforeVarDataV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.c(), AddPrimitiveBeforeVarDataV1::cNullValue()); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipPresentButAddedPrimitiveFieldBeforeVarData) +{ + AddPrimitiveBeforeVarDataV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.c(3); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddPrimitiveBeforeVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveBeforeVarDataV1::sbeBlockLength(), + AddPrimitiveBeforeVarDataV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedPrimitiveFieldBeforeVarData) +{ + AddPrimitiveBeforeVarDataV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.c(3); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddPrimitiveBeforeVarDataV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveBeforeVarDataV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedPrimitiveFieldInsideGroup) +{ + AddPrimitiveInsideGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.bCount(1).next().c(2).d(3); + encoder.checkEncodingIsComplete(); + + AddPrimitiveInsideGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveInsideGroupV1::sbeBlockLength(), + AddPrimitiveInsideGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddPrimitiveInsideGroupV1::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(bDecoder.d(), 3); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingPrimitiveFieldInsideGroupAsNullValue) +{ + AddPrimitiveInsideGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddPrimitiveInsideGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveInsideGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddPrimitiveInsideGroupV1::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(bDecoder.d(), AddPrimitiveInsideGroupV1::B::dNullValue()); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipPresentButAddedPrimitiveFieldInsideGroup) +{ + AddPrimitiveInsideGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.bCount(2).next().c(2).d(3).next().c(4).d(5); + encoder.checkEncodingIsComplete(); + + AddPrimitiveInsideGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveInsideGroupV1::sbeBlockLength(), + AddPrimitiveInsideGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddPrimitiveInsideGroupV1::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(bDecoder.next().c(), 4); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedPrimitiveFieldInsideGroup) +{ + AddPrimitiveInsideGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.bCount(2).next().c(2).d(3).next().c(4).d(5); + encoder.checkEncodingIsComplete(); + + AddPrimitiveInsideGroupV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddPrimitiveInsideGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddPrimitiveInsideGroupV0::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 2); + EXPECT_EQ(bDecoder.next().c(), 4); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedGroupBeforeVarData) +{ + AddGroupBeforeVarDataV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.cCount(1).next().d(2); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddGroupBeforeVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddGroupBeforeVarDataV1::sbeBlockLength(), + AddGroupBeforeVarDataV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddGroupBeforeVarDataV1::C &cDecoder = decoder.c(); + EXPECT_EQ(cDecoder.count(), 1u); + EXPECT_EQ(cDecoder.next().d(), 2); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingGroupBeforeVarDataAsNullValue) +{ + AddGroupBeforeVarDataV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddGroupBeforeVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddGroupBeforeVarDataV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddGroupBeforeVarDataV1::C &cDecoder = decoder.c(); + EXPECT_EQ(cDecoder.count(), 0u); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipMissingGroupBeforeVarData) +{ + AddGroupBeforeVarDataV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddGroupBeforeVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddGroupBeforeVarDataV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsNewDecoderToSkipPresentButAddedGroupBeforeVarData) +{ + AddGroupBeforeVarDataV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.cCount(1).next().d(2); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddGroupBeforeVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddGroupBeforeVarDataV1::sbeBlockLength(), + AddGroupBeforeVarDataV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_THROW( + { + try + { + decoder.b(); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b\" in state: V1_BLOCK") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedGroupBeforeVarData) +{ + AddGroupBeforeVarDataV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.cCount(1).next().d(2); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddGroupBeforeVarDataV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddGroupBeforeVarDataV1::sbeBlockLength(), + AddGroupBeforeVarDataV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + + // In reality, we would use a numGroups field in the message header to skip over unknown groups + // rather than the hardcoded knowledge of one extra group below: + + GroupSizeEncoding groupSizeEncodingDecoder; + groupSizeEncodingDecoder.wrap( + m_buffer, + decoder.sbePosition(), + GroupSizeEncoding::sbeSchemaVersion(), + BUFFER_LEN + ); + const std::uint64_t bytesToSkip = GroupSizeEncoding::encodedLength() + + groupSizeEncodingDecoder.blockLength() * groupSizeEncodingDecoder.numInGroup(); + decoder.sbePosition(decoder.sbePosition() + bytesToSkip); + + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedEnumFieldBeforeGroup) +{ + AddEnumBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.d(Direction::BUY); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddEnumBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddEnumBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.d(), Direction::BUY); + AddEnumBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingEnumFieldBeforeGroupAsNullValue) +{ + AddEnumBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddEnumBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddEnumBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.d(), Direction::NULL_VALUE); + AddEnumBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipPresentButAddedEnumFieldBeforeGroup) +{ + AddEnumBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.d(Direction::SELL); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddEnumBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddEnumBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddEnumBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedEnumFieldBeforeGroup) +{ + AddEnumBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.d(Direction::BUY); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddEnumBeforeGroupV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddEnumBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddEnumBeforeGroupV0::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedCompositeFieldBeforeGroup) +{ + AddCompositeBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + Point &d = encoder.d(); + d.x(-1); + d.y(-2); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddCompositeBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddCompositeBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + Point &d2 = decoder.d(); + EXPECT_EQ(d2.x(), -1); + EXPECT_EQ(d2.y(), -2); + AddCompositeBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipPresentButAddedCompositeFieldBeforeGroup) +{ + AddCompositeBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + Point &d = encoder.d(); + d.x(-1); + d.y(-2); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddCompositeBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddCompositeBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddCompositeBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedCompositeFieldBeforeGroup) +{ + AddCompositeBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + Point &d = encoder.d(); + d.x(-1); + d.y(-2); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddCompositeBeforeGroupV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddCompositeBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddCompositeBeforeGroupV0::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedArrayFieldBeforeGroup) +{ + AddArrayBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD(1, 2, 3, 4); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddArrayBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddArrayBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.d(0), 1); + EXPECT_EQ(decoder.d(1), 2); + EXPECT_EQ(decoder.d(2), 3); + EXPECT_EQ(decoder.d(3), 4); + AddArrayBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue1) +{ + AddArrayBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddArrayBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddArrayBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.d(0), AddArrayBeforeGroupV1::dNullValue()); + EXPECT_EQ(decoder.d(1), AddArrayBeforeGroupV1::dNullValue()); + EXPECT_EQ(decoder.d(2), AddArrayBeforeGroupV1::dNullValue()); + EXPECT_EQ(decoder.d(3), AddArrayBeforeGroupV1::dNullValue()); + AddArrayBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue2) +{ + AddArrayBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddArrayBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddArrayBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + char *d = decoder.d(); + EXPECT_EQ(d, nullptr); + AddArrayBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue3) +{ + AddArrayBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddArrayBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddArrayBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + const AddArrayBeforeGroupV1 &constDecoder = decoder; + const char *d = constDecoder.d(); + EXPECT_EQ(d, nullptr); + AddArrayBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipPresentButAddedArrayFieldBeforeGroup) +{ + AddArrayBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD(1, 2, 3, 4); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddArrayBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddArrayBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddArrayBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedArrayFieldBeforeGroup) +{ + AddArrayBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD(1, 2, 3, 4); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddArrayBeforeGroupV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddArrayBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddArrayBeforeGroupV0::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedBitSetFieldBeforeGroup) +{ + AddBitSetBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).d().guacamole(true).cheese(true).sourCream(false); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddBitSetBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddBitSetBeforeGroupV1::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + Flags &d = decoder.d(); + EXPECT_EQ(d.guacamole(), true); + EXPECT_EQ(d.cheese(), true); + EXPECT_EQ(d.sourCream(), false); + AddBitSetBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingBitSetFieldBeforeGroupAsNullValue) +{ + AddBitSetBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddBitSetBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddBitSetBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.dInActingVersion(), false); + AddBitSetBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipPresentButAddedBitSetFieldBeforeGroup) +{ + AddBitSetBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).d().guacamole(true).cheese(true).sourCream(false); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddBitSetBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddBitSetBeforeGroupV1::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddBitSetBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedBitSetFieldBeforeGroup) +{ + AddBitSetBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).d().guacamole(true).cheese(true).sourCream(false); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + AddBitSetBeforeGroupV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddBitSetBeforeGroupV1::sbeBlockLength(), + 1, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddBitSetBeforeGroupV0::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingEnumInsideGroupInSchemaDefinedOrder) +{ + EnumInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(Direction::BUY) + .bCount(1) + .next() + .c(Direction::SELL); + encoder.checkEncodingIsComplete(); + + EnumInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + EnumInsideGroup::sbeBlockLength(), + EnumInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), Direction::BUY); + EnumInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), Direction::SELL); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingEnumInsideGroupBeforeCallingNext) +{ + EnumInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(Direction::BUY); + EnumInsideGroup::B &bEncoder = encoder.bCount(1); + EXPECT_THROW( + { + try + { + bEncoder.c(Direction::SELL); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingEnumInsideGroupBeforeCallingNext) +{ + EnumInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(Direction::BUY) + .bCount(1) + .next() + .c(Direction::SELL); + encoder.checkEncodingIsComplete(); + + EnumInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + EnumInsideGroup::sbeBlockLength(), + EnumInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), Direction::BUY); + EnumInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_THROW( + { + try + { + b.c(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingTopLevelEnum) +{ + EnumInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(Direction::BUY) + .bCount(1) + .next() + .c(Direction::SELL); + + encoder.a(Direction::SELL); + encoder.checkEncodingIsComplete(); + + EnumInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + EnumInsideGroup::sbeBlockLength(), + EnumInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), Direction::SELL); + EnumInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), Direction::SELL); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingBitSetInsideGroupInSchemaDefinedOrder) +{ + BitSetInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Flags &a = encoder.a(); + a.cheese(true).guacamole(true).sourCream(false); + BitSetInsideGroup::B &b = encoder.bCount(1) + .next(); + Flags &c = b.c(); + c.cheese(false).guacamole(false).sourCream(true); + encoder.checkEncodingIsComplete(); + + BitSetInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + BitSetInsideGroup::sbeBlockLength(), + BitSetInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Flags &aFlags = decoder.a(); + EXPECT_EQ(aFlags.guacamole(), true); + EXPECT_EQ(aFlags.cheese(), true); + EXPECT_EQ(aFlags.sourCream(), false); + BitSetInsideGroup::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + Flags &cFlags = bGroup.next().c(); + EXPECT_EQ(cFlags.guacamole(), false); + EXPECT_EQ(cFlags.cheese(), false); + EXPECT_EQ(cFlags.sourCream(), true); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingBitSetInsideGroupBeforeCallingNext) +{ + BitSetInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Flags &a = encoder.a(); + a.cheese(true).guacamole(true).sourCream(false); + BitSetInsideGroup::B &b = encoder.bCount(1); + EXPECT_THROW( + { + try + { + b.c(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingBitSetInsideGroupBeforeCallingNext) +{ + BitSetInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Flags &a = encoder.a(); + a.cheese(true).guacamole(true).sourCream(false); + BitSetInsideGroup::B &b = encoder.bCount(1) + .next(); + Flags &c = b.c(); + c.cheese(false).guacamole(false).sourCream(true); + encoder.checkEncodingIsComplete(); + + BitSetInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + BitSetInsideGroup::sbeBlockLength(), + BitSetInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Flags &aFlags = decoder.a(); + EXPECT_EQ(aFlags.guacamole(), true); + EXPECT_EQ(aFlags.cheese(), true); + EXPECT_EQ(aFlags.sourCream(), false); + BitSetInsideGroup::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + EXPECT_THROW( + { + try + { + bGroup.c(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingTopLevelBitSetViaReWrap) +{ + BitSetInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + Flags &a = encoder.a(); + a.cheese(true).guacamole(true).sourCream(false); + BitSetInsideGroup::B &b = encoder.bCount(1) + .next(); + Flags &c = b.c(); + c.cheese(false).guacamole(false).sourCream(true); + + Flags &aPrime = encoder.a(); + aPrime.sourCream(true); + encoder.checkEncodingIsComplete(); + + BitSetInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + BitSetInsideGroup::sbeBlockLength(), + BitSetInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + Flags &aFlags = decoder.a(); + EXPECT_EQ(aFlags.guacamole(), true); + EXPECT_EQ(aFlags.cheese(), true); + EXPECT_EQ(aFlags.sourCream(), true); + BitSetInsideGroup::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + Flags &cFlags = bGroup.next().c(); + EXPECT_EQ(cFlags.guacamole(), false); + EXPECT_EQ(cFlags.cheese(), false); + EXPECT_EQ(cFlags.sourCream(), true); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingArrayInsideGroupInSchemaDefinedOrder) +{ + ArrayInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA(1, 2, 3, 4); + ArrayInsideGroup::B &b = encoder.bCount(1) + .next(); + b.putC(5, 6, 7, 8); + encoder.checkEncodingIsComplete(); + + ArrayInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + ArrayInsideGroup::sbeBlockLength(), + ArrayInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(0), 1); + EXPECT_EQ(decoder.a(1), 2); + EXPECT_EQ(decoder.a(2), 3); + EXPECT_EQ(decoder.a(3), 4); + ArrayInsideGroup::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + bGroup.next(); + EXPECT_EQ(bGroup.c(0), 5); + EXPECT_EQ(bGroup.c(1), 6); + EXPECT_EQ(bGroup.c(2), 7); + EXPECT_EQ(bGroup.c(3), 8); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingArrayInsideGroupBeforeCallingNext1) +{ + ArrayInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA(1, 2, 3, 4); + ArrayInsideGroup::B &bEncoder = encoder.bCount(1); + EXPECT_THROW( + { + try + { + bEncoder.putC(5, 6, 7, 8); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.c\" in state: V0_B_N")); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingArrayInsideGroupBeforeCallingNext2) +{ + ArrayInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA(1, 2, 3, 4); + ArrayInsideGroup::B &bEncoder = encoder.bCount(1); + const char c[4] = {5, 6, 7, 8}; + const char *cPtr = c; + EXPECT_THROW( + { + try + { + bEncoder.putC(cPtr); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.c\" in state: V0_B_N")); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingArrayInsideGroupBeforeCallingNext1) +{ + ArrayInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA(1, 2, 3, 4); + ArrayInsideGroup::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.putC(5, 6, 7, 8); + encoder.checkEncodingIsComplete(); + + ArrayInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + ArrayInsideGroup::sbeBlockLength(), + ArrayInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(0), 1); + EXPECT_EQ(decoder.a(1), 2); + EXPECT_EQ(decoder.a(2), 3); + EXPECT_EQ(decoder.a(3), 4); + ArrayInsideGroup::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + EXPECT_THROW( + { + try + { + bGroup.c(0); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.c\" in state: V0_B_N")); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingArrayInsideGroupBeforeCallingNext2) +{ + ArrayInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA(1, 2, 3, 4); + ArrayInsideGroup::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.putC(5, 6, 7, 8); + encoder.checkEncodingIsComplete(); + + ArrayInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + ArrayInsideGroup::sbeBlockLength(), + ArrayInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(0), 1); + EXPECT_EQ(decoder.a(1), 2); + EXPECT_EQ(decoder.a(2), 3); + EXPECT_EQ(decoder.a(3), 4); + ArrayInsideGroup::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + EXPECT_THROW( + { + try + { + const std::uint64_t charCount = 4; + char c[charCount]; + bGroup.getC(c, charCount); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.c\" in state: V0_B_N")); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingArrayInsideGroupBeforeCallingNext3) +{ + ArrayInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA(1, 2, 3, 4); + ArrayInsideGroup::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.putC(5, 6, 7, 8); + encoder.checkEncodingIsComplete(); + + ArrayInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + ArrayInsideGroup::sbeBlockLength(), + ArrayInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(0), 1); + EXPECT_EQ(decoder.a(1), 2); + EXPECT_EQ(decoder.a(2), 3); + EXPECT_EQ(decoder.a(3), 4); + ArrayInsideGroup::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + EXPECT_THROW( + { + try + { + bGroup.c(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.c\" in state: V0_B_N")); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingTopLevelArray) +{ + ArrayInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA(1, 2, 3, 4); + ArrayInsideGroup::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.putC(5, 6, 7, 8); + + encoder.putA(9, 10, 11, 12); + encoder.checkEncodingIsComplete(); + + ArrayInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + ArrayInsideGroup::sbeBlockLength(), + ArrayInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(0), 9); + EXPECT_EQ(decoder.a(1), 10); + EXPECT_EQ(decoder.a(2), 11); + EXPECT_EQ(decoder.a(3), 12); + ArrayInsideGroup::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + bGroup.next(); + EXPECT_EQ(bGroup.c(0), 5); + EXPECT_EQ(bGroup.c(1), 6); + EXPECT_EQ(bGroup.c(2), 7); + EXPECT_EQ(bGroup.c(3), 8); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingGroupFieldsInSchemaDefinedOrder1) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.bCount(0); + MultipleGroups::D &dEncoder = encoder.dCount(1); + dEncoder.next(); + dEncoder.e(43); + encoder.checkEncodingIsComplete(); + + MultipleGroups decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleGroups::sbeBlockLength(), + MultipleGroups::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + MultipleGroups::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 0u); + MultipleGroups::D &dGroup = decoder.d(); + EXPECT_EQ(dGroup.count(), 1u); + dGroup.next(); + EXPECT_EQ(dGroup.e(), 43); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingGroupFieldsInSchemaDefinedOrder2) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(41); + MultipleGroups::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(42); + MultipleGroups::D &dEncoder = encoder.dCount(1); + dEncoder.next(); + dEncoder.e(43); + encoder.checkEncodingIsComplete(); + + MultipleGroups decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleGroups::sbeBlockLength(), + MultipleGroups::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 41); + MultipleGroups::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + bGroup.next(); + EXPECT_EQ(bGroup.c(), 42); + MultipleGroups::D &dGroup = decoder.d(); + EXPECT_EQ(dGroup.count(), 1u); + dGroup.next(); + EXPECT_EQ(dGroup.e(), 43); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingTopLevelPrimitiveFieldsAfterGroups) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(41); + MultipleGroups::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(42); + MultipleGroups::D &dEncoder = encoder.dCount(1); + dEncoder.next(); + dEncoder.e(43); + encoder.a(44); + encoder.checkEncodingIsComplete(); + + MultipleGroups decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleGroups::sbeBlockLength(), + MultipleGroups::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 44); + MultipleGroups::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + bGroup.next(); + EXPECT_EQ(bGroup.c(), 42); + MultipleGroups::D &dGroup = decoder.d(); + EXPECT_EQ(dGroup.count(), 1u); + dGroup.next(); + EXPECT_EQ(dGroup.e(), 43); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedEncodingOfGroupField) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(41); + EXPECT_THROW( + { + try + { + encoder.dCount(0); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot encode count of repeating group \"d\" in state: V0_BLOCK") + ); + throw; + } + }, std::logic_error); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReEncodingEarlierGroupFields) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(41); + MultipleGroups::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(42); + MultipleGroups::D &dEncoder = encoder.dCount(1); + dEncoder.next(); + dEncoder.e(43); + EXPECT_THROW( + { + try + { + encoder.bCount(1); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot encode count of repeating group \"b\" in state: V0_D_1_BLOCK") + ); + throw; + } + }, std::logic_error); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReEncodingLatestGroupField) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(41); + MultipleGroups::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(42); + MultipleGroups::D &dEncoder = encoder.dCount(1); + dEncoder.next(); + dEncoder.e(43); + EXPECT_THROW( + { + try + { + encoder.dCount(1); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot encode count of repeating group \"d\" in state: V0_D_1_BLOCK") + ); + throw; + } + }, std::logic_error); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfGroupField) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(41); + MultipleGroups::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(42); + MultipleGroups::D &dEncoder = encoder.dCount(1); + dEncoder.next(); + dEncoder.e(43); + encoder.checkEncodingIsComplete(); + + MultipleGroups decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleGroups::sbeBlockLength(), + MultipleGroups::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 41); + EXPECT_THROW( + { + try + { + decoder.d(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot decode count of repeating group \"d\" in state: V0_BLOCK") + ); + throw; + } + }, std::logic_error); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReDecodingEarlierGroupField) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(41); + MultipleGroups::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(42); + MultipleGroups::D &dEncoder = encoder.dCount(1); + dEncoder.next(); + dEncoder.e(43); + encoder.checkEncodingIsComplete(); + + MultipleGroups decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleGroups::sbeBlockLength(), + MultipleGroups::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 41); + MultipleGroups::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + EXPECT_EQ(bGroup.next().c(), 42); + MultipleGroups::D &dGroup = decoder.d(); + EXPECT_EQ(dGroup.count(), 1u); + EXPECT_EQ(dGroup.next().e(), 43); + EXPECT_THROW( + { + try + { + decoder.b(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot decode count of repeating group \"b\" in state: V0_D_1_BLOCK") + ); + throw; + } + }, std::logic_error); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsReDecodingLatestGroupField) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(41); + MultipleGroups::B &bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(42); + MultipleGroups::D &dEncoder = encoder.dCount(1); + dEncoder.next(); + dEncoder.e(43); + encoder.checkEncodingIsComplete(); + + MultipleGroups decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleGroups::sbeBlockLength(), + MultipleGroups::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 41); + MultipleGroups::B &bGroup = decoder.b(); + EXPECT_EQ(bGroup.count(), 1u); + EXPECT_EQ(bGroup.next().c(), 42); + MultipleGroups::D &dGroup = decoder.d(); + EXPECT_EQ(dGroup.count(), 1u); + EXPECT_EQ(dGroup.next().e(), 43); + EXPECT_THROW( + { + try + { + decoder.d(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot decode count of repeating group \"d\" in state: V0_D_1_BLOCK") + ); + throw; + } + }, std::logic_error); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedVarData) +{ + AddVarDataV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.checkEncodingIsComplete(); + + AddVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddVarDataV1::sbeBlockLength(), + AddVarDataV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue1) +{ + AddVarDataV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + AddVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddVarDataV1::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.b(), nullptr); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue2) +{ + AddVarDataV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + AddVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddVarDataV1::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), ""); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue3) +{ + AddVarDataV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + AddVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddVarDataV1::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsJsonEscapedString(), ""); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue4) +{ + AddVarDataV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + AddVarDataV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddVarDataV1::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 42); + char b[16]; + EXPECT_EQ(decoder.getB(b, 16), 0u); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingAsciiInsideGroupInSchemaDefinedOrder1) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + bGroup.next().putC("EURUSD"); + encoder.checkEncodingIsComplete(); + + AsciiInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AsciiInsideGroup::sbeBlockLength(), + AsciiInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.getAAsString(), "GBPUSD"); + AsciiInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().getCAsString(), "EURUSD"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingAsciiInsideGroupInSchemaDefinedOrder2) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + std::string a("GBPUSD"); + encoder.putA(a); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + bGroup.next() + .c(0, 'E') + .c(1, 'U') + .c(2, 'R') + .c(3, 'U') + .c(4, 'S') + .c(5, 'D'); + encoder.checkEncodingIsComplete(); + + AsciiInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AsciiInsideGroup::sbeBlockLength(), + AsciiInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + char aOut[6]; + decoder.getA(aOut, 6); + EXPECT_STREQ(aOut, "GBPUSD"); + AsciiInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(0), 'E'); + EXPECT_EQ(b.c(1), 'U'); + EXPECT_EQ(b.c(2), 'R'); + EXPECT_EQ(b.c(3), 'U'); + EXPECT_EQ(b.c(4), 'S'); + EXPECT_EQ(b.c(5), 'D'); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingAsciiInsideGroupBeforeCallingNext1) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + EXPECT_THROW( + { + try + { + bGroup.putC("EURUSD"); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingAsciiInsideGroupBeforeCallingNext2) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + EXPECT_THROW( + { + try + { + const std::string c("EURUSD"); + bGroup.putC(c); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingAsciiInsideGroupBeforeCallingNext3) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + EXPECT_THROW( + { + try + { + bGroup.c(0, 'E') + .c(1, 'U') + .c(2, 'R') + .c(3, 'U') + .c(4, 'S') + .c(5, 'D'); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingAsciiInsideGroupBeforeCallingNext1) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + bGroup.next().putC("EURUSD"); + encoder.checkEncodingIsComplete(); + + AsciiInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AsciiInsideGroup::sbeBlockLength(), + AsciiInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.getAAsString(), "GBPUSD"); + AsciiInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_THROW( + { + try + { + b.getCAsString(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingAsciiInsideGroupBeforeCallingNext2) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + bGroup.next().putC("EURUSD"); + encoder.checkEncodingIsComplete(); + + AsciiInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AsciiInsideGroup::sbeBlockLength(), + AsciiInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.getAAsString(), "GBPUSD"); + AsciiInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_THROW( + { + try + { + b.c(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingAsciiInsideGroupBeforeCallingNext3) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + bGroup.next().putC("EURUSD"); + encoder.checkEncodingIsComplete(); + + AsciiInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AsciiInsideGroup::sbeBlockLength(), + AsciiInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.getAAsString(), "GBPUSD"); + AsciiInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_THROW( + { + try + { + char c[6]; + b.getC(c, 6); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingAsciiInsideGroupBeforeCallingNext4) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + bGroup.next().putC("EURUSD"); + encoder.checkEncodingIsComplete(); + + AsciiInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AsciiInsideGroup::sbeBlockLength(), + AsciiInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.getAAsString(), "GBPUSD"); + AsciiInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_THROW( + { + try + { + b.c(0); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsDecodingAsciiInsideGroupBeforeCallingNext5) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + bGroup.next().putC("EURUSD"); + encoder.checkEncodingIsComplete(); + + AsciiInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AsciiInsideGroup::sbeBlockLength(), + AsciiInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.getAAsString(), "GBPUSD"); + AsciiInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_THROW( + { + try + { + b.getCAsJsonEscapedString(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Cannot access field \"b.c\" in state: V0_B_N") + ); + throw; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsReEncodingTopLevelAscii) +{ + AsciiInsideGroup encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("GBPUSD"); + AsciiInsideGroup::B &bGroup = encoder.bCount(1); + bGroup.next().putC("EURUSD"); + + encoder.putA("CADUSD"); + encoder.checkEncodingIsComplete(); + + AsciiInsideGroup decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AsciiInsideGroup::sbeBlockLength(), + AsciiInsideGroup::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.getAAsString(), "CADUSD"); + AsciiInsideGroup::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + b.next(); + EXPECT_EQ(b.getCAsString(), "EURUSD"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup1) +{ + AddAsciiBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD("EURUSD"); + AddAsciiBeforeGroupV1::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV1::sbeBlockLength(), + AddAsciiBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + EXPECT_EQ(decoder.getDAsString(), "EURUSD"); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup2) +{ + AddAsciiBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD("EURUSD"); + AddAsciiBeforeGroupV1::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV1::sbeBlockLength(), + AddAsciiBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + const char *d = decoder.d(); + const std::string dAsString(d, 6); + ASSERT_EQ(dAsString, "EURUSD"); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup3) +{ + AddAsciiBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD("EURUSD"); + AddAsciiBeforeGroupV1::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV1::sbeBlockLength(), + AddAsciiBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + const AddAsciiBeforeGroupV1 &constDecoder = decoder; + EXPECT_EQ(constDecoder.a(), 1); + const char *d = constDecoder.d(); + const std::string dAsString(d, 6); + ASSERT_EQ(dAsString, "EURUSD"); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup4) +{ + AddAsciiBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD("EURUSD"); + AddAsciiBeforeGroupV1::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV1::sbeBlockLength(), + AddAsciiBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + char d[6]; + decoder.getD(d, 6); + const std::string dAsString(d, 6); + ASSERT_EQ(dAsString, "EURUSD"); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup5) +{ + AddAsciiBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD("EURUSD"); + AddAsciiBeforeGroupV1::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV1::sbeBlockLength(), + AddAsciiBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + ASSERT_EQ(decoder.d(0), 'E'); + ASSERT_EQ(decoder.d(1), 'U'); + ASSERT_EQ(decoder.d(2), 'R'); + ASSERT_EQ(decoder.d(3), 'U'); + ASSERT_EQ(decoder.d(4), 'S'); + ASSERT_EQ(decoder.d(5), 'D'); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup6) +{ + AddAsciiBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD("EURUSD"); + AddAsciiBeforeGroupV1::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV1::sbeBlockLength(), + AddAsciiBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + ASSERT_EQ(decoder.dLength(), 6u); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue1) +{ + AddAsciiBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + AddAsciiBeforeGroupV0::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + ASSERT_EQ(decoder.d(0), AddAsciiBeforeGroupV1::dNullValue()); + ASSERT_EQ(decoder.d(1), AddAsciiBeforeGroupV1::dNullValue()); + ASSERT_EQ(decoder.d(2), AddAsciiBeforeGroupV1::dNullValue()); + ASSERT_EQ(decoder.d(3), AddAsciiBeforeGroupV1::dNullValue()); + ASSERT_EQ(decoder.d(4), AddAsciiBeforeGroupV1::dNullValue()); + ASSERT_EQ(decoder.d(5), AddAsciiBeforeGroupV1::dNullValue()); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue2) +{ + AddAsciiBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + AddAsciiBeforeGroupV0::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + char d[6]; + ASSERT_EQ(decoder.getD(d, 6), 0u); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue3) +{ + AddAsciiBeforeGroupV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + AddAsciiBeforeGroupV0::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV0::sbeBlockLength(), + 0, + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + ASSERT_EQ(decoder.getDAsString(), ""); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsNewDecoderToSkipPresentButAddedAsciiFieldBeforeGroup) +{ + AddAsciiBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD("EURUSD"); + AddAsciiBeforeGroupV1::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV1 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV1::sbeBlockLength(), + AddAsciiBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddAsciiBeforeGroupV1::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsOldDecoderToSkipAddedAsciiFieldBeforeGroup) +{ + AddAsciiBeforeGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + encoder.putD("EURUSD"); + AddAsciiBeforeGroupV1::B &bGroup = encoder.bCount(1); + bGroup.next().c(2); + encoder.checkEncodingIsComplete(); + + AddAsciiBeforeGroupV0 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddAsciiBeforeGroupV1::sbeBlockLength(), + AddAsciiBeforeGroupV1::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + AddAsciiBeforeGroupV0::B &b = decoder.b(); + EXPECT_EQ(b.count(), 1u); + EXPECT_EQ(b.next().c(), 2); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodeAndDecodeOfMessagesWithNoBlock) +{ + NoBlock encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.putA("abc"); + encoder.checkEncodingIsComplete(); + + NoBlock decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + NoBlock::sbeBlockLength(), + NoBlock::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.getAAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodeAndDecodeOfGroupsWithNoBlock) +{ + GroupWithNoBlock encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + GroupWithNoBlock::A &aGroup = encoder.aCount(1); + aGroup.next().putB("abc"); + encoder.checkEncodingIsComplete(); + + GroupWithNoBlock decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + GroupWithNoBlock::sbeBlockLength(), + GroupWithNoBlock::sbeSchemaVersion(), + BUFFER_LEN + ); + GroupWithNoBlock::A &a = decoder.a(); + EXPECT_EQ(a.count(), 1u); + EXPECT_EQ(a.next().getBAsString(), "abc"); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingElementOfEmptyGroup1) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + MultipleGroups::B &bGroup = encoder.bCount(0); + MultipleGroups::D &dGroup = encoder.dCount(1); + dGroup.next().e(43); + + EXPECT_THROW( + { + try + { + bGroup.c(44); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.c\" in state: V0_D_1_BLOCK")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingElementOfEmptyGroup2) +{ + NestedGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + NestedGroups::B &bGroup = encoder.bCount(1); + bGroup.next(); + bGroup.c(43); + NestedGroups::B::D &dGroup = bGroup.dCount(0); + bGroup.fCount(0); + encoder.hCount(0); + + EXPECT_THROW( + { + try + { + dGroup.e(44); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.d.e\" in state: V0_H_DONE")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingElementOfEmptyGroup3) +{ + NestedGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + NestedGroups::B &bGroup = encoder.bCount(1); + bGroup.next(); + bGroup.c(43); + NestedGroups::B::D &dGroup = bGroup.dCount(0); + bGroup.fCount(0); + + EXPECT_THROW( + { + try + { + dGroup.e(44); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.d.e\" in state: V0_B_1_F_DONE")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingElementOfEmptyGroup4) +{ + AddPrimitiveInsideGroupV1 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + AddPrimitiveInsideGroupV1::B &bGroup = encoder.bCount(0); + + EXPECT_THROW( + { + try + { + bGroup.c(43); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.c\" in state: V1_B_DONE")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsEncodingElementOfEmptyGroup5) +{ + GroupAndVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + GroupAndVarLength::B &bGroup = encoder.bCount(0); + encoder.putD("abc"); + + EXPECT_THROW( + { + try + { + bGroup.c(43); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr("Cannot access field \"b.c\" in state: V0_D_DONE")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingNestedGroupWithVarDataInSchemaDefinedOrder) +{ + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + NestedGroupWithVarLength::B &bGroup = encoder.bCount(3); + bGroup.next().c(2).dCount(0); + bGroup.next().c(3).dCount(1).next().e(4).putF("abc"); + bGroup.next().c(5).dCount(2).next().e(6).putF("def").next().e(7).putF("ghi"); + encoder.checkEncodingIsComplete(); + + NestedGroupWithVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + NestedGroupWithVarLength::sbeBlockLength(), + NestedGroupWithVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + NestedGroupWithVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 3u); + EXPECT_EQ(bDecoder.next().c(), 2); + NestedGroupWithVarLength::B::D &dDecoder1 = bDecoder.d(); + EXPECT_EQ(dDecoder1.count(), 0u); + EXPECT_EQ(bDecoder.next().c(), 3); + NestedGroupWithVarLength::B::D &dDecoder2 = bDecoder.d(); + EXPECT_EQ(dDecoder2.count(), 1u); + EXPECT_EQ(dDecoder2.next().e(), 4); + EXPECT_EQ(dDecoder2.getFAsString(), "abc"); + EXPECT_EQ(bDecoder.next().c(), 5); + NestedGroupWithVarLength::B::D &dDecoder3 = bDecoder.d(); + EXPECT_EQ(dDecoder3.count(), 2u); + EXPECT_EQ(dDecoder3.next().e(), 6); + EXPECT_EQ(dDecoder3.getFAsString(), "def"); + EXPECT_EQ(dDecoder3.next().e(), 7); + EXPECT_EQ(dDecoder3.getFAsString(), "ghi"); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedEncodingOfVarLengthFieldInNestedGroupToNextInnerElement1) +{ + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + NestedGroupWithVarLength::B &bGroup = encoder.bCount(1); + NestedGroupWithVarLength::B::D &dGroup = bGroup.next().c(5).dCount(2); + dGroup.next().e(7); + + EXPECT_THROW( + { + try + { + dGroup.next(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Cannot access next element in repeating group \"b.d\" in state: V0_B_1_D_N_BLOCK")); + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedEncodingOfVarLengthFieldInNestedGroupToNextInnerElement2) +{ + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + NestedGroupWithVarLength::B &bGroup = encoder.bCount(2); + NestedGroupWithVarLength::B::D &dGroup = bGroup.next().c(5).dCount(2); + dGroup.next().e(7); + + EXPECT_THROW( + { + try + { + dGroup.next(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Cannot access next element in repeating group \"b.d\" in state: V0_B_N_D_N_BLOCK")); + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextInnerElement1) +{ + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + NestedGroupWithVarLength::B &bGroup = encoder.bCount(1); + NestedGroupWithVarLength::B::D &dGroup = bGroup.next().c(2).dCount(2); + dGroup.next().e(3).putF("abc"); + dGroup.next().e(4).putF("def"); + encoder.checkEncodingIsComplete(); + + NestedGroupWithVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + NestedGroupWithVarLength::sbeBlockLength(), + NestedGroupWithVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + NestedGroupWithVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 1u); + EXPECT_EQ(bDecoder.next().c(), 2); + NestedGroupWithVarLength::B::D &dDecoder = bDecoder.d(); + EXPECT_EQ(dDecoder.count(), 2u); + EXPECT_EQ(dDecoder.next().e(), 3); + + EXPECT_THROW( + { + try + { + dDecoder.next(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Cannot access next element in repeating group \"b.d\" in state: V0_B_1_D_N_BLOCK.")); + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextInnerElement2) +{ + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + NestedGroupWithVarLength::B &bGroup = encoder.bCount(2); + NestedGroupWithVarLength::B::D &dGroup = bGroup.next().c(2).dCount(2); + dGroup.next().e(3).putF("abc"); + dGroup.next().e(4).putF("def"); + bGroup.next().c(5).dCount(0); + encoder.checkEncodingIsComplete(); + + NestedGroupWithVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + NestedGroupWithVarLength::sbeBlockLength(), + NestedGroupWithVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + NestedGroupWithVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 2); + NestedGroupWithVarLength::B::D &dDecoder = bDecoder.d(); + EXPECT_EQ(dDecoder.count(), 2u); + EXPECT_EQ(dDecoder.next().e(), 3); + + EXPECT_THROW( + { + try + { + dDecoder.next(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Cannot access next element in repeating group \"b.d\" in state: V0_B_N_D_N_BLOCK.")); + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextOuterElement1) +{ + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + NestedGroupWithVarLength::B &bGroup = encoder.bCount(2); + NestedGroupWithVarLength::B::D &dGroup = bGroup.next().c(2).dCount(2); + dGroup.next().e(3).putF("abc"); + dGroup.next().e(4).putF("def"); + bGroup.next().c(5).dCount(0); + encoder.checkEncodingIsComplete(); + + NestedGroupWithVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + NestedGroupWithVarLength::sbeBlockLength(), + NestedGroupWithVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + NestedGroupWithVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 2); + NestedGroupWithVarLength::B::D &dDecoder = bDecoder.d(); + EXPECT_EQ(dDecoder.count(), 2u); + EXPECT_EQ(dDecoder.next().e(), 3); + + EXPECT_THROW( + { + try + { + bDecoder.next(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Cannot access next element in repeating group \"b\" in state: V0_B_N_D_N_BLOCK.")); + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextOuterElement2) +{ + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + NestedGroupWithVarLength::B &bGroup = encoder.bCount(2); + NestedGroupWithVarLength::B::D &dGroup = bGroup.next().c(2).dCount(1); + dGroup.next().e(3).putF("abc"); + bGroup.next().c(5).dCount(0); + encoder.checkEncodingIsComplete(); + + NestedGroupWithVarLength decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + NestedGroupWithVarLength::sbeBlockLength(), + NestedGroupWithVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + EXPECT_EQ(decoder.a(), 1); + NestedGroupWithVarLength::B &bDecoder = decoder.b(); + EXPECT_EQ(bDecoder.count(), 2u); + EXPECT_EQ(bDecoder.next().c(), 2); + NestedGroupWithVarLength::B::D &dDecoder = bDecoder.d(); + EXPECT_EQ(dDecoder.count(), 1u); + EXPECT_EQ(dDecoder.next().e(), 3); + + EXPECT_THROW( + { + try + { + bDecoder.next(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Cannot access next element in repeating group \"b\" in state: V0_B_N_D_1_BLOCK.")); + EXPECT_THAT(e.what(), + testing::HasSubstr( + "Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsIncompleteMessagesDueToMissingVarLengthField1) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).putB("abc"); + + EXPECT_THROW( + { + try + { + encoder.checkEncodingIsComplete(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), + testing::HasSubstr( + std::string("Not fully encoded, current state: V0_B_DONE, ") + + "allowed transitions: \"cLength()\", \"c(?)\"")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsIncompleteMessagesDueToMissingVarLengthField2) +{ + NoBlock encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + + EXPECT_THROW( + { + try + { + encoder.checkEncodingIsComplete(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), + testing::HasSubstr( + std::string("Not fully encoded, current state: V0_BLOCK, ") + + "allowed transitions: \"aLength()\", \"a(?)\"")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsIncompleteMessagesDueToMissingTopLevelGroup1) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).bCount(0); + + EXPECT_THROW( + { + try + { + encoder.checkEncodingIsComplete(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr( + "Not fully encoded, current state: V0_B_DONE, allowed transitions:" + " \"b.resetCountToIndex()\", \"dCount(0)\", \"dCount(>0)\"")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsIncompleteMessagesDueToMissingTopLevelGroup2) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).bCount(1).next().c(2); + + EXPECT_THROW( + { + try + { + encoder.checkEncodingIsComplete(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr( + "Not fully encoded, current state: V0_B_1_BLOCK, allowed transitions: " + "\"b.c(?)\", \"b.resetCountToIndex()\", \"dCount(0)\", \"dCount(>0)\"")); + throw e; + } + }, + std::logic_error + ); +} + +TEST_F(FieldAccessOrderCheckTest, disallowsIncompleteMessagesDueToMissingTopLevelGroup3) +{ + MultipleGroups encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1); + + EXPECT_THROW( + { + try + { + encoder.checkEncodingIsComplete(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr( + "Not fully encoded, current state: V0_BLOCK, allowed transitions: " + "\"a(?)\", \"bCount(0)\", \"bCount(>0)\"")); + throw e; + } + }, + std::logic_error + ); +} + +class DisallowsIncompleteMessagesPart1Test : public FieldAccessOrderCheckTest, + public testing::WithParamInterface> +{ +}; + +TEST_P(DisallowsIncompleteMessagesPart1Test, disallowsIncompleteMessagesDueToMissingNestedGroup1) +{ + const auto bCount = std::get<0>(GetParam()); + const auto expectedState = std::get<1>(GetParam()); + + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).bCount(bCount).next().c(2); + + EXPECT_THROW( + { + try + { + encoder.checkEncodingIsComplete(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr( + "Not fully encoded, current state: " + expectedState)); + throw e; + } + }, + std::logic_error + ); +} + +INSTANTIATE_TEST_SUITE_P( + FieldAccessOrderCheckTest, + DisallowsIncompleteMessagesPart1Test, + testing::Values( + std::make_tuple(1, "V0_B_1_BLOCK"), + std::make_tuple(2, "V0_B_N_BLOCK") + ) +); + +class DisallowsIncompleteMessagesPart2Test : public FieldAccessOrderCheckTest, + public testing::WithParamInterface> +{ +}; + +TEST_P(DisallowsIncompleteMessagesPart2Test, disallowsIncompleteMessagesDueToMissingNestedGroup2) +{ + const auto bCount = std::get<0>(GetParam()); + const auto dCount = std::get<1>(GetParam()); + const auto expectedState = std::get<2>(GetParam()); + + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).bCount(bCount).next().c(2).dCount(dCount); + + EXPECT_THROW( + { + try + { + encoder.checkEncodingIsComplete(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr( + "Not fully encoded, current state: " + expectedState)); + throw e; + } + }, + std::logic_error + ); +} + +INSTANTIATE_TEST_SUITE_P( + FieldAccessOrderCheckTest, + DisallowsIncompleteMessagesPart2Test, + testing::Values( + std::make_tuple(1, 1, "V0_B_1_D_N"), + std::make_tuple(1, 2, "V0_B_1_D_N"), + std::make_tuple(2, 0, "V0_B_N_D_DONE"), + std::make_tuple(2, 1, "V0_B_N_D_N"), + std::make_tuple(2, 2, "V0_B_N_D_N") + ) +); + +class DisallowsIncompleteMessagesPart3Test : public FieldAccessOrderCheckTest, + public testing::WithParamInterface> +{ +}; + +TEST_P(DisallowsIncompleteMessagesPart3Test, disallowsIncompleteMessagesDueToMissingVarDataInNestedGroup) +{ + const auto bCount = std::get<0>(GetParam()); + const auto dCount = std::get<1>(GetParam()); + const auto expectedState = std::get<2>(GetParam()); + + NestedGroupWithVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(1).bCount(bCount).next().c(2).dCount(dCount).next().e(10); + + EXPECT_THROW( + { + try + { + encoder.checkEncodingIsComplete(); + } + catch (const std::logic_error &e) + { + EXPECT_THAT(e.what(), testing::HasSubstr( + "Not fully encoded, current state: " + expectedState)); + throw e; + } + }, + std::logic_error + ); +} + +INSTANTIATE_TEST_SUITE_P( + FieldAccessOrderCheckTest, + DisallowsIncompleteMessagesPart3Test, + testing::Values( + std::make_tuple(1, 1, "V0_B_1_D_1_BLOCK"), + std::make_tuple(1, 2, "V0_B_1_D_N_BLOCK"), + std::make_tuple(2, 1, "V0_B_N_D_1_BLOCK"), + std::make_tuple(2, 2, "V0_B_N_D_N_BLOCK") + ) +); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java new file mode 100644 index 0000000000..97d51b199c --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java @@ -0,0 +1,3425 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe; + +import order.check.*; +import org.agrona.ExpandableArrayBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.UnsafeBuffer; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.nio.charset.StandardCharsets; +import java.util.Random; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assumptions.assumeFalse; + +public class FieldAccessOrderCheckTest +{ + private static final Class INCORRECT_ORDER_EXCEPTION_CLASS = IllegalStateException.class; + private static final int OFFSET = 0; + private final MutableDirectBuffer buffer = new ExpandableArrayBuffer(); + private final MessageHeaderEncoder messageHeaderEncoder = new MessageHeaderEncoder(); + private final MessageHeaderDecoder messageHeaderDecoder = new MessageHeaderDecoder(); + + @BeforeAll + static void assumeDebugMode() + { + final boolean productionMode = Boolean.getBoolean("agrona.disable.bounds.checks"); + assumeFalse(productionMode); + } + + @BeforeEach + void setUp() + { + new Random().nextBytes(buffer.byteArray()); + } + + @Test + void allowsEncodingAndDecodingVariableLengthFieldsInSchemaDefinedOrder() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.b("abc"); + encoder.c("def"); + encoder.checkEncodingIsComplete(); + + final MultipleVarLengthDecoder decoder = new MultipleVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b(), equalTo("abc")); + assertThat(decoder.c(), equalTo("def")); + assertThat(decoder.toString(), containsString("a=42|b='abc'|c='def'")); + } + + @Test + void allowsDecodingVariableLengthFieldsAfterRewind() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.b("abc"); + encoder.c("def"); + encoder.checkEncodingIsComplete(); + + final MultipleVarLengthDecoder decoder = new MultipleVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b(), equalTo("abc")); + assertThat(decoder.c(), equalTo("def")); + assertThat(decoder.toString(), containsString("a=42|b='abc'|c='def'")); + + decoder.sbeRewind(); + + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b(), equalTo("abc")); + assertThat(decoder.c(), equalTo("def")); + assertThat(decoder.toString(), containsString("a=42|b='abc'|c='def'")); + } + + @Test + void allowsDecodingToSkipVariableLengthFields() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.b("abc"); + encoder.c("def"); + encoder.checkEncodingIsComplete(); + + final MultipleVarLengthDecoder decoder = new MultipleVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.skipB(), equalTo(3)); + assertThat(decoder.c(), equalTo("def")); + assertThat(decoder.toString(), containsString("a=42|b='abc'|c='def'")); + } + + @Test + void allowsReEncodingTopLevelPrimitiveFields() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.b("abc"); + encoder.c("def"); + encoder.a(43); + encoder.checkEncodingIsComplete(); + + final MultipleVarLengthDecoder decoder = new MultipleVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(43)); + assertThat(decoder.b(), equalTo("abc")); + assertThat(decoder.c(), equalTo("def")); + } + + @Test + void disallowsSkippingEncodingOfVariableLengthField1() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.c("def")); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void disallowsSkippingEncodingOfVariableLengthField2() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final CharSequence def = new StringBuilder("def"); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.c(def)); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void disallowsSkippingEncodingOfVariableLengthField3() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final byte[] value = "def".getBytes(StandardCharsets.US_ASCII); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.putC(value, 0, value.length)); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void disallowsSkippingEncodingOfVariableLengthField4() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final byte[] value = "def".getBytes(StandardCharsets.US_ASCII); + final UnsafeBuffer buffer = new UnsafeBuffer(value); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.putC(buffer, 0, buffer.capacity())); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void disallowsReEncodingEarlierVariableLengthFields() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.b("abc"); + encoder.c("def"); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.b("ghi")); + assertThat(exception.getMessage(), containsString("Cannot access field \"b\" in state: V0_C_DONE")); + } + + @Test + void disallowsReEncodingLatestVariableLengthField() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.b("abc"); + encoder.c("def"); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.c("ghi")); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_C_DONE")); + } + + @Test + void disallowsSkippingDecodingOfVariableLengthField1() + { + final MultipleVarLengthDecoder decoder = decodeUntilVarLengthFields(); + + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void disallowsSkippingDecodingOfVariableLengthField2() + { + final MultipleVarLengthDecoder decoder = decodeUntilVarLengthFields(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> decoder.wrapC(new UnsafeBuffer())); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void disallowsSkippingDecodingOfVariableLengthField3() + { + final MultipleVarLengthDecoder decoder = decodeUntilVarLengthFields(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> decoder.getC(new StringBuilder())); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void disallowsSkippingDecodingOfVariableLengthField4() + { + final MultipleVarLengthDecoder decoder = decodeUntilVarLengthFields(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> decoder.getC(new byte[3], 0, 3)); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void disallowsSkippingDecodingOfVariableLengthField5() + { + final MultipleVarLengthDecoder decoder = decodeUntilVarLengthFields(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> decoder.getC(new ExpandableArrayBuffer(), 0, 3)); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_BLOCK")); + } + + @Test + void allowsRepeatedDecodingOfVariableLengthDataLength() + { + final MultipleVarLengthDecoder decoder = decodeUntilVarLengthFields(); + assertThat(decoder.bLength(), equalTo(3)); + assertThat(decoder.bLength(), equalTo(3)); + assertThat(decoder.bLength(), equalTo(3)); + assertThat(decoder.b(), equalTo("abc")); + assertThat(decoder.cLength(), equalTo(3)); + assertThat(decoder.cLength(), equalTo(3)); + assertThat(decoder.cLength(), equalTo(3)); + } + + @Test + void disallowsReDecodingEarlierVariableLengthField() + { + final MultipleVarLengthDecoder decoder = decodeUntilVarLengthFields(); + assertThat(decoder.b(), equalTo("abc")); + assertThat(decoder.c(), equalTo("def")); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::b); + assertThat(exception.getMessage(), containsString("Cannot access field \"b\" in state: V0_C_DONE")); + } + + @Test + void disallowsReDecodingLatestVariableLengthField() + { + final MultipleVarLengthDecoder decoder = decodeUntilVarLengthFields(); + assertThat(decoder.b(), equalTo("abc")); + assertThat(decoder.c(), equalTo("def")); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"c\" in state: V0_C_DONE")); + } + + private MultipleVarLengthDecoder decodeUntilVarLengthFields() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.b("abc"); + encoder.c("def"); + encoder.checkEncodingIsComplete(); + + final MultipleVarLengthDecoder decoder = new MultipleVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + return decoder; + } + + @Test + void allowsEncodingAndDecodingGroupAndVariableLengthFieldsInSchemaDefinedOrder() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + assertThat(bs.next().c(), equalTo(2)); + assertThat(decoder.d(), equalTo("abc")); + assertThat(decoder.toString(), containsString("a=42|b=[(c=1),(c=2)]|d='abc'")); + } + + @Test + void allowsEncoderToResetZeroGroupLengthToZero() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(0).resetCountToIndex(); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(0)); + assertThat(decoder.d(), equalTo("abc")); + assertThat(decoder.toString(), containsString("a=42|b=[]|d='abc'")); + } + + @Test + void allowsEncoderToResetNonZeroGroupLengthToZeroBeforeCallingNext() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2).resetCountToIndex(); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(0)); + assertThat(decoder.d(), equalTo("abc")); + assertThat(decoder.toString(), containsString("a=42|b=[]|d='abc'")); + } + + @Test + void allowsEncoderToResetNonZeroGroupLengthToNonZero() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2).next().c(43).resetCountToIndex(); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(1)); + assertThat(bs.next().c(), equalTo(43)); + assertThat(decoder.d(), equalTo("abc")); + assertThat(decoder.toString(), containsString("a=42|b=[(c=43)]|d='abc'")); + } + + @Test + void disallowsEncoderToResetGroupLengthMidGroupElement() + { + final NestedGroupsEncoder encoder = new NestedGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final NestedGroupsEncoder.BEncoder bEncoder = encoder.bCount(2).next().c(43); + final IllegalStateException exception = assertThrows(IllegalStateException.class, bEncoder::resetCountToIndex); + assertThat(exception.getMessage(), + containsString("Cannot reset count of repeating group \"b\" in state: V0_B_N_BLOCK")); + } + + @Test + void allowsDecodingGroupAndVariableLengthFieldsAfterRewind() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + assertThat(bs.next().c(), equalTo(2)); + assertThat(decoder.d(), equalTo("abc")); + assertThat(decoder.toString(), containsString("a=42|b=[(c=1),(c=2)]|d='abc'")); + + decoder.sbeRewind(); + + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs2 = decoder.b(); + assertThat(bs2.count(), equalTo(2)); + assertThat(bs2.next().c(), equalTo(1)); + assertThat(bs2.next().c(), equalTo(2)); + assertThat(decoder.d(), equalTo("abc")); + assertThat(decoder.toString(), containsString("a=42|b=[(c=1),(c=2)]|d='abc'")); + } + + @Test + void allowsDecodingToSkipMessage() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final int nextEncodeOffset = encoder.limit(); + encoder.wrapAndApplyHeader(buffer, nextEncodeOffset, messageHeaderEncoder); + encoder.a(43); + encoder.bCount(2) + .next() + .c(3) + .next() + .c(4); + encoder.d("def"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + + decoder.sbeSkip(); + final int nextDecodeOffset = decoder.limit(); + assertThat(nextDecodeOffset, equalTo(nextEncodeOffset)); + + decoder.wrapAndApplyHeader(buffer, nextDecodeOffset, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(43)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(3)); + assertThat(bs.next().c(), equalTo(4)); + assertThat(decoder.d(), equalTo("def")); + } + + @Test + void allowsDecodingToDetermineMessageLengthBeforeReadingFields() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(43); + encoder.bCount(2) + .next() + .c(3) + .next() + .c(4); + encoder.d("def"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + + assertThat(decoder.sbeDecodedLength(), equalTo(18)); + assertThat(decoder.a(), equalTo(43)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(3)); + assertThat(bs.next().c(), equalTo(4)); + assertThat(decoder.d(), equalTo("def")); + } + + @Test + void allowsEncodingAndDecodingEmptyGroupAndVariableLengthFieldsInSchemaDefinedOrder() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(0); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(0)); + assertThat(decoder.d(), equalTo("abc")); + assertThat(decoder.toString(), containsString("a=42|b=[]|d='abc'")); + } + + @Test + @Disabled("Our access checks are too strict to allow the behaviour in this test.") + void allowsReEncodingPrimitiveFieldInGroupElementAfterTopLevelVariableLengthField() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final GroupAndVarLengthEncoder.BEncoder bEncoder = encoder.bCount(2); + bEncoder + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + bEncoder.c(3); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + assertThat(bs.next().c(), equalTo(3)); + assertThat(decoder.d(), equalTo("abc")); + } + + @Test + @Disabled("Our access checks are too strict to allow the behaviour in this test.") + void allowsReWrappingGroupDecoderAfterAccessingGroupCount() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final GroupAndVarLengthEncoder.BEncoder bEncoder = encoder.bCount(2); + bEncoder + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b().count(), equalTo(2)); + final GroupAndVarLengthDecoder.BDecoder b = decoder.b(); + assertThat(b.next().c(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + assertThat(decoder.d(), equalTo("abc")); + } + + @Test + void disallowsEncodingGroupElementBeforeCallingNext() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final GroupAndVarLengthEncoder.BEncoder bEncoder = encoder.bCount(1); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.c(1)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingGroupElementBeforeCallingNext() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, bs::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsSkippingEncodingOfGroup() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.d("abc")); + assertThat(exception.getMessage(), containsString("Cannot access field \"d\" in state: V0_BLOCK")); + } + + @Test + void disallowsReEncodingVariableLengthFieldAfterGroup() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.d("def")); + assertThat(exception.getMessage(), containsString("Cannot access field \"d\" in state: V0_D_DONE")); + } + + @Test + void disallowsReEncodingGroupCount() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.bCount(1)); + assertThat(exception.getMessage(), + containsString("Cannot encode count of repeating group \"b\" in state: V0_D_DONE")); + } + + @Test + @Disabled("Our access checks are too strict to allow the behaviour in this test.") + void allowsReEncodingGroupElementBlockFieldAfterTopLevelVariableLengthField() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final GroupAndVarLengthEncoder.BEncoder b = encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + b.c(3); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + assertThat(bs.next().c(), equalTo(3)); + assertThat(decoder.d(), equalTo("abc")); + } + + @Test + void disallowsMissedDecodingOfGroupBeforeVariableLengthField() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::d); + assertThat(exception.getMessage(), containsString("Cannot access field \"d\" in state: V0_BLOCK")); + } + + @Test + void disallowsReDecodingVariableLengthFieldAfterGroup() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + assertThat(bs.next().c(), equalTo(2)); + assertThat(decoder.d(), equalTo("abc")); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::d); + assertThat(exception.getMessage(), containsString("Cannot access field \"d\" in state: V0_D_DONE")); + } + + @Test + void disallowsReDecodingGroupAfterVariableLengthField() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .next() + .c(2); + encoder.d("abc"); + encoder.checkEncodingIsComplete(); + + final GroupAndVarLengthDecoder decoder = new GroupAndVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final GroupAndVarLengthDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + assertThat(bs.next().c(), equalTo(2)); + assertThat(decoder.d(), equalTo("abc")); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::b); + assertThat(exception.getMessage(), + containsString("Cannot decode count of repeating group \"b\" in state: V0_D_DONE")); + } + + @Test + void allowsEncodingAndDecodingVariableLengthFieldInsideGroupInSchemaDefinedOrder() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .d("abc") + .next() + .c(2) + .d("def"); + encoder.e("ghi"); + encoder.checkEncodingIsComplete(); + + final VarLengthInsideGroupDecoder decoder = new VarLengthInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final VarLengthInsideGroupDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + assertThat(bs.d(), equalTo("abc")); + assertThat(bs.next().c(), equalTo(2)); + assertThat(bs.d(), equalTo("def")); + assertThat(decoder.e(), equalTo("ghi")); + assertThat(decoder.toString(), containsString("a=42|b=[(c=1|d='abc'),(c=2|d='def')]|e='ghi'")); + } + + @Test + @Disabled("Our access checks are too strict to allow the behaviour in this test.") + void allowsReEncodingGroupElementPrimitiveFieldAfterElementVariableLengthField() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final VarLengthInsideGroupEncoder.BEncoder bEncoder = encoder.bCount(1); + bEncoder + .next() + .c(1) + .d("abc"); + bEncoder.c(2); + encoder.e("ghi"); + encoder.checkEncodingIsComplete(); + + final VarLengthInsideGroupDecoder decoder = new VarLengthInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final VarLengthInsideGroupDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(1)); + assertThat(bs.next().c(), equalTo(2)); + assertThat(bs.d(), equalTo("abc")); + assertThat(decoder.e(), equalTo("ghi")); + } + + @Test + void disallowsMissedGroupElementVariableLengthFieldToEncodeAtTopLevel() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(1).next().c(1); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.e("abc")); + assertThat(exception.getMessage(), containsString("Cannot access field \"e\" in state: V0_B_1_BLOCK")); + } + + @Test + void disallowsMissedGroupElementVariableLengthFieldToEncodeNextElement() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final VarLengthInsideGroupEncoder.BEncoder b = encoder.bCount(2) + .next(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, b::next); + assertThat(exception.getMessage(), + containsString("Cannot access next element in repeating group \"b\" in state: V0_B_N_BLOCK")); + } + + @Test + void disallowsMissedGroupElementEncoding() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .d("abc"); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.e("abc")); + assertThat(exception.getMessage(), containsString("Cannot access field \"e\" in state: V0_B_N_D_DONE")); + } + + @Test + void disallowsReEncodingGroupElementVariableLengthField() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final VarLengthInsideGroupEncoder.BEncoder b = encoder.bCount(1) + .next() + .c(1) + .d("abc"); + encoder.e("def"); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.d("ghi")); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.d\" in state: V0_E_DONE")); + } + + @Test + void disallowsReDecodingGroupElementVariableLengthField() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .d("abc") + .next() + .c(2) + .d("def"); + encoder.e("ghi"); + encoder.checkEncodingIsComplete(); + + final VarLengthInsideGroupDecoder decoder = new VarLengthInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final VarLengthInsideGroupDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + assertThat(bs.d(), equalTo("abc")); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, bs::d); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.d\" in state: V0_B_N_D_DONE")); + } + + @Test + void disallowsMissedDecodingOfGroupElementVariableLengthFieldToNextElement() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .d("abc") + .next() + .c(2) + .d("def"); + encoder.e("ghi"); + encoder.checkEncodingIsComplete(); + + final VarLengthInsideGroupDecoder decoder = new VarLengthInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final VarLengthInsideGroupDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, bs::next); + assertThat(exception.getMessage(), + containsString("Cannot access next element in repeating group \"b\" in state: V0_B_N_BLOCK")); + } + + @Test + void disallowsMissedDecodingOfGroupElementVariableLengthFieldToTopLevel() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(1) + .next() + .c(1) + .d("abc"); + encoder.e("ghi"); + encoder.checkEncodingIsComplete(); + + final VarLengthInsideGroupDecoder decoder = new VarLengthInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final VarLengthInsideGroupDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(1)); + assertThat(bs.next().c(), equalTo(1)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::e); + assertThat(exception.getMessage(), containsString("Cannot access field \"e\" in state: V0_B_1_BLOCK")); + } + + @Test + void disallowsMissedDecodingOfGroupElement() + { + final VarLengthInsideGroupEncoder encoder = new VarLengthInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(2) + .next() + .c(1) + .d("abc") + .next() + .c(2) + .d("def"); + encoder.e("ghi"); + encoder.checkEncodingIsComplete(); + + final VarLengthInsideGroupDecoder decoder = new VarLengthInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final VarLengthInsideGroupDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + assertThat(bs.next().c(), equalTo(1)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::e); + assertThat(exception.getMessage(), containsString("Cannot access field \"e\" in state: V0_B_N_BLOCK")); + } + + @Test + void allowsEncodingNestedGroupsInSchemaDefinedOrder() + { + final NestedGroupsEncoder encoder = new NestedGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final NestedGroupsEncoder.BEncoder b = encoder.bCount(2) + .next(); + b.c(1); + b.dCount(2) + .next() + .e(2) + .next() + .e(3); + b.fCount(1) + .next() + .g(4); + b.next(); + b.c(5); + b.dCount(1) + .next() + .e(6); + b.fCount(1) + .next() + .g(7); + encoder.hCount(1) + .next() + .i(8); + encoder.checkEncodingIsComplete(); + + final NestedGroupsDecoder decoder = new NestedGroupsDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final NestedGroupsDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(2)); + final NestedGroupsDecoder.BDecoder b0 = bs.next(); + assertThat(b0.c(), equalTo(1)); + final NestedGroupsDecoder.BDecoder.DDecoder b0ds = b0.d(); + assertThat(b0ds.count(), equalTo(2)); + assertThat(b0ds.next().e(), equalTo(2)); + assertThat(b0ds.next().e(), equalTo(3)); + final NestedGroupsDecoder.BDecoder.FDecoder b0fs = b0.f(); + assertThat(b0fs.count(), equalTo(1)); + assertThat(b0fs.next().g(), equalTo(4)); + final NestedGroupsDecoder.BDecoder b1 = bs.next(); + assertThat(b1.c(), equalTo(5)); + final NestedGroupsDecoder.BDecoder.DDecoder b1ds = b1.d(); + assertThat(b1ds.count(), equalTo(1)); + assertThat(b1ds.next().e(), equalTo(6)); + final NestedGroupsDecoder.BDecoder.FDecoder b1fs = b1.f(); + assertThat(b1fs.count(), equalTo(1)); + assertThat(b1fs.next().g(), equalTo(7)); + final NestedGroupsDecoder.HDecoder hs = decoder.h(); + assertThat(hs.count(), equalTo(1)); + assertThat(hs.next().i(), equalTo(8)); + assertThat(decoder.toString(), + containsString("a=42|b=[(c=1|d=[(e=2),(e=3)]|f=[(g=4)]),(c=5|d=[(e=6)]|f=[(g=7)])]|h=[(i=8)]")); + } + + @Test + void allowsEncodingEmptyNestedGroupsInSchemaDefinedOrder() + { + final NestedGroupsEncoder encoder = new NestedGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(0); + encoder.hCount(0); + encoder.checkEncodingIsComplete(); + + final NestedGroupsDecoder decoder = new NestedGroupsDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + final NestedGroupsDecoder.BDecoder bs = decoder.b(); + assertThat(bs.count(), equalTo(0)); + final NestedGroupsDecoder.HDecoder hs = decoder.h(); + assertThat(hs.count(), equalTo(0)); + assertThat(decoder.toString(), containsString("a=42|b=[]|h=[]")); + } + + @Test + void disallowsMissedEncodingOfNestedGroup() + { + final NestedGroupsEncoder encoder = new NestedGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final NestedGroupsEncoder.BEncoder b = encoder.bCount(1) + .next() + .c(1); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.fCount(1)); + assertThat(exception.getMessage(), + containsString("Cannot encode count of repeating group \"b.f\" in state: V0_B_1_BLOCK")); + } + + @Test + void allowsEncodingAndDecodingCompositeInsideGroupInSchemaDefinedOrder() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + encoder.bCount(1) + .next() + .c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(1)); + assertThat(a.y(), equalTo(2)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c = b.next().c(); + assertThat(c.x(), equalTo(3)); + assertThat(c.y(), equalTo(4)); + assertThat(decoder.toString(), containsString("a=(x=1|y=2)|b=[(c=(x=3|y=4))]")); + } + + @Test + void disallowsEncodingCompositeInsideGroupBeforeCallingNext() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + final CompositeInsideGroupEncoder.BEncoder bEncoder = encoder.bCount(1); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, bEncoder::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingCompositeInsideGroupBeforeCallingNext() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + encoder.bCount(1) + .next() + .c().x(3).y(4); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(1)); + assertThat(a.y(), equalTo(2)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, b::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void allowsReEncodingTopLevelCompositeViaReWrap() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + encoder.bCount(1) + .next() + .c().x(3).y(4); + encoder.a().x(5).y(6); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(5)); + assertThat(a.y(), equalTo(6)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c = b.next().c(); + assertThat(c.x(), equalTo(3)); + assertThat(c.y(), equalTo(4)); + } + + @Test + void allowsReEncodingTopLevelCompositeViaEncoderReference() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + final PointEncoder aEncoder = encoder.a(); + aEncoder.x(1).y(2); + encoder.bCount(1) + .next() + .c().x(3).y(4); + aEncoder.x(5).y(6); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(5)); + assertThat(a.y(), equalTo(6)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c = b.next().c(); + assertThat(c.x(), equalTo(3)); + assertThat(c.y(), equalTo(4)); + } + + @Test + void allowsReEncodingGroupElementCompositeViaReWrap() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + final CompositeInsideGroupEncoder.BEncoder bEncoder = encoder.bCount(1).next(); + bEncoder.c().x(3).y(4); + bEncoder.c().x(5).y(6); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(1)); + assertThat(a.y(), equalTo(2)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c = b.next().c(); + assertThat(c.x(), equalTo(5)); + assertThat(c.y(), equalTo(6)); + } + + @Test + void allowsReEncodingGroupElementCompositeViaEncoderReference() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + final CompositeInsideGroupEncoder.BEncoder bEncoder = encoder.bCount(1).next(); + final PointEncoder cEncoder = bEncoder.c(); + cEncoder.x(3).y(4); + cEncoder.x(5).y(6); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(1)); + assertThat(a.y(), equalTo(2)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c = b.next().c(); + assertThat(c.x(), equalTo(5)); + assertThat(c.y(), equalTo(6)); + } + + @Test + void allowsReDecodingTopLevelCompositeViaReWrap() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + encoder.bCount(1) + .next() + .c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a1 = decoder.a(); + assertThat(a1.x(), equalTo(1)); + assertThat(a1.y(), equalTo(2)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c = b.next().c(); + assertThat(c.x(), equalTo(3)); + assertThat(c.y(), equalTo(4)); + final PointDecoder a2 = decoder.a(); + assertThat(a2.x(), equalTo(1)); + assertThat(a2.y(), equalTo(2)); + } + + @Test + void allowsReDecodingTopLevelCompositeViaEncoderReference() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + encoder.bCount(1) + .next() + .c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(1)); + assertThat(a.y(), equalTo(2)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c = b.next().c(); + assertThat(c.x(), equalTo(3)); + assertThat(c.y(), equalTo(4)); + assertThat(a.x(), equalTo(1)); + assertThat(a.y(), equalTo(2)); + } + + @Test + void allowsReDecodingGroupElementCompositeViaReWrap() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + encoder.bCount(1) + .next() + .c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(1)); + assertThat(a.y(), equalTo(2)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c1 = b.next().c(); + assertThat(c1.x(), equalTo(3)); + assertThat(c1.y(), equalTo(4)); + final PointDecoder c2 = b.c(); + assertThat(c2.x(), equalTo(3)); + assertThat(c2.y(), equalTo(4)); + } + + @Test + void allowsReDecodingGroupElementCompositeViaEncoderReference() + { + final CompositeInsideGroupEncoder encoder = new CompositeInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().x(1).y(2); + encoder.bCount(1) + .next() + .c().x(3).y(4); + encoder.checkEncodingIsComplete(); + + final CompositeInsideGroupDecoder decoder = new CompositeInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final PointDecoder a = decoder.a(); + assertThat(a.x(), equalTo(1)); + assertThat(a.y(), equalTo(2)); + final CompositeInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final PointDecoder c = b.next().c(); + assertThat(c.x(), equalTo(3)); + assertThat(c.y(), equalTo(4)); + assertThat(c.x(), equalTo(3)); + assertThat(c.y(), equalTo(4)); + } + + @Test + void allowsNewDecoderToDecodeAddedPrimitiveField() + { + final AddPrimitiveV1Encoder encoder = new AddPrimitiveV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).b(2); + encoder.checkEncodingIsComplete(); + + final AddPrimitiveV1Decoder decoder = new AddPrimitiveV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.b(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingPrimitiveFieldAsNullValue() + { + final AddPrimitiveV0Encoder encoder = new AddPrimitiveV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddPrimitiveV1Decoder decoder = new AddPrimitiveV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.b(), equalTo(AddPrimitiveV1Decoder.bNullValue())); + } + + @Test + void allowsNewDecoderToDecodeAddedPrimitiveFieldBeforeGroup() + { + final AddPrimitiveBeforeGroupV1Encoder encoder = new AddPrimitiveBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d(3).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + final AddPrimitiveBeforeGroupV1Decoder decoder = new AddPrimitiveBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(), equalTo(3)); + final AddPrimitiveBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingPrimitiveFieldBeforeGroupAsNullValue() + { + final AddPrimitiveBeforeGroupV0Encoder encoder = new AddPrimitiveBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddPrimitiveBeforeGroupV1Decoder decoder = new AddPrimitiveBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(), equalTo(AddPrimitiveBeforeGroupV1Decoder.dNullValue())); + final AddPrimitiveBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToSkipPresentButAddedPrimitiveFieldBeforeGroup() + { + final AddPrimitiveBeforeGroupV1Encoder encoder = new AddPrimitiveBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d(3).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + final AddPrimitiveBeforeGroupV1Decoder decoder = new AddPrimitiveBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddPrimitiveBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsOldDecoderToSkipAddedPrimitiveFieldBeforeGroup() + { + final AddPrimitiveBeforeGroupV1Encoder encoder = new AddPrimitiveBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d(3).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddPrimitiveBeforeGroupV0Decoder decoder = new AddPrimitiveBeforeGroupV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddPrimitiveBeforeGroupV0Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeAddedPrimitiveFieldBeforeVarData() + { + final AddPrimitiveBeforeVarDataV1Encoder encoder = new AddPrimitiveBeforeVarDataV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).c(3).b("abc"); + encoder.checkEncodingIsComplete(); + + final AddPrimitiveBeforeVarDataV1Decoder decoder = new AddPrimitiveBeforeVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.c(), equalTo(3)); + assertThat(decoder.b(), equalTo("abc")); + } + + @Test + void allowsNewDecoderToDecodeMissingPrimitiveFieldBeforeVarDataAsNullValue() + { + final AddPrimitiveBeforeVarDataV0Encoder encoder = new AddPrimitiveBeforeVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).b("abc"); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddPrimitiveBeforeVarDataV1Decoder decoder = new AddPrimitiveBeforeVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.c(), equalTo(AddPrimitiveBeforeVarDataV1Decoder.cNullValue())); + assertThat(decoder.b(), equalTo("abc")); + } + + @Test + void allowsNewDecoderToSkipPresentButAddedPrimitiveFieldBeforeVarData() + { + final AddPrimitiveBeforeVarDataV1Encoder encoder = new AddPrimitiveBeforeVarDataV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).c(3).b("abc"); + encoder.checkEncodingIsComplete(); + + final AddPrimitiveBeforeVarDataV1Decoder decoder = new AddPrimitiveBeforeVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.b(), equalTo("abc")); + } + + @Test + void allowsOldDecoderToSkipAddedPrimitiveFieldBeforeVarData() + { + final AddPrimitiveBeforeVarDataV1Encoder encoder = new AddPrimitiveBeforeVarDataV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).c(3).b("abc"); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddPrimitiveBeforeVarDataV0Decoder decoder = new AddPrimitiveBeforeVarDataV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.b(), equalTo("abc")); + } + + @Test + void allowsNewDecoderToDecodeAddedPrimitiveFieldInsideGroup() + { + final AddPrimitiveInsideGroupV1Encoder encoder = new AddPrimitiveInsideGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2).d(3); + encoder.checkEncodingIsComplete(); + + final AddPrimitiveInsideGroupV1Decoder decoder = new AddPrimitiveInsideGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddPrimitiveInsideGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + assertThat(b.d(), equalTo(3)); + } + + @Test + void allowsNewDecoderToDecodeMissingPrimitiveFieldInsideGroupAsNullValue() + { + final AddPrimitiveInsideGroupV0Encoder encoder = new AddPrimitiveInsideGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddPrimitiveInsideGroupV1Decoder decoder = new AddPrimitiveInsideGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddPrimitiveInsideGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + assertThat(b.d(), equalTo(AddPrimitiveInsideGroupV1Decoder.BDecoder.dNullValue())); + } + + @Test + void allowsNewDecoderToSkipPresentButAddedPrimitiveFieldInsideGroup() + { + final AddPrimitiveInsideGroupV1Encoder encoder = new AddPrimitiveInsideGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(2).next().c(2).d(3).next().c(4).d(5); + encoder.checkEncodingIsComplete(); + + final AddPrimitiveInsideGroupV1Decoder decoder = new AddPrimitiveInsideGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddPrimitiveInsideGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(2)); + assertThat(b.next().c(), equalTo(2)); + assertThat(b.next().c(), equalTo(4)); + } + + @Test + void allowsOldDecoderToSkipAddedPrimitiveFieldInsideGroup() + { + final AddPrimitiveInsideGroupV1Encoder encoder = new AddPrimitiveInsideGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(2).next().c(2).d(3).next().c(4).d(5); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddPrimitiveInsideGroupV0Decoder decoder = new AddPrimitiveInsideGroupV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddPrimitiveInsideGroupV0Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(2)); + assertThat(b.next().c(), equalTo(2)); + assertThat(b.next().c(), equalTo(4)); + } + + @Test + void allowsNewDecoderToDecodeAddedGroupBeforeVarData() + { + final AddGroupBeforeVarDataV1Encoder encoder = new AddGroupBeforeVarDataV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).cCount(1).next().d(2); + encoder.b("abc"); + encoder.checkEncodingIsComplete(); + + final AddGroupBeforeVarDataV1Decoder decoder = new AddGroupBeforeVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddGroupBeforeVarDataV1Decoder.CDecoder c = decoder.c(); + assertThat(c.count(), equalTo(1)); + assertThat(c.next().d(), equalTo(2)); + assertThat(decoder.b(), equalTo("abc")); + } + + @Test + void allowsNewDecoderToDecodeMissingGroupBeforeVarDataAsNullValue() + { + final AddGroupBeforeVarDataV0Encoder encoder = new AddGroupBeforeVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).b("abc"); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddGroupBeforeVarDataV1Decoder decoder = new AddGroupBeforeVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddGroupBeforeVarDataV1Decoder.CDecoder c = decoder.c(); + assertThat(c.count(), equalTo(0)); + assertThat(decoder.b(), equalTo("abc")); + assertThat(decoder.toString(), containsString("a=1|c=[]|b='abc'")); + } + + @Test + void allowsNewDecoderToSkipMissingGroupBeforeVarData() + { + final AddGroupBeforeVarDataV0Encoder encoder = new AddGroupBeforeVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).b("abc"); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddGroupBeforeVarDataV1Decoder decoder = new AddGroupBeforeVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.b(), equalTo("abc")); + } + + @Test + void disallowsNewDecoderToSkipPresentButAddedGroupBeforeVarData() + { + final AddGroupBeforeVarDataV1Encoder encoder = new AddGroupBeforeVarDataV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).cCount(1).next().d(2); + encoder.b("abc"); + encoder.checkEncodingIsComplete(); + + final AddGroupBeforeVarDataV1Decoder decoder = new AddGroupBeforeVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::b); + assertThat(exception.getMessage(), containsString("Cannot access field \"b\" in state: V1_BLOCK")); + } + + @Test + void allowsOldDecoderToSkipAddedGroupBeforeVarData() + { + final AddGroupBeforeVarDataV1Encoder encoder = new AddGroupBeforeVarDataV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + messageHeaderEncoder.numGroups(1); + encoder.a(1).cCount(1).next().d(2); + encoder.b("abc"); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddGroupBeforeVarDataV0Decoder decoder = new AddGroupBeforeVarDataV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + + for (int i = 0; i < messageHeaderDecoder.numGroups(); i++) + { + skipGroup(decoder); + } + + assertThat(decoder.b(), equalTo("abc")); + } + + private void skipGroup(final AddGroupBeforeVarDataV0Decoder decoder) + { + final GroupSizeEncodingDecoder groupSizeEncodingDecoder = new GroupSizeEncodingDecoder() + .wrap(buffer, decoder.limit()); + final int bytesToSkip = groupSizeEncodingDecoder.encodedLength() + + groupSizeEncodingDecoder.blockLength() * groupSizeEncodingDecoder.numInGroup(); + decoder.limit(decoder.limit() + bytesToSkip); + } + + @Test + void allowsNewDecoderToDecodeAddedEnumFieldBeforeGroup() + { + final AddEnumBeforeGroupV1Encoder encoder = new AddEnumBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d(Direction.BUY).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + final AddEnumBeforeGroupV1Decoder decoder = new AddEnumBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(), equalTo(Direction.BUY)); + final AddEnumBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingEnumFieldBeforeGroupAsNullValue() + { + final AddEnumBeforeGroupV0Encoder encoder = new AddEnumBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddEnumBeforeGroupV1Decoder decoder = new AddEnumBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(), equalTo(Direction.NULL_VAL)); + final AddEnumBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToSkipPresentButAddedEnumFieldBeforeGroup() + { + final AddEnumBeforeGroupV1Encoder encoder = new AddEnumBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d(Direction.SELL).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + final AddEnumBeforeGroupV1Decoder decoder = new AddEnumBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddEnumBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsOldDecoderToSkipAddedEnumFieldBeforeGroup() + { + final AddEnumBeforeGroupV1Encoder encoder = new AddEnumBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d(Direction.BUY).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddEnumBeforeGroupV0Decoder decoder = new AddEnumBeforeGroupV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddEnumBeforeGroupV0Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeAddedCompositeFieldBeforeGroup() + { + final AddCompositeBeforeGroupV1Encoder encoder = new AddCompositeBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d().x(-1).y(-2); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + final AddCompositeBeforeGroupV1Decoder decoder = new AddCompositeBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final PointDecoder d = decoder.d(); + assertThat(d, notNullValue()); + assertThat(d.x(), equalTo(-1)); + assertThat(d.y(), equalTo(-2)); + final AddCompositeBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingCompositeFieldBeforeGroupAsNullValue() + { + final AddCompositeBeforeGroupV0Encoder encoder = new AddCompositeBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddCompositeBeforeGroupV1Decoder decoder = new AddCompositeBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(), nullValue()); + final AddCompositeBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToSkipPresentButAddedCompositeFieldBeforeGroup() + { + final AddCompositeBeforeGroupV1Encoder encoder = new AddCompositeBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d().x(-1).y(-2); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + final AddCompositeBeforeGroupV1Decoder decoder = new AddCompositeBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddCompositeBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsOldDecoderToSkipAddedCompositeFieldBeforeGroup() + { + final AddCompositeBeforeGroupV1Encoder encoder = new AddCompositeBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d().x(-1).y(-2); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddCompositeBeforeGroupV0Decoder decoder = new AddCompositeBeforeGroupV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddCompositeBeforeGroupV0Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeAddedArrayFieldBeforeGroup() + { + final AddArrayBeforeGroupV1Encoder encoder = new AddArrayBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1) + .putD((short)1, (short)2, (short)3, (short)4) + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + final AddArrayBeforeGroupV1Decoder decoder = new AddArrayBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(0), equalTo((short)1)); + assertThat(decoder.d(1), equalTo((short)2)); + assertThat(decoder.d(2), equalTo((short)3)); + assertThat(decoder.d(3), equalTo((short)4)); + final AddArrayBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue1() + { + final AddArrayBeforeGroupV0Encoder encoder = new AddArrayBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddArrayBeforeGroupV1Decoder decoder = new AddArrayBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(0), equalTo(AddArrayBeforeGroupV1Decoder.dNullValue())); + assertThat(decoder.d(1), equalTo(AddArrayBeforeGroupV1Decoder.dNullValue())); + assertThat(decoder.d(2), equalTo(AddArrayBeforeGroupV1Decoder.dNullValue())); + assertThat(decoder.d(3), equalTo(AddArrayBeforeGroupV1Decoder.dNullValue())); + final AddArrayBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue2() + { + final AddArrayBeforeGroupV0Encoder encoder = new AddArrayBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddArrayBeforeGroupV1Decoder decoder = new AddArrayBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.getD(new byte[8], 0, 8), equalTo(0)); + final AddArrayBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue3() + { + final AddArrayBeforeGroupV0Encoder encoder = new AddArrayBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddArrayBeforeGroupV1Decoder decoder = new AddArrayBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.getD(new ExpandableArrayBuffer(), 0, 8), equalTo(0)); + final AddArrayBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingArrayFieldBeforeGroupAsNullValue4() + { + final AddArrayBeforeGroupV0Encoder encoder = new AddArrayBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddArrayBeforeGroupV1Decoder decoder = new AddArrayBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final UnsafeBuffer buffer = new UnsafeBuffer(); + decoder.wrapD(buffer); + assertThat(buffer.capacity(), equalTo(0)); + final AddArrayBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToSkipPresentButAddedArrayFieldBeforeGroup() + { + final AddArrayBeforeGroupV1Encoder encoder = new AddArrayBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1) + .putD((short)1, (short)2, (short)3, (short)4) + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + final AddArrayBeforeGroupV1Decoder decoder = new AddArrayBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddArrayBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsOldDecoderToSkipAddedArrayFieldBeforeGroup() + { + final AddArrayBeforeGroupV1Encoder encoder = new AddArrayBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1) + .putD((short)1, (short)2, (short)3, (short)4) + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddArrayBeforeGroupV0Decoder decoder = new AddArrayBeforeGroupV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddArrayBeforeGroupV0Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeAddedBitSetFieldBeforeGroup() + { + final AddBitSetBeforeGroupV1Encoder encoder = new AddBitSetBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d().guacamole(true).cheese(true).sourCream(false); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + final AddBitSetBeforeGroupV1Decoder decoder = new AddBitSetBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final FlagsDecoder d = decoder.d(); + assertThat(d, notNullValue()); + assertThat(d.guacamole(), equalTo(true)); + assertThat(d.cheese(), equalTo(true)); + assertThat(d.sourCream(), equalTo(false)); + final AddBitSetBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingBitSetFieldBeforeGroupAsNullValue() + { + final AddBitSetBeforeGroupV0Encoder encoder = new AddBitSetBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddBitSetBeforeGroupV1Decoder decoder = new AddBitSetBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(), nullValue()); + final AddBitSetBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToSkipPresentButAddedBitSetFieldBeforeGroup() + { + final AddBitSetBeforeGroupV1Encoder encoder = new AddBitSetBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d().guacamole(true).cheese(true).sourCream(false); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + final AddBitSetBeforeGroupV1Decoder decoder = new AddBitSetBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddBitSetBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsOldDecoderToSkipAddedBitSetFieldBeforeGroup() + { + final AddBitSetBeforeGroupV1Encoder encoder = new AddBitSetBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).d().guacamole(true).cheese(true).sourCream(false); + encoder.bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddBitSetBeforeGroupV0Decoder decoder = new AddBitSetBeforeGroupV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddBitSetBeforeGroupV0Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsEncodingAndDecodingEnumInsideGroupInSchemaDefinedOrder() + { + final EnumInsideGroupEncoder encoder = new EnumInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(Direction.BUY) + .bCount(1) + .next() + .c(Direction.SELL); + encoder.checkEncodingIsComplete(); + + final EnumInsideGroupDecoder decoder = new EnumInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(Direction.BUY)); + final EnumInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(Direction.SELL)); + assertThat(decoder.toString(), containsString("a=BUY|b=[(c=SELL)]")); + } + + @Test + void disallowsEncodingEnumInsideGroupBeforeCallingNext() + { + final EnumInsideGroupEncoder encoder = new EnumInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(Direction.BUY); + final EnumInsideGroupEncoder.BEncoder bEncoder = encoder.bCount(1); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.c(Direction.SELL)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingEnumInsideGroupBeforeCallingNext() + { + final EnumInsideGroupEncoder encoder = new EnumInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(Direction.BUY) + .bCount(1) + .next() + .c(Direction.SELL); + encoder.checkEncodingIsComplete(); + + final EnumInsideGroupDecoder decoder = new EnumInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(Direction.BUY)); + final EnumInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, b::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void allowsReEncodingTopLevelEnum() + { + final EnumInsideGroupEncoder encoder = new EnumInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(Direction.BUY) + .bCount(1) + .next() + .c(Direction.SELL); + + encoder.a(Direction.SELL); + encoder.checkEncodingIsComplete(); + + + final EnumInsideGroupDecoder decoder = new EnumInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(Direction.SELL)); + final EnumInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(Direction.SELL)); + } + + @Test + void allowsEncodingAndDecodingBitSetInsideGroupInSchemaDefinedOrder() + { + final BitSetInsideGroupEncoder encoder = new BitSetInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().cheese(true).guacamole(true).sourCream(false); + encoder.bCount(1) + .next() + .c().cheese(false).guacamole(false).sourCream(true); + encoder.checkEncodingIsComplete(); + + final BitSetInsideGroupDecoder decoder = new BitSetInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final FlagsDecoder a = decoder.a(); + assertThat(a.guacamole(), equalTo(true)); + assertThat(a.cheese(), equalTo(true)); + assertThat(a.sourCream(), equalTo(false)); + final BitSetInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final FlagsDecoder c = b.next().c(); + assertThat(c.guacamole(), equalTo(false)); + assertThat(c.cheese(), equalTo(false)); + assertThat(c.sourCream(), equalTo(true)); + assertThat(decoder.toString(), containsString("a={guacamole,cheese}|b=[(c={sourCream})]")); + } + + @Test + void disallowsEncodingBitSetInsideGroupBeforeCallingNext() + { + final BitSetInsideGroupEncoder encoder = new BitSetInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().cheese(true).guacamole(true).sourCream(false); + final BitSetInsideGroupEncoder.BEncoder bEncoder = encoder.bCount(1); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, bEncoder::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingBitSetInsideGroupBeforeCallingNext() + { + final BitSetInsideGroupEncoder encoder = new BitSetInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().cheese(true).guacamole(true).sourCream(false); + encoder.bCount(1) + .next() + .c().guacamole(false).cheese(false).sourCream(true); + encoder.checkEncodingIsComplete(); + + final BitSetInsideGroupDecoder decoder = new BitSetInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final FlagsDecoder a = decoder.a(); + assertThat(a.guacamole(), equalTo(true)); + assertThat(a.cheese(), equalTo(true)); + assertThat(a.sourCream(), equalTo(false)); + final BitSetInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, b::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void allowsReEncodingTopLevelBitSetViaReWrap() + { + final BitSetInsideGroupEncoder encoder = new BitSetInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a().cheese(true).guacamole(true).sourCream(false); + encoder.bCount(1) + .next() + .c().cheese(false).guacamole(false).sourCream(true); + + encoder.a().sourCream(true); + encoder.checkEncodingIsComplete(); + + final BitSetInsideGroupDecoder decoder = new BitSetInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final FlagsDecoder a = decoder.a(); + assertThat(a.guacamole(), equalTo(true)); + assertThat(a.cheese(), equalTo(true)); + assertThat(a.sourCream(), equalTo(true)); + final BitSetInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + final FlagsDecoder c = b.next().c(); + assertThat(c.guacamole(), equalTo(false)); + assertThat(c.cheese(), equalTo(false)); + assertThat(c.sourCream(), equalTo(true)); + } + + @Test + void allowsEncodingAndDecodingArrayInsideGroupInSchemaDefinedOrder() + { + final ArrayInsideGroupEncoder encoder = new ArrayInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.putA((short)1, (short)2, (short)3, (short)4); + encoder.bCount(1) + .next() + .putC((short)5, (short)6, (short)7, (short)8); + encoder.checkEncodingIsComplete(); + + final ArrayInsideGroupDecoder decoder = new ArrayInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(0), equalTo((short)1)); + assertThat(decoder.a(1), equalTo((short)2)); + assertThat(decoder.a(2), equalTo((short)3)); + assertThat(decoder.a(3), equalTo((short)4)); + final ArrayInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + b.next(); + assertThat(b.c(0), equalTo((short)5)); + assertThat(b.c(1), equalTo((short)6)); + assertThat(b.c(2), equalTo((short)7)); + assertThat(b.c(3), equalTo((short)8)); + assertThat(decoder.toString(), containsString("a=[1,2,3,4]|b=[(c=[5,6,7,8])]")); + } + + @Test + void disallowsEncodingArrayInsideGroupBeforeCallingNext1() + { + final ArrayInsideGroupEncoder.BEncoder bEncoder = encodeUntilGroupWithArrayInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.putC((short)5, (short)6, (short)7, (short)8)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsEncodingArrayInsideGroupBeforeCallingNext2() + { + final ArrayInsideGroupEncoder.BEncoder bEncoder = encodeUntilGroupWithArrayInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.c(0, (short)5)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsEncodingArrayInsideGroupBeforeCallingNext3() + { + final ArrayInsideGroupEncoder.BEncoder bEncoder = encodeUntilGroupWithArrayInside(); + final byte[] bytes = {5, 6, 7, 8}; + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.putC(bytes, 0, 4)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsEncodingArrayInsideGroupBeforeCallingNext4() + { + final ArrayInsideGroupEncoder.BEncoder bEncoder = encodeUntilGroupWithArrayInside(); + final UnsafeBuffer buffer = new UnsafeBuffer(new byte[8]); + buffer.putByte(0, (byte)5); + buffer.putByte(2, (byte)6); + buffer.putByte(4, (byte)7); + buffer.putByte(6, (byte)8); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.putC(buffer, 0, 4)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + private ArrayInsideGroupEncoder.BEncoder encodeUntilGroupWithArrayInside() + { + final ArrayInsideGroupEncoder encoder = new ArrayInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.putA((short)1, (short)2, (short)3, (short)4); + return encoder.bCount(1); + } + + @Test + void disallowsDecodingArrayInsideGroupBeforeCallingNext1() + { + final ArrayInsideGroupDecoder.BDecoder b = decodeUntilGroupWithArrayInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.c(0)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingArrayInsideGroupBeforeCallingNext2() + { + final ArrayInsideGroupDecoder.BDecoder b = decodeUntilGroupWithArrayInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.getC(new byte[8], 0, 8)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingArrayInsideGroupBeforeCallingNext3() + { + final ArrayInsideGroupDecoder.BDecoder b = decodeUntilGroupWithArrayInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.getC(new ExpandableArrayBuffer(), 0, 8)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingArrayInsideGroupBeforeCallingNext4() + { + final ArrayInsideGroupDecoder.BDecoder b = decodeUntilGroupWithArrayInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.wrapC(new UnsafeBuffer())); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + private ArrayInsideGroupDecoder.BDecoder decodeUntilGroupWithArrayInside() + { + final ArrayInsideGroupEncoder encoder = new ArrayInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.putA((short)1, (short)2, (short)3, (short)4); + encoder.bCount(1) + .next() + .putC((short)5, (short)6, (short)7, (short)8); + encoder.checkEncodingIsComplete(); + + final ArrayInsideGroupDecoder decoder = new ArrayInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(0), equalTo((short)1)); + assertThat(decoder.a(1), equalTo((short)2)); + assertThat(decoder.a(2), equalTo((short)3)); + assertThat(decoder.a(3), equalTo((short)4)); + final ArrayInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + return b; + } + + @Test + void allowsReEncodingTopLevelArrayViaReWrap() + { + final ArrayInsideGroupEncoder encoder = new ArrayInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.putA((short)1, (short)2, (short)3, (short)4); + encoder.bCount(1) + .next() + .putC((short)5, (short)6, (short)7, (short)8); + + encoder.putA((short)9, (short)10, (short)11, (short)12); + encoder.checkEncodingIsComplete(); + + final ArrayInsideGroupDecoder decoder = new ArrayInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(0), equalTo((short)9)); + assertThat(decoder.a(1), equalTo((short)10)); + assertThat(decoder.a(2), equalTo((short)11)); + assertThat(decoder.a(3), equalTo((short)12)); + final ArrayInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + b.next(); + assertThat(b.c(0), equalTo((short)5)); + assertThat(b.c(1), equalTo((short)6)); + assertThat(b.c(2), equalTo((short)7)); + assertThat(b.c(3), equalTo((short)8)); + } + + @Test + void allowsEncodingAndDecodingGroupFieldsInSchemaDefinedOrder1() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.bCount(0); + encoder.dCount(1).next().e(43); + encoder.checkEncodingIsComplete(); + + final MultipleGroupsDecoder decoder = new MultipleGroupsDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b().count(), equalTo(0)); + final MultipleGroupsDecoder.DDecoder d = decoder.d(); + assertThat(d.count(), equalTo(1)); + assertThat(d.next().e(), equalTo(43)); + assertThat(decoder.toString(), containsString("a=42|b=[]|d=[(e=43)]")); + } + + @Test + void allowsEncodingAndDecodingGroupFieldsInSchemaDefinedOrder2() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(41); + encoder.bCount(1).next().c(42); + encoder.dCount(1).next().e(43); + encoder.checkEncodingIsComplete(); + + final MultipleGroupsDecoder decoder = new MultipleGroupsDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(41)); + final MultipleGroupsDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(42)); + final MultipleGroupsDecoder.DDecoder d = decoder.d(); + assertThat(d.count(), equalTo(1)); + assertThat(d.next().e(), equalTo(43)); + } + + @Test + void allowsReEncodingTopLevelPrimitiveFieldsAfterGroups() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(41); + encoder.bCount(1).next().c(42); + encoder.dCount(1).next().e(43); + encoder.a(44); + encoder.checkEncodingIsComplete(); + + final MultipleGroupsDecoder decoder = new MultipleGroupsDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(44)); + final MultipleGroupsDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(42)); + final MultipleGroupsDecoder.DDecoder d = decoder.d(); + assertThat(d.count(), equalTo(1)); + assertThat(d.next().e(), equalTo(43)); + } + + @Test + void disallowsMissedEncodingOfGroupField() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(41); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.dCount(0)); + assertThat(exception.getMessage(), + containsString("Cannot encode count of repeating group \"d\" in state: V0_BLOCK")); + } + + @Test + void disallowsReEncodingEarlierGroupFields() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(41); + encoder.bCount(1).next().c(42); + encoder.dCount(1).next().e(43); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.bCount(1)); + assertThat(exception.getMessage(), + containsString("Cannot encode count of repeating group \"b\" in state: V0_D_1_BLOCK")); + } + + @Test + void disallowsReEncodingLatestGroupField() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(41); + encoder.bCount(1).next().c(42); + encoder.dCount(1).next().e(43); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> encoder.dCount(1)); + assertThat(exception.getMessage(), + containsString("Cannot encode count of repeating group \"d\" in state: V0_D_1_BLOCK")); + } + + @Test + void disallowsMissedDecodingOfGroupField() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(41); + encoder.bCount(1).next().c(42); + encoder.dCount(1).next().e(43); + encoder.checkEncodingIsComplete(); + + final MultipleGroupsDecoder decoder = new MultipleGroupsDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(41)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::d); + assertThat(exception.getMessage(), + containsString("Cannot decode count of repeating group \"d\" in state: V0_BLOCK")); + } + + @Test + void disallowsReDecodingEarlierGroupField() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(41); + encoder.bCount(1).next().c(42); + encoder.dCount(1).next().e(43); + encoder.checkEncodingIsComplete(); + + final MultipleGroupsDecoder decoder = new MultipleGroupsDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(41)); + final MultipleGroupsDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(42)); + final MultipleGroupsDecoder.DDecoder d = decoder.d(); + assertThat(d.count(), equalTo(1)); + assertThat(d.next().e(), equalTo(43)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::b); + assertThat(exception.getMessage(), + containsString("Cannot decode count of repeating group \"b\" in state: V0_D_1_BLOCK")); + } + + @Test + void disallowsReDecodingLatestGroupField() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(41); + encoder.bCount(1).next().c(42); + encoder.dCount(1).next().e(43); + encoder.checkEncodingIsComplete(); + + final MultipleGroupsDecoder decoder = new MultipleGroupsDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(41)); + final MultipleGroupsDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(42)); + final MultipleGroupsDecoder.DDecoder d = decoder.d(); + assertThat(d.count(), equalTo(1)); + assertThat(d.next().e(), equalTo(43)); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, decoder::d); + assertThat(exception.getMessage(), + containsString("Cannot decode count of repeating group \"d\" in state: V0_D_1_BLOCK")); + } + + @Test + void allowsNewDecoderToDecodeAddedVarData() + { + final AddVarDataV1Encoder encoder = new AddVarDataV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.b("abc"); + encoder.checkEncodingIsComplete(); + + final AddVarDataV1Decoder decoder = new AddVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b(), equalTo("abc")); + } + + @Test + void allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue1() + { + final AddVarDataV0Encoder encoder = new AddVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddVarDataV1Decoder decoder = new AddVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b(), equalTo("")); + assertThat(decoder.toString(), containsString("a=42|b=''")); + } + + @Test + void allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue2() + { + final AddVarDataV0Encoder encoder = new AddVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddVarDataV1Decoder decoder = new AddVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.getB(new StringBuilder()), equalTo(0)); + } + + @Test + void allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue3() + { + final AddVarDataV0Encoder encoder = new AddVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddVarDataV1Decoder decoder = new AddVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.getB(new byte[3], 0, 3), equalTo(0)); + } + + @Test + void allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue4() + { + final AddVarDataV0Encoder encoder = new AddVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddVarDataV1Decoder decoder = new AddVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.getB(new ExpandableArrayBuffer(), 0, 3), equalTo(0)); + } + + @Test + void allowsNewDecoderToDecodeMissingAddedVarDataAsNullValue5() + { + final AddVarDataV0Encoder encoder = new AddVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddVarDataV1Decoder decoder = new AddVarDataV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.bLength(), equalTo(0)); + } + + @Test + void allowsEncodingAndDecodingAsciiInsideGroupInSchemaDefinedOrder1() + { + final AsciiInsideGroupEncoder encoder = new AsciiInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a("GBPUSD"); + encoder.bCount(1) + .next() + .c("EURUSD"); + encoder.checkEncodingIsComplete(); + + final AsciiInsideGroupDecoder decoder = new AsciiInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo("GBPUSD")); + final AsciiInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + b.next(); + assertThat(b.c(), equalTo("EURUSD")); + assertThat(decoder.toString(), containsString("a=GBPUSD|b=[(c=EURUSD)]")); + } + + @Test + void allowsEncodingAndDecodingAsciiInsideGroupInSchemaDefinedOrder2() + { + final AsciiInsideGroupEncoder encoder = new AsciiInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + final byte[] gbpUsdBytes = "GBPUSD".getBytes(StandardCharsets.US_ASCII); + encoder.putA(gbpUsdBytes, 0); + encoder.bCount(1) + .next() + .c(0, (byte)'E') + .c(1, (byte)'U') + .c(2, (byte)'R') + .c(3, (byte)'U') + .c(4, (byte)'S') + .c(5, (byte)'D'); + encoder.checkEncodingIsComplete(); + + final AsciiInsideGroupDecoder decoder = new AsciiInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final byte[] aBytes = new byte[6]; + decoder.getA(aBytes, 0); + assertThat(aBytes, equalTo(gbpUsdBytes)); + final AsciiInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + b.next(); + assertThat(b.c(0), equalTo((byte)'E')); + assertThat(b.c(1), equalTo((byte)'U')); + assertThat(b.c(2), equalTo((byte)'R')); + assertThat(b.c(3), equalTo((byte)'U')); + assertThat(b.c(4), equalTo((byte)'S')); + assertThat(b.c(5), equalTo((byte)'D')); + } + + @Test + void disallowsEncodingAsciiInsideGroupBeforeCallingNext1() + { + final AsciiInsideGroupEncoder.BEncoder bEncoder = encodeUntilGroupWithAsciiInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.c("EURUSD")); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsEncodingAsciiInsideGroupBeforeCallingNext2() + { + final AsciiInsideGroupEncoder.BEncoder bEncoder = encodeUntilGroupWithAsciiInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.c(0, (byte)'E')); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsEncodingAsciiInsideGroupBeforeCallingNext3() + { + final AsciiInsideGroupEncoder.BEncoder bEncoder = encodeUntilGroupWithAsciiInside(); + final byte[] eurUsdBytes = "EURUSD".getBytes(StandardCharsets.US_ASCII); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.putC(eurUsdBytes, 0)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + private AsciiInsideGroupEncoder.BEncoder encodeUntilGroupWithAsciiInside() + { + final AsciiInsideGroupEncoder encoder = new AsciiInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a("GBPUSD"); + return encoder.bCount(1); + } + + @Test + void disallowsDecodingAsciiInsideGroupBeforeCallingNext1() + { + final AsciiInsideGroupDecoder.BDecoder b = decodeUntilGroupWithAsciiInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.c(0)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingAsciiInsideGroupBeforeCallingNext2() + { + final AsciiInsideGroupDecoder.BDecoder b = decodeUntilGroupWithAsciiInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.getC(new byte[6], 0)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingAsciiInsideGroupBeforeCallingNext3() + { + final AsciiInsideGroupDecoder.BDecoder b = decodeUntilGroupWithAsciiInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, b::c); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + @Test + void disallowsDecodingAsciiInsideGroupBeforeCallingNext4() + { + final AsciiInsideGroupDecoder.BDecoder b = decodeUntilGroupWithAsciiInside(); + final Exception exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> b.getC(new StringBuilder())); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_B_N")); + } + + private AsciiInsideGroupDecoder.BDecoder decodeUntilGroupWithAsciiInside() + { + final AsciiInsideGroupEncoder encoder = new AsciiInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a("GBPUSD"); + encoder.bCount(1) + .next() + .c("EURUSD"); + encoder.checkEncodingIsComplete(); + + final AsciiInsideGroupDecoder decoder = new AsciiInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo("GBPUSD")); + final AsciiInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + return b; + } + + @Test + void allowsReEncodingTopLevelAsciiViaReWrap() + { + final AsciiInsideGroupEncoder encoder = new AsciiInsideGroupEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a("GBPUSD"); + encoder.bCount(1) + .next() + .c("EURUSD"); + + encoder.a("CADUSD"); + encoder.checkEncodingIsComplete(); + + final AsciiInsideGroupDecoder decoder = new AsciiInsideGroupDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo("CADUSD")); + final AsciiInsideGroupDecoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + b.next(); + assertThat(b.c(), equalTo("EURUSD")); + } + + @Test + void allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup1() + { + final AddAsciiBeforeGroupV1Encoder encoder = new AddAsciiBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1) + .d("EURUSD") + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(), equalTo("EURUSD")); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup2() + { + final AddAsciiBeforeGroupV1Encoder encoder = new AddAsciiBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1) + .d("EURUSD") + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final StringBuilder aValue = new StringBuilder(); + decoder.getD(aValue); + assertThat(aValue.toString(), equalTo("EURUSD")); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + + @Test + void allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup3() + { + final AddAsciiBeforeGroupV1Encoder encoder = new AddAsciiBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + final byte[] eurUsdBytes = "EURUSD".getBytes(StandardCharsets.US_ASCII); + encoder.a(1) + .putD(eurUsdBytes, 0) + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final byte[] aBytes = new byte[6]; + decoder.getD(aBytes, 0); + assertThat(aBytes, equalTo(eurUsdBytes)); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + + @Test + void allowsNewDecoderToDecodeAddedAsciiFieldBeforeGroup4() + { + final AddAsciiBeforeGroupV1Encoder encoder = new AddAsciiBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1) + .d(0, (byte)'E') + .d(1, (byte)'U') + .d(2, (byte)'R') + .d(3, (byte)'U') + .d(4, (byte)'S') + .d(5, (byte)'D') + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(0), equalTo((byte)'E')); + assertThat(decoder.d(1), equalTo((byte)'U')); + assertThat(decoder.d(2), equalTo((byte)'R')); + assertThat(decoder.d(3), equalTo((byte)'U')); + assertThat(decoder.d(4), equalTo((byte)'S')); + assertThat(decoder.d(5), equalTo((byte)'D')); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue1() + { + final AddAsciiBeforeGroupV0Encoder encoder = new AddAsciiBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(0), equalTo(AddAsciiBeforeGroupV1Decoder.dNullValue())); + assertThat(decoder.d(1), equalTo(AddAsciiBeforeGroupV1Decoder.dNullValue())); + assertThat(decoder.d(2), equalTo(AddAsciiBeforeGroupV1Decoder.dNullValue())); + assertThat(decoder.d(3), equalTo(AddAsciiBeforeGroupV1Decoder.dNullValue())); + assertThat(decoder.d(4), equalTo(AddAsciiBeforeGroupV1Decoder.dNullValue())); + assertThat(decoder.d(5), equalTo(AddAsciiBeforeGroupV1Decoder.dNullValue())); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue2() + { + final AddAsciiBeforeGroupV0Encoder encoder = new AddAsciiBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.d(), equalTo("")); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue3() + { + final AddAsciiBeforeGroupV0Encoder encoder = new AddAsciiBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final StringBuilder aValue = new StringBuilder(); + assertThat(decoder.getD(aValue), equalTo(0)); + assertThat(aValue.length(), equalTo(0)); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToDecodeMissingAsciiFieldBeforeGroupAsNullValue4() + { + final AddAsciiBeforeGroupV0Encoder encoder = new AddAsciiBeforeGroupV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion0(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + assertThat(decoder.getD(new byte[6], 0), equalTo(0)); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsNewDecoderToSkipPresentButAddedAsciiFieldBeforeGroup() + { + final AddAsciiBeforeGroupV1Encoder encoder = new AddAsciiBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1) + .d("EURUSD") + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + final AddAsciiBeforeGroupV1Decoder decoder = new AddAsciiBeforeGroupV1Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddAsciiBeforeGroupV1Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsOldDecoderToSkipAddedAsciiFieldBeforeGroup() + { + final AddAsciiBeforeGroupV1Encoder encoder = new AddAsciiBeforeGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1) + .d("EURUSD") + .bCount(1) + .next().c(2); + encoder.checkEncodingIsComplete(); + + modifyHeaderToLookLikeVersion1(); + + final AddAsciiBeforeGroupV0Decoder decoder = new AddAsciiBeforeGroupV0Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final AddAsciiBeforeGroupV0Decoder.BDecoder b = decoder.b(); + assertThat(b.count(), equalTo(1)); + assertThat(b.next().c(), equalTo(2)); + } + + @Test + void allowsEncodeAndDecodeOfMessagesWithNoBlock() + { + final NoBlockEncoder encoder = new NoBlockEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a("abc"); + encoder.checkEncodingIsComplete(); + + final NoBlockDecoder decoder = new NoBlockDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo("abc")); + } + + @Test + void allowsEncodeAndDecodeOfGroupsWithNoBlock() + { + final GroupWithNoBlockEncoder encoder = new GroupWithNoBlockEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.aCount(1).next().b("abc"); + encoder.checkEncodingIsComplete(); + + final GroupWithNoBlockDecoder decoder = new GroupWithNoBlockDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + final GroupWithNoBlockDecoder.ADecoder a = decoder.a(); + assertThat(a.count(), equalTo(1)); + assertThat(a.next().b(), equalTo("abc")); + } + + @Test + void disallowsEncodingElementOfEmptyGroup1() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final MultipleGroupsEncoder.BEncoder bEncoder = encoder.bCount(0); + encoder.dCount(1).next().e(43); + final IllegalStateException exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.c(44)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_D_1_BLOCK")); + } + + @Test + void disallowsEncodingElementOfEmptyGroup2() + { + final NestedGroupsEncoder encoder = new NestedGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final NestedGroupsEncoder.BEncoder bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(43); + final NestedGroupsEncoder.BEncoder.DEncoder dEncoder = bEncoder.dCount(0); + bEncoder.fCount(0); + encoder.hCount(0); + final IllegalStateException exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> dEncoder.e(44)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.d.e\" in state: V0_H_DONE")); + } + + @Test + void disallowsEncodingElementOfEmptyGroup3() + { + final NestedGroupsEncoder encoder = new NestedGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final NestedGroupsEncoder.BEncoder bEncoder = encoder.bCount(1); + bEncoder.next(); + bEncoder.c(43); + final NestedGroupsEncoder.BEncoder.DEncoder dEncoder = bEncoder.dCount(0); + bEncoder.fCount(0); + final IllegalStateException exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> dEncoder.e(44)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.d.e\" in state: V0_B_1_F_DONE")); + } + + @Test + void disallowsEncodingElementOfEmptyGroup4() + { + final AddPrimitiveInsideGroupV1Encoder encoder = new AddPrimitiveInsideGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final AddPrimitiveInsideGroupV1Encoder.BEncoder bEncoder = encoder.bCount(0); + final IllegalStateException exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.c(43)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V1_B_DONE")); + } + + @Test + void disallowsEncodingElementOfEmptyGroup5() + { + final GroupAndVarLengthEncoder encoder = new GroupAndVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(42); + final GroupAndVarLengthEncoder.BEncoder bEncoder = encoder.bCount(0); + encoder.d("abc"); + final IllegalStateException exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, () -> bEncoder.c(43)); + assertThat(exception.getMessage(), containsString("Cannot access field \"b.c\" in state: V0_D_DONE")); + } + + @Test + void allowsEncodingAndDecodingNestedGroupWithVarDataInSchemaDefinedOrder() + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + final NestedGroupWithVarLengthEncoder.BEncoder bEncoder = encoder.bCount(3); + bEncoder.next().c(2).dCount(0); + bEncoder.next().c(3).dCount(1).next().e(4).f("abc"); + bEncoder.next().c(5).dCount(2).next().e(6).f("def").next().e(7).f("ghi"); + encoder.checkEncodingIsComplete(); + + final NestedGroupWithVarLengthDecoder decoder = new NestedGroupWithVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final NestedGroupWithVarLengthDecoder.BDecoder bDecoder = decoder.b(); + assertThat(bDecoder.count(), equalTo(3)); + assertThat(bDecoder.next().c(), equalTo(2)); + assertThat(bDecoder.d().count(), equalTo(0)); + assertThat(bDecoder.next().c(), equalTo(3)); + final NestedGroupWithVarLengthDecoder.BDecoder.DDecoder dDecoder = bDecoder.d(); + assertThat(dDecoder.count(), equalTo(1)); + assertThat(dDecoder.next().e(), equalTo(4)); + assertThat(dDecoder.f(), equalTo("abc")); + assertThat(bDecoder.next().c(), equalTo(5)); + assertThat(bDecoder.d(), sameInstance(dDecoder)); + assertThat(dDecoder.count(), equalTo(2)); + assertThat(dDecoder.next().e(), equalTo(6)); + assertThat(dDecoder.f(), equalTo("def")); + assertThat(dDecoder.next().e(), equalTo(7)); + assertThat(dDecoder.f(), equalTo("ghi")); + } + + @CsvSource(value = { + "1,V0_B_1_D_N_BLOCK", + "2,V0_B_N_D_N_BLOCK" + }) + @ParameterizedTest + void disallowsMissedEncodingOfVarLengthFieldInNestedGroupToNextInnerElement( + final int bCount, + final String expectedState) + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + final NestedGroupWithVarLengthEncoder.BEncoder bEncoder = encoder.bCount(bCount); + final NestedGroupWithVarLengthEncoder.BEncoder.DEncoder dEncoder = bEncoder.next().c(5).dCount(2); + dEncoder.next().e(7); + final IllegalStateException exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, dEncoder::next); + assertThat(exception.getMessage(), + containsString("Cannot access next element in repeating group \"b.d\" in state: " + expectedState)); + assertThat(exception.getMessage(), + containsString("Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + @CsvSource(value = { + "1,V0_B_N_D_1_BLOCK", + "2,V0_B_N_D_N_BLOCK", + }) + @ParameterizedTest + void disallowsMissedEncodingOfVarLengthFieldInNestedGroupToNextOuterElement( + final int dCount, + final String expectedState) + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + final NestedGroupWithVarLengthEncoder.BEncoder bEncoder = encoder.bCount(2); + bEncoder.next().c(3).dCount(dCount).next().e(4); + final IllegalStateException exception = + assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, bEncoder::next); + assertThat(exception.getMessage(), + containsString("Cannot access next element in repeating group \"b\" in state: " + expectedState)); + assertThat(exception.getMessage(), + containsString("Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + @Test + void disallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextInnerElement1() + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + final NestedGroupWithVarLengthEncoder.BEncoder bEncoder = encoder.bCount(1); + bEncoder.next().c(2).dCount(2).next().e(3).f("abc").next().e(4).f("def"); + encoder.checkEncodingIsComplete(); + + final NestedGroupWithVarLengthDecoder decoder = new NestedGroupWithVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final NestedGroupWithVarLengthDecoder.BDecoder bDecoder = decoder.b(); + assertThat(bDecoder.count(), equalTo(1)); + assertThat(bDecoder.next().c(), equalTo(2)); + final NestedGroupWithVarLengthDecoder.BDecoder.DDecoder dDecoder = bDecoder.d(); + assertThat(dDecoder.count(), equalTo(2)); + assertThat(dDecoder.next().e(), equalTo(3)); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, dDecoder::next); + assertThat(exception.getMessage(), + containsString("Cannot access next element in repeating group \"b.d\" in state: V0_B_1_D_N_BLOCK.")); + assertThat(exception.getMessage(), + containsString("Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + @Test + void disallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextInnerElement2() + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + final NestedGroupWithVarLengthEncoder.BEncoder bEncoder = encoder.bCount(2); + bEncoder.next().c(2).dCount(2).next().e(3).f("abc").next().e(4).f("def"); + bEncoder.next().c(5).dCount(0); + encoder.checkEncodingIsComplete(); + + final NestedGroupWithVarLengthDecoder decoder = new NestedGroupWithVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final NestedGroupWithVarLengthDecoder.BDecoder bDecoder = decoder.b(); + assertThat(bDecoder.count(), equalTo(2)); + assertThat(bDecoder.next().c(), equalTo(2)); + final NestedGroupWithVarLengthDecoder.BDecoder.DDecoder dDecoder = bDecoder.d(); + assertThat(dDecoder.count(), equalTo(2)); + assertThat(dDecoder.next().e(), equalTo(3)); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, dDecoder::next); + assertThat(exception.getMessage(), + containsString("Cannot access next element in repeating group \"b.d\" in state: V0_B_N_D_N_BLOCK.")); + assertThat(exception.getMessage(), + containsString("Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + @Test + void disallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextOuterElement1() + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + final NestedGroupWithVarLengthEncoder.BEncoder bEncoder = encoder.bCount(2); + bEncoder.next().c(2).dCount(2).next().e(3).f("abc").next().e(4).f("def"); + bEncoder.next().c(5).dCount(0); + encoder.checkEncodingIsComplete(); + + final NestedGroupWithVarLengthDecoder decoder = new NestedGroupWithVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final NestedGroupWithVarLengthDecoder.BDecoder bDecoder = decoder.b(); + assertThat(bDecoder.count(), equalTo(2)); + assertThat(bDecoder.next().c(), equalTo(2)); + final NestedGroupWithVarLengthDecoder.BDecoder.DDecoder dDecoder = bDecoder.d(); + assertThat(dDecoder.count(), equalTo(2)); + assertThat(dDecoder.next().e(), equalTo(3)); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, bDecoder::next); + assertThat(exception.getMessage(), + containsString("Cannot access next element in repeating group \"b\" in state: V0_B_N_D_N_BLOCK.")); + assertThat(exception.getMessage(), + containsString("Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + @Test + void disallowsMissedDecodingOfVarLengthFieldInNestedGroupToNextOuterElement2() + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + final NestedGroupWithVarLengthEncoder.BEncoder bEncoder = encoder.bCount(2); + bEncoder.next().c(2).dCount(1).next().e(3).f("abc"); + bEncoder.next().c(5).dCount(0); + encoder.checkEncodingIsComplete(); + + final NestedGroupWithVarLengthDecoder decoder = new NestedGroupWithVarLengthDecoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + assertThat(decoder.a(), equalTo(1)); + final NestedGroupWithVarLengthDecoder.BDecoder bDecoder = decoder.b(); + assertThat(bDecoder.count(), equalTo(2)); + assertThat(bDecoder.next().c(), equalTo(2)); + final NestedGroupWithVarLengthDecoder.BDecoder.DDecoder dDecoder = bDecoder.d(); + assertThat(dDecoder.count(), equalTo(1)); + assertThat(dDecoder.next().e(), equalTo(3)); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, bDecoder::next); + assertThat(exception.getMessage(), + containsString("Cannot access next element in repeating group \"b\" in state: V0_B_N_D_1_BLOCK.")); + assertThat(exception.getMessage(), + containsString("Expected one of these transitions: [\"b.d.e(?)\", \"b.d.fLength()\", \"b.d.f(?)\"].")); + } + + @Test + void disallowsIncompleteMessagesDueToMissingVarLengthField1() + { + final MultipleVarLengthEncoder encoder = new MultipleVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).b("abc"); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, encoder::checkEncodingIsComplete); + assertThat(exception.getMessage(), containsString( + "Not fully encoded, current state: V0_B_DONE, allowed transitions: \"cLength()\", \"c(?)\"")); + } + + @Test + void disallowsIncompleteMessagesDueToMissingVarLengthField2() + { + final NoBlockEncoder encoder = new NoBlockEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, encoder::checkEncodingIsComplete); + assertThat(exception.getMessage(), containsString( + "Not fully encoded, current state: V0_BLOCK, allowed transitions: \"aLength()\", \"a(?)\"")); + } + + @Test + void disallowsIncompleteMessagesDueToMissingTopLevelGroup1() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(0); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, encoder::checkEncodingIsComplete); + assertThat(exception.getMessage(), containsString( + "Not fully encoded, current state: V0_B_DONE, allowed transitions: " + + "\"b.resetCountToIndex()\", \"dCount(0)\", \"dCount(>0)\"")); + } + + @Test + void disallowsIncompleteMessagesDueToMissingTopLevelGroup2() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(1).next().c(2); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, encoder::checkEncodingIsComplete); + assertThat(exception.getMessage(), containsString( + "Not fully encoded, current state: V0_B_1_BLOCK, allowed transitions: " + + "\"b.c(?)\", \"b.resetCountToIndex()\", \"dCount(0)\", \"dCount(>0)\"")); + } + + @Test + void disallowsIncompleteMessagesDueToMissingTopLevelGroup3() + { + final MultipleGroupsEncoder encoder = new MultipleGroupsEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, encoder::checkEncodingIsComplete); + assertThat(exception.getMessage(), containsString( + "Not fully encoded, current state: V0_BLOCK, allowed transitions: " + + "\"a(?)\", \"bCount(0)\", \"bCount(>0)\"")); + } + + @CsvSource(value = { + "1,V0_B_1_BLOCK", + "2,V0_B_N_BLOCK", + }) + @ParameterizedTest + void disallowsIncompleteMessagesDueToMissingNestedGroup1(final int bCount, final String expectedState) + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(bCount).next().c(2); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, encoder::checkEncodingIsComplete); + assertThat(exception.getMessage(), containsString("Not fully encoded, current state: " + expectedState)); + } + + @CsvSource(value = { + "1,1,V0_B_1_D_N", + "1,2,V0_B_1_D_N", + "2,0,V0_B_N_D_DONE", + "2,1,V0_B_N_D_N", + "2,2,V0_B_N_D_N", + }) + @ParameterizedTest + void disallowsIncompleteMessagesDueToMissingNestedGroup2( + final int bCount, + final int dCount, + final String expectedState) + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(bCount).next().c(2).dCount(dCount); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, encoder::checkEncodingIsComplete); + assertThat(exception.getMessage(), containsString("Not fully encoded, current state: " + expectedState)); + } + + @CsvSource(value = { + "1,1,V0_B_1_D_1_BLOCK", + "1,2,V0_B_1_D_N_BLOCK", + "2,1,V0_B_N_D_1_BLOCK", + "2,2,V0_B_N_D_N_BLOCK", + }) + @ParameterizedTest + void disallowsIncompleteMessagesDueToMissingVarDataInNestedGroup( + final int bCount, + final int dCount, + final String expectedState) + { + final NestedGroupWithVarLengthEncoder encoder = new NestedGroupWithVarLengthEncoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderEncoder); + encoder.a(1).bCount(bCount).next().c(2).dCount(dCount).next().e(10); + final Exception exception = assertThrows(INCORRECT_ORDER_EXCEPTION_CLASS, encoder::checkEncodingIsComplete); + assertThat(exception.getMessage(), containsString("Not fully encoded, current state: " + expectedState)); + } + + private void modifyHeaderToLookLikeVersion0() + { + messageHeaderDecoder.wrap(buffer, OFFSET); + final int v1TemplateId = messageHeaderDecoder.templateId() + 1_000; + messageHeaderEncoder.wrap(buffer, OFFSET); + messageHeaderEncoder.templateId(v1TemplateId).version(0); + } + + private void modifyHeaderToLookLikeVersion1() + { + messageHeaderDecoder.wrap(buffer, OFFSET); + assert messageHeaderDecoder.version() == 1; + final int v0TemplateId = messageHeaderDecoder.templateId() - 1_000; + messageHeaderEncoder.wrap(buffer, OFFSET); + messageHeaderEncoder.templateId(v0TemplateId); + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index f12fef3751..3f253ed778 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -15,6 +15,12 @@ */ package uk.co.real_logic.sbe.generation.java; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; import org.agrona.DirectBuffer; import org.agrona.MutableDirectBuffer; import org.agrona.concurrent.UnsafeBuffer; @@ -22,23 +28,23 @@ import org.agrona.generation.StringWriterOutputManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import uk.co.real_logic.sbe.Tests; -import uk.co.real_logic.sbe.ir.Ir; -import uk.co.real_logic.sbe.xml.IrGenerator; -import uk.co.real_logic.sbe.xml.MessageSchema; -import uk.co.real_logic.sbe.xml.ParserOptions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.ByteOrder; +import java.util.Arrays; import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static uk.co.real_logic.sbe.generation.java.JavaGenerator.MESSAGE_HEADER_DECODER_TYPE; import static uk.co.real_logic.sbe.generation.java.ReflectionUtil.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -251,6 +257,37 @@ void shouldGenerateBasicMessage() throws Exception assertThat(msgFlyweight.toString(), startsWith("[Car]")); } + @Test + void shouldGenerateWithoutPrecedenceChecksByDefault() throws Exception + { + final PrecedenceChecks.Context context = new PrecedenceChecks.Context(); + final PrecedenceChecks precedenceChecks = PrecedenceChecks.newInstance(context); + generator(precedenceChecks).generate(); + + final Field field = Arrays.stream(compileCarEncoder().getDeclaredFields()) + .filter(f -> f.getName().equals(context.precedenceChecksFlagName())) + .findFirst() + .orElse(null); + + assertNull(field); + } + + @Test + void shouldGeneratePrecedenceChecksWhenEnabled() throws Exception + { + final PrecedenceChecks.Context context = new PrecedenceChecks.Context() + .shouldGeneratePrecedenceChecks(true); + final PrecedenceChecks precedenceChecks = PrecedenceChecks.newInstance(context); + generator(precedenceChecks).generate(); + + final Field field = Arrays.stream(compileCarEncoder().getDeclaredFields()) + .filter(f -> f.getName().equals(context.precedenceChecksFlagName())) + .findFirst() + .orElse(null); + + assertNotNull(field); + } + @Test void shouldGenerateRepeatingGroupDecoder() throws Exception { @@ -298,8 +335,12 @@ void shouldGenerateVarDataCodecs() throws Exception final Object encoder = wrap(buffer, compileCarEncoder().getConstructor().newInstance()); final Object decoder = getCarDecoder(buffer, encoder); + setEmptyFuelFiguresGroup(encoder); + setEmptyPerformanceFiguresGroup(encoder); setManufacturer(encoder, expectedManufacturer); + skipFuelFiguresGroup(decoder); + skipPerformanceFiguresGroup(decoder); final String manufacturer = getManufacturer(decoder); assertEquals(expectedManufacturer, manufacturer); @@ -402,28 +443,30 @@ void shouldGenerateGetFixedLengthStringUsingAppendable() throws Exception assertThat(result.toString(), is("R11R12")); } - @Test - void shouldGenerateGetVariableStringUsingAppendable() throws Exception + @ParameterizedTest + @ValueSource(strings = {"Red", "", "Red and Blue"}) + void shouldGenerateGetVariableStringUsingAppendable(final String color) throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); final StringBuilder result = new StringBuilder(); generator().generate(); final Object encoder = wrap(buffer, compileCarEncoder().getDeclaredConstructor().newInstance()); - final Object decoder = getCarDecoder(buffer, encoder); - set(encoder, "color", String.class, "Red"); - get(decoder, "color", result); - assertThat(result.toString(), is("Red")); + setEmptyFuelFiguresGroup(encoder); + setEmptyPerformanceFiguresGroup(encoder); + set(encoder, "manufacturer", String.class, "Bristol"); + set(encoder, "model", String.class, "Britannia"); + set(encoder, "activationCode", String.class, "12345"); + set(encoder, "color", String.class, color); - result.setLength(0); - set(encoder, "color", String.class, ""); - get(decoder, "color", result); - assertThat(result.toString(), is("")); - - result.setLength(0); - set(encoder, "color", String.class, "Red and Blue"); - get(decoder, "color", result); - assertThat(result.toString(), is("Red and Blue")); + final Object decoder = getCarDecoder(buffer, encoder); + skipFuelFiguresGroup(decoder); + skipPerformanceFiguresGroup(decoder); + assertThat(get(decoder, "manufacturer"), equalTo("Bristol")); + assertThat(get(decoder, "model"), equalTo("Britannia")); + assertThat(get(decoder, "activationCode"), equalTo("12345")); + assertThat(get(decoder, "color", result), equalTo(color.length())); + assertThat(result.toString(), equalTo(color)); } @Test @@ -664,6 +707,12 @@ private JavaGenerator generator() return new JavaGenerator(ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); } + private JavaGenerator generator(final PrecedenceChecks precedenceChecks) + { + return new JavaGenerator(ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, false, + precedenceChecks, outputManager); + } + private void generateTypeStubs() throws IOException { final JavaGenerator javaGenerator = generator(); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java index a48074eb89..beead1799e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java @@ -41,10 +41,30 @@ static Object get(final Object object, final String fieldName) throws Exception return object.getClass().getMethod(fieldName).invoke(object); } - static void get(final Object object, final String fieldName, final Appendable arg) throws Exception + static Object get(final Object object, final String fieldName, final Appendable arg) throws Exception { final String methodName = "get" + Generators.toUpperFirstChar(fieldName); - object.getClass().getMethod(methodName, Appendable.class).invoke(object, arg); + return object.getClass().getMethod(methodName, Appendable.class).invoke(object, arg); + } + + static void skipFuelFiguresGroup(final Object decoder) throws Exception + { + skipGroup(decoder, "fuelFigures"); + } + + static void skipPerformanceFiguresGroup(final Object decoder) throws Exception + { + skipGroup(decoder, "performanceFigures"); + } + + private static void skipGroup(final Object decoder, final String groupName) throws Exception + { + final Object group = get(decoder, groupName); + while ((boolean)get(group, "hasNext")) + { + get(group, "next"); + get(group, "sbeSkip"); + } } static String getManufacturer(final Object decoder) throws Exception @@ -52,6 +72,16 @@ static String getManufacturer(final Object decoder) throws Exception return (String)get(decoder, "manufacturer"); } + static void setEmptyFuelFiguresGroup(final Object encoder) throws Exception + { + encoder.getClass().getMethod("fuelFiguresCount", int.class).invoke(encoder, 0); + } + + static void setEmptyPerformanceFiguresGroup(final Object encoder) throws Exception + { + encoder.getClass().getMethod("performanceFiguresCount", int.class).invoke(encoder, 0); + } + static void setManufacturer(final Object encoder, final String value) throws Exception { encoder.getClass().getMethod("manufacturer", String.class).invoke(encoder, value); diff --git a/sbe-tool/src/test/resources/field-order-check-schema.xml b/sbe-tool/src/test/resources/field-order-check-schema.xml new file mode 100644 index 0000000000..e4d62ebfd6 --- /dev/null +++ b/sbe-tool/src/test/resources/field-order-check-schema.xml @@ -0,0 +1,292 @@ + + + + + + + + + + + + + + + + + + + + + + + + 1 + 2 + + + + 1 + 2 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b166f352b8ca67d5a286f151726762e306331d4a Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 6 Dec 2023 14:26:01 +0000 Subject: [PATCH 275/805] 1.30.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f407f84d1d..034552a83e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.30.0-SNAPSHOT \ No newline at end of file +1.30.0 From 25b007dfda00f629f251dfa7b53cfe8e7f0e79f5 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 6 Dec 2023 14:27:05 +0000 Subject: [PATCH 276/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 034552a83e..e576fe33d3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.30.0 +1.31.0-SNAPSHOT From fb3292d1d87b934bd1c889c3bd63cb0f36f94d78 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 14 Dec 2023 10:24:33 +0100 Subject: [PATCH 277/805] [C/C++] Add Clang 17. --- .github/workflows/ci.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6a6ef95ea..c6d62899c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -202,8 +202,9 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | - curl -L https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.version }} main" + sudo mkdir -p /etc/apt/keyrings/ + curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/llvm-snapshot.gpg + echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz @@ -218,7 +219,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '13', '14', '15', '16' ] + version: [ '13', '14', '15', '16', '17' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} @@ -239,8 +240,9 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | - curl -L https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ matrix.version }} main" + sudo mkdir -p /etc/apt/keyrings/ + curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/llvm-snapshot.gpg + echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz From 062a127e62b6928b0d294d7ef1f5020556d9e344 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 14 Dec 2023 12:32:58 +0100 Subject: [PATCH 278/805] [C/C++] Add GCC 13. --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6d62899c2..e317d2bfc8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -147,7 +147,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '11', '12' ] + version: [ '11', '12', '13' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} @@ -168,6 +168,8 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | + sudo add-apt-repository ppa:ubuntu-toolchain-r/ppa + sudo apt-get update sudo apt-get install -y g++-${{ matrix.version }} curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz From fa671da7efb8c4834e50a15f8e88745f1dbb936e Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 2 Jan 2024 13:11:36 +0100 Subject: [PATCH 279/805] Update copyright. --- CMakeLists.txt | 2 +- CONTRIBUTING.md | 2 +- README.md | 2 +- build.gradle | 2 +- config/checkstyle/checkstyle.xml | 2 +- sbe-benchmarks/src/main/cpp/CMakeLists.txt | 2 +- sbe-benchmarks/src/main/cpp/CarBench.cpp | 2 +- sbe-benchmarks/src/main/cpp/CodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/MarketDataBench.cpp | 2 +- sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/benchlet-main.cpp | 2 +- sbe-benchmarks/src/main/cpp/benchlet.h | 2 +- .../src/main/java/uk/co/real_logic/sbe/CarBenchmark.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/package-info.java | 2 +- sbe-samples/src/main/cpp/CMakeLists.txt | 2 +- sbe-samples/src/main/cpp/GeneratedStubExample.cpp | 2 +- sbe-samples/src/main/cpp/OtfExample.cpp | 2 +- .../uk/co/real_logic/sbe/examples/ExampleTokenListener.java | 2 +- .../co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java | 2 +- .../sbe/examples/ExampleUsingGeneratedStubExtension.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java | 2 +- .../main/java/uk/co/real_logic/sbe/examples/package-info.java | 2 +- sbe-tool/src/main/cpp/CMakeLists.txt | 2 +- sbe-tool/src/main/cpp/otf/Encoding.h | 2 +- sbe-tool/src/main/cpp/otf/IrDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/Token.h | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java | 2 +- .../main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java | 2 +- .../java/uk/co/real_logic/sbe/codec/java/MethodSelector.java | 2 +- .../main/java/uk/co/real_logic/sbe/codec/java/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/CodeGenerator.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/Generators.java | 2 +- .../uk/co/real_logic/sbe/generation/TargetCodeGenerator.java | 2 +- .../co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/c/COutputManager.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/c/package-info.java | 2 +- .../real_logic/sbe/generation/common/FieldPrecedenceModel.java | 2 +- .../co/real_logic/sbe/generation/common/PrecedenceChecks.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java | 2 +- .../real_logic/sbe/generation/cpp/NamespaceOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/csharp/CSharp.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java | 2 +- .../sbe/generation/csharp/CSharpNamespaceOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/package-info.java | 2 +- .../uk/co/real_logic/sbe/generation/golang/GolangGenerator.java | 2 +- .../real_logic/sbe/generation/golang/GolangOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/golang/package-info.java | 2 +- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 2 +- .../uk/co/real_logic/sbe/generation/java/JavaOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/JavaUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/package-info.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/RustOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/RustUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/SubGroup.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/package-info.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/package-info.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java | 2 +- .../main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/json/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java | 2 +- .../main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java | 2 +- .../main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/otf/package-info.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java | 2 +- .../java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java | 2 +- .../main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java | 2 +- .../java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java | 2 +- .../uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/package-info.java | 2 +- sbe-tool/src/test/c/BoundsCheckTest.cpp | 2 +- sbe-tool/src/test/c/CComplianceTest.c | 2 +- sbe-tool/src/test/c/CMakeLists.txt | 2 +- sbe-tool/src/test/c/CodeGenTest.cpp | 2 +- sbe-tool/src/test/c/GroupWithDataTest.cpp | 2 +- sbe-tool/src/test/c/Issue889Test.cpp | 2 +- sbe-tool/src/test/cpp/BoundsCheckTest.cpp | 2 +- sbe-tool/src/test/cpp/CMakeLists.txt | 2 +- sbe-tool/src/test/cpp/CodeGenTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeElementsTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp | 2 +- sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp | 2 +- sbe-tool/src/test/cpp/GroupWithDataTest.cpp | 2 +- sbe-tool/src/test/cpp/Issue835Test.cpp | 2 +- sbe-tool/src/test/cpp/Issue889Test.cpp | 2 +- sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp | 2 +- sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp | 2 +- .../src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java | 2 +- .../java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java | 2 +- sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java | 2 +- .../test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java | 2 +- .../real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java | 2 +- .../real_logic/sbe/generation/java/CharacterEncodingTest.java | 2 +- .../sbe/generation/java/CompositeElementsGenerationTest.java | 2 +- .../real_logic/sbe/generation/java/ConstantCharArrayTest.java | 2 +- .../sbe/generation/java/FixedSizeDataGeneratorTest.java | 2 +- .../real_logic/sbe/generation/java/GenerateFixBinaryTest.java | 2 +- .../real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java | 2 +- .../real_logic/sbe/generation/java/JavaOutputManagerTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java | 2 +- .../sbe/generation/java/PackageOutputManagerTest.java | 2 +- .../co/real_logic/sbe/generation/java/QualifiedYieldTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/ReflectionUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/RewindTest.java | 2 +- .../co/real_logic/sbe/generation/java/SchemaExtensionTest.java | 2 +- .../java/SinceVersionTransformedSchemaJavaGenerationTest.java | 2 +- .../sbe/generation/java/SkipAndDecodedLengthTest.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/ToStringTest.java | 2 +- .../sbe/generation/java/ValueRefWithLowerCaseEnum.java | 2 +- .../real_logic/sbe/generation/java/WarningFormattingTest.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java | 2 +- .../uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java | 2 +- .../co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java | 2 +- .../uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java | 2 +- .../real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java | 2 +- 180 files changed, 180 insertions(+), 180 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 878df9b951..7b78278fca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2023 Real Logic Limited. +# Copyright 2013-2024 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ab34fb164c..24b6402de5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ If you are adding a new file it should have the following header: ``` /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 8affd43e68..c393d2dd26 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Or run test directly with `Cargo` License (See LICENSE file for full license) ------------------------------------------- -Copyright 2013-2023 Real Logic Limited. +Copyright 2013-2024 Real Logic Limited. Copyright 2017 MarketFactory Inc. Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/build.gradle b/build.gradle index 3d08ca9f4a..47a0287f06 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 84cd75c377..4f40d0b3fa 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -23,7 +23,7 @@ - + diff --git a/sbe-benchmarks/src/main/cpp/CMakeLists.txt b/sbe-benchmarks/src/main/cpp/CMakeLists.txt index d35adebb49..085e8bf224 100644 --- a/sbe-benchmarks/src/main/cpp/CMakeLists.txt +++ b/sbe-benchmarks/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2023 Real Logic Limited. +# Copyright 2013-2024 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/CarBench.cpp b/sbe-benchmarks/src/main/cpp/CarBench.cpp index 101974e8de..42c757efd2 100644 --- a/sbe-benchmarks/src/main/cpp/CarBench.cpp +++ b/sbe-benchmarks/src/main/cpp/CarBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/CodecBench.h b/sbe-benchmarks/src/main/cpp/CodecBench.h index 2cbb379e15..14cf19547e 100644 --- a/sbe-benchmarks/src/main/cpp/CodecBench.h +++ b/sbe-benchmarks/src/main/cpp/CodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp b/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp index 84cbee18ee..a320b30ab7 100644 --- a/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp +++ b/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h index f55c4bed4c..fb044428ae 100644 --- a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h index 69cbf98890..fbe11e6de0 100644 --- a/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/benchlet-main.cpp b/sbe-benchmarks/src/main/cpp/benchlet-main.cpp index e292d64255..f60927438f 100644 --- a/sbe-benchmarks/src/main/cpp/benchlet-main.cpp +++ b/sbe-benchmarks/src/main/cpp/benchlet-main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/benchlet.h b/sbe-benchmarks/src/main/cpp/benchlet.h index 37c39222fa..c883dd0faf 100644 --- a/sbe-benchmarks/src/main/cpp/benchlet.h +++ b/sbe-benchmarks/src/main/cpp/benchlet.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java index 117dfefec0..1531933165 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java index a182c61331..1125c6ccc3 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java index 974d94de21..5e8842c2c8 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/CMakeLists.txt b/sbe-samples/src/main/cpp/CMakeLists.txt index ea9213e665..dd6a5f0b32 100644 --- a/sbe-samples/src/main/cpp/CMakeLists.txt +++ b/sbe-samples/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2023 Real Logic Limited. +# Copyright 2013-2024 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/GeneratedStubExample.cpp b/sbe-samples/src/main/cpp/GeneratedStubExample.cpp index 810c667be8..2ee019f9df 100644 --- a/sbe-samples/src/main/cpp/GeneratedStubExample.cpp +++ b/sbe-samples/src/main/cpp/GeneratedStubExample.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/OtfExample.cpp b/sbe-samples/src/main/cpp/OtfExample.cpp index fe9ceeb64a..ed24a59a6c 100644 --- a/sbe-samples/src/main/cpp/OtfExample.cpp +++ b/sbe-samples/src/main/cpp/OtfExample.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java index a64d203640..fb03fb954e 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java index 8af8d1094d..16e4617ce3 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java index f9b1233468..02daba6701 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java index 86a754fa3c..a45f734aea 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java index fd12f685ba..a582d13016 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/CMakeLists.txt b/sbe-tool/src/main/cpp/CMakeLists.txt index a2c4081141..c79be7c58a 100644 --- a/sbe-tool/src/main/cpp/CMakeLists.txt +++ b/sbe-tool/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2023 Real Logic Limited. +# Copyright 2013-2024 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/Encoding.h b/sbe-tool/src/main/cpp/otf/Encoding.h index bad608a880..c6464e5ffc 100644 --- a/sbe-tool/src/main/cpp/otf/Encoding.h +++ b/sbe-tool/src/main/cpp/otf/Encoding.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index 2b4571b5b7..6374fecdd2 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h b/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h index 78a49c8eda..56249a832b 100644 --- a/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h index c61658aa35..8b59b5df7d 100644 --- a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/Token.h b/sbe-tool/src/main/cpp/otf/Token.h index b187a86198..69e06224cc 100644 --- a/sbe-tool/src/main/cpp/otf/Token.h +++ b/sbe-tool/src/main/cpp/otf/Token.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java index 307e4a3b02..92cb21c32d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java index 70553f642b..27411749b5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index 7c5ec14a9f..aae460dc2b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index eac6dd4ba1..0af4506b75 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java index a69e280d0d..93e86eee1e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java index 4ebebf2f83..7f17222cdc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java index 4ffba79157..f10999cff9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java index df4040e2bf..03dcf30090 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java index be906f06e0..a6ba5850ea 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java index 83afb9928b..461cb2bb22 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 6552a72c00..54a9766449 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 8b71264be2..f77143e47b 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java index 5877162f56..0da63b7c09 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java index cadc1399fb..fa0cbe1f10 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java index d0e6656cc4..956b86d379 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java index 0e79f88568..3122926ba5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java index 9825a3e6b7..cd5e1856aa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index b47e1d2f4a..0c7f258720 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java index 3e561bd207..76b75687d2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java index 7616ad4b28..43c45fa9f7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java index 5c58a2d237..4ea7958015 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java index ee55d214d5..157309f319 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 8fe17df71a..d7ab193126 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java index c2c500f5bc..6ec2505238 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index 1140ae8b02..cac937c67f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java index d1431f3343..54b9fdd77c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index 1f5e238bff..8fad299bb9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java index c225f8b4a9..1675d69fed 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java index d658a7e759..0aa379216b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java index 9bc17ee5fa..c30d9ed062 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 3e6dd222eb..3934c154cc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java index 516093b5f8..9bbe32bc86 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index c29db9cbc2..5bdc6e38b0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java index e7ae8909e2..cfe10b0723 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java index dd303f9a0e..7a6cae1bac 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 67c949cbe0..7d0b79a0aa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 56b5e10cf2..00c9ac03f6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index cb06bbc96a..b1620446a2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java index 2e28bd67c8..49f5f6747d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 13fa241a40..8f2724759f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index d7fd2cc55d..6407220065 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java index e2e3f52525..bfaccf83ee 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java index 6f1c114103..db4e41a9ff 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java index 744fb0c15c..318cc3061f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java index 57e946b0df..1ca42e82d1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java index 2f7a309a99..0485f9a903 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index d80ca04b46..359975a8b5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java index 4bbcfaef95..82ad99d714 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java index 9b57dee5bf..b72f8b46a0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java index e4b14a08f4..db6d2cb849 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java index a6845a15ae..83ab2d1538 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java index 34a0ea2c56..b4533bccb0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java index bd74f67e44..5e58d4f0e7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java index f889af19a8..9ae537b397 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java index 22e7595740..a7214788a4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java index 947f6fb053..3f2e518d31 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java index c480a328bc..7bbe1fb11f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java index 23910e4910..f9c243555b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java index 0a7671a020..df2782b168 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java index 8cd16555fc..0f8916d55b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java index efd0d150b8..d3e1aebfb7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java index bc5d5ee6c2..06dfbeb735 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java index 966f5f0e2e..f7d6052df2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index ac175bb37b..e7842ea47c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java index e805dd8fc0..60a9cdc66e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java index 7fad3ab7ea..8d3c48ea3f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java index dd93a87fb7..d445da2f92 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java index 7def2d9aed..49cf4ca722 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index de4ceff388..8f507ca366 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java index 1fbe750a2e..3c1e6a78f2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index a196df56d0..46dac06dfd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java index 9e38fd8c94..93aa9c8260 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java index 191f4e8279..2eee8a20c0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java index 2c8b402f88..11bdccbe08 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java index 8f1ec8c23c..c52ae6feed 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java index 63618fdebf..fb6914774f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java index 2d65a39044..b96605d860 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java index 8b54fb6cfc..db25c1a291 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index d9ecb33df3..008e5a1629 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java index 3ffcf30830..c16ea698f3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/BoundsCheckTest.cpp b/sbe-tool/src/test/c/BoundsCheckTest.cpp index f7656e2dd8..047fab85e6 100644 --- a/sbe-tool/src/test/c/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/c/BoundsCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CComplianceTest.c b/sbe-tool/src/test/c/CComplianceTest.c index 3ba67f78da..9acbb22334 100644 --- a/sbe-tool/src/test/c/CComplianceTest.c +++ b/sbe-tool/src/test/c/CComplianceTest.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index bb58cfc3cb..52bf553afd 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2023 Real Logic Limited. +# Copyright 2013-2024 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CodeGenTest.cpp b/sbe-tool/src/test/c/CodeGenTest.cpp index 68494c7993..cda5433609 100644 --- a/sbe-tool/src/test/c/CodeGenTest.cpp +++ b/sbe-tool/src/test/c/CodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/GroupWithDataTest.cpp b/sbe-tool/src/test/c/GroupWithDataTest.cpp index d8da323877..f643b2de43 100644 --- a/sbe-tool/src/test/c/GroupWithDataTest.cpp +++ b/sbe-tool/src/test/c/GroupWithDataTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/Issue889Test.cpp b/sbe-tool/src/test/c/Issue889Test.cpp index c621653028..800065e7da 100644 --- a/sbe-tool/src/test/c/Issue889Test.cpp +++ b/sbe-tool/src/test/c/Issue889Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp index 2adf48f06c..aaa6a174a0 100644 --- a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 8c698c83c3..b1319e2389 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2023 Real Logic Limited. +# Copyright 2013-2024 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index 6675172c8d..ea00b8120c 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeElementsTest.cpp b/sbe-tool/src/test/cpp/CompositeElementsTest.cpp index 6b772b976e..cede889d68 100644 --- a/sbe-tool/src/test/cpp/CompositeElementsTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeElementsTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp index 39759c1d50..f767072ac6 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp index 2ef126a774..22ebe9ecc2 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp index 89aeeca267..2c5fa0b1a0 100644 --- a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/GroupWithDataTest.cpp b/sbe-tool/src/test/cpp/GroupWithDataTest.cpp index 2c0c242d8b..03d35c2dee 100644 --- a/sbe-tool/src/test/cpp/GroupWithDataTest.cpp +++ b/sbe-tool/src/test/cpp/GroupWithDataTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Issue835Test.cpp b/sbe-tool/src/test/cpp/Issue835Test.cpp index 01aa455037..9f59ae3fb0 100644 --- a/sbe-tool/src/test/cpp/Issue835Test.cpp +++ b/sbe-tool/src/test/cpp/Issue835Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Issue889Test.cpp b/sbe-tool/src/test/cpp/Issue889Test.cpp index f730936a16..2acafb021a 100644 --- a/sbe-tool/src/test/cpp/Issue889Test.cpp +++ b/sbe-tool/src/test/cpp/Issue889Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp b/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp index 6ff568dd9d..881dd0c020 100644 --- a/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp +++ b/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp b/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp index ad46bab3a9..fe8a58e6b1 100644 --- a/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp +++ b/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java index 63bcc2e412..335e3a59b0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java index 97d51b199c..e233b02c26 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java index a354a11d43..d0a0bdbdeb 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java index eeea08ac0d..616aa06603 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java index 4f5228f46f..be6fad4b98 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java index 11df1c5919..b09495875d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index 63e2f6010b..8b3575e0ab 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index 48b436b289..f96c1ee283 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java index 59fe07b2f3..4e063e9b4a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java index 8342f439e7..487ce653d3 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java index 124faba06c..ffc38c539f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java index 7b823d5a86..e6fe0c252a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java index 7827dac2b3..cd334d9cc1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java index 82a280ed5e..277404993f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java index 6448428ff8..babefc9391 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 3f253ed778..3ceaf14e14 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java index d953828de5..1eff4fa662 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java index 09d6f5b00e..d949d6dfe8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java index 6122cdfd13..36e78d2a28 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java index 36ef9bed42..c5f0133783 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java index beead1799e..2db082c6fc 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java index c2c3e07f4b..de19ed99ed 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java index 1774666139..ee85bc2abe 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java index c626e044d4..d69fc82a26 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java index 8d8fcf3d4d..a69c9bfadb 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java index 11b28123e1..daec79f9ec 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java index 98cdf3852b..2a51451651 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java index f48ce8e830..2871b78d54 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index f7dcc14c28..d6d7652b83 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java index e99a73f272..7f89f2e18d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java index cf900c22d0..c888b3f9c5 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java index 0f20f59520..ee2eef15e9 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java index 1cab824202..0d0416dd5a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index 824e3acd1f..d534863d86 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java index 80ccc9f1a2..5519bcbf15 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java index 9306e75f95..d0bf85fb41 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java index f6eea310f5..b4bdfe9b52 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java index 40c59916e7..b5995c4dac 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java index 73999d9fd4..3d392e0e95 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java index b726352632..a44ee8d4cd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java index fdba65bc5b..38d399d1e0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java index d982667e8a..b3b3f7ae4e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java index cd32bde628..63495cd586 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java index edd151623a..a0648b730c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java index 08c0132c6e..70d8159f9b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java index bda3393aa9..bfb2965116 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright 2017 MarketFactory Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java index 3a45e114bd..265b088c7d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java index 1e784cffcc..b8c2c130fb 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java index 3e73957429..7c134861be 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java index 2b6dfa3607..f4ec8c63db 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java index b04463d244..256e832ded 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java index 7a06142707..32690f6b87 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From b75bd644f6d1babc42b1803bf1b581ffa988723f Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 10 Jan 2024 12:22:43 +0000 Subject: [PATCH 280/805] [Java] Remove unused initialOffset member from generated codecs. --- .../sbe/generation/java/JavaGenerator.java | 15 ++++----------- .../sbe/ir/generated/FrameCodecDecoder.java | 13 +++---------- .../sbe/ir/generated/FrameCodecEncoder.java | 9 +-------- .../sbe/ir/generated/TokenCodecDecoder.java | 13 +++---------- .../sbe/ir/generated/TokenCodecEncoder.java | 9 +-------- 5 files changed, 12 insertions(+), 47 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 3934c154cc..bd277284bd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -3419,7 +3419,6 @@ private CharSequence generateDecoderFlyweightCode( .append(" {\n") .append(" this.buffer = buffer;\n") .append(" }\n") - .append(" this.initialOffset = offset;\n") .append(" this.offset = offset;\n") .append(" this.actingBlockLength = actingBlockLength;\n") .append(" this.actingVersion = actingVersion;\n") @@ -3448,7 +3447,7 @@ private CharSequence generateDecoderFlyweightCode( methods.append(" public ").append(className).append(" sbeRewind()\n") .append(" {\n") - .append(" return wrap(buffer, initialOffset, actingBlockLength, actingVersion);\n") + .append(" return wrap(buffer, offset, actingBlockLength, actingVersion);\n") .append(" }\n\n"); methods.append(" public int sbeDecodedLength()\n") @@ -3516,7 +3515,6 @@ private CharSequence generateFlyweightCode( " public static final java.nio.ByteOrder BYTE_ORDER = java.nio.ByteOrder.%14$s;\n\n" + " private final %9$s parentMessage = this;\n" + " private %11$s buffer;\n" + - " private int initialOffset;\n" + " private int offset;\n" + " private int limit;\n" + "%13$s" + @@ -3545,10 +3543,6 @@ private CharSequence generateFlyweightCode( " {\n" + " return buffer;\n" + " }\n\n" + - " public int initialOffset()\n" + - " {\n" + - " return initialOffset;\n" + - " }\n\n" + " public int offset()\n" + " {\n" + " return offset;\n" + @@ -3599,7 +3593,6 @@ private CharSequence generateEncoderFlyweightCode( " {\n" + " this.buffer = buffer;\n" + " }\n" + - " this.initialOffset = offset;\n" + " this.offset = offset;\n" + " limit(offset + BLOCK_LENGTH);\n\n" + generateEncoderWrapListener(fieldPrecedenceModel, " ") + @@ -4250,7 +4243,7 @@ private void generateEncoderDisplay(final StringBuilder sb, final String decoder append(sb, INDENT, " }"); sb.append('\n'); append(sb, INDENT, " final " + decoderName + " decoder = new " + decoderName + "();"); - append(sb, INDENT, " decoder.wrap(buffer, initialOffset, BLOCK_LENGTH, SCHEMA_VERSION);"); + append(sb, INDENT, " decoder.wrap(buffer, offset, BLOCK_LENGTH, SCHEMA_VERSION);"); sb.append('\n'); append(sb, INDENT, " return decoder.appendTo(builder);"); append(sb, INDENT, "}"); @@ -4369,7 +4362,7 @@ private void generateDecoderDisplay( append(sb, INDENT, " }"); sb.append('\n'); append(sb, INDENT, " final int originalLimit = limit();"); - append(sb, INDENT, " limit(initialOffset + actingBlockLength);"); + append(sb, INDENT, " limit(offset + actingBlockLength);"); append(sb, INDENT, " builder.append(\"[" + name + "](sbeTemplateId=\");"); append(sb, INDENT, " builder.append(TEMPLATE_ID);"); append(sb, INDENT, " builder.append(\"|sbeSchemaId=\");"); @@ -4631,7 +4624,7 @@ private void appendMessageToString(final StringBuilder sb, final String decoderN append(sb, INDENT, " }"); sb.append('\n'); append(sb, INDENT, " final " + decoderName + " decoder = new " + decoderName + "();"); - append(sb, INDENT, " decoder.wrap(buffer, initialOffset, actingBlockLength, actingVersion);"); + append(sb, INDENT, " decoder.wrap(buffer, offset, actingBlockLength, actingVersion);"); sb.append('\n'); append(sb, INDENT, " return decoder.appendTo(new StringBuilder()).toString();"); append(sb, INDENT, "}"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index 89962bd61f..81f28e8dc5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -97,7 +97,6 @@ private void codecState(int newState) private final FrameCodecDecoder parentMessage = this; private DirectBuffer buffer; - private int initialOffset; private int offset; private int limit; int actingBlockLength; @@ -133,11 +132,6 @@ public DirectBuffer buffer() return buffer; } - public int initialOffset() - { - return initialOffset; - } - public int offset() { return offset; @@ -166,7 +160,6 @@ public FrameCodecDecoder wrap( { this.buffer = buffer; } - this.initialOffset = offset; this.offset = offset; this.actingBlockLength = actingBlockLength; this.actingVersion = actingVersion; @@ -202,7 +195,7 @@ public FrameCodecDecoder wrapAndApplyHeader( public FrameCodecDecoder sbeRewind() { - return wrap(buffer, initialOffset, actingBlockLength, actingVersion); + return wrap(buffer, offset, actingBlockLength, actingVersion); } public int sbeDecodedLength() @@ -924,7 +917,7 @@ public String toString() } final FrameCodecDecoder decoder = new FrameCodecDecoder(); - decoder.wrap(buffer, initialOffset, actingBlockLength, actingVersion); + decoder.wrap(buffer, offset, actingBlockLength, actingVersion); return decoder.appendTo(new StringBuilder()).toString(); } @@ -937,7 +930,7 @@ public StringBuilder appendTo(final StringBuilder builder) } final int originalLimit = limit(); - limit(initialOffset + actingBlockLength); + limit(offset + actingBlockLength); builder.append("[FrameCodec](sbeTemplateId="); builder.append(TEMPLATE_ID); builder.append("|sbeSchemaId="); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java index a5524033fc..aaf9df42c9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java @@ -97,7 +97,6 @@ private void codecState(int newState) private final FrameCodecEncoder parentMessage = this; private MutableDirectBuffer buffer; - private int initialOffset; private int offset; private int limit; @@ -131,11 +130,6 @@ public MutableDirectBuffer buffer() return buffer; } - public int initialOffset() - { - return initialOffset; - } - public int offset() { return offset; @@ -147,7 +141,6 @@ public FrameCodecEncoder wrap(final MutableDirectBuffer buffer, final int offset { this.buffer = buffer; } - this.initialOffset = offset; this.offset = offset; limit(offset + BLOCK_LENGTH); @@ -727,7 +720,7 @@ public StringBuilder appendTo(final StringBuilder builder) } final FrameCodecDecoder decoder = new FrameCodecDecoder(); - decoder.wrap(buffer, initialOffset, BLOCK_LENGTH, SCHEMA_VERSION); + decoder.wrap(buffer, offset, BLOCK_LENGTH, SCHEMA_VERSION); return decoder.appendTo(builder); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index 6a48488936..57abf338a1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -144,7 +144,6 @@ private void codecState(int newState) private final TokenCodecDecoder parentMessage = this; private DirectBuffer buffer; - private int initialOffset; private int offset; private int limit; int actingBlockLength; @@ -180,11 +179,6 @@ public DirectBuffer buffer() return buffer; } - public int initialOffset() - { - return initialOffset; - } - public int offset() { return offset; @@ -213,7 +207,6 @@ public TokenCodecDecoder wrap( { this.buffer = buffer; } - this.initialOffset = offset; this.offset = offset; this.actingBlockLength = actingBlockLength; this.actingVersion = actingVersion; @@ -249,7 +242,7 @@ public TokenCodecDecoder wrapAndApplyHeader( public TokenCodecDecoder sbeRewind() { - return wrap(buffer, initialOffset, actingBlockLength, actingVersion); + return wrap(buffer, offset, actingBlockLength, actingVersion); } public int sbeDecodedLength() @@ -2684,7 +2677,7 @@ public String toString() } final TokenCodecDecoder decoder = new TokenCodecDecoder(); - decoder.wrap(buffer, initialOffset, actingBlockLength, actingVersion); + decoder.wrap(buffer, offset, actingBlockLength, actingVersion); return decoder.appendTo(new StringBuilder()).toString(); } @@ -2697,7 +2690,7 @@ public StringBuilder appendTo(final StringBuilder builder) } final int originalLimit = limit(); - limit(initialOffset + actingBlockLength); + limit(offset + actingBlockLength); builder.append("[TokenCodec](sbeTemplateId="); builder.append(TEMPLATE_ID); builder.append("|sbeSchemaId="); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java index a0ece1099d..e81e14bc4a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java @@ -144,7 +144,6 @@ private void codecState(int newState) private final TokenCodecEncoder parentMessage = this; private MutableDirectBuffer buffer; - private int initialOffset; private int offset; private int limit; @@ -178,11 +177,6 @@ public MutableDirectBuffer buffer() return buffer; } - public int initialOffset() - { - return initialOffset; - } - public int offset() { return offset; @@ -194,7 +188,6 @@ public TokenCodecEncoder wrap(final MutableDirectBuffer buffer, final int offset { this.buffer = buffer; } - this.initialOffset = offset; this.offset = offset; limit(offset + BLOCK_LENGTH); @@ -2034,7 +2027,7 @@ public StringBuilder appendTo(final StringBuilder builder) } final TokenCodecDecoder decoder = new TokenCodecDecoder(); - decoder.wrap(buffer, initialOffset, BLOCK_LENGTH, SCHEMA_VERSION); + decoder.wrap(buffer, offset, BLOCK_LENGTH, SCHEMA_VERSION); return decoder.appendTo(builder); } From ab9336080e000c90a01f1d1b0921fcc8fadc531c Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 10 Jan 2024 14:15:34 +0000 Subject: [PATCH 281/805] [Java] Fix warning. --- .../java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java index e233b02c26..80a4ba4416 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java @@ -42,6 +42,7 @@ public class FieldAccessOrderCheckTest private final MutableDirectBuffer buffer = new ExpandableArrayBuffer(); private final MessageHeaderEncoder messageHeaderEncoder = new MessageHeaderEncoder(); private final MessageHeaderDecoder messageHeaderDecoder = new MessageHeaderDecoder(); + private final Random random = new Random(); @BeforeAll static void assumeDebugMode() @@ -53,7 +54,7 @@ static void assumeDebugMode() @BeforeEach void setUp() { - new Random().nextBytes(buffer.byteArray()); + random.nextBytes(buffer.byteArray()); } @Test From 363f450ae2ccf59b5df0bf4ec77364c5089adfd3 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 18 Jan 2024 16:07:52 +0000 Subject: [PATCH 282/805] [Java] Check for being in a composite when generating array access methods based on version. --- .../sbe/generation/java/JavaGenerator.java | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index bd277284bd..5c479aedb9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -131,8 +131,7 @@ public JavaGenerator( shouldDecodeUnknownEnumValues, shouldSupportTypesPackageNames, PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), - outputManager - ); + outputManager); } /** @@ -1466,7 +1465,7 @@ private void generateDecoderVarData( sb.append("\n") .append(indent).append(" public int ").append(methodPropName).append("Length()\n") .append(indent).append(" {\n") - .append(generateArrayFieldNotPresentCondition(token.version(), indent)) + .append(generateArrayFieldNotPresentCondition(false, token.version(), indent)) .append(lengthAccessOrderListenerCall) .append(indent).append(" final int limit = parentMessage.limit();\n") .append(indent).append(" return ").append(PrimitiveType.UINT32 == lengthType ? "(int)" : "") @@ -1563,7 +1562,7 @@ private void generateDataDecodeMethods( indent + " return dataLength;\n" + indent + " }\n", Generators.toUpperFirstChar(propertyName), - generateStringNotPresentConditionForAppendable(token.version(), indent), + generateStringNotPresentConditionForAppendable(false, token.version(), indent), sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", generateGet(lengthType, "limit", byteOrderStr), @@ -1621,7 +1620,7 @@ private void generateDataDecodeMethods( indent + " return new String(tmp, %6$s);\n" + indent + " }\n", formatPropertyName(propertyName), - generateStringNotPresentCondition(token.version(), indent), + generateStringNotPresentCondition(false, token.version(), indent), sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", generateGet(lengthType, "limit", byteOrderStr), @@ -1644,7 +1643,7 @@ private void generateDataDecodeMethods( indent + " return dataLength;\n" + indent + " }\n", Generators.toUpperFirstChar(propertyName), - generateStringNotPresentConditionForAppendable(token.version(), indent), + generateStringNotPresentConditionForAppendable(false, token.version(), indent), sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", generateGet(lengthType, "limit", byteOrderStr), @@ -1853,7 +1852,7 @@ private void generateVarDataTypedDecoder( indent + " }\n", propertyName, exchangeType, - generateArrayFieldNotPresentCondition(token.version(), indent), + generateArrayFieldNotPresentCondition(false, token.version(), indent), accessOrderListenerCall, sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", @@ -2713,9 +2712,10 @@ private CharSequence generateFieldNotPresentCondition( indent + " }\n\n"; } - private static CharSequence generateArrayFieldNotPresentCondition(final int sinceVersion, final String indent) + private static CharSequence generateArrayFieldNotPresentCondition( + final boolean inComposite, final int sinceVersion, final String indent) { - if (0 == sinceVersion) + if (inComposite || 0 == sinceVersion) { return ""; } @@ -2728,9 +2728,9 @@ private static CharSequence generateArrayFieldNotPresentCondition(final int sinc } private static CharSequence generateStringNotPresentConditionForAppendable( - final int sinceVersion, final String indent) + final boolean inComposite, final int sinceVersion, final String indent) { - if (0 == sinceVersion) + if (inComposite || 0 == sinceVersion) { return ""; } @@ -2742,9 +2742,10 @@ private static CharSequence generateStringNotPresentConditionForAppendable( indent + " }\n\n"; } - private static CharSequence generateStringNotPresentCondition(final int sinceVersion, final String indent) + private static CharSequence generateStringNotPresentCondition( + final boolean inComposite, final int sinceVersion, final String indent) { - if (0 == sinceVersion) + if (inComposite || 0 == sinceVersion) { return ""; } @@ -2836,7 +2837,7 @@ private CharSequence generatePrimitiveArrayPropertyDecode( indent + " }\n", Generators.toUpperFirstChar(propertyName), fieldLength, - generateArrayFieldNotPresentCondition(propertyToken.version(), indent), + generateArrayFieldNotPresentCondition(inComposite, propertyToken.version(), indent), accessOrderListenerCall, offset); @@ -2852,7 +2853,7 @@ private CharSequence generatePrimitiveArrayPropertyDecode( indent + " return new String(dst, 0, end, %s);\n" + indent + " }\n\n", propertyName, - generateStringNotPresentCondition(propertyToken.version(), indent), + generateStringNotPresentCondition(inComposite, propertyToken.version(), indent), accessOrderListenerCall, fieldLength, offset, @@ -2886,7 +2887,7 @@ private CharSequence generatePrimitiveArrayPropertyDecode( indent + " return %3$d;\n" + indent + " }\n\n", Generators.toUpperFirstChar(propertyName), - generateStringNotPresentConditionForAppendable(propertyToken.version(), indent), + generateStringNotPresentConditionForAppendable(inComposite, propertyToken.version(), indent), fieldLength, offset, accessOrderListenerCall); @@ -2904,7 +2905,7 @@ else if (encoding.primitiveType() == PrimitiveType.UINT8) indent + " return bytesCopied;\n" + indent + " }\n", Generators.toUpperFirstChar(propertyName), - generateArrayFieldNotPresentCondition(propertyToken.version(), indent), + generateArrayFieldNotPresentCondition(inComposite, propertyToken.version(), indent), accessOrderListenerCall, fieldLength, offset); @@ -2920,7 +2921,7 @@ else if (encoding.primitiveType() == PrimitiveType.UINT8) indent + " }\n", Generators.toUpperFirstChar(propertyName), fqMutableBuffer, - generateArrayFieldNotPresentCondition(propertyToken.version(), indent), + generateArrayFieldNotPresentCondition(inComposite, propertyToken.version(), indent), accessOrderListenerCall, fieldLength, offset); From a43b4ae6cd1111aa6a10aaf2a4874fdfed87089a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 18 Jan 2024 17:04:42 +0000 Subject: [PATCH 283/805] [C++] Fix type conversion warnings. --- sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp index 2c5fa0b1a0..9f7bb9184c 100644 --- a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -123,9 +123,9 @@ TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingVariableLengthFieldsI encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); encoder.a(42); auto *bIn = "abc"; - encoder.putB(bIn, strlen(bIn)); + encoder.putB(bIn, static_cast(strlen(bIn))); auto *cIn = "def"; - encoder.putC(cIn, strlen(cIn)); + encoder.putC(cIn, static_cast(strlen(cIn))); encoder.checkEncodingIsComplete(); MultipleVarLength decoder; @@ -262,7 +262,7 @@ TEST_F(FieldAccessOrderCheckTest, disallowsSkippingEncodingOfVariableLengthField try { auto *cIn = "cIn"; - encoder.putC(cIn, std::strlen(cIn)); + encoder.putC(cIn, static_cast(std::strlen(cIn))); } catch (const std::exception &e) { From b8ac926f0aba3807d43fd30e6c3b336bd310a45f Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 18 Jan 2024 17:21:20 +0000 Subject: [PATCH 284/805] Captured types in IR should be for the minimum version used in a schema. Issue #967. --- .../main/java/uk/co/real_logic/sbe/ir/Ir.java | 9 ++++++- .../sbe/ir/SinceVersionValidationTest.java | 19 ++++++++++++++ sbe-tool/src/test/resources/issue967.xml | 25 +++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 sbe-tool/src/test/resources/issue967.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java index 0485f9a903..3587a8a05f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java @@ -328,7 +328,14 @@ private int captureType( while (endSignal != token.signal() || !name.equals(token.name())); updateComponentTokenCounts(typeTokens); - typesByNameMap.put(null == referencedName ? name : referencedName, typeTokens); + + final String typeName = null == referencedName ? name : referencedName; + final List existingTypeTokens = typesByNameMap.get(typeName); + + if (null == existingTypeTokens || existingTypeTokens.get(0).version() > typeTokens.get(0).version()) + { + typesByNameMap.put(typeName, typeTokens); + } return i; } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java index d0bf85fb41..a2223ced19 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java @@ -16,10 +16,15 @@ package uk.co.real_logic.sbe.ir; import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; import java.io.InputStream; +import java.util.List; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.lessThan; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; import static uk.co.real_logic.sbe.Tests.getLocalResource; @@ -43,4 +48,18 @@ void shouldErrorOnTypeWithGreaterSinceVersion() throws Exception fail("expected IllegalStateException"); } + + @Test + void shouldApplySinceVersionOnComposites() throws Exception + { + try (InputStream in = getLocalResource("issue967.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + final List priceNull9Tokens = ir.getType("PRICENULL9"); + assertThat(priceNull9Tokens.get(0).version(), lessThan(13)); + } + } } diff --git a/sbe-tool/src/test/resources/issue967.xml b/sbe-tool/src/test/resources/issue967.xml new file mode 100644 index 0000000000..2190821b61 --- /dev/null +++ b/sbe-tool/src/test/resources/issue967.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + -9 + + + + + + + \ No newline at end of file From b35481928a63a4ebe9e4a29c5222a644974458e0 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 18 Jan 2024 17:32:03 +0000 Subject: [PATCH 285/805] [C++] Provide access to acting block length of repeating group via the sbeActingBlockLength() method. Issue #968. --- .../uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 0c7f258720..a22556e639 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -785,7 +785,6 @@ private void generateGroupClassHeader( codecStateNullAssignment); } - if (null != fieldPrecedenceModel) { sb.append("\n").append(indent).append("private:"); @@ -808,6 +807,11 @@ private void generateGroupClassHeader( indent + " return %2$d;\n" + indent + " }\n\n" + + indent + " SBE_NODISCARD std::uint64_t sbeActingBlockLength() SBE_NOEXCEPT\n" + + indent + " {\n" + + indent + " return m_blockLength;\n" + + indent + " }\n\n" + + indent + " SBE_NODISCARD std::uint64_t sbePosition() const SBE_NOEXCEPT\n" + indent + " {\n" + indent + " return *m_positionPtr;\n" + From 18d778189a82fd14761b141cbe4bf71b511044a0 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 22 Jan 2024 21:46:53 +0100 Subject: [PATCH 286/805] [Java] Upgrade to Versions 0.51.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 47a0287f06..3e9a6dea27 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { plugins { id 'java-library' id 'com.github.johnrengelman.shadow' version '8.1.1' apply false - id 'com.github.ben-manes.versions' version '0.50.0' + id 'com.github.ben-manes.versions' version '0.51.0' } defaultTasks 'clean', 'build' From 92e5488c4a34a7af4760cd0152e031d4d3d969a8 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 29 Jan 2024 11:20:06 +0000 Subject: [PATCH 287/805] Warnings cleanup. --- .../uk/co/real_logic/sbe/ValidationUtil.java | 2 +- .../sbe/generation/c/CGenerator.java | 2 +- .../sbe/generation/cpp/CppGenerator.java | 40 ++++++--------- .../generation/csharp/CSharpGenerator.java | 49 +++++++------------ .../sbe/generation/java/JavaGenerator.java | 34 +++++-------- .../uk/co/real_logic/sbe/ir/IrDecoder.java | 2 +- ...ava => ValueRefWithLowerCaseEnumTest.java} | 2 +- .../test/resources/nested-composite-name.xml | 1 - 8 files changed, 51 insertions(+), 81 deletions(-) rename sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/{ValueRefWithLowerCaseEnum.java => ValueRefWithLowerCaseEnumTest.java} (98%) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index 0af4506b75..3ba64ef105 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -266,7 +266,7 @@ public static boolean isJavaKeyword(final String token) private static boolean isJavaIdentifier(final String token) { - if (token.length() == 0) + if (token.isEmpty()) { return false; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index f77143e47b..301532e771 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1085,7 +1085,7 @@ private static CharSequence generateFileHeader(final String structName, final Li "#include \n", structName.toUpperCase())); - if (typesToInclude != null && typesToInclude.size() != 0) + if (typesToInclude != null && !typesToInclude.isEmpty()) { sb.append("\n"); for (final String incName : typesToInclude) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index a22556e639..c82a0f0a14 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -228,11 +228,9 @@ private CharSequence generateFullyEncodedCheck(final FieldPrecedenceModel fieldP .append(indent).append(INDENT).append("switch (m_codecState)\n") .append(indent).append(INDENT).append("{\n"); - fieldPrecedenceModel.forEachTerminalEncoderState(state -> - { + fieldPrecedenceModel.forEachTerminalEncoderState((state) -> sb.append(indent).append(TWO_INDENT).append("case ").append(stateCaseForSwitchCase(state)).append(":\n") - .append(indent).append(THREE_INDENT).append("return;\n"); - }); + .append(indent).append(THREE_INDENT).append("return;\n")); sb.append(indent).append(TWO_INDENT).append("default:\n") .append(indent).append(THREE_INDENT) @@ -456,14 +454,12 @@ private static void generateAccessOrderListener( sb.append(indent).append("switch (codecState())\n") .append(indent).append("{\n"); - fieldPrecedenceModel.forEachTransition(interaction, transitionGroup -> + fieldPrecedenceModel.forEachTransition(interaction, (transitionGroup) -> { - transitionGroup.forEachStartState(startState -> - { + transitionGroup.forEachStartState((startState) -> sb.append(indent).append(INDENT) - .append("case ").append(stateCaseForSwitchCase(startState)).append(":\n"); - }); + .append("case ").append(stateCaseForSwitchCase(startState)).append(":\n")); if (!transitionGroup.alwaysEndsInStartState()) { @@ -2935,21 +2931,19 @@ private static void generateLookupTableDefinitions( sb.append("\n").append("const std::string ").append(className).append("::STATE_NAME_LOOKUP[") .append(fieldPrecedenceModel.stateCount()).append("] =\n") .append("{\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> - { - sb.append(INDENT).append("\"").append(state.name()).append("\",\n"); - }); + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> + sb.append(INDENT).append("\"").append(state.name()).append("\",\n")); sb.append("};\n\n"); sb.append("const std::string ").append(className).append("::STATE_TRANSITIONS_LOOKUP[") .append(fieldPrecedenceModel.stateCount()).append("] =\n") .append("{\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> { sb.append(INDENT).append("\""); final MutableBoolean isFirst = new MutableBoolean(true); final Set transitionDescriptions = new HashSet<>(); - fieldPrecedenceModel.forEachTransitionFrom(state, transitionGroup -> + fieldPrecedenceModel.forEachTransitionFrom(state, (transitionGroup) -> { if (transitionDescriptions.add(transitionGroup.exampleCode())) { @@ -3007,12 +3001,10 @@ private static CharSequence generateFieldOrderStateEnum(final FieldPrecedenceMod sb.append(" */\n"); sb.append(INDENT).append("enum class CodecState\n") .append(INDENT).append("{\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> - { + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> sb.append(INDENT).append(INDENT).append(unqualifiedStateCase(state)) - .append(" = ").append(state.number()) - .append(",\n"); - }); + .append(" = ").append(state.number()) + .append(",\n")); sb.append(INDENT).append("};\n\n"); return sb; @@ -3068,12 +3060,10 @@ private static CharSequence generateDecoderWrapListener(final FieldPrecedenceMod .append(INDENT).append(INDENT).append("{\n"); fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> - { sb.append(INDENT).append(TWO_INDENT).append("case ").append(version).append(":\n") - .append(INDENT).append(THREE_INDENT).append("codecState(") - .append(qualifiedStateCase(state)).append(");\n") - .append(INDENT).append(THREE_INDENT).append("break;\n"); - }); + .append(INDENT).append(THREE_INDENT).append("codecState(") + .append(qualifiedStateCase(state)).append(");\n") + .append(INDENT).append(THREE_INDENT).append("break;\n")); sb.append(INDENT).append(TWO_INDENT).append("default:\n") .append(INDENT).append(THREE_INDENT).append("codecState(") diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index d7ab193126..f141c7876f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -720,24 +720,23 @@ private CharSequence generateCompositePropertyElements(final List tokens, { final Token token = tokens.get(i); final String propertyName = formatPropertyName(token.name()); - final FieldPrecedenceModel fieldPrecedenceModel = null; switch (token.signal()) { case ENCODING: - sb.append(generatePrimitiveProperty(propertyName, token, token, fieldPrecedenceModel, indent)); + sb.append(generatePrimitiveProperty(propertyName, token, token, null, indent)); break; case BEGIN_ENUM: - sb.append(generateEnumProperty(propertyName, token, token, fieldPrecedenceModel, indent)); + sb.append(generateEnumProperty(propertyName, token, token, null, indent)); break; case BEGIN_SET: - sb.append(generateBitSetProperty(propertyName, token, token, fieldPrecedenceModel, indent)); + sb.append(generateBitSetProperty(propertyName, token, token, null, indent)); break; case BEGIN_COMPOSITE: - sb.append(generateCompositeProperty(propertyName, token, token, fieldPrecedenceModel, indent)); + sb.append(generateCompositeProperty(propertyName, token, token, null, indent)); break; default: @@ -1515,30 +1514,26 @@ private static CharSequence generateFieldOrderStates( sb.append(indent).append("/// \n"); sb.append(indent).append("private enum CodecState\n") .append(indent).append("{\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> - { + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> sb.append(indent).append(INDENT).append(unqualifiedStateCase(state)) - .append(" = ").append(state.number()) - .append(",\n"); - }); + .append(" = ").append(state.number()) + .append(",\n")); sb.append(indent).append("}\n\n"); sb.append("\n").append(indent).append("private static readonly string[] StateNameLookup = new []\n") .append(indent).append("{\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> - { - sb.append(indent).append(INDENT).append("\"").append(state.name()).append("\",\n"); - }); + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> + sb.append(indent).append(INDENT).append("\"").append(state.name()).append("\",\n")); sb.append(indent).append("};\n\n"); sb.append(indent).append("private static readonly string[] StateTransitionsLookup = new []\n") .append(indent).append("{\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> { sb.append(indent).append(INDENT).append("\""); final MutableBoolean isFirst = new MutableBoolean(true); final Set transitionDescriptions = new HashSet<>(); - fieldPrecedenceModel.forEachTransitionFrom(state, transitionGroup -> + fieldPrecedenceModel.forEachTransitionFrom(state, (transitionGroup) -> { if (transitionDescriptions.add(transitionGroup.exampleCode())) { @@ -1603,11 +1598,9 @@ private CharSequence generateFullyEncodedCheck( .append(indent).append(INDENT).append("switch (_codecState)\n") .append(indent).append(INDENT).append("{\n"); - fieldPrecedenceModel.forEachTerminalEncoderState(state -> - { + fieldPrecedenceModel.forEachTerminalEncoderState((state) -> sb.append(indent).append(TWO_INDENT).append("case ").append(stateCaseForSwitchCase(state)).append(":\n") - .append(indent).append(THREE_INDENT).append("return;\n"); - }); + .append(indent).append(THREE_INDENT).append("return;\n")); sb.append(indent).append(TWO_INDENT).append("default:\n") .append(indent).append(THREE_INDENT) @@ -1771,13 +1764,11 @@ private static void generateAccessOrderListener( sb.append(indent).append("switch (codecState())\n") .append(indent).append("{\n"); - fieldPrecedenceModel.forEachTransition(interaction, transitionGroup -> + fieldPrecedenceModel.forEachTransition(interaction, (transitionGroup) -> { - transitionGroup.forEachStartState(startState -> - { + transitionGroup.forEachStartState((startState) -> sb.append(indent).append(INDENT) - .append("case ").append(stateCaseForSwitchCase(startState)).append(":\n"); - }); + .append("case ").append(stateCaseForSwitchCase(startState)).append(":\n")); sb.append(indent).append(TWO_INDENT).append("codecState(") .append(qualifiedStateCase(transitionGroup.endState())).append(");\n") .append(indent).append(TWO_INDENT).append("break;\n"); @@ -1927,12 +1918,10 @@ private static CharSequence generateDecoderWrapListener( .append(indent).append(INDENT).append("{\n"); fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> - { sb.append(indent).append(TWO_INDENT).append("case ").append(version).append(":\n") - .append(indent).append(THREE_INDENT).append("codecState(") - .append(qualifiedStateCase(state)).append(");\n") - .append(indent).append(THREE_INDENT).append("break;\n"); - }); + .append(indent).append(THREE_INDENT).append("codecState(") + .append(qualifiedStateCase(state)).append(");\n") + .append(indent).append(THREE_INDENT).append("break;\n")); sb.append(indent).append(TWO_INDENT).append("default:\n") .append(indent).append(THREE_INDENT).append("codecState(") diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 5c479aedb9..fe49069b5c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -368,30 +368,26 @@ private CharSequence generateFieldOrderStates(final FieldPrecedenceModel fieldPr sb.append(" */\n"); sb.append(" private static class CodecStates\n") .append(" {\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> - { + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> sb.append(" private static final int ") - .append(unqualifiedStateCase(state)) - .append(" = ").append(state.number()) - .append(";\n"); - }); + .append(unqualifiedStateCase(state)) + .append(" = ").append(state.number()) + .append(";\n")); sb.append("\n").append(" private static final String[] STATE_NAME_LOOKUP =\n") .append(" {\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> - { - sb.append(" \"").append(state.name()).append("\",\n"); - }); + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> + sb.append(" \"").append(state.name()).append("\",\n")); sb.append(" };\n\n"); sb.append(" private static final String[] STATE_TRANSITIONS_LOOKUP =\n") .append(" {\n"); - fieldPrecedenceModel.forEachStateOrderedByStateNumber(state -> + fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> { sb.append(" \""); final MutableBoolean isFirst = new MutableBoolean(true); final Set transitionDescriptions = new HashSet<>(); - fieldPrecedenceModel.forEachTransitionFrom(state, transitionGroup -> + fieldPrecedenceModel.forEachTransitionFrom(state, (transitionGroup) -> { if (transitionDescriptions.add(transitionGroup.exampleCode())) { @@ -458,11 +454,9 @@ private void generateFullyEncodedCheck( .append(" switch (codecState)\n") .append(" {\n"); - fieldPrecedenceModel.forEachTerminalEncoderState(state -> - { + fieldPrecedenceModel.forEachTerminalEncoderState((state) -> sb.append(" case ").append(stateCaseForSwitchCase(state)).append(":\n") - .append(" return;\n"); - }); + .append(" return;\n")); sb.append(" default:\n") .append(" throw new IllegalStateException(\"Not fully encoded, current state: \" +\n") @@ -773,12 +767,10 @@ private static CharSequence generateDecoderWrapListener( .append(indent).append(" {\n"); fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> - { sb.append(indent).append(" case ").append(version).append(":\n") - .append(indent).append(" codecState(") - .append(qualifiedStateCase(state)).append(");\n") - .append(indent).append(" break;\n"); - }); + .append(indent).append(" codecState(") + .append(qualifiedStateCase(state)).append(");\n") + .append(indent).append(" break;\n")); sb.append(indent).append(" default:\n") .append(indent).append(" codecState(") diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index 359975a8b5..b7da2ead1c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -126,7 +126,7 @@ public Ir decode() i = captureHeader(tokens); } - final ByteOrder byteOrder = tokens.size() > 0 ? tokens.get(0).encoding().byteOrder() : null; + final ByteOrder byteOrder = !tokens.isEmpty() ? tokens.get(0).encoding().byteOrder() : null; final Ir ir = new Ir( irPackageName, irNamespaceName, irId, irVersion, null, semanticVersion, byteOrder, irHeader); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnumTest.java similarity index 98% rename from sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java rename to sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnumTest.java index 2a51451651..675f99d05e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnum.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnumTest.java @@ -31,7 +31,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.StringContains.containsString; -class ValueRefWithLowerCaseEnum +class ValueRefWithLowerCaseEnumTest { private static final Class BUFFER_CLASS = MutableDirectBuffer.class; private static final String BUFFER_NAME = BUFFER_CLASS.getName(); diff --git a/sbe-tool/src/test/resources/nested-composite-name.xml b/sbe-tool/src/test/resources/nested-composite-name.xml index e7fb3a0566..1005edff29 100644 --- a/sbe-tool/src/test/resources/nested-composite-name.xml +++ b/sbe-tool/src/test/resources/nested-composite-name.xml @@ -1,6 +1,5 @@ Date: Mon, 29 Jan 2024 12:00:31 +0000 Subject: [PATCH 288/805] [C++] Fix warnings. --- sbe-tool/src/main/cpp/otf/IrDecoder.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index 6374fecdd2..0b5c048669 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -48,8 +48,7 @@ namespace sbe { namespace otf { class IrDecoder { public: - IrDecoder() : - m_length(0) + IrDecoder() { } @@ -142,7 +141,7 @@ class IrDecoder // OS specifics static long long getFileSize(const char *filename) { - struct stat fileStat; + struct stat fileStat{}; if (::stat(filename, &fileStat) != 0) { @@ -165,7 +164,7 @@ class IrDecoder int fd = fileno(fptr); while (remaining > 0) { - unsigned int bytes = static_cast(4098 < remaining ? 4098 : remaining); + auto bytes = static_cast(4098 < remaining ? 4098 : remaining); long long sz = ::read(fd, buffer + (length - remaining), bytes); remaining -= sz; if (sz < 0) @@ -183,8 +182,8 @@ class IrDecoder std::shared_ptr> m_headerTokens; std::vector>> m_messages; std::unique_ptr m_buffer; - std::uint64_t m_length; - int m_id; + std::uint64_t m_length = 0; + int m_id = 0; int decodeIr() { @@ -232,10 +231,10 @@ class IrDecoder tokenCodec.wrapForDecode( m_buffer.get(), offset, tokenCodec.sbeBlockLength(), tokenCodec.sbeSchemaVersion(), m_length); - Signal signal = static_cast(tokenCodec.signal()); - PrimitiveType type = static_cast(tokenCodec.primitiveType()); - Presence presence = static_cast(tokenCodec.presence()); - ByteOrder byteOrder = static_cast(tokenCodec.byteOrder()); + auto signal = static_cast(tokenCodec.signal()); + auto type = static_cast(tokenCodec.primitiveType()); + auto presence = static_cast(tokenCodec.presence()); + auto byteOrder = static_cast(tokenCodec.byteOrder()); std::int32_t tokenOffset = tokenCodec.tokenOffset(); std::int32_t tokenSize = tokenCodec.tokenSize(); std::int32_t id = tokenCodec.fieldId(); From 8d442477bf5d0f2779d5a59920523e60f4cf7729 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 2 Feb 2024 12:05:34 +0100 Subject: [PATCH 289/805] [Gradle] Use `lifecycle` logging and `--console=plain`. --- gradle.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 65930afd28..dbc8af63bb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,8 @@ org.gradle.java.installations.auto-download=false org.gradle.java.installations.fromEnv=BUILD_JAVA_HOME -org.gradle.logging.level=warn +org.gradle.console=plain +org.gradle.logging.level=lifecycle org.gradle.warning.mode=all # HTTP timeouts for Gradle From dfa6d8987b560b05864e6429d33c1137ec9882cb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 2 Feb 2024 12:09:50 +0100 Subject: [PATCH 290/805] [CI] Upgrade to Github actions to v4. --- .github/workflows/ci.yml | 52 ++++++++++++++++++------------------ .github/workflows/codeql.yml | 22 +++++++-------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e317d2bfc8..4661a213ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,21 +32,21 @@ jobs: os: [ 'ubuntu-22.04', 'windows-latest' ] steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Setup java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -56,7 +56,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Setup java 8 to run the Gradle script - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 8 @@ -75,21 +75,21 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Cache NuGet dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('csharp/**/*.sln') }} @@ -118,16 +118,16 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} @@ -153,16 +153,16 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} @@ -189,16 +189,16 @@ jobs: CXX: clang++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} @@ -227,16 +227,16 @@ jobs: CXX: clang++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} @@ -265,7 +265,7 @@ jobs: CXX: clang++ steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install CMake run: | curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz @@ -286,7 +286,7 @@ jobs: CXX: cl steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install CMake run: | $client = new-object System.Net.WebClient @@ -305,16 +305,16 @@ jobs: rust: [ stable, beta, nightly ] steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fba15354c6..37de50f0d6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,21 +37,21 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Setup java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -92,21 +92,21 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Cache NuGet dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('csharp/**/*.sln') }} @@ -148,16 +148,16 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Cache Gradle wrappers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} From ecb63d82cd5c36fea3c0155ad8b6490802c2244f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 2 Feb 2024 12:22:56 +0100 Subject: [PATCH 291/805] [CI] Expect Gradle to detect that it is running in a terminal. --- gradle.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index dbc8af63bb..13abd18beb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,6 @@ org.gradle.java.installations.auto-download=false org.gradle.java.installations.fromEnv=BUILD_JAVA_HOME -org.gradle.console=plain org.gradle.logging.level=lifecycle org.gradle.warning.mode=all From 8005dbc317e6346471c6d54a21878440703097e8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 5 Feb 2024 10:07:07 +0100 Subject: [PATCH 292/805] [Java] Upgrade to JUnit 5.10.2. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3e9a6dea27..8cf1d0f03d 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' -def junitVersion = '5.10.1' +def junitVersion = '5.10.2' def jmhVersion = '1.37' def agronaVersion = '1.20.0' def agronaVersionRange = '[1.20.0,2.0[' // allow any release >= 1.20.0 and < 2.0.0 From a4430f2a60a9764b9e5697411693f91aacc70194 Mon Sep 17 00:00:00 2001 From: Odysseas Georgoudis Date: Tue, 6 Feb 2024 18:36:32 +0000 Subject: [PATCH 293/805] [C++] make message header members constexpr (#971) --- .../uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index c82a0f0a14..54a1683371 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -2673,10 +2673,10 @@ private CharSequence generateMessageFlyweightCode( "%22$s" + "public:\n" + - " static const %1$s SBE_BLOCK_LENGTH = %2$s;\n" + - " static const %3$s SBE_TEMPLATE_ID = %4$s;\n" + - " static const %5$s SBE_SCHEMA_ID = %6$s;\n" + - " static const %7$s SBE_SCHEMA_VERSION = %8$s;\n" + + " static constexpr %1$s SBE_BLOCK_LENGTH = %2$s;\n" + + " static constexpr %3$s SBE_TEMPLATE_ID = %4$s;\n" + + " static constexpr %5$s SBE_SCHEMA_ID = %6$s;\n" + + " static constexpr %7$s SBE_SCHEMA_VERSION = %8$s;\n" + " static constexpr const char* SBE_SEMANTIC_VERSION = \"%13$s\";\n\n" + " enum MetaAttribute\n" + From 3e22c2e779ae05643c6b295e2b154000dd3a389a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 16 Feb 2024 11:32:12 +0000 Subject: [PATCH 294/805] [C++] Code tidy up and address Issue #970. --- sbe-tool/src/main/cpp/otf/IrDecoder.h | 29 ++++++++++++------- sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h | 21 ++++++-------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index 0b5c048669..b4ed9cefd8 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -48,9 +48,7 @@ namespace sbe { namespace otf { class IrDecoder { public: - IrDecoder() - { - } + IrDecoder() = default; int decode(char *irBuffer, std::uint64_t length) { @@ -106,11 +104,13 @@ class IrDecoder std::shared_ptr> result; std::for_each(m_messages.begin(), m_messages.end(), - [&](std::shared_ptr> tokens) + [&](const std::shared_ptr> &tokens) { Token &token = tokens->at(0); - if (token.signal() == Signal::BEGIN_MESSAGE && token.fieldId() == id && token.tokenVersion() == version) + if (token.signal() == Signal::BEGIN_MESSAGE && + token.fieldId() == id && + token.tokenVersion() <= version) { result = tokens; } @@ -124,7 +124,7 @@ class IrDecoder std::shared_ptr> result; std::for_each(m_messages.begin(), m_messages.end(), - [&](std::shared_ptr> tokens) + [&](const std::shared_ptr> &tokens) { Token &token = tokens->at(0); @@ -191,9 +191,14 @@ class IrDecoder FrameCodec frame; std::uint64_t offset = 0; - char tmp[256]; + char tmp[256] = {}; - frame.wrapForDecode(m_buffer.get(), offset, frame.sbeBlockLength(), frame.sbeSchemaVersion(), m_length); + frame.wrapForDecode( + m_buffer.get(), + offset, + FrameCodec::sbeBlockLength(), + FrameCodec::sbeSchemaVersion(), + m_length); frame.getPackageName(tmp, sizeof(tmp)); @@ -229,7 +234,11 @@ class IrDecoder TokenCodec tokenCodec; tokenCodec.wrapForDecode( - m_buffer.get(), offset, tokenCodec.sbeBlockLength(), tokenCodec.sbeSchemaVersion(), m_length); + m_buffer.get(), + offset, + TokenCodec::sbeBlockLength(), + TokenCodec::sbeSchemaVersion(), + m_length); auto signal = static_cast(tokenCodec.signal()); auto type = static_cast(tokenCodec.primitiveType()); @@ -240,7 +249,7 @@ class IrDecoder std::int32_t id = tokenCodec.fieldId(); std::int32_t version = tokenCodec.tokenVersion(); std::int32_t componentTokenCount = tokenCodec.componentTokenCount(); - char tmpBuffer[256]; + char tmpBuffer[256] = {}; std::uint64_t tmpLen = 0; tmpLen = tokenCodec.getName(tmpBuffer, sizeof(tmpBuffer)); diff --git a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h index 8b59b5df7d..edd65bff17 100644 --- a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h @@ -157,14 +157,13 @@ static void decodeComposite( std::uint64_t actingVersion, TokenListener &listener) { - listener.onBeginComposite(fieldToken, *tokens.get(), tokenIndex, toIndex); + listener.onBeginComposite(fieldToken, *tokens, tokenIndex, toIndex); for (size_t i = tokenIndex + 1; i < toIndex;) { Token &token = tokens->at(i); const size_t nextFieldIndex = i + token.componentTokenCount(); - - const std::size_t offset = static_cast(token.offset()); + const auto offset = static_cast(token.offset()); switch (token.signal()) { @@ -183,12 +182,12 @@ static void decodeComposite( case Signal::BEGIN_ENUM: listener.onEnum( - fieldToken, buffer + bufferIndex + offset, *tokens.get(), i, nextFieldIndex - 1, actingVersion); + fieldToken, buffer + bufferIndex + offset, *tokens, i, nextFieldIndex - 1, actingVersion); break; case Signal::BEGIN_SET: listener.onBitSet( - fieldToken, buffer + bufferIndex + offset, *tokens.get(), i, nextFieldIndex - 1, actingVersion); + fieldToken, buffer + bufferIndex + offset, *tokens, i, nextFieldIndex - 1, actingVersion); break; case Signal::ENCODING: @@ -202,7 +201,7 @@ static void decodeComposite( i += token.componentTokenCount(); } - listener.onEndComposite(fieldToken, *tokens.get(), tokenIndex, toIndex); + listener.onEndComposite(fieldToken, *tokens, tokenIndex, toIndex); } template @@ -246,13 +245,11 @@ static size_t decodeFields( break; case Signal::BEGIN_ENUM: - listener.onEnum( - fieldToken, buffer + offset, *tokens.get(), tokenIndex, nextFieldIndex - 2, actingVersion); + listener.onEnum(fieldToken, buffer + offset, *tokens, tokenIndex, nextFieldIndex - 2, actingVersion); break; case Signal::BEGIN_SET: - listener.onBitSet( - fieldToken, buffer + offset, *tokens.get(), tokenIndex, nextFieldIndex - 2, actingVersion); + listener.onBitSet(fieldToken, buffer + offset, *tokens, tokenIndex, nextFieldIndex - 2, actingVersion); break; case Signal::ENCODING: @@ -342,7 +339,7 @@ std::pair decodeGroups( const bool isPresent = token.tokenVersion() <= static_cast(actingVersion); Token &dimensionsTypeComposite = tokens->at(tokenIndex + 1); - std::size_t dimensionsLength = static_cast(dimensionsTypeComposite.encodedLength()); + auto dimensionsLength = static_cast(dimensionsTypeComposite.encodedLength()); if ((bufferIndex + dimensionsLength) > length) { @@ -391,7 +388,7 @@ std::pair decodeGroups( tokenIndex += token.componentTokenCount(); } - return std::pair(bufferIndex, tokenIndex); + return { bufferIndex, tokenIndex }; } /** From 04d10387c783a9de9e23800e0ee433143714cbec Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:07:43 +0100 Subject: [PATCH 295/805] [CI] Ensure that the HEAD of the PR branch is checked out instead of the generated merge commit. --- .github/workflows/ci.yml | 18 ++++++++++++++++++ .github/workflows/codeql.yml | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4661a213ea..5fa80caccd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -76,6 +78,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -119,6 +123,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -154,6 +160,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -190,6 +198,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -228,6 +238,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -266,6 +278,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Install CMake run: | curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz @@ -287,6 +301,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Install CMake run: | $client = new-object System.Net.WebClient @@ -306,6 +322,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 37de50f0d6..98c49cca6a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -38,6 +38,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -93,6 +95,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -149,6 +153,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: From 39b75cfdf3806a08c6c9d68c4720ec400511b43a Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 22 Feb 2024 10:31:49 +0000 Subject: [PATCH 296/805] [Java] Formatting. --- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index fe49069b5c..0c8481b997 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -617,9 +617,9 @@ private static void generateAccessOrderListener( sb.append(indent).append("switch (codecState())\n") .append(indent).append("{\n"); - fieldPrecedenceModel.forEachTransition(interaction, transitionGroup -> + fieldPrecedenceModel.forEachTransition(interaction, (transitionGroup) -> { - transitionGroup.forEachStartState(startState -> + transitionGroup.forEachStartState((startState) -> sb.append(indent).append(" case ").append(stateCaseForSwitchCase(startState)).append(":\n")); sb.append(indent).append(" codecState(") .append(qualifiedStateCase(transitionGroup.endState())).append(");\n") From a146c569323d3c2f72c1a3bd1b19f0e1b5c63b45 Mon Sep 17 00:00:00 2001 From: pcdv Date: Thu, 22 Feb 2024 11:39:39 +0100 Subject: [PATCH 297/805] [Java] Cope with optional sets not being present when pretty printing decoders for debugging. Issue #976 (#977) Co-authored-by: Paul COLIN DE VERDIERE --- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 0c8481b997..9acd9cf9a7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -4564,9 +4564,6 @@ private int writeTokenDisplay( break; case BEGIN_SET: - append(sb, indent, "this." + fieldName + "().appendTo(builder);"); - break; - case BEGIN_COMPOSITE: { final String typeName = formatClassName(decoderName(typeToken.applicableTypeName())); From 104d79d0c6fb44b0553639cd2f20925adcff5329 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 22 Feb 2024 10:45:22 +0000 Subject: [PATCH 298/805] [Java] Formatting. --- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 9acd9cf9a7..f4889e3751 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -4568,7 +4568,7 @@ private int writeTokenDisplay( { final String typeName = formatClassName(decoderName(typeToken.applicableTypeName())); append(sb, indent, "final " + typeName + " " + fieldName + " = this." + fieldName + "();"); - append(sb, indent, "if (" + fieldName + " != null)"); + append(sb, indent, "if (null != " + fieldName + ")"); append(sb, indent, "{"); append(sb, indent, " " + fieldName + ".appendTo(builder);"); append(sb, indent, "}"); From 6d9c83d59d6647444fbe96bbc4540a1909f80303 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 22 Feb 2024 10:55:51 +0000 Subject: [PATCH 299/805] Upgrade codeql-actions to v3. --- .github/workflows/codeql.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 98c49cca6a..613037cdf9 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -64,7 +64,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -73,7 +73,7 @@ jobs: run: ./gradlew - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" @@ -122,7 +122,7 @@ jobs: dotnet-version: ${{ matrix.dotnet }} - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -131,7 +131,7 @@ jobs: run: ./csharp/build.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" @@ -175,7 +175,7 @@ jobs: echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -184,7 +184,7 @@ jobs: run: ./cppbuild/cppbuild - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:${{ matrix.language }}" upload: false @@ -199,6 +199,6 @@ jobs: output: sarif-results/${{ matrix.language }}.sarif - name: Upload SARIF - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: sarif-results/${{ matrix.language }}.sarif From f63f24f5b6981cfaa507d0fa43f51d921bc1de8b Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 22 Feb 2024 11:03:40 +0000 Subject: [PATCH 300/805] Upgrade CodeQl to use setup-dotnet to v3. --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 613037cdf9..6909739161 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -117,7 +117,7 @@ jobs: restore-keys: | ${{ runner.os }}-nuget- - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ matrix.dotnet }} From 6511ecef1cfec1c622f59f8dbb48e5853c1ceda5 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 22 Feb 2024 11:13:54 +0000 Subject: [PATCH 301/805] Upgrade CodeQl to use setup-dotnet to v4. --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6909739161..e9842e0a1e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -117,7 +117,7 @@ jobs: restore-keys: | ${{ runner.os }}-nuget- - name: Setup dotnet - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ matrix.dotnet }} From ddd64672e4fa73600413d5d1c7999f99715bbf9f Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Thu, 22 Feb 2024 11:19:45 +0000 Subject: [PATCH 302/805] Use 3.1.x for C# in CI --- .github/workflows/ci.yml | 4 ++-- .github/workflows/codeql.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5fa80caccd..d3272dee71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: strategy: fail-fast: false matrix: - dotnet: [ '3.1.301' ] + dotnet: [ '3.1.x' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 @@ -100,7 +100,7 @@ jobs: restore-keys: | ${{ runner.os }}-nuget- - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ matrix.dotnet }} - name: Build diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e9842e0a1e..d9819c349b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -88,7 +88,7 @@ jobs: fail-fast: false matrix: language: [ 'csharp' ] - dotnet: [ '3.1.301' ] + dotnet: [ '3.1.x' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 From 66813a4b6a8a9d2a97e5f241c590f86ea77d2879 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Mon, 26 Feb 2024 13:25:23 +0000 Subject: [PATCH 303/805] Upgrade .NET SDK to 8.0.201. (#978) I've updated the .NET SDK to `8.0`, which is the most recent LTS version. Support ends on 10 November 2026. There are several C# projects in the SBE solution. Only `sbe-dll` is consumed by users of SBE. Previously, `sbe-dll` had two targets: - `.NET Standard 2.0` (2017, supported by `.NET Framework >= 4.6.1` and `.NET Core >= 2.0`, which were both superseded by `.NET`) - `.NET Framework 4.5` (2012) In this commit, I have removed the _ancient_ `.NET Framework 4.5` target. This makes it easier to build SBE on Linux, as one only needs a recent .NET installation. I have also changed the other C# projects to target `.NET 8.0` and updated their dependencies. --- .github/workflows/ci.yml | 2 +- csharp/sbe-benchmarks/sbe-benchmarks.csproj | 9 ++++----- csharp/sbe-dll/sbe-dll.csproj | 8 ++------ csharp/sbe-generated/sbe-generated.csproj | 13 +++++-------- csharp/sbe-samples-car/sbe-samples-car.csproj | 6 +----- .../sbe-samples-extension.csproj | 9 ++------- csharp/sbe-tests/sbe-tests.csproj | 11 +++++------ 7 files changed, 20 insertions(+), 38 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3272dee71..cfb5c13454 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: strategy: fail-fast: false matrix: - dotnet: [ '3.1.x' ] + dotnet: [ '8.0.x' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 diff --git a/csharp/sbe-benchmarks/sbe-benchmarks.csproj b/csharp/sbe-benchmarks/sbe-benchmarks.csproj index 8d10e86c4f..3324fe01c2 100644 --- a/csharp/sbe-benchmarks/sbe-benchmarks.csproj +++ b/csharp/sbe-benchmarks/sbe-benchmarks.csproj @@ -1,11 +1,11 @@  - net461;netcoreapp3.1 + net8.0 Org.SbeTool.Sbe.Benchmarks sbe-benchmarks exe - Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014. All rights reserved. + Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014-2024. All rights reserved. SBE Exe @@ -16,9 +16,8 @@ - - - + + diff --git a/csharp/sbe-dll/sbe-dll.csproj b/csharp/sbe-dll/sbe-dll.csproj index 2c369ba21e..747306310d 100644 --- a/csharp/sbe-dll/sbe-dll.csproj +++ b/csharp/sbe-dll/sbe-dll.csproj @@ -1,11 +1,11 @@  - net45;netstandard2.0 + netstandard2.0 True SBE Org.SbeTool.Sbe.Dll Org.SbeTool.Sbe.Dll - Copyright (C) Bill Segall 2018-2021, MarketFactory Inc 2017, Adaptive 2014. All rights reserved. + Copyright (C) Bill Segall 2018-2021, MarketFactory Inc 2017, Adaptive 2014-2024. All rights reserved. true Bill Segall, MarketFactory Inc, Adaptive Consulting Apache-2.0 @@ -37,10 +37,6 @@ - - - - diff --git a/csharp/sbe-generated/sbe-generated.csproj b/csharp/sbe-generated/sbe-generated.csproj index 806168d7d5..f5b42e2355 100644 --- a/csharp/sbe-generated/sbe-generated.csproj +++ b/csharp/sbe-generated/sbe-generated.csproj @@ -1,26 +1,23 @@  - net45;netstandard2.0 + net8.0 Org.SbeTool.Sbe.Generated Org.SbeTool.Sbe.Generated - Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014. All rights reserved. + Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014-2024. All rights reserved. + 9 - TRACE,SBE_ENABLE_PRECEDENCE_CHECKS + TRACE;SBE_ENABLE_PRECEDENCE_CHECKS - TRACE,SBE_ENABLE_PRECEDENCE_CHECKS + TRACE;SBE_ENABLE_PRECEDENCE_CHECKS - - - - diff --git a/csharp/sbe-samples-car/sbe-samples-car.csproj b/csharp/sbe-samples-car/sbe-samples-car.csproj index 8ee29c2329..cf39c0d9ef 100644 --- a/csharp/sbe-samples-car/sbe-samples-car.csproj +++ b/csharp/sbe-samples-car/sbe-samples-car.csproj @@ -1,7 +1,7 @@  - net45;netcoreapp3.1 + net8.0 exe Org.SbeTool.Sbe.Example.Car Org.SbeTool.Sbe.Example.Car @@ -16,8 +16,4 @@ - - - - diff --git a/csharp/sbe-samples-extension/sbe-samples-extension.csproj b/csharp/sbe-samples-extension/sbe-samples-extension.csproj index 97899b3aa4..f4f7a7e311 100644 --- a/csharp/sbe-samples-extension/sbe-samples-extension.csproj +++ b/csharp/sbe-samples-extension/sbe-samples-extension.csproj @@ -1,11 +1,11 @@  - net45;netstandard2.0 + net8.0 exe Org.SbeTool.Sbe.Example.Extension Org.SbeTool.Sbe.Example.Extension - Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014. All rights reserved. + Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014-2024. All rights reserved. @@ -17,9 +17,4 @@ - - - - - diff --git a/csharp/sbe-tests/sbe-tests.csproj b/csharp/sbe-tests/sbe-tests.csproj index 468a1ab8ba..4d8bcee13f 100644 --- a/csharp/sbe-tests/sbe-tests.csproj +++ b/csharp/sbe-tests/sbe-tests.csproj @@ -1,10 +1,10 @@  - net45;netcoreapp3.1 + net8.0 Org.SbeTool.Sbe.Tests Org.SbeTool.Sbe.UnitTests True - Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014. All rights reserved. + Copyright (C) Bill Segall 2018, MarketFactory Inc 2017, Adaptive 2014-2024. All rights reserved. @@ -18,10 +18,9 @@ - - - - + + + From c942cc6cf3e9f97e5d475c0e4b7e9a44df160228 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 26 Feb 2024 21:27:37 +0100 Subject: [PATCH 304/805] [CI] Build PRs against merge commit. --- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/codeql.yml | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfb5c13454..7ac853b7cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -79,7 +79,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -124,7 +124,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -161,7 +161,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -199,7 +199,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -239,7 +239,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -279,7 +279,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Install CMake run: | curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz @@ -302,7 +302,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Install CMake run: | $client = new-object System.Net.WebClient @@ -323,7 +323,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d9819c349b..db70001ed7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -96,7 +96,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: @@ -154,7 +154,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.sha }} - name: Cache Gradle dependencies uses: actions/cache@v4 with: From fae3e45ae39d78f5b8db2bf06cab752be352b0cc Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 14 Mar 2024 13:37:57 +0100 Subject: [PATCH 305/805] [Java] Upgrade to Agrona 1.21.0. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 8cf1d0f03d..bb0605be01 100644 --- a/build.gradle +++ b/build.gradle @@ -58,8 +58,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.2' def jmhVersion = '1.37' -def agronaVersion = '1.20.0' -def agronaVersionRange = '[1.20.0,2.0[' // allow any release >= 1.20.0 and < 2.0.0 +def agronaVersion = '1.21.0' +def agronaVersionRange = '[1.21.0,2.0[' // allow any release >= 1.20.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 4c32cfbfff12bce30053ac9b986ca773918f3f9c Mon Sep 17 00:00:00 2001 From: BenBudr <34384555+BenBudr@users.noreply.github.com> Date: Wed, 20 Mar 2024 09:17:32 +0000 Subject: [PATCH 306/805] [C++] small test fix (#980) --- sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp index 9f7bb9184c..ecd3df1336 100644 --- a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -3624,7 +3624,7 @@ TEST_F(FieldAccessOrderCheckTest, allowsEncodingAndDecodingAsciiInsideGroupInSch AsciiInsideGroup::sbeSchemaVersion(), BUFFER_LEN ); - char aOut[6]; + char aOut[7] = {'\0'}; decoder.getA(aOut, 6); EXPECT_STREQ(aOut, "GBPUSD"); AsciiInsideGroup::B &b = decoder.b(); From 6d3f6b629ddef538839a684451ee4e6ce9b0cd70 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Thu, 21 Mar 2024 10:47:20 -0500 Subject: [PATCH 307/805] [Rust] Updated RustGenerator.generatePrimitiveOptionalDecoder() to resolve Issue #972 (#981) Co-authored-by: Michael Ward --- build.gradle | 1 + rust/Cargo.toml | 1 + rust/tests/issue_972_test.rs | 37 +++++++++++++++++++ .../sbe/generation/rust/RustGenerator.java | 8 ---- sbe-tool/src/test/resources/issue972.xml | 25 +++++++++++++ 5 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 rust/tests/issue_972_test.rs create mode 100644 sbe-tool/src/test/resources/issue972.xml diff --git a/build.gradle b/build.gradle index bb0605be01..a8d9b00dfb 100644 --- a/build.gradle +++ b/build.gradle @@ -587,6 +587,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe.validation.xsd': validationXsdPath) args = ['sbe-tool/src/test/resources/issue435.xml', 'sbe-tool/src/test/resources/issue895.xml', + 'sbe-tool/src/test/resources/issue972.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', 'sbe-tool/src/test/resources/nested-composite-name.xml', ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 020747c06d..6d47fc3746 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -13,6 +13,7 @@ examples_uk_co_real_logic_sbe_benchmarks_fix = { path = "../generated/rust/uk_co issue_435 = { path = "../generated/rust/issue435" } issue_895 = { path = "../generated/rust/issue895" } +issue_972 = { path = "../generated/rust/issue972" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } nested_composite_name = { path = "../generated/rust/nested-composite-name" } diff --git a/rust/tests/issue_972_test.rs b/rust/tests/issue_972_test.rs new file mode 100644 index 0000000000..bc3a938247 --- /dev/null +++ b/rust/tests/issue_972_test.rs @@ -0,0 +1,37 @@ +use issue_972::*; + +fn create_encoder(buffer: &mut Vec) -> Issue972Encoder { + let issue_972 = Issue972Encoder::default().wrap( + WriteBuf::new(buffer.as_mut_slice()), + message_header_codec::ENCODED_LENGTH, + ); + let mut header = issue_972.header(0); + header.parent().unwrap() +} + +#[test] +fn round_trip() -> SbeResult<()> { + // encode... + let mut buffer = vec![0u8; 256]; + let encoder = create_encoder(&mut buffer); + let mut new_composite_encoder = encoder.new_field_encoder(); + new_composite_encoder.f1(2007); + new_composite_encoder.f2(2012); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + assert_eq!(SBE_BLOCK_LENGTH, header.block_length()); + assert_eq!(SBE_SCHEMA_VERSION, header.version()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_SCHEMA_ID, header.schema_id()); + + let decoder = Issue972Decoder::default().header(header); + if let Either::Right(composite) = decoder.new_field_decoder() { + assert_eq!(2007, composite.f1().unwrap()); + assert_eq!(2012, composite.f2().unwrap()); + } else { + panic!() + } + Ok(()) +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index b1620446a2..d30bd318f6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -766,18 +766,10 @@ private static void generatePrimitiveOptionalDecoder( formatFunctionName(name), rustPrimitiveType); - if (fieldToken.version() > 0) - { - indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", fieldToken.version()); - indent(sb, level + 2, "return None;\n"); - indent(sb, level + 1, "}\n\n"); - } - indent(sb, level + 1, "let value = self.get_buf().get_%s_at(self.%s);\n", rustPrimitiveType, getBufOffset(fieldToken)); - final String literal = generateRustLiteral(primitiveType, encoding.applicableNullValue().toString()); if (literal.endsWith("::NAN")) { diff --git a/sbe-tool/src/test/resources/issue972.xml b/sbe-tool/src/test/resources/issue972.xml new file mode 100644 index 0000000000..f64bd616be --- /dev/null +++ b/sbe-tool/src/test/resources/issue972.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 7800371538ce8f6953bf89bbda1ef057a7fb7e1e Mon Sep 17 00:00:00 2001 From: Grzegorz Gierlach Date: Thu, 21 Mar 2024 16:48:28 +0100 Subject: [PATCH 308/805] [Rust] Take slices by reference. (#979) --- rust/tests/baseline_test.rs | 6 +++--- rust/tests/big_endian_test.rs | 6 +++--- rust/tests/extension_test.rs | 6 +++--- .../uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 8 ++++---- .../co/real_logic/sbe/generation/rust/RustGenerator.java | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index c223c83989..bff75170c4 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -176,8 +176,8 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car.model_year(2013); car.available(BooleanType::T); car.code(Model::A); - car.some_numbers([1, 2, 3, 4]); - car.vehicle_code([97, 98, 99, 100, 101, 102]); // abcdef + car.some_numbers(&[1, 2, 3, 4]); + car.vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef extras.set_cruise_control(true); extras.set_sports_pack(true); @@ -187,7 +187,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { let mut engine = car.engine_encoder(); engine.capacity(2000); engine.num_cylinders(4); - engine.manufacturer_code([49, 50, 51]); // 123 + engine.manufacturer_code(&[49, 50, 51]); // 123 engine.efficiency(35); engine.booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index a1e107bc8d..a5a749c94a 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -170,8 +170,8 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car.model_year(2013); car.available(BooleanType::T); car.code(Model::A); - car.some_numbers([0, 1, 2, 3, 4]); - car.vehicle_code(*b"abcdef"); + car.some_numbers(&[0, 1, 2, 3, 4]); + car.vehicle_code(b"abcdef"); extras.set_cruise_control(true); extras.set_sports_pack(true); @@ -181,7 +181,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { let mut engine = car.engine_encoder(); engine.capacity(2000); engine.num_cylinders(4); - engine.manufacturer_code(*b"123"); + engine.manufacturer_code(b"123"); engine.efficiency(35); engine.booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index ad813c056f..07c81e9fb7 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -177,8 +177,8 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car.model_year(2013); car.available(BooleanType::T); car.code(Model::A); - car.some_numbers([0, 1, 2, 3]); - car.vehicle_code([97, 98, 99, 100, 101, 102]); // abcdef + car.some_numbers(&[0, 1, 2, 3]); + car.vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef extras.set_cruise_control(true); extras.set_sports_pack(true); @@ -188,7 +188,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { let mut engine = car.engine_encoder(); engine.capacity(2000); engine.num_cylinders(4); - engine.manufacturer_code([49, 50, 51]); // 123 + engine.manufacturer_code(&[49, 50, 51]); // 123 engine.efficiency(35); engine.booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 7d0b79a0aa..a51b2746da 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -56,7 +56,7 @@ void generate() throws IOException { indent(libRs, 0, "#![forbid(unsafe_code)]\n"); indent(libRs, 0, "#![allow(clippy::upper_case_acronyms)]\n"); - indent(libRs, 0, "#![allow(non_camel_case_types)]\n"); + indent(libRs, 0, "#![allow(non_camel_case_types)]\n\n"); indent(libRs, 0, "use ::core::{convert::TryInto};\n\n"); final ArrayList modules = new ArrayList<>(); @@ -225,8 +225,8 @@ static void generateWriteBuf(final Writer writer, final ByteOrder byteOrder) thr indent(writer, 1, "#[inline]\n"); indent(writer, 1, - "pub fn put_bytes_at(&mut self, index: usize, bytes: [u8; COUNT]) -> usize {\n"); - indent(writer, 2, "self.data[index..index + COUNT].copy_from_slice(&bytes);\n"); + "pub fn put_bytes_at(&mut self, index: usize, bytes: &[u8; COUNT]) -> usize {\n"); + indent(writer, 2, "self.data[index..index + COUNT].copy_from_slice(bytes);\n"); indent(writer, 2, "COUNT\n"); indent(writer, 1, "}\n\n"); @@ -245,7 +245,7 @@ static void generateWriteBuf(final Writer writer, final ByteOrder byteOrder) thr // put__at indent(writer, 1, "#[inline]\n"); indent(writer, 1, "pub fn put_%1$s_at(&mut self, index: usize, value: %1$s) {\n", primitiveType); - indent(writer, 2, "self.put_bytes_at(index, %s::to_%s_bytes(value));\n", primitiveType, endianness); + indent(writer, 2, "self.put_bytes_at(index, &%s::to_%s_bytes(value));\n", primitiveType, endianness); indent(writer, 1, "}\n\n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index d30bd318f6..d0067d836c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -379,7 +379,7 @@ private static void generatePrimitiveEncoder( indent(sb, level, "/// - encodedLength: %d\n", typeToken.encodedLength()); indent(sb, level, "/// - version: %d\n", typeToken.version()); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: [%s; %d]) {\n", + indent(sb, level, "pub fn %s(&mut self, value: &[%s; %d]) {\n", formatFunctionName(name), rustPrimitiveType, arrayLength); From a29ea3e4ea581aacdf7cceff67540f12bcb1bf34 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Fri, 22 Mar 2024 04:03:52 -0500 Subject: [PATCH 309/805] [Rust] updated code generator to prevent rust warning for "ambiguous glob re-exports" (#982) Co-authored-by: Michael Ward --- rust/benches/car_benchmark.rs | 2 +- rust/tests/baseline_test.rs | 19 ++++++++---- rust/tests/big_endian_test.rs | 15 ++++++++-- rust/tests/extension_test.rs | 19 ++++++++---- rust/tests/issue_435_test.rs | 4 +++ rust/tests/issue_895_test.rs | 6 +--- rust/tests/issue_972_test.rs | 2 +- .../sbe/generation/rust/LibRsDef.java | 8 +---- .../sbe/generation/rust/MessageCoderDef.java | 3 +- .../sbe/generation/rust/RustGenerator.java | 30 ++++++++++++++----- 10 files changed, 74 insertions(+), 34 deletions(-) diff --git a/rust/benches/car_benchmark.rs b/rust/benches/car_benchmark.rs index 92b964147a..06b542452a 100644 --- a/rust/benches/car_benchmark.rs +++ b/rust/benches/car_benchmark.rs @@ -1,6 +1,6 @@ +use car_codec::encoder::*; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use examples_uk_co_real_logic_sbe_benchmarks::*; -use car_codec::encoder::*; const MANUFACTURER: &[u8] = b"MANUFACTURER"; const MODEL: &[u8] = b"MODEL"; diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index bff75170c4..58a8503d20 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -1,8 +1,17 @@ -use std::fs::File; -use std::io::prelude::*; - -use examples_baseline::*; -use car_codec::encoder::*; +use examples_baseline::{ + boolean_type::BooleanType, + boost_type::BoostType, + car_codec::{ + encoder::{AccelerationEncoder, FuelFiguresEncoder, PerformanceFiguresEncoder}, + *, + }, + message_header_codec, + message_header_codec::MessageHeaderDecoder, + model::Model, + optional_extras::OptionalExtras, + Encoder, ReadBuf, SbeResult, WriteBuf, +}; +use std::{fs::File, io::prelude::*}; fn read_sbe_file_generated_from_java_example() -> std::io::Result> { // Generated by the generateCarExampleDataFile gradle task. diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index a5a749c94a..aabea63ce2 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -1,5 +1,16 @@ -use baseline_bigendian::*; -use car_codec::encoder::*; +use baseline_bigendian::{ + boolean_type::BooleanType, + boost_type::BoostType, + car_codec::{ + encoder::{AccelerationEncoder, FuelFiguresEncoder, PerformanceFiguresEncoder}, + *, + }, + message_header_codec, + message_header_codec::MessageHeaderDecoder, + model::Model, + optional_extras::OptionalExtras, + Encoder, ReadBuf, SbeResult, WriteBuf, +}; #[test] fn big_endian_baseline_example() -> SbeResult<()> { diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index 07c81e9fb7..072b9b8baa 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -1,8 +1,17 @@ -use std::fs::File; -use std::io::prelude::*; - -use examples_extension::*; -use car_codec::encoder::*; +use examples_extension::{ + boolean_type::BooleanType, + boost_type::BoostType, + car_codec::{ + encoder::{AccelerationEncoder, FuelFiguresEncoder, PerformanceFiguresEncoder}, + *, + }, + message_header_codec, + message_header_codec::MessageHeaderDecoder, + model::Model, + optional_extras::OptionalExtras, + Encoder, ReadBuf, SbeResult, WriteBuf, +}; +use std::{fs::File, io::prelude::*}; fn read_sbe_file_generated_from_java_example() -> std::io::Result> { // Generated by the generateCarExampleDataFile gradle task. diff --git a/rust/tests/issue_435_test.rs b/rust/tests/issue_435_test.rs index 87bd9a075e..8ac9ce8a50 100644 --- a/rust/tests/issue_435_test.rs +++ b/rust/tests/issue_435_test.rs @@ -1,4 +1,8 @@ use ::issue_435::*; +use issue_435::{ + enum_ref::EnumRef, issue_435_codec::*, message_header_codec::MessageHeaderDecoder, + set_ref::SetRef, +}; fn create_encoder(buffer: &mut Vec) -> Issue435Encoder { let issue_435 = Issue435Encoder::default().wrap( diff --git a/rust/tests/issue_895_test.rs b/rust/tests/issue_895_test.rs index dd9b19fa04..96968d2459 100644 --- a/rust/tests/issue_895_test.rs +++ b/rust/tests/issue_895_test.rs @@ -1,8 +1,4 @@ -use issue_895::{ - issue_895_codec::{decoder::Issue895Decoder, encoder::Issue895Encoder}, - MessageHeaderDecoder, ReadBuf, SbeResult, WriteBuf, ENCODED_LENGTH, SBE_BLOCK_LENGTH, - SBE_SCHEMA_ID, SBE_SCHEMA_VERSION, SBE_TEMPLATE_ID, -}; +use issue_895::{issue_895_codec::*, message_header_codec::*, *}; fn create_encoder(buffer: &mut Vec) -> Issue895Encoder { let issue_895 = diff --git a/rust/tests/issue_972_test.rs b/rust/tests/issue_972_test.rs index bc3a938247..2cbab324d0 100644 --- a/rust/tests/issue_972_test.rs +++ b/rust/tests/issue_972_test.rs @@ -1,4 +1,4 @@ -use issue_972::*; +use issue_972::{issue_972_codec::*, message_header_codec::MessageHeaderDecoder, *}; fn create_encoder(buffer: &mut Vec) -> Issue972Encoder { let issue_972 = Issue972Encoder::default().wrap( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index a51b2746da..3c5ae1542d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -78,13 +78,6 @@ void generate() throws IOException } indent(libRs, 0, "\n"); - // add re-export of modules - for (final String module : modules) - { - indent(libRs, 0, "pub use crate::%s::*;\n", toLowerSnakeCase(module)); - } - indent(libRs, 0, "\n"); - generateSbeErrorEnum(libRs); generateEitherEnum(libRs); @@ -163,6 +156,7 @@ static void generateReadBuf(final Appendable writer, final ByteOrder byteOrder) indent(writer, 0, "}\n"); // impl ReadBuf ... + indent(writer, 0, "#[allow(dead_code)]\n"); indent(writer, 0, "impl<%s> %s<%s> {\n", BUF_LIFETIME, READ_BUF_TYPE, BUF_LIFETIME); indent(writer, 1, "#[inline]\n"); indent(writer, 1, "pub fn new(data: &%s [u8]) -> Self {\n", BUF_LIFETIME); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 00c9ac03f6..dbe6fabc8f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -63,7 +63,8 @@ void generate( final List varData) throws IOException { indent(sb, 0, "pub mod %s {\n", codecType.toString().toLowerCase()); - indent(sb, 1, "use super::*;\n\n"); + indent(sb, 1, "use super::*;\n"); + indent(sb, 1, "use message_header_codec::*;\n\n"); // i.e. Decoder or Encoder final String msgTypeName = formatStructName(msgToken.name()) + codecType.name(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index d0067d836c..6569599993 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -449,7 +449,9 @@ private static void generateEnumEncoder( final String name) throws IOException { final String referencedName = typeToken.referencedName(); - final String enumType = formatStructName(referencedName == null ? typeToken.name() : referencedName); + final String enumType = format("%s::%s", + toLowerSnakeCase(referencedName == null ? typeToken.name() : referencedName), + formatStructName(referencedName == null ? typeToken.name() : referencedName)); if (fieldToken.isConstantEncoding()) { @@ -479,7 +481,10 @@ private static void generateBitSetEncoder( { final Encoding encoding = bitsetToken.encoding(); final String rustPrimitiveType = rustTypeName(encoding.primitiveType()); - final String structTypeName = formatStructName(bitsetToken.applicableTypeName()); + final String referencedName = bitsetToken.referencedName(); + final String structTypeName = format("%s::%s", + toLowerSnakeCase(referencedName == null ? bitsetToken.name() : referencedName), + formatStructName(bitsetToken.applicableTypeName())); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", formatFunctionName(name), structTypeName); @@ -496,7 +501,9 @@ private static void generateCompositeEncoder( final String name) throws IOException { final String encoderName = toLowerSnakeCase(encoderName(name)); - final String encoderTypeName = encoderName(formatStructName(typeToken.applicableTypeName())); + final String encoderTypeName = format("%s::%s", + codecModName(typeToken.referencedName() == null ? typeToken.name() : typeToken.referencedName()), + encoderName(formatStructName(typeToken.applicableTypeName()))); indent(sb, level, "/// COMPOSITE ENCODER\n"); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(self) -> %2$s {\n", @@ -556,7 +563,10 @@ private static void generateCompositeDecoder( final String name) throws IOException { final String decoderName = toLowerSnakeCase(decoderName(name)); - final String decoderTypeName = decoderName(formatStructName(typeToken.applicableTypeName())); + final String referencedName = typeToken.referencedName(); + final String decoderTypeName = format("%s::%s", + codecModName(referencedName == null ? typeToken.name() : referencedName), + decoderName(formatStructName(typeToken.applicableTypeName()))); indent(sb, level, "/// COMPOSITE DECODER\n"); indent(sb, level, "#[inline]\n"); if (fieldToken.version() > 0) @@ -575,7 +585,7 @@ private static void generateCompositeDecoder( } else { - indent(sb, level, "pub fn %s(self) -> %2$s {\n", + indent(sb, level, "pub fn %s(self) -> %s {\n", decoderName, decoderTypeName); @@ -593,7 +603,11 @@ private static void generateBitSetDecoder( { final Encoding encoding = bitsetToken.encoding(); final String rustPrimitiveType = rustTypeName(encoding.primitiveType()); - final String structTypeName = formatStructName(bitsetToken.applicableTypeName()); + final String referencedName = bitsetToken.referencedName(); + final String structTypeName = format("%s::%s", + toLowerSnakeCase(referencedName == null ? bitsetToken.name() : referencedName), + formatStructName(bitsetToken.applicableTypeName())); + indent(sb, level, "/// BIT SET DECODER\n"); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&self) -> %s {\n", formatFunctionName(name), structTypeName); @@ -834,7 +848,9 @@ private static void generateEnumDecoder( final String name) throws IOException { final String referencedName = typeToken.referencedName(); - final String enumType = formatStructName(referencedName == null ? typeToken.name() : referencedName); + final String enumType = format("%s::%s", + toLowerSnakeCase(referencedName == null ? typeToken.name() : referencedName), + formatStructName(referencedName == null ? typeToken.name() : referencedName)); if (fieldToken.isConstantEncoding()) { From cef4546dbf24aa857a40ae2fd2722cdb3a1e8179 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 11:48:56 +0100 Subject: [PATCH 310/805] [Java] Upgrade to ASM 9.7. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index a8d9b00dfb..cafd1885c7 100644 --- a/build.gradle +++ b/build.gradle @@ -24,8 +24,8 @@ buildscript { mavenCentral() } dependencies { - classpath 'org.ow2.asm:asm:9.6' - classpath 'org.ow2.asm:asm-commons:9.6' + classpath 'org.ow2.asm:asm:9.7' + classpath 'org.ow2.asm:asm-commons:9.7' } } From 5bb47ee1068a90145e5b48cdf0596d60b2e2dba3 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 11:55:56 +0100 Subject: [PATCH 311/805] [Java] Fix Javadoc copyright year range. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cafd1885c7..0f74a5e005 100644 --- a/build.gradle +++ b/build.gradle @@ -197,7 +197,7 @@ subprojects { javadoc { failOnError false title = '

    Simple Binary Encoding (SBE)

    ' - options.bottom = 'Copyright © 2013-2022 Real Logic Limited. All Rights Reserved.' + options.bottom = 'Copyright © 2013-2024 Real Logic Limited. All Rights Reserved.' options.encoding = 'UTF-8' options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' From f83d97680ce68bed3f85eea99c8069177b6c0ddd Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 13:00:16 +0100 Subject: [PATCH 312/805] [Go] Capitalize enum element names to make them accessible outside the declaration unit. --- .../generation/golang/GolangGenerator.java | 2 +- .../golang/GolangGeneratorTest.java | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index 8fad299bb9..74f3d851c4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1574,7 +1574,7 @@ private void generateEnumDecls( { sb.append(String.format( "\t%1$s%2$s%3$sEnum\n", - token.name(), + formatPropertyName(token.name()), generateWhitespace(longest - token.name().length() + 1), enumName)); } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java new file mode 100644 index 0000000000..4c7cbab82c --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.golang; + +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +class GolangGeneratorTest +{ + @Test + void shouldUseUpperCaseTypeNamesWhenReferencingEnumValues() throws Exception + { + try (InputStream in = Tests.getLocalResource("value-ref-with-lower-case-enum.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final GolangGenerator generator = new GolangGenerator(ir, outputManager); + generator.generate(); + + final String engineTypeSource = outputManager.getSource("issue505.EngineType").toString(); + assertThat(engineTypeSource, allOf( + containsString("type EngineTypeEnum uint8"), + containsString("type EngineTypeValues struct {\n" + + "\tGas EngineTypeEnum\n" + + "\tNullValue EngineTypeEnum\n}"))); + } + } +} From f33cd87414d3dcd5e1b96870c8b62d9fc8c1ee92 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 13:09:01 +0100 Subject: [PATCH 313/805] [Go] Use upper case type name when referencing enums. Fixes #983 --- .../uk/co/real_logic/sbe/generation/golang/GolangGenerator.java | 2 +- .../real_logic/sbe/generation/golang/GolangGeneratorTest.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index 74f3d851c4..6580e373bb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1768,7 +1768,7 @@ private void generateTypeBody( sb.append("\t").append(propertyName) .append(generateWhitespace(length)) .append(arrayspec) - .append(encodingToken.applicableTypeName()) + .append(formatTypeName(encodingToken.applicableTypeName())) .append("Enum\n"); break; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java index 4c7cbab82c..3de2d9c91d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java @@ -53,6 +53,8 @@ void shouldUseUpperCaseTypeNamesWhenReferencingEnumValues() throws Exception containsString("type EngineTypeValues struct {\n" + "\tGas EngineTypeEnum\n" + "\tNullValue EngineTypeEnum\n}"))); + final String messageSource = outputManager.getSource("issue505.SomeMessage").toString(); + assertThat(messageSource, containsString("type SomeMessage struct {\n\tEngineType EngineTypeEnum\n}")); } } } From 05c9f3c0ec5f082480a746d89c442cd27033962f Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 13:34:01 +0100 Subject: [PATCH 314/805] [Go] Use upper case type name when referencing bit sets. --- .../generation/golang/GolangGenerator.java | 2 +- .../golang/GolangGeneratorTest.java | 31 +++++++++++++++++++ .../message-with-lower-case-bitset.xml | 28 +++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 sbe-tool/src/test/resources/message-with-lower-case-bitset.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index 6580e373bb..e4667ceabb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1776,7 +1776,7 @@ private void generateTypeBody( sb.append("\t").append(propertyName) .append(generateWhitespace(length)) .append(arrayspec) - .append(encodingToken.applicableTypeName()) + .append(formatTypeName(encodingToken.applicableTypeName())) .append("\n"); break; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java index 3de2d9c91d..367e8644da 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java @@ -57,4 +57,35 @@ void shouldUseUpperCaseTypeNamesWhenReferencingEnumValues() throws Exception assertThat(messageSource, containsString("type SomeMessage struct {\n\tEngineType EngineTypeEnum\n}")); } } + + @Test + void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception + { + try (InputStream in = Tests.getLocalResource("message-with-lower-case-bitset.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final GolangGenerator generator = new GolangGenerator(ir, outputManager); + generator.generate(); + + final String eventTypeSource = outputManager.getSource("test.EventType").toString(); + assertThat(eventTypeSource, + containsString("type EventType [8]bool\n" + + "type EventTypeChoiceValue uint8\n" + + "type EventTypeChoiceValues struct {\n" + + "\tA EventTypeChoiceValue\n" + + "\tBb EventTypeChoiceValue\n" + + "\tCcc EventTypeChoiceValue\n" + + "\tD EventTypeChoiceValue\n" + + "\tEeeee EventTypeChoiceValue\n}\n\n" + + "var EventTypeChoice = EventTypeChoiceValues{0, 1, 2, 3, 4}")); + final String messageSource = outputManager.getSource("test.SomeMessage").toString(); + assertThat(messageSource, containsString("type SomeMessage struct {\n\tMyEvent EventType\n}")); + } + } } diff --git a/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml b/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml new file mode 100644 index 0000000000..b9bd91c5d4 --- /dev/null +++ b/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + 0 + 1 + 2 + 3 + 4 + + + + + + + From 62adfb4d5e512d66c832a203955c84e8d355d3cc Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:43:46 +0100 Subject: [PATCH 315/805] [Go] Use upper case names when generating methods for enum. --- .../generation/golang/GolangGenerator.java | 10 +- .../golang/GolangGeneratorTest.java | 242 +++++++++++++++++- .../value-ref-with-lower-case-enum.xml | 3 + 3 files changed, 246 insertions(+), 9 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index e4667ceabb..f87e32c710 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1055,12 +1055,16 @@ private int generateFieldEncodeDecode( // Encode of a constant is a nullop, decode is assignment if (signalToken.isConstantEncoding()) { + final String rawValue = signalToken.encoding().constValue().toString(); + final int dotIndex = rawValue.indexOf('.'); + final String constantValue = toUpperFirstChar(rawValue.substring(0, dotIndex)) + "." + + toUpperFirstChar(rawValue.substring(dotIndex + 1)); decode.append(String.format( "\t%1$s.%2$s = %3$s\n", - varName, propertyName, signalToken.encoding().constValue())); + varName, propertyName, constantValue)); init.append(String.format( "\t%1$s.%2$s = %3$s\n", - varName, propertyName, signalToken.encoding().constValue())); + varName, propertyName, constantValue)); } else { @@ -1510,7 +1514,7 @@ private void generateEnum(final List tokens) throws IOException for (final Token token : tokens.subList(1, tokens.size() - 1)) { - generateSinceActingDeprecated(sb, enumName + "Enum", token.name(), token); + generateSinceActingDeprecated(sb, enumName + "Enum", formatPropertyName(token.name()), token); } out.append(generateFileHeader(ir.namespaces())); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java index 367e8644da..9e24f804b6 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java @@ -28,11 +28,13 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; class GolangGeneratorTest { @Test + @SuppressWarnings("MethodLength") void shouldUseUpperCaseTypeNamesWhenReferencingEnumValues() throws Exception { try (InputStream in = Tests.getLocalResource("value-ref-with-lower-case-enum.xml")) @@ -48,13 +50,208 @@ void shouldUseUpperCaseTypeNamesWhenReferencingEnumValues() throws Exception generator.generate(); final String engineTypeSource = outputManager.getSource("issue505.EngineType").toString(); - assertThat(engineTypeSource, allOf( - containsString("type EngineTypeEnum uint8"), - containsString("type EngineTypeValues struct {\n" + + assertEquals("// Generated SBE (Simple Binary Encoding) message codec\n" + + "\n" + + "package issue505\n" + + "\n" + + "import (\n" + + "\t\"fmt\"\n" + + "\t\"io\"\n" + + "\t\"reflect\"\n" + + ")\n" + + "\n" + + "type EngineTypeEnum uint8\n" + + "type EngineTypeValues struct {\n" + "\tGas EngineTypeEnum\n" + - "\tNullValue EngineTypeEnum\n}"))); + "\tOIl EngineTypeEnum\n" + + "\tWinD EngineTypeEnum\n" + + "\tSOLAR EngineTypeEnum\n" + + "\tNullValue EngineTypeEnum\n" + + "}\n" + + "\n" + + "var EngineType = EngineTypeValues{0, 1, 2, 3, 255}\n" + + "\n" + + "func (e EngineTypeEnum) Encode(_m *SbeGoMarshaller, _w io.Writer) error {\n" + + "\tif err := _m.WriteUint8(_w, uint8(e)); err != nil {\n" + + "\t\treturn err\n" + + "\t}\n" + + "\treturn nil\n" + + "}\n" + + "\n" + + "func (e *EngineTypeEnum) Decode(_m *SbeGoMarshaller, _r io.Reader, actingVersion uint16) error {\n" + + "\tif err := _m.ReadUint8(_r, (*uint8)(e)); err != nil {\n" + + "\t\treturn err\n" + + "\t}\n" + + "\treturn nil\n" + + "}\n" + + "\n" + + "func (e EngineTypeEnum) RangeCheck(actingVersion uint16, schemaVersion uint16) error {\n" + + "\tif actingVersion > schemaVersion {\n" + + "\t\treturn nil\n" + + "\t}\n" + + "\tvalue := reflect.ValueOf(EngineType)\n" + + "\tfor idx := 0; idx < value.NumField(); idx++ {\n" + + "\t\tif e == value.Field(idx).Interface() {\n" + + "\t\t\treturn nil\n" + + "\t\t}\n" + + "\t}\n" + + "\treturn fmt.Errorf(\"Range check failed on EngineType, unknown enumeration value %d\", e)\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) EncodedLength() int64 {\n" + + "\treturn 1\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) GasSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EngineTypeEnum) GasInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.GasSinceVersion()\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) GasDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) OIlSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EngineTypeEnum) OIlInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.OIlSinceVersion()\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) OIlDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) WinDSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EngineTypeEnum) WinDInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.WinDSinceVersion()\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) WinDDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) SOLARSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EngineTypeEnum) SOLARInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.SOLARSinceVersion()\n" + + "}\n" + + "\n" + + "func (*EngineTypeEnum) SOLARDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n", engineTypeSource); + final String messageSource = outputManager.getSource("issue505.SomeMessage").toString(); - assertThat(messageSource, containsString("type SomeMessage struct {\n\tEngineType EngineTypeEnum\n}")); + assertEquals("// Generated SBE (Simple Binary Encoding) message codec\n" + + "\n" + + "package issue505\n" + + "\n" + + "import (\n" + + "\t\"io\"\n" + + "\t\"io/ioutil\"\n" + + ")\n" + + "\n" + + "type SomeMessage struct {\n" + + "\tEngineType EngineTypeEnum\n" + + "}\n" + + "\n" + + "func (s *SomeMessage) Encode(_m *SbeGoMarshaller, _w io.Writer, doRangeCheck bool) error {\n" + + "\tif doRangeCheck {\n" + + "\t\tif err := s.RangeCheck(s.SbeSchemaVersion(), s.SbeSchemaVersion()); err != nil {\n" + + "\t\t\treturn err\n" + + "\t\t}\n" + + "\t}\n" + + "\treturn nil\n" + + "}\n" + + "\n" + + "func (s *SomeMessage) Decode(_m *SbeGoMarshaller, _r io.Reader, actingVersion uint16, " + + "blockLength uint16, doRangeCheck bool) error {\n" + + "\ts.EngineType = EngineType.Gas\n" + + "\tif actingVersion > s.SbeSchemaVersion() && blockLength > s.SbeBlockLength() {\n" + + "\t\tio.CopyN(ioutil.Discard, _r, int64(blockLength-s.SbeBlockLength()))\n" + + "\t}\n" + + "\tif doRangeCheck {\n" + + "\t\tif err := s.RangeCheck(actingVersion, s.SbeSchemaVersion()); err != nil {\n" + + "\t\t\treturn err\n" + + "\t\t}\n" + + "\t}\n" + + "\treturn nil\n" + + "}\n" + + "\n" + + "func (s *SomeMessage) RangeCheck(actingVersion uint16, schemaVersion uint16) error {\n" + + "\tif err := s.EngineType.RangeCheck(actingVersion, schemaVersion); err != nil {\n" + + "\t\treturn err\n" + + "\t}\n" + + "\treturn nil\n" + + "}\n" + + "\n" + + "func SomeMessageInit(s *SomeMessage) {\n" + + "\ts.EngineType = EngineType.Gas\n" + + "\treturn\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeBlockLength() (blockLength uint16) {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeTemplateId() (templateId uint16) {\n" + + "\treturn 1\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeSchemaId() (schemaId uint16) {\n" + + "\treturn 505\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeSchemaVersion() (schemaVersion uint16) {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeSemanticType() (semanticType []byte) {\n" + + "\treturn []byte(\"\")\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeSemanticVersion() (semanticVersion string) {\n" + + "\treturn \"1.0\"\n" + + "}\n" + + "\n" + + "func (*SomeMessage) EngineTypeId() uint16 {\n" + + "\treturn 1\n" + + "}\n" + + "\n" + + "func (*SomeMessage) EngineTypeSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (s *SomeMessage) EngineTypeInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= s.EngineTypeSinceVersion()\n" + + "}\n" + + "\n" + + "func (*SomeMessage) EngineTypeDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*SomeMessage) EngineTypeMetaAttribute(meta int) string {\n" + + "\tswitch meta {\n" + + "\tcase 1:\n" + + "\t\treturn \"\"\n" + + "\tcase 2:\n" + + "\t\treturn \"\"\n" + + "\tcase 3:\n" + + "\t\treturn \"\"\n" + + "\tcase 4:\n" + + "\t\treturn \"constant\"\n" + + "\t}\n" + + "\treturn \"\"\n" + + "}\n", messageSource); } } @@ -74,6 +271,7 @@ void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception generator.generate(); final String eventTypeSource = outputManager.getSource("test.EventType").toString(); + System.out.println(eventTypeSource); assertThat(eventTypeSource, containsString("type EventType [8]bool\n" + "type EventTypeChoiceValue uint8\n" + @@ -84,8 +282,40 @@ void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception "\tD EventTypeChoiceValue\n" + "\tEeeee EventTypeChoiceValue\n}\n\n" + "var EventTypeChoice = EventTypeChoiceValues{0, 1, 2, 3, 4}")); + final String messageSource = outputManager.getSource("test.SomeMessage").toString(); - assertThat(messageSource, containsString("type SomeMessage struct {\n\tMyEvent EventType\n}")); + assertThat(messageSource, + allOf( + containsString("type SomeMessage struct {\n\tMyEvent EventType\n}"), + containsString("func (s *SomeMessage) Encode(_m *SbeGoMarshaller, _w io.Writer," + + " doRangeCheck bool) error {\n" + + "\tif doRangeCheck {\n" + + "\t\tif err := s.RangeCheck(s.SbeSchemaVersion(), s.SbeSchemaVersion()); err != nil {\n" + + "\t\t\treturn err\n" + + "\t\t}\n" + + "\t}\n" + + "\tif err := s.MyEvent.Encode(_m, _w); err != nil {\n" + + "\t\treturn err\n" + + "\t}\n" + + "\treturn nil\n" + + "}\n"), + containsString("func (s *SomeMessage) Decode(_m *SbeGoMarshaller, _r io.Reader," + + " actingVersion uint16, blockLength uint16, doRangeCheck bool) error {\n" + + "\tif s.MyEventInActingVersion(actingVersion) {\n" + + "\t\tif err := s.MyEvent.Decode(_m, _r, actingVersion); err != nil {\n" + + "\t\t\treturn err\n" + + "\t\t}\n" + + "\t}\n" + + "\tif actingVersion > s.SbeSchemaVersion() && blockLength > s.SbeBlockLength() {\n" + + "\t\tio.CopyN(ioutil.Discard, _r, int64(blockLength-s.SbeBlockLength()))\n" + + "\t}\n" + + "\tif doRangeCheck {\n" + + "\t\tif err := s.RangeCheck(actingVersion, s.SbeSchemaVersion()); err != nil {\n" + + "\t\t\treturn err\n" + + "\t\t}\n" + + "\t}\n" + + "\treturn nil\n" + + "}\n"))); } } } diff --git a/sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml b/sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml index c33b4133c8..421a94e11a 100644 --- a/sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml +++ b/sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml @@ -15,6 +15,9 @@ 0 + 1 + 2 + 3
    From b5bb3c16c49f3826860b4240ae79f02bc1d77b08 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 15:49:00 +0100 Subject: [PATCH 316/805] [Go] Use upper case names when generating methods for bitset. --- .../generation/golang/GolangGenerator.java | 2 +- .../golang/GolangGeneratorTest.java | 200 ++++++++++++++++-- .../message-with-lower-case-bitset.xml | 2 +- 3 files changed, 185 insertions(+), 19 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index f87e32c710..ef9c04cc3b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1475,7 +1475,7 @@ private void generateChoiceSet(final List tokens) throws IOException for (final Token token : tokens.subList(1, tokens.size() - 1)) { - generateSinceActingDeprecated(sb, choiceName, token.name(), token); + generateSinceActingDeprecated(sb, choiceName, formatPropertyName(token.name()), token); } out.append(generateFileHeader(ir.namespaces())); out.append(sb); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java index 9e24f804b6..14ce4087c8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java @@ -25,9 +25,6 @@ import java.io.InputStream; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; import static org.junit.jupiter.api.Assertions.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -256,6 +253,7 @@ void shouldUseUpperCaseTypeNamesWhenReferencingEnumValues() throws Exception } @Test + @SuppressWarnings("MethodLength") void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception { try (InputStream in = Tests.getLocalResource("message-with-lower-case-bitset.xml")) @@ -271,24 +269,129 @@ void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception generator.generate(); final String eventTypeSource = outputManager.getSource("test.EventType").toString(); - System.out.println(eventTypeSource); - assertThat(eventTypeSource, - containsString("type EventType [8]bool\n" + + assertEquals("// Generated SBE (Simple Binary Encoding) message codec\n" + + "\n" + + "package test\n" + + "\n" + + "import (\n" + + "\t\"io\"\n" + + ")\n" + + "\n" + + "type EventType [8]bool\n" + "type EventTypeChoiceValue uint8\n" + "type EventTypeChoiceValues struct {\n" + "\tA EventTypeChoiceValue\n" + "\tBb EventTypeChoiceValue\n" + "\tCcc EventTypeChoiceValue\n" + "\tD EventTypeChoiceValue\n" + - "\tEeeee EventTypeChoiceValue\n}\n\n" + - "var EventTypeChoice = EventTypeChoiceValues{0, 1, 2, 3, 4}")); + "\tEeEee EventTypeChoiceValue\n" + + "}\n" + + "\n" + + "var EventTypeChoice = EventTypeChoiceValues{0, 1, 2, 3, 4}\n" + + "\n" + + "func (e *EventType) Encode(_m *SbeGoMarshaller, _w io.Writer) error {\n" + + "\tvar wireval uint8 = 0\n" + + "\tfor k, v := range e {\n" + + "\t\tif v {\n" + + "\t\t\twireval |= (1 << uint(k))\n" + + "\t\t}\n" + + "\t}\n" + + "\treturn _m.WriteUint8(_w, wireval)\n" + + "}\n" + + "\n" + + "func (e *EventType) Decode(_m *SbeGoMarshaller, _r io.Reader, actingVersion uint16) error {\n" + + "\tvar wireval uint8\n" + + "\n" + + "\tif err := _m.ReadUint8(_r, &wireval); err != nil {\n" + + "\t\treturn err\n" + + "\t}\n" + + "\n" + + "\tvar idx uint\n" + + "\tfor idx = 0; idx < 8; idx++ {\n" + + "\t\te[idx] = (wireval & (1 << idx)) > 0\n" + + "\t}\n" + + "\treturn nil\n" + + "}\n" + + "\n" + + "func (EventType) EncodedLength() int64 {\n" + + "\treturn 1\n" + + "}\n" + + "\n" + + "func (*EventType) ASinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EventType) AInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.ASinceVersion()\n" + + "}\n" + + "\n" + + "func (*EventType) ADeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*EventType) BbSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EventType) BbInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.BbSinceVersion()\n" + + "}\n" + + "\n" + + "func (*EventType) BbDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*EventType) CccSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EventType) CccInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.CccSinceVersion()\n" + + "}\n" + + "\n" + + "func (*EventType) CccDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*EventType) DSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EventType) DInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.DSinceVersion()\n" + + "}\n" + + "\n" + + "func (*EventType) DDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*EventType) EeEeeSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (e *EventType) EeEeeInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= e.EeEeeSinceVersion()\n" + + "}\n" + + "\n" + + "func (*EventType) EeEeeDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n", eventTypeSource); final String messageSource = outputManager.getSource("test.SomeMessage").toString(); - assertThat(messageSource, - allOf( - containsString("type SomeMessage struct {\n\tMyEvent EventType\n}"), - containsString("func (s *SomeMessage) Encode(_m *SbeGoMarshaller, _w io.Writer," + - " doRangeCheck bool) error {\n" + + assertEquals("// Generated SBE (Simple Binary Encoding) message codec\n" + + "\n" + + "package test\n" + + "\n" + + "import (\n" + + "\t\"io\"\n" + + "\t\"io/ioutil\"\n" + + ")\n" + + "\n" + + "type SomeMessage struct {\n" + + "\tMyEvent EventType\n" + + "}\n" + + "\n" + + "func (s *SomeMessage) Encode(_m *SbeGoMarshaller, _w io.Writer, doRangeCheck bool) error {\n" + "\tif doRangeCheck {\n" + "\t\tif err := s.RangeCheck(s.SbeSchemaVersion(), s.SbeSchemaVersion()); err != nil {\n" + "\t\t\treturn err\n" + @@ -298,9 +401,10 @@ void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception "\t\treturn err\n" + "\t}\n" + "\treturn nil\n" + - "}\n"), - containsString("func (s *SomeMessage) Decode(_m *SbeGoMarshaller, _r io.Reader," + - " actingVersion uint16, blockLength uint16, doRangeCheck bool) error {\n" + + "}\n" + + "\n" + + "func (s *SomeMessage) Decode(_m *SbeGoMarshaller, _r io.Reader, actingVersion uint16, " + + "blockLength uint16, doRangeCheck bool) error {\n" + "\tif s.MyEventInActingVersion(actingVersion) {\n" + "\t\tif err := s.MyEvent.Decode(_m, _r, actingVersion); err != nil {\n" + "\t\t\treturn err\n" + @@ -315,7 +419,69 @@ void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception "\t\t}\n" + "\t}\n" + "\treturn nil\n" + - "}\n"))); + "}\n" + + "\n" + + "func (s *SomeMessage) RangeCheck(actingVersion uint16, schemaVersion uint16) error {\n" + + "\treturn nil\n" + + "}\n" + + "\n" + + "func SomeMessageInit(s *SomeMessage) {\n" + + "\treturn\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeBlockLength() (blockLength uint16) {\n" + + "\treturn 1\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeTemplateId() (templateId uint16) {\n" + + "\treturn 1\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeSchemaId() (schemaId uint16) {\n" + + "\treturn 973\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeSchemaVersion() (schemaVersion uint16) {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeSemanticType() (semanticType []byte) {\n" + + "\treturn []byte(\"\")\n" + + "}\n" + + "\n" + + "func (*SomeMessage) SbeSemanticVersion() (semanticVersion string) {\n" + + "\treturn \"1.0\"\n" + + "}\n" + + "\n" + + "func (*SomeMessage) MyEventId() uint16 {\n" + + "\treturn 1\n" + + "}\n" + + "\n" + + "func (*SomeMessage) MyEventSinceVersion() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (s *SomeMessage) MyEventInActingVersion(actingVersion uint16) bool {\n" + + "\treturn actingVersion >= s.MyEventSinceVersion()\n" + + "}\n" + + "\n" + + "func (*SomeMessage) MyEventDeprecated() uint16 {\n" + + "\treturn 0\n" + + "}\n" + + "\n" + + "func (*SomeMessage) MyEventMetaAttribute(meta int) string {\n" + + "\tswitch meta {\n" + + "\tcase 1:\n" + + "\t\treturn \"\"\n" + + "\tcase 2:\n" + + "\t\treturn \"\"\n" + + "\tcase 3:\n" + + "\t\treturn \"\"\n" + + "\tcase 4:\n" + + "\t\treturn \"required\"\n" + + "\t}\n" + + "\treturn \"\"\n" + + "}\n", messageSource); } } } diff --git a/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml b/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml index b9bd91c5d4..ba08af1fc7 100644 --- a/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml +++ b/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml @@ -18,7 +18,7 @@ 1 2 3 - 4 + 4
    From 660c96b7835125ff913f00e6b14d0225f719e25a Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:25:57 +0100 Subject: [PATCH 317/805] [Go] Add tests with lower-case enums and bitsets. --- build.gradle | 2 + gocode/Makefile | 2 +- gocode/src/issue505/Issue505_test.go | 29 ++ gocode/src/test973/EventType.go | 107 +++++++ gocode/src/test973/MessageHeader.go | 192 ++++++++++++ gocode/src/test973/SbeMarshalling.go | 283 ++++++++++++++++++ gocode/src/test973/SomeMessage.go | 103 +++++++ gocode/src/test973/test973_test.go | 38 +++ .../golang/GolangGeneratorTest.java | 8 +- .../message-with-lower-case-bitset.xml | 2 +- 10 files changed, 760 insertions(+), 6 deletions(-) create mode 100644 gocode/src/issue505/Issue505_test.go create mode 100644 gocode/src/test973/EventType.go create mode 100644 gocode/src/test973/MessageHeader.go create mode 100644 gocode/src/test973/SbeMarshalling.go create mode 100644 gocode/src/test973/SomeMessage.go create mode 100644 gocode/src/test973/test973_test.go diff --git a/build.gradle b/build.gradle index 0f74a5e005..587bddc0a0 100644 --- a/build.gradle +++ b/build.gradle @@ -700,6 +700,8 @@ tasks.register('generateGolangCodecsWithXSD', JavaExec) { 'sbe-tool/src/test/resources/issue849.xml', 'sbe-tool/src/test/resources/since-deprecated-test-schema.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', + 'sbe-tool/src/test/resources/value-ref-with-lower-case-enum.xml', + 'sbe-tool/src/test/resources/message-with-lower-case-bitset.xml', 'gocode/resources/example-composite.xml', 'gocode/resources/group-with-data-extension-schema.xml', 'gocode/resources/simple.xml'] diff --git a/gocode/Makefile b/gocode/Makefile index 456cced904..eebb2b4f38 100644 --- a/gocode/Makefile +++ b/gocode/Makefile @@ -72,7 +72,7 @@ test: $(DEP) go install \ ;done)) (export GOPATH=$(GOPATH) && \ - (for t in baseline-bigendian mktdata group_with_data group_with_data_extension composite_elements composite since-deprecated simple issue435 issue472 issue483 issue488 issue560 issue847 issue848 issue849; do \ + (for t in baseline-bigendian mktdata group_with_data group_with_data_extension composite_elements composite since-deprecated simple issue435 issue472 issue483 issue488 issue560 issue847 issue848 issue849 issue505 test973; do \ cd $(GOPATH)/src/$$t && \ go build && \ go fmt && \ diff --git a/gocode/src/issue505/Issue505_test.go b/gocode/src/issue505/Issue505_test.go new file mode 100644 index 0000000000..5e939a4f0d --- /dev/null +++ b/gocode/src/issue505/Issue505_test.go @@ -0,0 +1,29 @@ +package issue505 + +import ( + "bytes" + "testing" +) + +func TestConstant(t *testing.T) { + message := new(SomeMessage) + SomeMessageInit(message) + + if message.EngineType != EngineType.Gas { + t.Log("message.EngineType != EngineType.Gas:\n", message.EngineType, EngineType.Gas) + t.Fail() + } + + m := NewSbeGoMarshaller() + var buf = new(bytes.Buffer) + var out = *new(SomeMessage) + if err := out.Decode(m, buf, message.SbeSchemaVersion(), message.SbeBlockLength(), true); err != nil { + t.Log("Decoding Error", err) + t.Fail() + } + + if out.EngineType != EngineType.Gas { + t.Log("out.EngineType != EngineType.Gas:\n", out.EngineType, EngineType.Gas) + t.Fail() + } +} diff --git a/gocode/src/test973/EventType.go b/gocode/src/test973/EventType.go new file mode 100644 index 0000000000..fe08752472 --- /dev/null +++ b/gocode/src/test973/EventType.go @@ -0,0 +1,107 @@ +// Generated SBE (Simple Binary Encoding) message codec + +package test973 + +import ( + "io" +) + +type EventType [8]bool +type EventTypeChoiceValue uint8 +type EventTypeChoiceValues struct { + A EventTypeChoiceValue + Bb EventTypeChoiceValue + Ccc EventTypeChoiceValue + D EventTypeChoiceValue + EeEee EventTypeChoiceValue +} + +var EventTypeChoice = EventTypeChoiceValues{0, 1, 2, 3, 4} + +func (e *EventType) Encode(_m *SbeGoMarshaller, _w io.Writer) error { + var wireval uint8 = 0 + for k, v := range e { + if v { + wireval |= (1 << uint(k)) + } + } + return _m.WriteUint8(_w, wireval) +} + +func (e *EventType) Decode(_m *SbeGoMarshaller, _r io.Reader, actingVersion uint16) error { + var wireval uint8 + + if err := _m.ReadUint8(_r, &wireval); err != nil { + return err + } + + var idx uint + for idx = 0; idx < 8; idx++ { + e[idx] = (wireval & (1 << idx)) > 0 + } + return nil +} + +func (EventType) EncodedLength() int64 { + return 1 +} + +func (*EventType) ASinceVersion() uint16 { + return 0 +} + +func (e *EventType) AInActingVersion(actingVersion uint16) bool { + return actingVersion >= e.ASinceVersion() +} + +func (*EventType) ADeprecated() uint16 { + return 0 +} + +func (*EventType) BbSinceVersion() uint16 { + return 0 +} + +func (e *EventType) BbInActingVersion(actingVersion uint16) bool { + return actingVersion >= e.BbSinceVersion() +} + +func (*EventType) BbDeprecated() uint16 { + return 0 +} + +func (*EventType) CccSinceVersion() uint16 { + return 0 +} + +func (e *EventType) CccInActingVersion(actingVersion uint16) bool { + return actingVersion >= e.CccSinceVersion() +} + +func (*EventType) CccDeprecated() uint16 { + return 0 +} + +func (*EventType) DSinceVersion() uint16 { + return 0 +} + +func (e *EventType) DInActingVersion(actingVersion uint16) bool { + return actingVersion >= e.DSinceVersion() +} + +func (*EventType) DDeprecated() uint16 { + return 0 +} + +func (*EventType) EeEeeSinceVersion() uint16 { + return 0 +} + +func (e *EventType) EeEeeInActingVersion(actingVersion uint16) bool { + return actingVersion >= e.EeEeeSinceVersion() +} + +func (*EventType) EeEeeDeprecated() uint16 { + return 0 +} diff --git a/gocode/src/test973/MessageHeader.go b/gocode/src/test973/MessageHeader.go new file mode 100644 index 0000000000..a7ed9008b5 --- /dev/null +++ b/gocode/src/test973/MessageHeader.go @@ -0,0 +1,192 @@ +// Generated SBE (Simple Binary Encoding) message codec + +package test973 + +import ( + "fmt" + "io" + "math" +) + +type MessageHeader struct { + BlockLength uint16 + TemplateId uint16 + SchemaId uint16 + Version uint16 +} + +func (m *MessageHeader) Encode(_m *SbeGoMarshaller, _w io.Writer) error { + if err := _m.WriteUint16(_w, m.BlockLength); err != nil { + return err + } + if err := _m.WriteUint16(_w, m.TemplateId); err != nil { + return err + } + if err := _m.WriteUint16(_w, m.SchemaId); err != nil { + return err + } + if err := _m.WriteUint16(_w, m.Version); err != nil { + return err + } + return nil +} + +func (m *MessageHeader) Decode(_m *SbeGoMarshaller, _r io.Reader, actingVersion uint16) error { + if !m.BlockLengthInActingVersion(actingVersion) { + m.BlockLength = m.BlockLengthNullValue() + } else { + if err := _m.ReadUint16(_r, &m.BlockLength); err != nil { + return err + } + } + if !m.TemplateIdInActingVersion(actingVersion) { + m.TemplateId = m.TemplateIdNullValue() + } else { + if err := _m.ReadUint16(_r, &m.TemplateId); err != nil { + return err + } + } + if !m.SchemaIdInActingVersion(actingVersion) { + m.SchemaId = m.SchemaIdNullValue() + } else { + if err := _m.ReadUint16(_r, &m.SchemaId); err != nil { + return err + } + } + if !m.VersionInActingVersion(actingVersion) { + m.Version = m.VersionNullValue() + } else { + if err := _m.ReadUint16(_r, &m.Version); err != nil { + return err + } + } + return nil +} + +func (m *MessageHeader) RangeCheck(actingVersion uint16, schemaVersion uint16) error { + if m.BlockLengthInActingVersion(actingVersion) { + if m.BlockLength < m.BlockLengthMinValue() || m.BlockLength > m.BlockLengthMaxValue() { + return fmt.Errorf("Range check failed on m.BlockLength (%v < %v > %v)", m.BlockLengthMinValue(), m.BlockLength, m.BlockLengthMaxValue()) + } + } + if m.TemplateIdInActingVersion(actingVersion) { + if m.TemplateId < m.TemplateIdMinValue() || m.TemplateId > m.TemplateIdMaxValue() { + return fmt.Errorf("Range check failed on m.TemplateId (%v < %v > %v)", m.TemplateIdMinValue(), m.TemplateId, m.TemplateIdMaxValue()) + } + } + if m.SchemaIdInActingVersion(actingVersion) { + if m.SchemaId < m.SchemaIdMinValue() || m.SchemaId > m.SchemaIdMaxValue() { + return fmt.Errorf("Range check failed on m.SchemaId (%v < %v > %v)", m.SchemaIdMinValue(), m.SchemaId, m.SchemaIdMaxValue()) + } + } + if m.VersionInActingVersion(actingVersion) { + if m.Version < m.VersionMinValue() || m.Version > m.VersionMaxValue() { + return fmt.Errorf("Range check failed on m.Version (%v < %v > %v)", m.VersionMinValue(), m.Version, m.VersionMaxValue()) + } + } + return nil +} + +func MessageHeaderInit(m *MessageHeader) { + return +} + +func (*MessageHeader) EncodedLength() int64 { + return 8 +} + +func (*MessageHeader) BlockLengthMinValue() uint16 { + return 0 +} + +func (*MessageHeader) BlockLengthMaxValue() uint16 { + return math.MaxUint16 - 1 +} + +func (*MessageHeader) BlockLengthNullValue() uint16 { + return math.MaxUint16 +} + +func (*MessageHeader) BlockLengthSinceVersion() uint16 { + return 0 +} + +func (m *MessageHeader) BlockLengthInActingVersion(actingVersion uint16) bool { + return actingVersion >= m.BlockLengthSinceVersion() +} + +func (*MessageHeader) BlockLengthDeprecated() uint16 { + return 0 +} + +func (*MessageHeader) TemplateIdMinValue() uint16 { + return 0 +} + +func (*MessageHeader) TemplateIdMaxValue() uint16 { + return math.MaxUint16 - 1 +} + +func (*MessageHeader) TemplateIdNullValue() uint16 { + return math.MaxUint16 +} + +func (*MessageHeader) TemplateIdSinceVersion() uint16 { + return 0 +} + +func (m *MessageHeader) TemplateIdInActingVersion(actingVersion uint16) bool { + return actingVersion >= m.TemplateIdSinceVersion() +} + +func (*MessageHeader) TemplateIdDeprecated() uint16 { + return 0 +} + +func (*MessageHeader) SchemaIdMinValue() uint16 { + return 0 +} + +func (*MessageHeader) SchemaIdMaxValue() uint16 { + return math.MaxUint16 - 1 +} + +func (*MessageHeader) SchemaIdNullValue() uint16 { + return math.MaxUint16 +} + +func (*MessageHeader) SchemaIdSinceVersion() uint16 { + return 0 +} + +func (m *MessageHeader) SchemaIdInActingVersion(actingVersion uint16) bool { + return actingVersion >= m.SchemaIdSinceVersion() +} + +func (*MessageHeader) SchemaIdDeprecated() uint16 { + return 0 +} + +func (*MessageHeader) VersionMinValue() uint16 { + return 0 +} + +func (*MessageHeader) VersionMaxValue() uint16 { + return math.MaxUint16 - 1 +} + +func (*MessageHeader) VersionNullValue() uint16 { + return math.MaxUint16 +} + +func (*MessageHeader) VersionSinceVersion() uint16 { + return 0 +} + +func (m *MessageHeader) VersionInActingVersion(actingVersion uint16) bool { + return actingVersion >= m.VersionSinceVersion() +} + +func (*MessageHeader) VersionDeprecated() uint16 { + return 0 +} diff --git a/gocode/src/test973/SbeMarshalling.go b/gocode/src/test973/SbeMarshalling.go new file mode 100644 index 0000000000..76cd098c51 --- /dev/null +++ b/gocode/src/test973/SbeMarshalling.go @@ -0,0 +1,283 @@ +// Copyright (C) 2017 MarketFactory, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file provides a simple bespoke marshalling layer for the +// standard binary encoding golang backend and is part of: +// +// https://github.com/real-logic/simple-binary-encoding + +package test973 + +import ( + "io" + "math" +) + +// Allocate via NewSbeGoMarshaller to initialize +type SbeGoMarshaller struct { + b8 []byte // statically allocated tmp space to avoid alloc + b1 []byte // previously created slice into b to save time + b2 []byte // previously created slice into b to save time + b4 []byte // previously created slice into b to save time +} + +func NewSbeGoMarshaller() *SbeGoMarshaller { + var m SbeGoMarshaller + m.b8 = make([]byte, 8) + m.b1 = m.b8[:1] + m.b2 = m.b8[:2] + m.b4 = m.b8[:4] + return &m +} + +// The "standard" MessageHeader. +// +// Most applications will use this as it's the default and optimized +// although it's possible to change it by: +// a) using a different sized BlockLength, or +// b) adding arbitrary fields +// +// If the MessageHeader is not "standard" then you can use the +// generated MessageHeader type in MessageHeader.go otherwise we +// recommend this one. +type SbeGoMessageHeader struct { + BlockLength uint16 + TemplateId uint16 + SchemaId uint16 + Version uint16 +} + +func (m SbeGoMessageHeader) Encode(_m *SbeGoMarshaller, _w io.Writer) error { + _m.b8[0] = byte(m.BlockLength) + _m.b8[1] = byte(m.BlockLength >> 8) + _m.b8[2] = byte(m.TemplateId) + _m.b8[3] = byte(m.TemplateId >> 8) + _m.b8[4] = byte(m.SchemaId) + _m.b8[5] = byte(m.SchemaId >> 8) + _m.b8[6] = byte(m.Version) + _m.b8[7] = byte(m.Version >> 8) + if _, err := _w.Write(_m.b8); err != nil { + return err + } + return nil +} + +func (m *SbeGoMessageHeader) Decode(_m *SbeGoMarshaller, _r io.Reader) error { + if _, err := io.ReadFull(_r, _m.b8); err != nil { + return err + } + m.BlockLength = uint16(_m.b8[0]) | uint16(_m.b8[1])<<8 + m.TemplateId = uint16(_m.b8[2]) | uint16(_m.b8[3])<<8 + m.SchemaId = uint16(_m.b8[4]) | uint16(_m.b8[5])<<8 + m.Version = uint16(_m.b8[6]) | uint16(_m.b8[7])<<8 + return nil +} + +func (m *SbeGoMarshaller) WriteUint8(w io.Writer, v uint8) error { + m.b1[0] = byte(v) + _, err := w.Write(m.b1) + return err +} + +func (m *SbeGoMarshaller) WriteUint16(w io.Writer, v uint16) error { + m.b2[0] = byte(v) + m.b2[1] = byte(v >> 8) + _, err := w.Write(m.b2) + return err +} + +func (m *SbeGoMarshaller) WriteUint32(w io.Writer, v uint32) error { + m.b4[0] = byte(v) + m.b4[1] = byte(v >> 8) + m.b4[2] = byte(v >> 16) + m.b4[3] = byte(v >> 24) + _, err := w.Write(m.b4) + return err +} + +func (m *SbeGoMarshaller) WriteUint64(w io.Writer, v uint64) error { + m.b8[0] = byte(v) + m.b8[1] = byte(v >> 8) + m.b8[2] = byte(v >> 16) + m.b8[3] = byte(v >> 24) + m.b8[4] = byte(v >> 32) + m.b8[5] = byte(v >> 40) + m.b8[6] = byte(v >> 48) + m.b8[7] = byte(v >> 56) + _, err := w.Write(m.b8) + return err +} + +func (m *SbeGoMarshaller) WriteInt8(w io.Writer, v int8) error { + m.b1[0] = byte(v) + _, err := w.Write(m.b1) + return err +} + +func (m *SbeGoMarshaller) WriteInt16(w io.Writer, v int16) error { + m.b2[0] = byte(v) + m.b2[1] = byte(v >> 8) + _, err := w.Write(m.b2) + return err +} + +func (m *SbeGoMarshaller) WriteInt32(w io.Writer, v int32) error { + m.b4[0] = byte(v) + m.b4[1] = byte(v >> 8) + m.b4[2] = byte(v >> 16) + m.b4[3] = byte(v >> 24) + _, err := w.Write(m.b4) + return err +} + +func (m *SbeGoMarshaller) WriteInt64(w io.Writer, v int64) error { + m.b8[0] = byte(v) + m.b8[1] = byte(v >> 8) + m.b8[2] = byte(v >> 16) + m.b8[3] = byte(v >> 24) + m.b8[4] = byte(v >> 32) + m.b8[5] = byte(v >> 40) + m.b8[6] = byte(v >> 48) + m.b8[7] = byte(v >> 56) + _, err := w.Write(m.b8) + return err +} + +func (m *SbeGoMarshaller) WriteFloat32(w io.Writer, v float32) error { + u32 := math.Float32bits(v) + m.b4[0] = byte(u32) + m.b4[1] = byte(u32 >> 8) + m.b4[2] = byte(u32 >> 16) + m.b4[3] = byte(u32 >> 24) + _, err := w.Write(m.b4) + return err +} + +func (m *SbeGoMarshaller) WriteFloat64(w io.Writer, v float64) error { + u64 := math.Float64bits(v) + m.b8[0] = byte(u64) + m.b8[1] = byte(u64 >> 8) + m.b8[2] = byte(u64 >> 16) + m.b8[3] = byte(u64 >> 24) + m.b8[4] = byte(u64 >> 32) + m.b8[5] = byte(u64 >> 40) + m.b8[6] = byte(u64 >> 48) + m.b8[7] = byte(u64 >> 56) + _, err := w.Write(m.b8) + return err +} + +func (m *SbeGoMarshaller) WriteBytes(w io.Writer, v []byte) error { + _, err := w.Write(v) + return err +} + +func (m *SbeGoMarshaller) ReadUint8(r io.Reader, v *uint8) error { + if _, err := io.ReadFull(r, m.b1); err != nil { + return err + } + *v = uint8(m.b1[0]) + return nil +} + +func (m *SbeGoMarshaller) ReadUint16(r io.Reader, v *uint16) error { + if _, err := io.ReadFull(r, m.b2); err != nil { + return err + } + *v = (uint16(m.b2[0]) | uint16(m.b2[1])<<8) + return nil +} + +func (m *SbeGoMarshaller) ReadUint32(r io.Reader, v *uint32) error { + if _, err := io.ReadFull(r, m.b4); err != nil { + return err + } + *v = (uint32(m.b4[0]) | uint32(m.b4[1])<<8 | + uint32(m.b4[2])<<16 | uint32(m.b4[3])<<24) + return nil +} + +func (m *SbeGoMarshaller) ReadUint64(r io.Reader, v *uint64) error { + if _, err := io.ReadFull(r, m.b8); err != nil { + return err + } + *v = (uint64(m.b8[0]) | uint64(m.b8[1])<<8 | + uint64(m.b8[2])<<16 | uint64(m.b8[3])<<24 | + uint64(m.b8[4])<<32 | uint64(m.b8[5])<<40 | + uint64(m.b8[6])<<48 | uint64(m.b8[7])<<56) + return nil +} + +func (m *SbeGoMarshaller) ReadInt8(r io.Reader, v *int8) error { + if _, err := io.ReadFull(r, m.b1); err != nil { + return err + } + *v = int8(m.b1[0]) + return nil +} + +func (m *SbeGoMarshaller) ReadInt16(r io.Reader, v *int16) error { + if _, err := io.ReadFull(r, m.b2); err != nil { + return err + } + *v = (int16(m.b2[0]) | int16(m.b2[1])<<8) + return nil +} + +func (m *SbeGoMarshaller) ReadInt32(r io.Reader, v *int32) error { + if _, err := io.ReadFull(r, m.b4); err != nil { + return err + } + *v = (int32(m.b4[0]) | int32(m.b4[1])<<8 | + int32(m.b4[2])<<16 | int32(m.b4[3])<<24) + return nil +} + +func (m *SbeGoMarshaller) ReadInt64(r io.Reader, v *int64) error { + if _, err := io.ReadFull(r, m.b8); err != nil { + return err + } + *v = (int64(m.b8[0]) | int64(m.b8[1])<<8 | + int64(m.b8[2])<<16 | int64(m.b8[3])<<24 | + int64(m.b8[4])<<32 | int64(m.b8[5])<<40 | + int64(m.b8[6])<<48 | int64(m.b8[7])<<56) + return nil +} + +func (m *SbeGoMarshaller) ReadFloat32(r io.Reader, v *float32) error { + if _, err := io.ReadFull(r, m.b4); err != nil { + return err + } + *v = math.Float32frombits(uint32(m.b4[0]) | uint32(m.b4[1])<<8 | + uint32(m.b4[2])<<16 | uint32(m.b4[3])<<24) + return nil +} + +func (m *SbeGoMarshaller) ReadFloat64(r io.Reader, v *float64) error { + if _, err := io.ReadFull(r, m.b8); err != nil { + return err + } + *v = math.Float64frombits(uint64(m.b8[0]) | uint64(m.b8[1])<<8 | + uint64(m.b8[2])<<16 | uint64(m.b8[3])<<24 | + uint64(m.b8[4])<<32 | uint64(m.b8[5])<<40 | + uint64(m.b8[6])<<48 | uint64(m.b8[7])<<56) + return nil +} + +func (m *SbeGoMarshaller) ReadBytes(r io.Reader, b []byte) error { + if _, err := io.ReadFull(r, b); err != nil { + return err + } + return nil +} diff --git a/gocode/src/test973/SomeMessage.go b/gocode/src/test973/SomeMessage.go new file mode 100644 index 0000000000..460c5e89d1 --- /dev/null +++ b/gocode/src/test973/SomeMessage.go @@ -0,0 +1,103 @@ +// Generated SBE (Simple Binary Encoding) message codec + +package test973 + +import ( + "io" + "io/ioutil" +) + +type SomeMessage struct { + MyEvent EventType +} + +func (s *SomeMessage) Encode(_m *SbeGoMarshaller, _w io.Writer, doRangeCheck bool) error { + if doRangeCheck { + if err := s.RangeCheck(s.SbeSchemaVersion(), s.SbeSchemaVersion()); err != nil { + return err + } + } + if err := s.MyEvent.Encode(_m, _w); err != nil { + return err + } + return nil +} + +func (s *SomeMessage) Decode(_m *SbeGoMarshaller, _r io.Reader, actingVersion uint16, blockLength uint16, doRangeCheck bool) error { + if s.MyEventInActingVersion(actingVersion) { + if err := s.MyEvent.Decode(_m, _r, actingVersion); err != nil { + return err + } + } + if actingVersion > s.SbeSchemaVersion() && blockLength > s.SbeBlockLength() { + io.CopyN(ioutil.Discard, _r, int64(blockLength-s.SbeBlockLength())) + } + if doRangeCheck { + if err := s.RangeCheck(actingVersion, s.SbeSchemaVersion()); err != nil { + return err + } + } + return nil +} + +func (s *SomeMessage) RangeCheck(actingVersion uint16, schemaVersion uint16) error { + return nil +} + +func SomeMessageInit(s *SomeMessage) { + return +} + +func (*SomeMessage) SbeBlockLength() (blockLength uint16) { + return 1 +} + +func (*SomeMessage) SbeTemplateId() (templateId uint16) { + return 1 +} + +func (*SomeMessage) SbeSchemaId() (schemaId uint16) { + return 973 +} + +func (*SomeMessage) SbeSchemaVersion() (schemaVersion uint16) { + return 0 +} + +func (*SomeMessage) SbeSemanticType() (semanticType []byte) { + return []byte("") +} + +func (*SomeMessage) SbeSemanticVersion() (semanticVersion string) { + return "1.0" +} + +func (*SomeMessage) MyEventId() uint16 { + return 1 +} + +func (*SomeMessage) MyEventSinceVersion() uint16 { + return 0 +} + +func (s *SomeMessage) MyEventInActingVersion(actingVersion uint16) bool { + return actingVersion >= s.MyEventSinceVersion() +} + +func (*SomeMessage) MyEventDeprecated() uint16 { + return 0 +} + +func (*SomeMessage) MyEventMetaAttribute(meta int) string { + switch meta { + case 1: + return "" + case 2: + return "" + case 3: + return "" + case 4: + return "required" + } + return "" +} diff --git a/gocode/src/test973/test973_test.go b/gocode/src/test973/test973_test.go new file mode 100644 index 0000000000..418550b473 --- /dev/null +++ b/gocode/src/test973/test973_test.go @@ -0,0 +1,38 @@ +package test973 + +import ( + "bytes" + "testing" +) + +func TestEncodeDecode(t *testing.T) { + message := new(SomeMessage) + SomeMessageInit(message) + + m := NewSbeGoMarshaller() + var buf = new(bytes.Buffer) + + message.MyEvent[EventTypeChoice.A] = true + message.MyEvent[EventTypeChoice.Ccc] = true + + if err := message.Encode(m, buf, true); err != nil { + t.Log("Encoding Error", err) + t.Fail() + } + + var out = *new(SomeMessage) + if err := out.Decode(m, buf, message.SbeSchemaVersion(), message.SbeBlockLength(), true); err != nil { + t.Log("Decoding Error", err) + t.Fail() + } + + if out.MyEvent != message.MyEvent { + t.Log("Value mismatch: ", out.MyEvent, message.MyEvent) + t.Fail() + } + + if !out.MyEvent[EventTypeChoice.A] || !out.MyEvent[EventTypeChoice.Ccc] || out.MyEvent[EventTypeChoice.EeEee] { + t.Log("Sanity check failed: ", out.MyEvent) + t.Fail() + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java index 14ce4087c8..af647727f2 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java @@ -268,10 +268,10 @@ void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception final GolangGenerator generator = new GolangGenerator(ir, outputManager); generator.generate(); - final String eventTypeSource = outputManager.getSource("test.EventType").toString(); + final String eventTypeSource = outputManager.getSource("test973.EventType").toString(); assertEquals("// Generated SBE (Simple Binary Encoding) message codec\n" + "\n" + - "package test\n" + + "package test973\n" + "\n" + "import (\n" + "\t\"io\"\n" + @@ -377,10 +377,10 @@ void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception "\treturn 0\n" + "}\n", eventTypeSource); - final String messageSource = outputManager.getSource("test.SomeMessage").toString(); + final String messageSource = outputManager.getSource("test973.SomeMessage").toString(); assertEquals("// Generated SBE (Simple Binary Encoding) message codec\n" + "\n" + - "package test\n" + + "package test973\n" + "\n" + "import (\n" + "\t\"io\"\n" + diff --git a/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml b/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml index ba08af1fc7..a160ddbceb 100644 --- a/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml +++ b/sbe-tool/src/test/resources/message-with-lower-case-bitset.xml @@ -1,6 +1,6 @@ Date: Fri, 29 Mar 2024 16:38:26 +0100 Subject: [PATCH 318/805] [CI] Add Golang build. --- .github/workflows/ci.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ac853b7cb..e458580f91 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -343,3 +343,32 @@ jobs: toolchain: ${{ matrix.rust }} override: true - run: ./gradlew runRustTests + + golang-build: + name: Golang ${{ matrix.version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + version: [ '1.22.x' ] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.sha }} + - name: Cache Gradle dependencies + uses: actions/cache@v4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache Gradle wrappers + uses: actions/cache@v4 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Generate codecs + run: ./gradlew generateGolangCodecs + - name: Go + run: cd gocode && make From 2c8ff6be8501e8bd60963db1987ebec682cff356 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:39:35 +0100 Subject: [PATCH 319/805] [CI] Add missing task. --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e458580f91..149150af21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -368,6 +368,10 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Setup Go + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.version }} - name: Generate codecs run: ./gradlew generateGolangCodecs - name: Go From 7dd2b76b6c4ac48fc94e36a9411137f235b52c96 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:49:03 +0100 Subject: [PATCH 320/805] [Go] Add dependency on sbe-all. --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 587bddc0a0..6bc00c4418 100644 --- a/build.gradle +++ b/build.gradle @@ -714,7 +714,8 @@ tasks.register('generateGolangCodecs') { 'generateGolangCodecTestBasic', 'generateGolangCodecTestComposite', 'generateGolangCodecsWithXIncludes', - 'generateGolangCodecsWithXSD' + 'generateGolangCodecsWithXSD', + ':sbe-all:jar' } /* From e1b8520f448c0ec4fab0306815c05621eb629e0e Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 17:25:55 +0100 Subject: [PATCH 321/805] [Java] Upgrade to Agrona 1.21.1. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 6bc00c4418..d932fa2ece 100644 --- a/build.gradle +++ b/build.gradle @@ -58,8 +58,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.2' def jmhVersion = '1.37' -def agronaVersion = '1.21.0' -def agronaVersionRange = '[1.21.0,2.0[' // allow any release >= 1.20.0 and < 2.0.0 +def agronaVersion = '1.21.1' +def agronaVersionRange = '[1.21.1,2.0[' // allow any release >= 1.21.1 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From b49348c443a547703c5d2507519659a760792310 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 29 Mar 2024 18:06:21 +0100 Subject: [PATCH 322/805] [Java] Use `BYTE_ORDER` constant instead of accessing `java.nio.ByteOrder` directly. --- .../sbe/generation/java/JavaGenerator.java | 2 +- .../sbe/ir/generated/FrameCodecDecoder.java | 42 ++--- .../sbe/ir/generated/FrameCodecEncoder.java | 24 +-- .../ir/generated/MessageHeaderDecoder.java | 8 +- .../ir/generated/MessageHeaderEncoder.java | 8 +- .../sbe/ir/generated/TokenCodecDecoder.java | 144 +++++++++--------- .../sbe/ir/generated/TokenCodecEncoder.java | 78 +++++----- .../ir/generated/VarDataEncodingDecoder.java | 2 +- .../ir/generated/VarDataEncodingEncoder.java | 2 +- .../generation/java/JavaGeneratorTest.java | 55 +++++-- 10 files changed, 200 insertions(+), 165 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index f4889e3751..8009f7a073 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -2949,7 +2949,7 @@ private static void generateArrayLengthMethod( private String byteOrderString(final Encoding encoding) { - return sizeOfPrimitive(encoding) == 1 ? "" : ", java.nio.ByteOrder." + encoding.byteOrder(); + return sizeOfPrimitive(encoding) == 1 ? "" : ", BYTE_ORDER"; } private CharSequence generatePrimitiveArrayPropertyEncode( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index 81f28e8dc5..12bdde9ae0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -297,7 +297,7 @@ public int irId() onIrIdAccessed(); } - return buffer.getInt(offset + 0, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 0, BYTE_ORDER); } @@ -364,7 +364,7 @@ public int irVersion() onIrVersionAccessed(); } - return buffer.getInt(offset + 4, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 4, BYTE_ORDER); } @@ -431,7 +431,7 @@ public int schemaVersion() onSchemaVersionAccessed(); } - return buffer.getInt(offset + 8, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 8, BYTE_ORDER); } @@ -503,7 +503,7 @@ public int packageNameLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipPackageName() @@ -515,7 +515,7 @@ public int skipPackageName() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -531,7 +531,7 @@ public int getPackageName(final MutableDirectBuffer dst, final int dstOffset, fi final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -548,7 +548,7 @@ public int getPackageName(final byte[] dst, final int dstOffset, final int lengt final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -565,7 +565,7 @@ public void wrapPackageName(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -579,7 +579,7 @@ public String packageName() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -661,7 +661,7 @@ public int namespaceNameLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipNamespaceName() @@ -673,7 +673,7 @@ public int skipNamespaceName() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -689,7 +689,7 @@ public int getNamespaceName(final MutableDirectBuffer dst, final int dstOffset, final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -706,7 +706,7 @@ public int getNamespaceName(final byte[] dst, final int dstOffset, final int len final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -723,7 +723,7 @@ public void wrapNamespaceName(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -737,7 +737,7 @@ public String namespaceName() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -819,7 +819,7 @@ public int semanticVersionLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipSemanticVersion() @@ -831,7 +831,7 @@ public int skipSemanticVersion() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -847,7 +847,7 @@ public int getSemanticVersion(final MutableDirectBuffer dst, final int dstOffset final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -864,7 +864,7 @@ public int getSemanticVersion(final byte[] dst, final int dstOffset, final int l final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -881,7 +881,7 @@ public void wrapSemanticVersion(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -895,7 +895,7 @@ public String semanticVersion() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java index aaf9df42c9..d7c0a14d12 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecEncoder.java @@ -243,7 +243,7 @@ public FrameCodecEncoder irId(final int value) onIrIdAccessed(); } - buffer.putInt(offset + 0, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 0, value, BYTE_ORDER); return this; } @@ -311,7 +311,7 @@ public FrameCodecEncoder irVersion(final int value) onIrVersionAccessed(); } - buffer.putInt(offset + 4, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 4, value, BYTE_ORDER); return this; } @@ -379,7 +379,7 @@ public FrameCodecEncoder schemaVersion(final int value) onSchemaVersionAccessed(); } - buffer.putInt(offset + 8, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 8, value, BYTE_ORDER); return this; } @@ -439,7 +439,7 @@ public FrameCodecEncoder putPackageName(final DirectBuffer src, final int srcOff final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -460,7 +460,7 @@ public FrameCodecEncoder putPackageName(final byte[] src, final int srcOffset, f final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -484,7 +484,7 @@ public FrameCodecEncoder packageName(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -545,7 +545,7 @@ public FrameCodecEncoder putNamespaceName(final DirectBuffer src, final int srcO final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -566,7 +566,7 @@ public FrameCodecEncoder putNamespaceName(final byte[] src, final int srcOffset, final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -590,7 +590,7 @@ public FrameCodecEncoder namespaceName(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -651,7 +651,7 @@ public FrameCodecEncoder putSemanticVersion(final DirectBuffer src, final int sr final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -672,7 +672,7 @@ public FrameCodecEncoder putSemanticVersion(final byte[] src, final int srcOffse final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -696,7 +696,7 @@ public FrameCodecEncoder semanticVersion(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java index 380c8a649e..f7b916999f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderDecoder.java @@ -87,7 +87,7 @@ public static int blockLengthMaxValue() public int blockLength() { - return (buffer.getShort(offset + 0, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(offset + 0, BYTE_ORDER) & 0xFFFF); } @@ -123,7 +123,7 @@ public static int templateIdMaxValue() public int templateId() { - return (buffer.getShort(offset + 2, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(offset + 2, BYTE_ORDER) & 0xFFFF); } @@ -159,7 +159,7 @@ public static int schemaIdMaxValue() public int schemaId() { - return (buffer.getShort(offset + 4, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(offset + 4, BYTE_ORDER) & 0xFFFF); } @@ -195,7 +195,7 @@ public static int versionMaxValue() public int version() { - return (buffer.getShort(offset + 6, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(offset + 6, BYTE_ORDER) & 0xFFFF); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java index b1255198e5..393b3a9add 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/MessageHeaderEncoder.java @@ -82,7 +82,7 @@ public static int blockLengthMaxValue() public MessageHeaderEncoder blockLength(final int value) { - buffer.putShort(offset + 0, (short)value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(offset + 0, (short)value, BYTE_ORDER); return this; } @@ -114,7 +114,7 @@ public static int templateIdMaxValue() public MessageHeaderEncoder templateId(final int value) { - buffer.putShort(offset + 2, (short)value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(offset + 2, (short)value, BYTE_ORDER); return this; } @@ -146,7 +146,7 @@ public static int schemaIdMaxValue() public MessageHeaderEncoder schemaId(final int value) { - buffer.putShort(offset + 4, (short)value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(offset + 4, (short)value, BYTE_ORDER); return this; } @@ -178,7 +178,7 @@ public static int versionMaxValue() public MessageHeaderEncoder version(final int value) { - buffer.putShort(offset + 6, (short)value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(offset + 6, (short)value, BYTE_ORDER); return this; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index 57abf338a1..e6e0fba7b9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -344,7 +344,7 @@ public int tokenOffset() onTokenOffsetAccessed(); } - return buffer.getInt(offset + 0, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 0, BYTE_ORDER); } @@ -411,7 +411,7 @@ public int tokenSize() onTokenSizeAccessed(); } - return buffer.getInt(offset + 4, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 4, BYTE_ORDER); } @@ -478,7 +478,7 @@ public int fieldId() onFieldIdAccessed(); } - return buffer.getInt(offset + 8, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 8, BYTE_ORDER); } @@ -545,7 +545,7 @@ public int tokenVersion() onTokenVersionAccessed(); } - return buffer.getInt(offset + 12, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 12, BYTE_ORDER); } @@ -612,7 +612,7 @@ public int componentTokenCount() onComponentTokenCountAccessed(); } - return buffer.getInt(offset + 16, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 16, BYTE_ORDER); } @@ -927,7 +927,7 @@ public int deprecated() onDeprecatedAccessed(); } - return buffer.getInt(offset + 24, java.nio.ByteOrder.LITTLE_ENDIAN); + return buffer.getInt(offset + 24, BYTE_ORDER); } @@ -999,7 +999,7 @@ public int nameLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipName() @@ -1011,7 +1011,7 @@ public int skipName() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -1027,7 +1027,7 @@ public int getName(final MutableDirectBuffer dst, final int dstOffset, final int final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1044,7 +1044,7 @@ public int getName(final byte[] dst, final int dstOffset, final int length) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1061,7 +1061,7 @@ public void wrapName(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -1075,7 +1075,7 @@ public String name() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -1157,7 +1157,7 @@ public int constValueLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipConstValue() @@ -1169,7 +1169,7 @@ public int skipConstValue() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -1185,7 +1185,7 @@ public int getConstValue(final MutableDirectBuffer dst, final int dstOffset, fin final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1202,7 +1202,7 @@ public int getConstValue(final byte[] dst, final int dstOffset, final int length final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1219,7 +1219,7 @@ public void wrapConstValue(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -1233,7 +1233,7 @@ public String constValue() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -1315,7 +1315,7 @@ public int minValueLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipMinValue() @@ -1327,7 +1327,7 @@ public int skipMinValue() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -1343,7 +1343,7 @@ public int getMinValue(final MutableDirectBuffer dst, final int dstOffset, final final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1360,7 +1360,7 @@ public int getMinValue(final byte[] dst, final int dstOffset, final int length) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1377,7 +1377,7 @@ public void wrapMinValue(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -1391,7 +1391,7 @@ public String minValue() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -1473,7 +1473,7 @@ public int maxValueLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipMaxValue() @@ -1485,7 +1485,7 @@ public int skipMaxValue() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -1501,7 +1501,7 @@ public int getMaxValue(final MutableDirectBuffer dst, final int dstOffset, final final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1518,7 +1518,7 @@ public int getMaxValue(final byte[] dst, final int dstOffset, final int length) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1535,7 +1535,7 @@ public void wrapMaxValue(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -1549,7 +1549,7 @@ public String maxValue() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -1631,7 +1631,7 @@ public int nullValueLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipNullValue() @@ -1643,7 +1643,7 @@ public int skipNullValue() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -1659,7 +1659,7 @@ public int getNullValue(final MutableDirectBuffer dst, final int dstOffset, fina final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1676,7 +1676,7 @@ public int getNullValue(final byte[] dst, final int dstOffset, final int length) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1693,7 +1693,7 @@ public void wrapNullValue(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -1707,7 +1707,7 @@ public String nullValue() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -1789,7 +1789,7 @@ public int characterEncodingLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipCharacterEncoding() @@ -1801,7 +1801,7 @@ public int skipCharacterEncoding() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -1817,7 +1817,7 @@ public int getCharacterEncoding(final MutableDirectBuffer dst, final int dstOffs final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1834,7 +1834,7 @@ public int getCharacterEncoding(final byte[] dst, final int dstOffset, final int final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1851,7 +1851,7 @@ public void wrapCharacterEncoding(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -1865,7 +1865,7 @@ public String characterEncoding() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -1947,7 +1947,7 @@ public int epochLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipEpoch() @@ -1959,7 +1959,7 @@ public int skipEpoch() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -1975,7 +1975,7 @@ public int getEpoch(final MutableDirectBuffer dst, final int dstOffset, final in final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -1992,7 +1992,7 @@ public int getEpoch(final byte[] dst, final int dstOffset, final int length) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2009,7 +2009,7 @@ public void wrapEpoch(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -2023,7 +2023,7 @@ public String epoch() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -2105,7 +2105,7 @@ public int timeUnitLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipTimeUnit() @@ -2117,7 +2117,7 @@ public int skipTimeUnit() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -2133,7 +2133,7 @@ public int getTimeUnit(final MutableDirectBuffer dst, final int dstOffset, final final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2150,7 +2150,7 @@ public int getTimeUnit(final byte[] dst, final int dstOffset, final int length) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2167,7 +2167,7 @@ public void wrapTimeUnit(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -2181,7 +2181,7 @@ public String timeUnit() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -2263,7 +2263,7 @@ public int semanticTypeLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipSemanticType() @@ -2275,7 +2275,7 @@ public int skipSemanticType() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -2291,7 +2291,7 @@ public int getSemanticType(final MutableDirectBuffer dst, final int dstOffset, f final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2308,7 +2308,7 @@ public int getSemanticType(final byte[] dst, final int dstOffset, final int leng final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2325,7 +2325,7 @@ public void wrapSemanticType(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -2339,7 +2339,7 @@ public String semanticType() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -2421,7 +2421,7 @@ public int descriptionLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipDescription() @@ -2433,7 +2433,7 @@ public int skipDescription() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -2449,7 +2449,7 @@ public int getDescription(final MutableDirectBuffer dst, final int dstOffset, fi final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2466,7 +2466,7 @@ public int getDescription(final byte[] dst, final int dstOffset, final int lengt final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2483,7 +2483,7 @@ public void wrapDescription(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -2497,7 +2497,7 @@ public String description() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) @@ -2579,7 +2579,7 @@ public int referencedNameLength() } final int limit = parentMessage.limit(); - return (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); } public int skipReferencedName() @@ -2591,7 +2591,7 @@ public int skipReferencedName() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int dataOffset = limit + headerLength; parentMessage.limit(dataOffset + dataLength); @@ -2607,7 +2607,7 @@ public int getReferencedName(final MutableDirectBuffer dst, final int dstOffset, final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2624,7 +2624,7 @@ public int getReferencedName(final byte[] dst, final int dstOffset, final int le final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); final int bytesCopied = Math.min(length, dataLength); parentMessage.limit(limit + headerLength + dataLength); buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); @@ -2641,7 +2641,7 @@ public void wrapReferencedName(final DirectBuffer wrapBuffer) final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); wrapBuffer.wrap(buffer, limit + headerLength, dataLength); } @@ -2655,7 +2655,7 @@ public String referencedName() final int headerLength = 2; final int limit = parentMessage.limit(); - final int dataLength = (buffer.getShort(limit, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); parentMessage.limit(limit + headerLength + dataLength); if (0 == dataLength) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java index e81e14bc4a..9e201cbf52 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java @@ -290,7 +290,7 @@ public TokenCodecEncoder tokenOffset(final int value) onTokenOffsetAccessed(); } - buffer.putInt(offset + 0, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 0, value, BYTE_ORDER); return this; } @@ -358,7 +358,7 @@ public TokenCodecEncoder tokenSize(final int value) onTokenSizeAccessed(); } - buffer.putInt(offset + 4, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 4, value, BYTE_ORDER); return this; } @@ -426,7 +426,7 @@ public TokenCodecEncoder fieldId(final int value) onFieldIdAccessed(); } - buffer.putInt(offset + 8, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 8, value, BYTE_ORDER); return this; } @@ -494,7 +494,7 @@ public TokenCodecEncoder tokenVersion(final int value) onTokenVersionAccessed(); } - buffer.putInt(offset + 12, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 12, value, BYTE_ORDER); return this; } @@ -562,7 +562,7 @@ public TokenCodecEncoder componentTokenCount(final int value) onComponentTokenCountAccessed(); } - buffer.putInt(offset + 16, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 16, value, BYTE_ORDER); return this; } @@ -838,7 +838,7 @@ public TokenCodecEncoder deprecated(final int value) onDeprecatedAccessed(); } - buffer.putInt(offset + 24, value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putInt(offset + 24, value, BYTE_ORDER); return this; } @@ -898,7 +898,7 @@ public TokenCodecEncoder putName(final DirectBuffer src, final int srcOffset, fi final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -919,7 +919,7 @@ public TokenCodecEncoder putName(final byte[] src, final int srcOffset, final in final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -943,7 +943,7 @@ public TokenCodecEncoder name(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1004,7 +1004,7 @@ public TokenCodecEncoder putConstValue(final DirectBuffer src, final int srcOffs final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1025,7 +1025,7 @@ public TokenCodecEncoder putConstValue(final byte[] src, final int srcOffset, fi final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1049,7 +1049,7 @@ public TokenCodecEncoder constValue(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1110,7 +1110,7 @@ public TokenCodecEncoder putMinValue(final DirectBuffer src, final int srcOffset final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1131,7 +1131,7 @@ public TokenCodecEncoder putMinValue(final byte[] src, final int srcOffset, fina final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1155,7 +1155,7 @@ public TokenCodecEncoder minValue(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1216,7 +1216,7 @@ public TokenCodecEncoder putMaxValue(final DirectBuffer src, final int srcOffset final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1237,7 +1237,7 @@ public TokenCodecEncoder putMaxValue(final byte[] src, final int srcOffset, fina final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1261,7 +1261,7 @@ public TokenCodecEncoder maxValue(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1322,7 +1322,7 @@ public TokenCodecEncoder putNullValue(final DirectBuffer src, final int srcOffse final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1343,7 +1343,7 @@ public TokenCodecEncoder putNullValue(final byte[] src, final int srcOffset, fin final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1367,7 +1367,7 @@ public TokenCodecEncoder nullValue(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1428,7 +1428,7 @@ public TokenCodecEncoder putCharacterEncoding(final DirectBuffer src, final int final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1449,7 +1449,7 @@ public TokenCodecEncoder putCharacterEncoding(final byte[] src, final int srcOff final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1473,7 +1473,7 @@ public TokenCodecEncoder characterEncoding(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1534,7 +1534,7 @@ public TokenCodecEncoder putEpoch(final DirectBuffer src, final int srcOffset, f final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1555,7 +1555,7 @@ public TokenCodecEncoder putEpoch(final byte[] src, final int srcOffset, final i final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1579,7 +1579,7 @@ public TokenCodecEncoder epoch(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1640,7 +1640,7 @@ public TokenCodecEncoder putTimeUnit(final DirectBuffer src, final int srcOffset final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1661,7 +1661,7 @@ public TokenCodecEncoder putTimeUnit(final byte[] src, final int srcOffset, fina final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1685,7 +1685,7 @@ public TokenCodecEncoder timeUnit(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1746,7 +1746,7 @@ public TokenCodecEncoder putSemanticType(final DirectBuffer src, final int srcOf final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1767,7 +1767,7 @@ public TokenCodecEncoder putSemanticType(final byte[] src, final int srcOffset, final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1791,7 +1791,7 @@ public TokenCodecEncoder semanticType(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1852,7 +1852,7 @@ public TokenCodecEncoder putDescription(final DirectBuffer src, final int srcOff final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1873,7 +1873,7 @@ public TokenCodecEncoder putDescription(final byte[] src, final int srcOffset, f final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1897,7 +1897,7 @@ public TokenCodecEncoder description(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; @@ -1958,7 +1958,7 @@ public TokenCodecEncoder putReferencedName(final DirectBuffer src, final int src final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -1979,7 +1979,7 @@ public TokenCodecEncoder putReferencedName(final byte[] src, final int srcOffset final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, src, srcOffset, length); return this; @@ -2003,7 +2003,7 @@ public TokenCodecEncoder referencedName(final String value) final int headerLength = 2; final int limit = parentMessage.limit(); parentMessage.limit(limit + headerLength + length); - buffer.putShort(limit, (short)length, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(limit, (short)length, BYTE_ORDER); buffer.putBytes(limit + headerLength, bytes, 0, length); return this; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java index fef5471086..530284ceff 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingDecoder.java @@ -87,7 +87,7 @@ public static int lengthMaxValue() public int length() { - return (buffer.getShort(offset + 0, java.nio.ByteOrder.LITTLE_ENDIAN) & 0xFFFF); + return (buffer.getShort(offset + 0, BYTE_ORDER) & 0xFFFF); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java index 69ecabf325..15461efd3a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/VarDataEncodingEncoder.java @@ -82,7 +82,7 @@ public static int lengthMaxValue() public VarDataEncodingEncoder length(final int value) { - buffer.putShort(offset + 0, (short)value, java.nio.ByteOrder.LITTLE_ENDIAN); + buffer.putShort(offset + 0, (short)value, BYTE_ORDER); return this; } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 3ceaf14e14..e93a7c1eba 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -15,12 +15,6 @@ */ package uk.co.real_logic.sbe.generation.java; -import uk.co.real_logic.sbe.Tests; -import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; -import uk.co.real_logic.sbe.ir.Ir; -import uk.co.real_logic.sbe.xml.IrGenerator; -import uk.co.real_logic.sbe.xml.MessageSchema; -import uk.co.real_logic.sbe.xml.ParserOptions; import org.agrona.DirectBuffer; import org.agrona.MutableDirectBuffer; import org.agrona.concurrent.UnsafeBuffer; @@ -29,7 +23,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; import java.io.IOException; import java.io.InputStream; @@ -40,11 +41,10 @@ import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import static uk.co.real_logic.sbe.generation.java.JavaGenerator.MESSAGE_HEADER_DECODER_TYPE; import static uk.co.real_logic.sbe.generation.java.ReflectionUtil.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -444,7 +444,7 @@ void shouldGenerateGetFixedLengthStringUsingAppendable() throws Exception } @ParameterizedTest - @ValueSource(strings = {"Red", "", "Red and Blue"}) + @ValueSource(strings = { "Red", "", "Red and Blue" }) void shouldGenerateGetVariableStringUsingAppendable(final String color) throws Exception { final UnsafeBuffer buffer = new UnsafeBuffer(new byte[4096]); @@ -601,6 +601,41 @@ void shouldCreateTypesInSamePackageIfSupportDisabled() throws Exception } } + @ParameterizedTest + @CsvSource( + { + "code-generation-schema.xml, java.nio.ByteOrder.LITTLE_ENDIAN", + "example-bigendian-test-schema.xml, java.nio.ByteOrder.BIG_ENDIAN" + }) + void shouldUseByteOrderConstantField(final String schemaFile, final String encodingType) throws Exception + { + try (InputStream in = Tests.getLocalResource(schemaFile)) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, false, outputManager); + + generator.generate(); + + for (final CharSequence code : new CharSequence[]{ + outputManager.getSource(ir.applicableNamespace() + ".CarEncoder"), + outputManager.getSource(ir.applicableNamespace() + ".CarDecoder") }) + { + assertThat(code.toString(), allOf( + containsString("public static final java.nio.ByteOrder BYTE_ORDER = " + encodingType + ";"), + not(containsString(encodingType + ")")), + containsString(", BYTE_ORDER)"))); + } + } + } + private Class getModelClass(final Object encoder) throws ClassNotFoundException { final String className = "Model"; From 7401858ebb3e441ff425b27b573500f2e2beab48 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Wed, 3 Apr 2024 09:52:42 -0500 Subject: [PATCH 323/805] 1.31.0 released --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index e576fe33d3..34aae156b1 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.31.0-SNAPSHOT +1.31.0 From 2fd4adbffb14a3d66cec7e8c61079eba9b990e1a Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Wed, 3 Apr 2024 09:56:52 -0500 Subject: [PATCH 324/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 34aae156b1..7341032ba0 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.31.0 +1.32.0-SNAPSHOT From c5aab07e0483bd019a0751b8d637bd70bf5a19f5 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Fri, 5 Apr 2024 10:19:41 -0500 Subject: [PATCH 325/805] [Rust] Updated code generator to resolve Issue #984 (#985) * [Rust] updated code generator to prevent rust warning for "ambiguous glob re-exports" * [Rust] defined new trait 'ActingVersion' * fixed code formatting issues * [Rust] fixed benchmarks * [Rust] added test for issue 984 --------- Co-authored-by: Michael Ward --- build.gradle | 1 + rust/Cargo.toml | 1 + rust/benches/car_benchmark.rs | 16 +++-- rust/benches/md_benchmark.rs | 10 ++- rust/tests/issue_435_test.rs | 3 +- rust/tests/issue_984_test.rs | 47 +++++++++++++ .../sbe/generation/rust/LibRsDef.java | 18 +++-- .../sbe/generation/rust/MessageCoderDef.java | 4 +- .../sbe/generation/rust/RustGenerator.java | 67 +++++++++++++------ .../sbe/generation/rust/SubGroup.java | 14 +++- sbe-tool/src/test/resources/issue984.xml | 31 +++++++++ 11 files changed, 174 insertions(+), 38 deletions(-) create mode 100644 rust/tests/issue_984_test.rs create mode 100644 sbe-tool/src/test/resources/issue984.xml diff --git a/build.gradle b/build.gradle index d932fa2ece..be16408906 100644 --- a/build.gradle +++ b/build.gradle @@ -588,6 +588,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { args = ['sbe-tool/src/test/resources/issue435.xml', 'sbe-tool/src/test/resources/issue895.xml', 'sbe-tool/src/test/resources/issue972.xml', + 'sbe-tool/src/test/resources/issue984.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', 'sbe-tool/src/test/resources/nested-composite-name.xml', ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6d47fc3746..4be04c957b 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -14,6 +14,7 @@ examples_uk_co_real_logic_sbe_benchmarks_fix = { path = "../generated/rust/uk_co issue_435 = { path = "../generated/rust/issue435" } issue_895 = { path = "../generated/rust/issue895" } issue_972 = { path = "../generated/rust/issue972" } +issue_984 = { path = "../generated/rust/issue984" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } nested_composite_name = { path = "../generated/rust/nested-composite-name" } diff --git a/rust/benches/car_benchmark.rs b/rust/benches/car_benchmark.rs index 06b542452a..5f78fff1e4 100644 --- a/rust/benches/car_benchmark.rs +++ b/rust/benches/car_benchmark.rs @@ -1,6 +1,12 @@ -use car_codec::encoder::*; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use examples_uk_co_real_logic_sbe_benchmarks::*; +use examples_uk_co_real_logic_sbe_benchmarks::{ + boolean_type::BooleanType, + car_codec::{decoder::*, encoder::*}, + message_header_codec::MessageHeaderDecoder, + model::Model, + optional_extras::OptionalExtras, + *, +}; const MANUFACTURER: &[u8] = b"MANUFACTURER"; const MODEL: &[u8] = b"MODEL"; @@ -36,8 +42,8 @@ fn encode(state: &mut State) -> SbeResult { car.model_year(2005); car.serial_number(12345); car.available(BooleanType::T); - car.vehicle_code([97, 98, 99, 100, 101, 102]); // abcdef - car.some_numbers([0, 1, 2, 3, 4]); + car.vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef + car.some_numbers(&[0, 1, 2, 3, 4]); extras.set_sports_pack(true); extras.set_sun_roof(true); @@ -46,7 +52,7 @@ fn encode(state: &mut State) -> SbeResult { let mut engine = car.engine_encoder(); engine.capacity(4200); engine.num_cylinders(8); - engine.manufacturer_code([97, 98, 99]); // abc + engine.manufacturer_code(&[97, 98, 99]); // abc car = engine.parent()?; fuel_figures = car.fuel_figures_encoder(3, fuel_figures); diff --git a/rust/benches/md_benchmark.rs b/rust/benches/md_benchmark.rs index ab7f4bf367..025df09f4f 100644 --- a/rust/benches/md_benchmark.rs +++ b/rust/benches/md_benchmark.rs @@ -1,6 +1,12 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use examples_uk_co_real_logic_sbe_benchmarks_fix::*; -use market_data_incremental_refresh_trades_codec::encoder::*; +use examples_uk_co_real_logic_sbe_benchmarks_fix::{ + market_data_incremental_refresh_trades_codec::{encoder::*, *}, + match_event_indicator::*, + md_update_action::*, + message_header_codec::*, + side::*, + *, +}; struct State { buffer: Vec, diff --git a/rust/tests/issue_435_test.rs b/rust/tests/issue_435_test.rs index 8ac9ce8a50..8664be42cd 100644 --- a/rust/tests/issue_435_test.rs +++ b/rust/tests/issue_435_test.rs @@ -1,7 +1,6 @@ -use ::issue_435::*; use issue_435::{ enum_ref::EnumRef, issue_435_codec::*, message_header_codec::MessageHeaderDecoder, - set_ref::SetRef, + set_ref::SetRef, *, }; fn create_encoder(buffer: &mut Vec) -> Issue435Encoder { diff --git a/rust/tests/issue_984_test.rs b/rust/tests/issue_984_test.rs new file mode 100644 index 0000000000..7ca0dcfc76 --- /dev/null +++ b/rust/tests/issue_984_test.rs @@ -0,0 +1,47 @@ +use issue_984::{ + message_header_codec::MessageHeaderDecoder, + simple_message_codec::{encoder::MyGroupEncoder, *}, + *, +}; + +fn create_encoder(buffer: &mut Vec) -> SimpleMessageEncoder { + let simple_msg = SimpleMessageEncoder::default().wrap( + WriteBuf::new(buffer.as_mut_slice()), + message_header_codec::ENCODED_LENGTH, + ); + let mut header = simple_msg.header(0); + header.parent().unwrap() +} + +#[test] +fn round_trip() -> SbeResult<()> { + // encode... + let mut buffer = vec![0u8; 256]; + let mut simple_msg_encoder = create_encoder(&mut buffer); + simple_msg_encoder.id(1985); + + let mut my_grp_encoder = simple_msg_encoder.my_group_encoder(1, MyGroupEncoder::default()); + my_grp_encoder.advance()?; + my_grp_encoder.f1(&[1, 2, 3, 4]); + my_grp_encoder.f2(&[1, 2, 3, 4, 5]); + my_grp_encoder.f3(&[1, 2, 3, 4, 5, 6]); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + assert_eq!(SBE_BLOCK_LENGTH, header.block_length()); + assert_eq!(SBE_SCHEMA_VERSION, header.version()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_SCHEMA_ID, header.schema_id()); + + let simple_msg_decoder = SimpleMessageDecoder::default().header(header); + assert_eq!(1985, simple_msg_decoder.id()); + let mut grp_decoder = simple_msg_decoder.my_group_decoder(); + assert_eq!(1, grp_decoder.count()); + grp_decoder.advance()?; + + assert_eq!([1, 2, 3, 4], grp_decoder.f1()); + assert_eq!([1, 2, 3, 4, 5], grp_decoder.f2()); + assert_eq!([1, 2, 3, 4, 5, 6], grp_decoder.f3()); + Ok(()) +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 3c5ae1542d..2ed6eb1fcb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -35,19 +35,23 @@ class LibRsDef { private final RustOutputManager outputManager; private final ByteOrder byteOrder; + private final String schemaVersionType; /** * Create a new 'lib.rs' for the library being generated * - * @param outputManager for generating the codecs to. - * @param byteOrder for the Encoding. + * @param outputManager for generating the codecs to. + * @param byteOrder for the Encoding. + * @param schemaVersionType for acting_version type */ LibRsDef( final RustOutputManager outputManager, - final ByteOrder byteOrder) + final ByteOrder byteOrder, + final String schemaVersionType) { this.outputManager = outputManager; this.byteOrder = byteOrder; + this.schemaVersionType = schemaVersionType; } void generate() throws IOException @@ -82,7 +86,7 @@ void generate() throws IOException generateEitherEnum(libRs); generateEncoderTraits(libRs); - generateDecoderTraits(libRs); + generateDecoderTraits(schemaVersionType, libRs); generateReadBuf(libRs, byteOrder); generateWriteBuf(libRs, byteOrder); @@ -101,8 +105,12 @@ static void generateEncoderTraits(final Writer writer) throws IOException indent(writer, 0, "}\n\n"); } - static void generateDecoderTraits(final Writer writer) throws IOException + static void generateDecoderTraits(final String schemaVersionType, final Writer writer) throws IOException { + indent(writer, 0, "pub trait ActingVersion {\n"); + indent(writer, 1, "fn acting_version(&self) -> %s;\n", schemaVersionType); + indent(writer, 0, "}\n\n"); + indent(writer, 0, "pub trait Reader<'a>: Sized {\n"); indent(writer, 1, "fn get_buf(&self) -> &ReadBuf<'a>;\n"); indent(writer, 0, "}\n\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index dbe6fabc8f..67c37f22fd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -76,7 +76,7 @@ void generate( } else { - RustGenerator.appendImplDecoderTrait(sb, msgTypeName); + RustGenerator.appendImplDecoderTrait(schemaVersionType(), sb, msgTypeName); } RustGenerator.appendImplWithLifetimeHeader(sb, msgTypeName); // impl start @@ -92,7 +92,7 @@ void generate( appendMessageHeaderDecoderFn(sb); RustGenerator.generateDecoderFields(sb, fields, 2); - RustGenerator.generateDecoderGroups(sb, groups, 2, this); + RustGenerator.generateDecoderGroups(schemaVersionType(), sb, groups, 2, this); RustGenerator.generateDecoderVarData(sb, varData, 2, false); } else diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 6569599993..1b53987098 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -127,11 +127,11 @@ public void generate() throws IOException } // lib.rs - final LibRsDef libRsDef = new LibRsDef(outputManager, ir.byteOrder()); + final LibRsDef libRsDef = new LibRsDef(outputManager, ir.byteOrder(), schemaVersionType()); generateEnums(ir, outputManager); generateBitSets(ir, outputManager); - generateComposites(ir, outputManager); + generateComposites(schemaVersionType(), ir, outputManager); for (final List tokens : ir.messages()) { @@ -428,6 +428,7 @@ private static void generatePrimitiveEncoder( indent(sb, level, "/// - semanticType: %s\n", encoding.semanticType()); indent(sb, level, "/// - encodedOffset: %d\n", typeToken.offset()); indent(sb, level, "/// - encodedLength: %d\n", typeToken.encodedLength()); + indent(sb, level, "/// - version: %d\n", typeToken.version()); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", formatFunctionName(name), @@ -575,7 +576,7 @@ private static void generateCompositeDecoder( decoderName, decoderTypeName); - indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", fieldToken.version()); + indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); indent(sb, level + 2, "return Either::Left(self);\n"); indent(sb, level + 1, "}\n\n"); @@ -613,7 +614,7 @@ private static void generateBitSetDecoder( if (bitsetToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", bitsetToken.version()); + indent(sb, level + 1, "if self.acting_version() < %d {\n", bitsetToken.version()); indent(sb, level + 2, "return %s::default();\n", structTypeName); indent(sb, level + 1, "}\n\n"); } @@ -673,7 +674,7 @@ private static void generatePrimitiveArrayDecoder( if (fieldToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", fieldToken.version()); + indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); indent(sb, level + 2, "return [%s; %d];\n", encoding.applicableNullValue(), arrayLength); indent(sb, level + 1, "}\n\n"); } @@ -827,7 +828,7 @@ private static void generatePrimitiveRequiredDecoder( if (fieldToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", fieldToken.version()); + indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); indent(sb, level + 2, "return %s;\n", generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString())); indent(sb, level + 1, "}\n\n"); @@ -876,7 +877,7 @@ private static void generateEnumDecoder( if (fieldToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version < %d {\n", fieldToken.version()); + indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); indent(sb, level + 2, "return %s::default();\n", enumType); indent(sb, level + 1, "}\n\n"); } @@ -889,6 +890,7 @@ private static void generateEnumDecoder( } static void generateDecoderGroups( + final String schemaVersionType, final StringBuilder sb, final List tokens, final int level, @@ -936,7 +938,7 @@ static void generateDecoderGroups( indent(sb, level, "pub fn %s(self) -> Option<%2$s> {\n", formatFunctionName(groupName), groupName); - indent(sb, level + 1, "if self.acting_version < %d {\n", groupToken.version()); + indent(sb, level + 1, "if self.acting_version() < %d {\n", groupToken.version()); indent(sb, level + 2, "return None;\n"); indent(sb, level + 1, "}\n\n"); @@ -952,7 +954,7 @@ static void generateDecoderGroups( indent(sb, level, "}\n\n"); final SubGroup subGroup = parentDef.addSubGroup(groupName, level, groupToken); - subGroup.generateDecoder(tokens, fields, groups, varData, index); + subGroup.generateDecoder(schemaVersionType, tokens, fields, groups, varData, index); } } @@ -984,7 +986,7 @@ static void generateDecoderVarData( { if (varDataToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", + indent(sb, level + 1, "if self.acting_version() < %d {\n", varDataToken.version()); indent(sb, level + 2, "return (self.parent.as_ref().unwrap().get_limit(), 0);\n"); indent(sb, level + 1, "}\n\n"); @@ -1000,7 +1002,7 @@ static void generateDecoderVarData( { if (varDataToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", + indent(sb, level + 1, "if self.acting_version() < %d {\n", varDataToken.version()); indent(sb, level + 2, "return (self.get_limit(), 0);\n"); indent(sb, level + 1, "}\n\n"); @@ -1020,7 +1022,7 @@ static void generateDecoderVarData( if (varDataToken.version() > 0) { - indent(sb, level + 1, "if self.acting_version > 0 && self.acting_version < %d {\n", + indent(sb, level + 1, "if self.acting_version() < %d {\n", varDataToken.version()); indent(sb, level + 2, "return &[] as &[u8];\n"); indent(sb, level + 1, "}\n\n"); @@ -1162,9 +1164,17 @@ static void appendImplEncoderTrait( } static void appendImplDecoderTrait( + final String schemaVersionType, final Appendable out, final String typeName) throws IOException { + indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, "ActingVersion", withLifetime(typeName)); + indent(out, 2, "#[inline]\n"); + indent(out, 2, "fn acting_version(&self) -> %s {\n", schemaVersionType); + indent(out, 3, "self.acting_version\n"); + indent(out, 2, "}\n"); + indent(out, 1, "}\n\n"); + indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withLifetime("Reader"), withLifetime(typeName)); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn get_buf(&self) -> &ReadBuf<'a> {\n"); @@ -1271,6 +1281,7 @@ private static void generateEnum( } private static void generateComposites( + final String schemaVersionType, final Ir ir, final RustOutputManager outputManager) throws IOException { @@ -1278,12 +1289,13 @@ private static void generateComposites( { if (!tokens.isEmpty() && tokens.get(0).signal() == Signal.BEGIN_COMPOSITE) { - generateComposite(tokens, outputManager); + generateComposite(schemaVersionType, tokens, outputManager); } } } private static void generateComposite( + final String schemaVersionType, final List tokens, final RustOutputManager outputManager) throws IOException { @@ -1306,7 +1318,7 @@ private static void generateComposite( generateCompositeEncoder(tokens, encoderName(compositeName), out); indent(out, 0, "\n"); - generateCompositeDecoder(tokens, decoderName(compositeName), out); + generateCompositeDecoder(schemaVersionType, tokens, decoderName(compositeName), out); } } @@ -1350,12 +1362,23 @@ static void appendImplEncoderForComposite( } static void appendImplReaderForComposite( + final String schemaVersionType, + final int version, final Appendable out, final int level, final String name) throws IOException { + indent(out, level, "impl<'a, P> ActingVersion for %s

    where P: Reader<'a> + ActingVersion + Default {\n", + name); + indent(out, level + 1, "#[inline]\n"); + indent(out, level + 1, "fn acting_version(&self) -> %s {\n", schemaVersionType); + indent(out, level + 2, "self.parent.as_ref().unwrap().acting_version()\n"); + indent(out, level + 1, "}\n"); + indent(out, level, "}\n\n"); + // impl Reader... - indent(out, level, "impl<'a, P> Reader<'a> for %s

    where P: Reader<'a> + Default {\n", name); + indent(out, level, "impl<'a, P> Reader<'a> for %s

    where P: Reader<'a> %s+ Default {\n", + name, version > 0 ? "+ ActingVersion " : ""); indent(out, level + 1, "#[inline]\n"); indent(out, level + 1, "fn get_buf(&self) -> &ReadBuf<'a> {\n"); indent(out, level + 2, "self.parent.as_ref().expect(\"parent missing\").get_buf()\n"); @@ -1364,14 +1387,17 @@ static void appendImplReaderForComposite( } static void appendImplDecoderForComposite( + final String schemaVersionType, + final int version, final Appendable out, final int level, final String name) throws IOException { - appendImplReaderForComposite(out, level, name); + appendImplReaderForComposite(schemaVersionType, version, out, level, name); // impl Decoder... - indent(out, level, "impl<'a, P> Decoder<'a> for %s

    where P: Decoder<'a> + Default {\n", name); + indent(out, level, "impl<'a, P> Decoder<'a> for %s

    where P: Decoder<'a> + ActingVersion + Default {\n", + name); indent(out, level + 1, "#[inline]\n"); indent(out, level + 1, "fn get_limit(&self) -> usize {\n"); indent(out, level + 2, "self.parent.as_ref().expect(\"parent missing\").get_limit()\n"); @@ -1447,6 +1473,7 @@ private static void generateCompositeEncoder( } private static void generateCompositeDecoder( + final String schemaVersionType, final List tokens, final String decoderName, final Writer out) throws IOException @@ -1460,10 +1487,12 @@ private static void generateCompositeDecoder( indent(out, 2, "offset: usize,\n"); indent(out, 1, "}\n\n"); - appendImplReaderForComposite(out, 1, decoderName); + final int version = tokens.stream().findFirst().get().version(); + appendImplReaderForComposite(schemaVersionType, version, out, 1, decoderName); // impl<'a, P> start - indent(out, 1, "impl<'a, P> %s

    where P: Reader<'a> + Default {\n", decoderName); + indent(out, 1, "impl<'a, P> %s

    where P: Reader<'a> %s+ Default {\n", + decoderName, version > 0 ? "+ ActingVersion " : ""); indent(out, 2, "pub fn wrap(mut self, parent: P, offset: usize) -> Self {\n"); indent(out, 3, "self.parent = Some(parent);\n"); indent(out, 3, "self.offset = offset;\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 6407220065..d7a6123ec9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -140,6 +140,7 @@ void generateEncoder( } void generateDecoder( + final String schemaVersionType, final List tokens, final List fields, final List groups, @@ -162,10 +163,11 @@ void generateDecoder( indent(sb, level, "offset: usize,\n"); indent(sb, level - 1, "}\n\n"); - RustGenerator.appendImplDecoderForComposite(sb, level - 1, name); + final int version = tokens.stream().findFirst().get().version(); + RustGenerator.appendImplDecoderForComposite(schemaVersionType, version, sb, level - 1, name); // define impl... - indent(sb, level - 1, "impl<'a, P> %s

    where P: Decoder<'a> + Default {\n", name); + indent(sb, level - 1, "impl<'a, P> %s

    where P: Decoder<'a> + ActingVersion + Default {\n", name); final int dimensionHeaderSize = tokens.get(index).encodedLength(); @@ -197,6 +199,12 @@ void generateDecoder( indent(sb, level + 1, "self.parent.take().ok_or(SbeErr::ParentNotSet)\n"); indent(sb, level, "}\n\n"); + // acting_version fn... + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn acting_version(&mut self) -> %s {\n", schemaVersionType); + indent(sb, level + 1, "self.parent.as_ref().unwrap().acting_version()\n"); + indent(sb, level, "}\n\n"); + // count function indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn count(&self) -> %s {\n", rustTypeName(numInGroupPrimitiveType)); @@ -221,7 +229,7 @@ void generateDecoder( indent(sb, level, "}\n\n"); RustGenerator.generateDecoderFields(sb, fields, level); - RustGenerator.generateDecoderGroups(sb, groups, level, this); + RustGenerator.generateDecoderGroups(schemaVersionType, sb, groups, level, this); RustGenerator.generateDecoderVarData(sb, varData, level, true); indent(sb, level - 1, "}\n\n"); // close impl diff --git a/sbe-tool/src/test/resources/issue984.xml b/sbe-tool/src/test/resources/issue984.xml new file mode 100644 index 0000000000..bfbc961ace --- /dev/null +++ b/sbe-tool/src/test/resources/issue984.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From c9be629310791b7af281e4091b39a37327ce4e25 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Sun, 7 Apr 2024 09:41:40 -0500 Subject: [PATCH 326/805] [Rust] updated SubGroup.generateDecoder() to resolve unnecessary cast warning in generated code (#986) * [Rust] updated code generator to prevent rust warning for "ambiguous glob re-exports" * [Rust] defined new trait 'ActingVersion' * fixed code formatting issues * [Rust] fixed benchmarks * [Rust] added test for issue 984 * [Rust] updated SubGroup.generateDecoder() to resolve unnecessary cast warning --------- Co-authored-by: Michael Ward --- .../java/uk/co/real_logic/sbe/generation/rust/SubGroup.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index d7a6123ec9..d0b5abc433 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -157,7 +157,7 @@ void generateDecoder( indent(sb, level - 1, "#[derive(Debug, Default)]\n"); indent(sb, level - 1, "pub struct %s

    {\n", name); indent(sb, level, "parent: Option

    ,\n"); - indent(sb, level, "block_length: usize,\n"); + indent(sb, level, "block_length: %s,\n", rustTypeName(blockLengthPrimitiveType)); indent(sb, level, "count: %s,\n", rustTypeName(numInGroupPrimitiveType)); indent(sb, level, "index: usize,\n"); indent(sb, level, "offset: usize,\n"); @@ -177,7 +177,7 @@ void generateDecoder( indent(sb, level + 1, "mut parent: P,\n"); indent(sb, level, ") -> Self {\n"); indent(sb, level + 1, "let initial_offset = parent.get_limit();\n"); - indent(sb, level + 1, "let block_length = parent.get_buf().get_%s_at(initial_offset) as usize;\n", + indent(sb, level + 1, "let block_length = parent.get_buf().get_%s_at(initial_offset);\n", rustTypeName(blockLengthPrimitiveType)); indent(sb, level + 1, "let count = parent.get_buf().get_%s_at(initial_offset + %d);\n", rustTypeName(numInGroupPrimitiveType), numInGroupToken.offset()); From 7e6e5039b15c728094c20772a5dd0dd7eceb91b2 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 11 Apr 2024 22:48:59 +0100 Subject: [PATCH 327/805] [Java, C#, C++] Fix precedence checks to account for non-contiguous versions. (#989) Relates to issue #988. An SBE message might not change in every version of a schema. For example, another message might change. Previously, the field precedence checking model would expect an exact match for `actingVersion` in `wrap` to enter one of its initial states. However, it is only aware of the versions in which a message schema has changed. Therefore, it was possible for `actingVersion` not to match any of these versions, in which case the initial state that represented a codec wrapped around the latest known version of the format was picked. Now, we do _not_ expect an exact match in `wrap`. Instead, we select the "best" match. For example, if a codec was changed in v1 and v3, and the acting version is v2, we will decode using v1. However, if the acting version is v4, we would decode as v3. --- .../sbe-tests/FieldAccessOrderCheckTests.cs | 19 +++ .../common/FieldPrecedenceModel.java | 10 +- .../sbe/generation/cpp/CppGenerator.java | 47 ++++--- .../generation/csharp/CSharpGenerator.java | 22 ++-- .../sbe/generation/java/JavaGenerator.java | 21 ++-- .../sbe/ir/generated/FrameCodecDecoder.java | 12 +- .../sbe/ir/generated/TokenCodecDecoder.java | 12 +- .../test/cpp/FieldAccessOrderCheckTest.cpp | 20 +++ .../sbe/FieldAccessOrderCheckTest.java | 115 +++++++++++++++++- .../resources/field-order-check-schema.xml | 42 ++++++- 10 files changed, 257 insertions(+), 63 deletions(-) diff --git a/csharp/sbe-tests/FieldAccessOrderCheckTests.cs b/csharp/sbe-tests/FieldAccessOrderCheckTests.cs index d0b7e16992..1ee4569643 100644 --- a/csharp/sbe-tests/FieldAccessOrderCheckTests.cs +++ b/csharp/sbe-tests/FieldAccessOrderCheckTests.cs @@ -3159,6 +3159,25 @@ public void DisallowsIncompleteMessagesDueToMissingVarDataInNestedGroup( var exception = Assert.ThrowsException(encoder.CheckEncodingIsComplete); StringAssert.Contains(exception.Message, $"Not fully encoded, current state: {expectedState}"); } + + [TestMethod] + public void AllowsSkippingFutureGroupWhenDecodingFromVersionWithNoChangesInMessage() + { + var encoder = new AddGroupBeforeVarDataV0() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + + _messageHeader.TemplateId = SkipVersionAddGroupBeforeVarDataV2.TemplateId; + _messageHeader.Version = 1; + + encoder.A = 42; + encoder.SetB("abc"); + + var decoder = new SkipVersionAddGroupBeforeVarDataV2() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + + Assert.AreEqual(42, decoder.A); + Assert.AreEqual(decoder.GetB(), "abc"); + } private void ModifyHeaderToLookLikeVersion0() { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java index 3122926ba5..58a68c17ff 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java @@ -46,7 +46,7 @@ public final class FieldPrecedenceModel new CodecInteraction.CodecInteractionFactory(groupPathsByField, topLevelBlockFields); private final Map> transitionsByInteraction = new LinkedHashMap<>(); private final Map> transitionsByState = new HashMap<>(); - private final Int2ObjectHashMap versionWrappedStates = new Int2ObjectHashMap<>(); + private final TreeMap versionWrappedStates = new TreeMap<>(); private final State notWrappedState = allocateState("NOT_WRAPPED"); private final String generatedRepresentationClassName; private State encoderWrappedState; @@ -103,13 +103,11 @@ public State latestVersionWrappedState() * Iterates over the states after a codec is wrapped over a particular version of data. * @param consumer the consumer of the states. */ - public void forEachWrappedStateByVersion(final IntObjConsumer consumer) + public void forEachWrappedStateByVersionDesc(final IntObjConsumer consumer) { - final Int2ObjectHashMap.EntryIterator iterator = versionWrappedStates.entrySet().iterator(); - while (iterator.hasNext()) + for (final Map.Entry entry : versionWrappedStates.descendingMap().entrySet()) { - iterator.next(); - consumer.accept(iterator.getIntKey(), iterator.getValue()); + consumer.accept(entry.getKey(), entry.getValue()); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 54a1683371..5b5e6f0721 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -3055,22 +3055,37 @@ private static CharSequence generateDecoderWrapListener(final FieldPrecedenceMod final StringBuilder sb = new StringBuilder(); sb.append(INDENT).append("void onWrapForDecode(std::uint64_t actingVersion)\n") - .append(INDENT).append("{\n") - .append(INDENT).append(INDENT).append("switch(actingVersion)\n") - .append(INDENT).append(INDENT).append("{\n"); - - fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> - sb.append(INDENT).append(TWO_INDENT).append("case ").append(version).append(":\n") - .append(INDENT).append(THREE_INDENT).append("codecState(") - .append(qualifiedStateCase(state)).append(");\n") - .append(INDENT).append(THREE_INDENT).append("break;\n")); - - sb.append(INDENT).append(TWO_INDENT).append("default:\n") - .append(INDENT).append(THREE_INDENT).append("codecState(") - .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())).append(");\n") - .append(INDENT).append(THREE_INDENT).append("break;\n") - .append(INDENT).append(INDENT).append("}\n") - .append(INDENT).append("}\n\n"); + .append(INDENT).append("{\n"); + + final MutableBoolean actingVersionCanBeTooLowToBeValid = new MutableBoolean(true); + + fieldPrecedenceModel.forEachWrappedStateByVersionDesc((version, state) -> + { + if (version == 0) + { + actingVersionCanBeTooLowToBeValid.set(false); + + sb.append(INDENT).append(" codecState(") + .append(qualifiedStateCase(state)).append(");\n"); + } + else + { + sb.append(INDENT).append(" if (actingVersion >= ").append(version).append(")\n") + .append(INDENT).append(" {\n") + .append(INDENT).append(" codecState(") + .append(qualifiedStateCase(state)).append(");\n") + .append(INDENT).append(" return;\n") + .append(INDENT).append(" }\n\n"); + } + }); + + if (actingVersionCanBeTooLowToBeValid.get()) + { + sb.append(INDENT) + .append(" throw std::runtime_error(\"Unsupported acting version: \" + actingVersion);\n"); + } + + sb.append(INDENT).append("}\n\n"); return sb; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index f141c7876f..8d15021814 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1912,22 +1912,20 @@ private static CharSequence generateDecoderWrapListener( } final StringBuilder sb = new StringBuilder(); + sb.append(indent).append("private void OnWrapForDecode(int actingVersion)\n") - .append(indent).append("{\n") - .append(indent).append(INDENT).append("switch(actingVersion)\n") - .append(indent).append(INDENT).append("{\n"); + .append(indent).append("{\n"); - fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> - sb.append(indent).append(TWO_INDENT).append("case ").append(version).append(":\n") - .append(indent).append(THREE_INDENT).append("codecState(") + fieldPrecedenceModel.forEachWrappedStateByVersionDesc((version, state) -> + sb.append(indent).append(" if (actingVersion >= ").append(version).append(")\n") + .append(indent).append(" {\n") + .append(indent).append(" codecState(") .append(qualifiedStateCase(state)).append(");\n") - .append(indent).append(THREE_INDENT).append("break;\n")); + .append(indent).append(" return;\n") + .append(indent).append(" }\n\n")); - sb.append(indent).append(TWO_INDENT).append("default:\n") - .append(indent).append(THREE_INDENT).append("codecState(") - .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())).append(");\n") - .append(indent).append(THREE_INDENT).append("break;\n") - .append(indent).append(INDENT).append("}\n") + sb.append(indent) + .append(" throw new InvalidOperationException(\"Unsupported acting version: \" + actingVersion);\n") .append(indent).append("}\n\n"); return sb; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 8009f7a073..1a5e17bb20 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -762,21 +762,18 @@ private static CharSequence generateDecoderWrapListener( final StringBuilder sb = new StringBuilder(); sb.append(indent).append("private void onWrap(final int actingVersion)\n") - .append(indent).append("{\n") - .append(indent).append(" switch(actingVersion)\n") - .append(indent).append(" {\n"); + .append(indent).append("{\n"); - fieldPrecedenceModel.forEachWrappedStateByVersion((version, state) -> - sb.append(indent).append(" case ").append(version).append(":\n") - .append(indent).append(" codecState(") + fieldPrecedenceModel.forEachWrappedStateByVersionDesc((version, state) -> + sb.append(indent).append(" if (actingVersion >= ").append(version).append(")\n") + .append(indent).append(" {\n") + .append(indent).append(" codecState(") .append(qualifiedStateCase(state)).append(");\n") - .append(indent).append(" break;\n")); + .append(indent).append(" return;\n") + .append(indent).append(" }\n\n")); - sb.append(indent).append(" default:\n") - .append(indent).append(" codecState(") - .append(qualifiedStateCase(fieldPrecedenceModel.latestVersionWrappedState())).append(");\n") - .append(indent).append(" break;\n") - .append(indent).append(" }\n") + sb.append(indent) + .append(" throw new IllegalStateException(\"Unsupported acting version: \" + actingVersion);\n") .append(indent).append("}\n\n"); return sb; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java index 12bdde9ae0..3563540650 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/FrameCodecDecoder.java @@ -139,15 +139,13 @@ public int offset() private void onWrap(final int actingVersion) { - switch(actingVersion) + if (actingVersion >= 0) { - case 0: - codecState(CodecStates.V0_BLOCK); - break; - default: - codecState(CodecStates.V0_BLOCK); - break; + codecState(CodecStates.V0_BLOCK); + return; } + + throw new IllegalStateException("Unsupported acting version: " + actingVersion); } public FrameCodecDecoder wrap( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index e6e0fba7b9..7b2e69831b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -186,15 +186,13 @@ public int offset() private void onWrap(final int actingVersion) { - switch(actingVersion) + if (actingVersion >= 0) { - case 0: - codecState(CodecStates.V0_BLOCK); - break; - default: - codecState(CodecStates.V0_BLOCK); - break; + codecState(CodecStates.V0_BLOCK); + return; } + + throw new IllegalStateException("Unsupported acting version: " + actingVersion); } public TokenCodecDecoder wrap( diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp index ecd3df1336..ef2b58d75c 100644 --- a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -51,6 +51,7 @@ #include "order_check/NoBlock.h" #include "order_check/GroupWithNoBlock.h" #include "order_check/NestedGroupWithVarLength.h" +#include "order_check/SkipVersionAddGroupBeforeVarDataV2.h" using namespace order::check; using ::testing::HasSubstr; @@ -4935,3 +4936,22 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple(2, 2, "V0_B_N_D_N_BLOCK") ) ); + +TEST_F(FieldAccessOrderCheckTest, allowsSkippingFutureGroupWhenDecodingFromVersionWithNoChangesInMessagePart1) +{ + AddGroupBeforeVarDataV0 encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42).putB("abc"); + + SkipVersionAddGroupBeforeVarDataV2 decoder; + decoder.wrapForDecode( + m_buffer, + OFFSET, + AddGroupBeforeVarDataV0::sbeBlockLength(), + 1, + BUFFER_LEN + ); + + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java index 80a4ba4416..6ac554b8a7 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; import java.nio.charset.StandardCharsets; import java.util.Random; @@ -3407,6 +3408,116 @@ void disallowsIncompleteMessagesDueToMissingVarDataInNestedGroup( assertThat(exception.getMessage(), containsString("Not fully encoded, current state: " + expectedState)); } + @Test + void decodesNullValueForFutureVersionBlockFieldWhenCurrentVersionHasNoChangesInMessage() + { + final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder(); + final SkipVersionAddPrimitiveV1Encoder encoder = new SkipVersionAddPrimitiveV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, headerEncoder); + + headerEncoder + .templateId(SkipVersionAddPrimitiveV2Encoder.TEMPLATE_ID) + .version(1); + + encoder.b("abc"); + + final SkipVersionAddPrimitiveV2Decoder decoder = new SkipVersionAddPrimitiveV2Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + + assertThat(decoder.a(), equalTo(SkipVersionAddPrimitiveV2Decoder.aNullValue())); + assertThat(decoder.b(), equalTo("abc")); + } + + @Test + void decodesEmptyFutureGroupWhenDecodingFromVersionWithNoChangesInMessage() + { + final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder(); + final SkipVersionAddGroupV1Encoder encoder = new SkipVersionAddGroupV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, headerEncoder); + + headerEncoder + .templateId(SkipVersionAddGroupV2Decoder.TEMPLATE_ID) + .version(1); + + encoder.a(42); + + final SkipVersionAddGroupV2Decoder decoder = new SkipVersionAddGroupV2Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b().count(), equalTo(0)); + } + + @Test + void decodesNullValueForFutureVarDataFieldWhenDecodingFromVersionWithNoChangesInMessage() + { + final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder(); + final SkipVersionAddVarDataV1Encoder encoder = new SkipVersionAddVarDataV1Encoder() + .wrapAndApplyHeader(buffer, OFFSET, headerEncoder); + + headerEncoder + .templateId(SkipVersionAddVarDataV2Decoder.TEMPLATE_ID) + .version(1); + + encoder.a(42); + + final SkipVersionAddVarDataV2Decoder decoder = new SkipVersionAddVarDataV2Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + + assertThat(decoder.a(), equalTo(42)); + assertThat(decoder.b(), equalTo("")); + } + + @Test + void allowsDecodingUnknownFutureVersions() + { + final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder(); + final SkipVersionAddPrimitiveV2Encoder encoder = new SkipVersionAddPrimitiveV2Encoder() + .wrapAndApplyHeader(buffer, OFFSET, headerEncoder); + + headerEncoder + .templateId(SkipVersionAddPrimitiveV2Encoder.TEMPLATE_ID) + .version(42); + + encoder.a(43).b("abc"); + + final SkipVersionAddPrimitiveV2Decoder decoder = new SkipVersionAddPrimitiveV2Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + + assertThat(decoder.a(), equalTo(43)); + assertThat(decoder.b(), equalTo("abc")); + } + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + void allowsSkippingFutureGroupWhenDecodingFromVersionWithNoChangesInMessage(final boolean decodeGroup) + { + final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder(); + final AddGroupBeforeVarDataV0Encoder encoder = new AddGroupBeforeVarDataV0Encoder() + .wrapAndApplyHeader(buffer, OFFSET, headerEncoder); + + headerEncoder + .templateId(SkipVersionAddGroupBeforeVarDataV2Decoder.TEMPLATE_ID) + .version(1); + + encoder.a(42).b("abc"); + + final SkipVersionAddGroupBeforeVarDataV2Decoder decoder = new SkipVersionAddGroupBeforeVarDataV2Decoder() + .wrapAndApplyHeader(buffer, OFFSET, messageHeaderDecoder); + + assertThat(decoder.a(), equalTo(42)); + + if (decodeGroup) + { + for (final SkipVersionAddGroupBeforeVarDataV2Decoder.CDecoder group : decoder.c()) + { + group.sbeSkip(); + } + } + + assertThat(decoder.b(), equalTo("abc")); + } + private void modifyHeaderToLookLikeVersion0() { messageHeaderDecoder.wrap(buffer, OFFSET); @@ -3418,9 +3529,9 @@ private void modifyHeaderToLookLikeVersion0() private void modifyHeaderToLookLikeVersion1() { messageHeaderDecoder.wrap(buffer, OFFSET); - assert messageHeaderDecoder.version() == 1; + assert messageHeaderDecoder.version() >= 1; final int v0TemplateId = messageHeaderDecoder.templateId() - 1_000; messageHeaderEncoder.wrap(buffer, OFFSET); - messageHeaderEncoder.templateId(v0TemplateId); + messageHeaderEncoder.templateId(v0TemplateId).version(1); } } diff --git a/sbe-tool/src/test/resources/field-order-check-schema.xml b/sbe-tool/src/test/resources/field-order-check-schema.xml index e4d62ebfd6..8bedfd4b3f 100644 --- a/sbe-tool/src/test/resources/field-order-check-schema.xml +++ b/sbe-tool/src/test/resources/field-order-check-schema.xml @@ -4,7 +4,7 @@ id="1" description="Unit Test" byteOrder="littleEndian" - version="1"> + version="3"> @@ -141,6 +141,7 @@ + @@ -289,4 +290,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4b6cbf7d35b08b688cdd74822ef8f1a5f1ca45f6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 11 Apr 2024 23:50:32 +0200 Subject: [PATCH 328/805] [C#] Fix assertion. --- csharp/sbe-tests/FieldAccessOrderCheckTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/sbe-tests/FieldAccessOrderCheckTests.cs b/csharp/sbe-tests/FieldAccessOrderCheckTests.cs index 1ee4569643..89ba377fd6 100644 --- a/csharp/sbe-tests/FieldAccessOrderCheckTests.cs +++ b/csharp/sbe-tests/FieldAccessOrderCheckTests.cs @@ -3194,7 +3194,7 @@ private void ModifyHeaderToLookLikeVersion1() { var messageHeaderDecoder = new MessageHeader(); messageHeaderDecoder.Wrap(_buffer, Offset, MessageHeader.SbeSchemaVersion); - Debug.Assert(messageHeaderDecoder.Version == 1); + Debug.Assert(messageHeaderDecoder.Version >= 1); int v0TemplateId = messageHeaderDecoder.TemplateId - 1_000; var messageHeaderEncoder = new MessageHeader(); messageHeaderEncoder.Wrap(_buffer, Offset, MessageHeader.SbeSchemaVersion); From 813a32870a5cbd98db0459a49c292d57703136f5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 11 Apr 2024 23:53:01 +0200 Subject: [PATCH 329/805] 1.31.1 released --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 7341032ba0..6bae540243 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.32.0-SNAPSHOT +1.31.1 From 261f8a33753ba6c6b40ac646799e75149054e4be Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 11 Apr 2024 23:56:18 +0200 Subject: [PATCH 330/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6bae540243..365468802a 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.31.1 +1.32.0-SNAPSHOT \ No newline at end of file From 782014f97b22eea8de05498dd9a73c7051a8c452 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:28:10 +0200 Subject: [PATCH 331/805] [CI] Fix GCC installation. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 149150af21..6c15932fdf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -176,7 +176,7 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | - sudo add-apt-repository ppa:ubuntu-toolchain-r/ppa + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install -y g++-${{ matrix.version }} curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz From 0053ff3e605efb2af3e79a2b20178a6e1f18255a Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 13 May 2024 11:15:03 +0200 Subject: [PATCH 332/805] [CI] Install JDK 8 for running Gradle commands. --- .github/workflows/ci.yml | 69 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c15932fdf..7c117207db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,6 +92,11 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - name: Cache NuGet dependencies uses: actions/cache@v4 with: @@ -144,6 +149,11 @@ jobs: curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - name: Build run: ./cppbuild/cppbuild @@ -182,6 +192,11 @@ jobs: curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - name: Build run: ./cppbuild/cppbuild @@ -222,6 +237,11 @@ jobs: curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - name: Build run: ./cppbuild/cppbuild @@ -262,6 +282,11 @@ jobs: curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - name: Build run: ./cppbuild/cppbuild @@ -280,11 +305,28 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} + - name: Cache Gradle dependencies + uses: actions/cache@v4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache Gradle wrappers + uses: actions/cache@v4 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install CMake run: | curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz tar xf cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz echo "cmake-${CMAKE_VERSION}-Darwin-x86_64/CMake.app/Contents/bin" >> $GITHUB_PATH + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -303,12 +345,29 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} + - name: Cache Gradle dependencies + uses: actions/cache@v4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Cache Gradle wrappers + uses: actions/cache@v4 + with: + path: ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install CMake run: | $client = new-object System.Net.WebClient $client.DownloadFile("https://github.com/Kitware/CMake/releases/download/v$Env:CMAKE_VERSION/cmake-$Env:CMAKE_VERSION-win64-x64.zip","cmake-$Env:CMAKE_VERSION-win64-x64.zip") 7z x cmake-$Env:CMAKE_VERSION-win64-x64.zip echo "cmake-$Env:CMAKE_VERSION-win64-x64/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - name: Build run: cppbuild/cppbuild.cmd @@ -342,6 +401,11 @@ jobs: profile: minimal toolchain: ${{ matrix.rust }} override: true + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - run: ./gradlew runRustTests golang-build: @@ -372,6 +436,11 @@ jobs: uses: actions/setup-go@v4 with: go-version: ${{ matrix.version }} + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 - name: Generate codecs run: ./gradlew generateGolangCodecs - name: Go From 3533f8d070c1502a53968e3d0d9dbfa2631bf54c Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 13 May 2024 11:38:16 +0200 Subject: [PATCH 333/805] [CI] Explicitly use `macos-14`. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c117207db..e6bb6a9736 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -296,7 +296,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'macos-latest' ] + os: [ 'macos-14' ] env: CC: clang CXX: clang++ From 2231d52a954ade38e64897afaf2cdb7680619a2e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 30 May 2024 10:15:34 +0200 Subject: [PATCH 334/805] Update name. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index be16408906..691665c2b4 100644 --- a/build.gradle +++ b/build.gradle @@ -136,8 +136,8 @@ def projectPom = { } developer { id = 'vyazelenko' - name = 'Dmitry Vyazelenko' - email = 'vyazelenko@yahoo.com' + name = 'Dmytro Vyazelenko' + email = 'vyazelenko@protonmail.com' url = 'https://github.com/vyazelenko' } } From f381fd433319824b8d462c86d00939103d510b5c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:21:31 +0200 Subject: [PATCH 335/805] [Java] Upgrade to Agrona 1.21.2. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 691665c2b4..1811fc9913 100644 --- a/build.gradle +++ b/build.gradle @@ -58,8 +58,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.2' def jmhVersion = '1.37' -def agronaVersion = '1.21.1' -def agronaVersionRange = '[1.21.1,2.0[' // allow any release >= 1.21.1 and < 2.0.0 +def agronaVersion = '1.21.2' +def agronaVersionRange = '[1.21.2,2.0[' // allow any release >= 1.21.2 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 2a2d308d280f24762b189e59cd6ed092c140cc5a Mon Sep 17 00:00:00 2001 From: Yuhanun Citgez <122264445+YuhanunCitgez@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:04:36 +0200 Subject: [PATCH 336/805] Rust Generation: Avoid warnings (#995) --- .../java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 2ed6eb1fcb..109d3ba4c5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -61,6 +61,7 @@ void generate() throws IOException indent(libRs, 0, "#![forbid(unsafe_code)]\n"); indent(libRs, 0, "#![allow(clippy::upper_case_acronyms)]\n"); indent(libRs, 0, "#![allow(non_camel_case_types)]\n\n"); + indent(libRs, 0, "#![allow(ambiguous_glob_reexports)]\n\n"); indent(libRs, 0, "use ::core::{convert::TryInto};\n\n"); final ArrayList modules = new ArrayList<>(); @@ -171,11 +172,6 @@ static void generateReadBuf(final Appendable writer, final ByteOrder byteOrder) indent(writer, 2, "Self { data }\n"); indent(writer, 1, "}\n\n"); - indent(writer, 1, "#[inline]\n"); - indent(writer, 1, "fn get_bytes(slice: &[u8]) -> [u8; COUNT] {\n"); - indent(writer, 2, "slice.try_into().expect(\"slice with incorrect length\")\n"); - indent(writer, 1, "}\n\n"); - indent(writer, 1, "#[inline]\n"); indent(writer, 1, "pub(crate) fn get_bytes_at(slice: &[u8], index: usize) -> [u8; N] {\n"); indent(writer, 2, "slice[index..index+N].try_into().expect(\"slice with incorrect length\")\n"); From e4dd8721fcf7b07d246b966149dc613174a4ddca Mon Sep 17 00:00:00 2001 From: adam-talos <87664036+adam-talos@users.noreply.github.com> Date: Tue, 18 Jun 2024 08:05:07 -0400 Subject: [PATCH 337/805] Fix to not allocate to the heap when iterating over repeating groups in golang 1.22 (#994) Verify by running ```golang go build -gcflags=all=-d=loopvar=2 ``` --- .../real_logic/sbe/generation/golang/GolangGenerator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java index ef9c04cc3b..1c1582380a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java @@ -1276,8 +1276,8 @@ private int generateGroupEncodeDecode( // Write the group itself encode.append(String.format( - "\tfor _, prop := range %1$s.%2$s {\n" + - "\t\tif err := prop.Encode(_m, _w); err != nil {\n" + + "\tfor i := range %1$s.%2$s {\n" + + "\t\tif err := %1$s.%2$s[i].Encode(_m, _w); err != nil {\n" + "\t\t\treturn err\n" + "\t\t}\n", varName, @@ -1329,8 +1329,8 @@ private int generateGroupEncodeDecode( // Range check the group itself rc.append(String.format( - "\tfor _, prop := range %1$s.%2$s {\n" + - "\t\tif err := prop.RangeCheck(actingVersion, schemaVersion); err != nil {\n" + + "\tfor i := range %1$s.%2$s {\n" + + "\t\tif err := %1$s.%2$s[i].RangeCheck(actingVersion, schemaVersion); err != nil {\n" + "\t\t\treturn err\n" + "\t\t}\n" + "\t}\n", From 5389910a15df61c0c0f1f27810d2c4cfb47d0a21 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 27 Sep 2023 13:48:36 +0100 Subject: [PATCH 338/805] [C#] Generate DTOs from SBE IR for non-perf-sensitive usecases. In some applications performance is not cricital. Some users would like to use SBE across their whole "estate", but don't want the "sharp edges" associated with using flyweight codecs, e.g., accidental escape. In this commit, I've added a first cut of DTO generation for C# and a simple test based on the Car Example. The DTOs support encoding and decoding via the generated codecs using `EncodeInto(CodecT codec)` and `DecodeFrom(CodecT codec)` methods. Currently there is no support for equality/comparison or read-only views over the data; although, these have been requested. Here are some points that we may or may not wish to change in the future: 1. Non-present (due to the encoded version) string/array data and repeating groups are represented as `null` rather than empty. 2. Non-present primitive values are represented as their associated null value rather than using nullable types. 3. Non-present bitsets are represented as `0`. 4. DTOs are generated via a separate `CodeGenerator` rather than a flag to the existing C# `CodeGenerator`. --- build.gradle | 16 +- csharp/sbe-dll/DirectBuffer.cs | 7 +- csharp/sbe-tests/DtoTests.cs | 110 ++ .../generation/csharp/CSharpDtoGenerator.java | 1076 +++++++++++++++++ .../sbe/generation/csharp/CSharpDtos.java | 35 + .../generation/csharp/CSharpGenerator.java | 109 +- .../sbe/generation/csharp/CSharpUtil.java | 116 +- 7 files changed, 1353 insertions(+), 116 deletions(-) create mode 100644 csharp/sbe-tests/DtoTests.cs create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java diff --git a/build.gradle b/build.gradle index 1811fc9913..7dbd8d24fc 100644 --- a/build.gradle +++ b/build.gradle @@ -735,7 +735,7 @@ tasks.register('generateCSharpCodecsWithXIncludes', JavaExec) { 'sbe-samples/src/main/resources/example-extension-schema.xml'] } -tasks.register('generateCSharpCodecsTests', JavaExec) { +tasks.register('generateCSharpTestCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( @@ -754,9 +754,21 @@ tasks.register('generateCSharpCodecsTests', JavaExec) { 'sbe-benchmarks/src/main/resources/fix-message-samples.xml'] } +tasks.register('generateCSharpTestDtos', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'csharp/sbe-generated', + 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharpDtos', + 'sbe.xinclude.aware': 'true', + 'sbe.validation.xsd': validationXsdPath) + args = ['sbe-samples/src/main/resources/example-extension-schema.xml'] +} + tasks.register('generateCSharpCodecs') { description = 'Generate csharp codecs' - dependsOn 'generateCSharpCodecsTests', + dependsOn 'generateCSharpTestCodecs', + 'generateCSharpTestDtos', 'generateCSharpCodecsWithXIncludes' } diff --git a/csharp/sbe-dll/DirectBuffer.cs b/csharp/sbe-dll/DirectBuffer.cs index 09eb64ec7e..87f08b96b5 100644 --- a/csharp/sbe-dll/DirectBuffer.cs +++ b/csharp/sbe-dll/DirectBuffer.cs @@ -694,7 +694,6 @@ public int SetBytes(int index, ReadOnlySpan src) ///

    /// Writes a string into the underlying buffer, encoding using the provided . - /// If there is not enough room in the buffer for the bytes it will throw IndexOutOfRangeException. /// /// encoding to use to write the bytes from the string /// source string @@ -702,13 +701,9 @@ public int SetBytes(int index, ReadOnlySpan src) /// count of bytes written public unsafe int SetBytesFromString(Encoding encoding, string src, int index) { - int available = _capacity - index; int byteCount = encoding.GetByteCount(src); - if (byteCount > available) - { - ThrowHelper.ThrowIndexOutOfRangeException(_capacity); - } + CheckLimit(index + byteCount); fixed (char* ptr = src) { diff --git a/csharp/sbe-tests/DtoTests.cs b/csharp/sbe-tests/DtoTests.cs new file mode 100644 index 0000000000..99fbcadc74 --- /dev/null +++ b/csharp/sbe-tests/DtoTests.cs @@ -0,0 +1,110 @@ +using Extension; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Org.SbeTool.Sbe.Dll; + +namespace Org.SbeTool.Sbe.Tests +{ + [TestClass] + public class DtoTests + { + [TestMethod] + public void ShouldRoundTripCar() + { + var inputByteArray = new byte[1024]; + var inputBuffer = new DirectBuffer(inputByteArray); + EncodeCar(inputBuffer); + var decoder = new Car(); + decoder.WrapForDecode(inputBuffer, 0, Car.BlockLength, Car.SchemaVersion); + var decoderString = decoder.ToString(); + var dto = new CarDto(); + dto.DecodeFrom(decoder); + var outputByteArray = new byte[1024]; + var outputBuffer = new DirectBuffer(outputByteArray); + var encoder = new Car(); + encoder.WrapForEncode(outputBuffer, 0); + dto.EncodeInto(encoder); + var dtoString = dto.ToString(); + CollectionAssert.AreEqual(inputByteArray, outputByteArray); + Assert.AreEqual(decoderString, dtoString); + } + + private static void EncodeCar(DirectBuffer buffer) + { + var car = new Car(); + car.WrapForEncode(buffer, 0); + car.SerialNumber = 1234; + car.ModelYear = 2013; + car.Available = BooleanType.T; + car.Code = Model.A; + car.SetVehicleCode("ABCDEF"); + + for (int i = 0, size = Car.SomeNumbersLength; i < size; i++) + { + car.SetSomeNumbers(i, (uint)i); + } + + car.Extras = OptionalExtras.CruiseControl | OptionalExtras.SportsPack; + + car.CupHolderCount = 119; + + car.Engine.Capacity = 2000; + car.Engine.NumCylinders = 4; + car.Engine.SetManufacturerCode("ABC"); + car.Engine.Efficiency = 35; + car.Engine.BoosterEnabled = BooleanType.T; + car.Engine.Booster.BoostType = BoostType.NITROUS; + car.Engine.Booster.HorsePower = 200; + + var fuelFigures = car.FuelFiguresCount(3); + fuelFigures.Next(); + fuelFigures.Speed = 30; + fuelFigures.Mpg = 35.9f; + fuelFigures.SetUsageDescription("this is a description"); + + fuelFigures.Next(); + fuelFigures.Speed = 55; + fuelFigures.Mpg = 49.0f; + fuelFigures.SetUsageDescription("this is a description"); + + fuelFigures.Next(); + fuelFigures.Speed = 75; + fuelFigures.Mpg = 40.0f; + fuelFigures.SetUsageDescription("this is a description"); + + Car.PerformanceFiguresGroup perfFigures = car.PerformanceFiguresCount(2); + perfFigures.Next(); + perfFigures.OctaneRating = 95; + + Car.PerformanceFiguresGroup.AccelerationGroup acceleration = perfFigures.AccelerationCount(3).Next(); + acceleration.Mph = 30; + acceleration.Seconds = 4.0f; + + acceleration.Next(); + acceleration.Mph = 60; + acceleration.Seconds = 7.5f; + + acceleration.Next(); + acceleration.Mph = 100; + acceleration.Seconds = 12.2f; + + perfFigures.Next(); + perfFigures.OctaneRating = 99; + acceleration = perfFigures.AccelerationCount(3).Next(); + + acceleration.Mph = 30; + acceleration.Seconds = 3.8f; + + acceleration.Next(); + acceleration.Mph = 60; + acceleration.Seconds = 7.1f; + + acceleration.Next(); + acceleration.Mph = 100; + acceleration.Seconds = 11.8f; + + car.SetManufacturer("Ford"); + car.SetModel("Fiesta"); + car.SetActivationCode("1234"); + } + } +} \ No newline at end of file diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java new file mode 100644 index 0000000000..a0f1e21d9d --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -0,0 +1,1076 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * Copyright (C) 2017 MarketFactory, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.generation.csharp; + +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.Signal; +import uk.co.real_logic.sbe.ir.Token; +import org.agrona.Verify; +import org.agrona.generation.OutputManager; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; + +import static uk.co.real_logic.sbe.generation.csharp.CSharpUtil.*; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; + +/** + * DTO generator for the CSharp programming language. + */ +@SuppressWarnings("CodeBlock2Expr") +public class CSharpDtoGenerator implements CodeGenerator +{ + private static final String INDENT = " "; + private static final String BASE_INDENT = INDENT; + + private final Ir ir; + private final OutputManager outputManager; + + /** + * Create a new C# DTO {@link CodeGenerator}. + * + * @param ir for the messages and types. + * @param outputManager for generating the DTOs to. + */ + public CSharpDtoGenerator(final Ir ir, final OutputManager outputManager) + { + Verify.notNull(ir, "ir"); + Verify.notNull(outputManager, "outputManager"); + + this.ir = ir; + this.outputManager = outputManager; + } + + /** + * {@inheritDoc} + */ + public void generate() throws IOException + { + generateDtosForTypes(); + + for (final List tokens : ir.messages()) + { + final Token msgToken = tokens.get(0); + final String codecClassName = formatClassName(msgToken.name()); + final String className = formatDtoClassName(msgToken.name()); + + final List messageBody = tokens.subList(1, tokens.size() - 1); + int offset = 0; + + final StringBuilder sb = new StringBuilder(); + + final List fields = new ArrayList<>(); + offset = collectFields(messageBody, offset, fields); + generateFields(sb, fields, BASE_INDENT + INDENT); + + final List groups = new ArrayList<>(); + offset = collectGroups(messageBody, offset, groups); + generateGroups(sb, codecClassName, groups, BASE_INDENT + INDENT); + + final List varData = new ArrayList<>(); + collectVarData(messageBody, offset, varData); + generateVarData(sb, varData, BASE_INDENT + INDENT); + + generateDecodeFrom(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); + generateEncodeInto(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); + generateDisplay(sb, codecClassName, "WrapForEncode", null, BASE_INDENT + INDENT); + + try (Writer out = outputManager.createOutput(className)) + { + out.append(generateFileHeader(ir.applicableNamespace(), "using System.Collections.Generic;\n")); + out.append(generateDocumentation(BASE_INDENT, msgToken)); + + out.append(BASE_INDENT).append("public sealed partial class ").append(className).append("\n") + .append(BASE_INDENT).append("{") + .append(sb) + .append(BASE_INDENT).append("}\n") + .append("}\n"); + } + } + } + + private void generateGroups( + final StringBuilder sb, + final String parentMessageClassName, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String groupClassName = formatDtoClassName(groupName); + + sb.append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("public List<").append(groupClassName).append("> ") + .append(formatPropertyName(groupName)) + .append(" { get; set; } = new List<").append(groupClassName).append(">();\n"); + + sb.append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("public sealed partial class ").append(groupClassName).append("\n") + .append(indent).append("{"); + + i++; + i += tokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + generateFields(sb, fields, indent + INDENT); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + final String codecClassName = parentMessageClassName + "." + formatClassName(groupName) + "Group"; + generateGroups(sb, codecClassName, groups, indent + INDENT); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + generateVarData(sb, varData, indent + INDENT); + + generateDecodeFrom(sb, codecClassName, fields, groups, varData, indent + INDENT); + generateEncodeInto(sb, codecClassName, fields, groups, varData, indent + INDENT); + + sb.append(indent).append("}\n"); + } + } + + private void generateCompositeDecodeFrom( + final StringBuilder sb, + final String codecClassName, + final List tokens, + final String indent) + { + sb.append("\n") + .append(indent).append("public void DecodeFrom(").append(codecClassName).append(" codec)\n") + .append(indent).append("{\n"); + + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + + generateFieldDecodeFrom(sb, token, token, codecClassName, indent + INDENT); + + i += tokens.get(i).componentTokenCount(); + } + + sb.append(indent).append("}\n"); + } + + private void generateCompositeEncodeInto( + final StringBuilder sb, + final String codecClassName, + final List tokens, + final String indent) + { + sb.append("\n") + .append(indent).append("public void EncodeInto(").append(codecClassName).append(" codec)\n") + .append(indent).append("{\n"); + + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + + generateFieldEncodeInto(sb, token, token, indent + INDENT); + + i += tokens.get(i).componentTokenCount(); + } + + sb.append(indent).append("}\n"); + } + + private void generateDecodeFrom( + final StringBuilder sb, + final String codecClassName, + final List fields, + final List groups, + final List varData, + final String indent) + { + sb.append("\n") + .append(indent).append("public void DecodeFrom(").append(codecClassName).append(" codec)\n") + .append(indent).append("{\n"); + + generateFieldsDecodeFrom(sb, fields, codecClassName, indent + INDENT); + generateGroupsDecodeFrom(sb, groups, indent + INDENT); + generateVarDataDecodeFrom(sb, varData, indent + INDENT); + + sb.append(indent).append("}\n"); + } + + private void generateFieldsDecodeFrom( + final StringBuilder sb, + final List tokens, + final String codecClassName, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + + generateFieldDecodeFrom(sb, signalToken, encodingToken, codecClassName, indent); + } + } + } + + private void generateFieldDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String codecClassName, final String indent) + { + switch (typeToken.signal()) + { + case ENCODING: + generatePrimitiveDecodeFrom(sb, fieldToken, typeToken, codecClassName, indent); + break; + + case BEGIN_SET: + generatePropertyDecodeFrom(sb, fieldToken, "0", indent); + break; + + case BEGIN_ENUM: + final String enumName = formatClassName(typeToken.applicableTypeName()); + final String nullValue = formatNamespace(ir.packageName()) + "." + enumName + ".NULL_VALUE"; + generatePropertyDecodeFrom(sb, fieldToken, nullValue, indent); + break; + + case BEGIN_COMPOSITE: + generateComplexDecodeFrom(sb, fieldToken, indent); + break; + + default: + break; + } + } + + private void generatePrimitiveDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String codecClassName, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + return; + } + + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + final String nullValue = codecClassName + "." + formatPropertyName(fieldToken.name()) + "NullValue"; + generatePropertyDecodeFrom(sb, fieldToken, nullValue, indent); + } + else if (arrayLength > 1) + { + generateArrayDecodeFrom(sb, fieldToken, typeToken, indent); + } + } + + private void generateArrayDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + wrapInActingVersionCheck( + sb, + fieldToken, + indent, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName) + .append(" = codec.Get").append(formattedPropertyName).append("();\n"); + }, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName).append(" = null;\n"); + } + ); + } + else + { + final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); + + wrapInActingVersionCheck( + sb, + fieldToken, + indent, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName) + .append(" = new ").append(typeName).append("[") + .append(typeToken.arrayLength()).append("];\n") + .append(blkIndent).append("codec.").append(formattedPropertyName) + .append(".CopyTo(new Span<").append(typeName).append(">(") + .append(formattedPropertyName).append("));\n"); + }, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName).append(" = null;\n"); + } + ); + } + } + + private void generatePropertyDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final String nullValue, + final String indent) + { + + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + wrapInActingVersionCheck( + sb, + fieldToken, + indent, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName).append(" = codec.") + .append(formattedPropertyName).append(";\n"); + }, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName).append(" = ").append(nullValue).append(";\n"); + } + ); + } + + private void generateComplexDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final String indent) + { + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + wrapInActingVersionCheck( + sb, + fieldToken, + indent, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName).append(" = new ") + .append(formatDtoClassName(propertyName)).append("();\n") + .append(blkIndent).append(formattedPropertyName).append(".DecodeFrom(codec.") + .append(formattedPropertyName).append(");\n"); + }, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName).append(" = null;\n"); + } + ); + } + + private void generateGroupsDecodeFrom( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String formattedPropertyName = formatPropertyName(groupName); + final String groupDtoClassName = formatDtoClassName(groupName); + final String groupCodecVarName = groupName + "Codec"; + + sb.append("\n") + .append(indent) + .append(formattedPropertyName).append(" = new List<").append(groupDtoClassName).append(">();\n"); + + wrapInActingVersionCheck( + sb, + groupToken, + indent, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append("var ").append(groupCodecVarName).append(" = codec.") + .append(formattedPropertyName).append(";\n") + .append(blkIndent).append("while (").append(groupCodecVarName).append(".HasNext)\n") + .append(blkIndent).append("{\n") + .append(blkIndent).append(INDENT) + .append("var element = new ").append(groupDtoClassName).append("();\n") + .append(blkIndent).append(INDENT) + .append("element.DecodeFrom(").append(groupCodecVarName).append(".Next());\n") + .append(blkIndent).append(INDENT) + .append(formattedPropertyName).append(".Add(element);\n") + .append(blkIndent).append("}\n"); + }, + null + ); + + i++; + i += tokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + } + } + + private void generateVarDataDecodeFrom( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0; i < tokens.size(); i++) + { + final Token token = tokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + + final String formattedPropertyName = formatPropertyName(propertyName); + final String accessor = characterEncoding == null ? + "Get" + formattedPropertyName + "Bytes" : + "Get" + formattedPropertyName; + + wrapInActingVersionCheck( + sb, + token, + indent, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName) + .append(" = codec.").append(accessor).append("();\n"); + }, + (blkSb, blkIndent) -> + { + blkSb.append(blkIndent).append(formattedPropertyName).append(" = null;\n"); + } + ); + } + } + } + + private void wrapInActingVersionCheck( + final StringBuilder sb, + final Token token, + final String indent, + final BiConsumer generatePresentBlock, + final BiConsumer generateNotPresentBlock) + { + final String propertyName = token.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (token.version() > 0) + { + sb.append("\n").append(indent).append("if (codec.").append(formattedPropertyName) + .append("InActingVersion())\n") + .append(indent).append("{\n"); + generatePresentBlock.accept(sb, indent + INDENT); + sb.append(indent).append("}\n"); + if (null != generateNotPresentBlock) + { + sb.append(indent).append("else\n") + .append(indent).append("{\n"); + generateNotPresentBlock.accept(sb, indent + INDENT); + sb.append(indent).append("}\n"); + } + } + else + { + generatePresentBlock.accept(sb, indent); + } + } + + private void generateEncodeInto( + final StringBuilder sb, + final String codecClassName, + final List fields, + final List groups, + final List varData, + final String indent) + { + sb.append("\n") + .append(indent).append("public void EncodeInto(").append(codecClassName).append(" codec)\n") + .append(indent).append("{\n"); + + generateFieldsEncodeInto(sb, fields, indent + INDENT); + generateGroupsEncodeInto(sb, groups, indent + INDENT); + generateVarDataEncodeInto(sb, varData, indent + INDENT); + + sb.append(indent).append("}\n"); + } + + private void generateFieldsEncodeInto( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + generateFieldEncodeInto(sb, signalToken, encodingToken, indent); + } + } + } + + private void generateFieldEncodeInto( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + + switch (typeToken.signal()) + { + case ENCODING: + generatePrimitiveEncodeInto(sb, fieldToken, typeToken, indent); + break; + + case BEGIN_SET: + case BEGIN_ENUM: + generatePropertyEncodeInto(sb, fieldToken, indent); + break; + + case BEGIN_COMPOSITE: + generateComplexEncodeInto(sb, fieldToken, indent); + break; + + default: + break; + } + } + + private void generatePrimitiveEncodeInto( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + return; + } + + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + generatePropertyEncodeInto(sb, fieldToken, indent); + } + else if (arrayLength > 1) + { + generateArrayEncodeInto(sb, fieldToken, typeToken, indent); + } + } + + private void generateArrayEncodeInto( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + sb.append(indent).append("codec.Set").append(formattedPropertyName).append("(") + .append(formattedPropertyName).append(");\n"); + } + else + { + final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); + + sb.append(indent).append("new Span<").append(typeName).append(">(").append(formattedPropertyName) + .append(").CopyTo(codec.").append(formattedPropertyName).append("AsSpan());\n"); + } + } + + private void generatePropertyEncodeInto( + final StringBuilder sb, + final Token fieldToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + sb.append(indent).append("codec.").append(formattedPropertyName).append(" = ") + .append(formattedPropertyName).append(";\n"); + } + + private void generateComplexEncodeInto( + final StringBuilder sb, + final Token fieldToken, + final String indent) + { + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + sb.append(indent).append(formattedPropertyName).append(".EncodeInto(codec.") + .append(formattedPropertyName).append(");\n"); + } + + private void generateGroupsEncodeInto( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String formattedPropertyName = formatPropertyName(groupName); + final String groupCodecVarName = groupName + "Codec"; + + sb.append("\n") + .append(indent).append("var ").append(groupCodecVarName) + .append(" = codec.").append(formattedPropertyName) + .append("Count(").append(formattedPropertyName).append(".Count);\n\n") + .append(indent).append("foreach (var group in ").append(formattedPropertyName).append(")\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("group.EncodeInto(").append(groupCodecVarName) + .append(".Next()").append(");\n") + .append(indent).append("}\n\n"); + + i++; + i += tokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + } + } + + private void generateVarDataEncodeInto( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (final Token token : tokens) + { + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + + sb.append(indent).append("codec.Set").append(formatPropertyName(propertyName)) + .append("(").append(formatPropertyName(propertyName)).append(");\n"); + } + } + } + + private void generateDisplay( + final StringBuilder sb, + final String codecClassName, + final String wrapMethod, + final String actingVersion, + final String indent) + { + sb.append("\n") + .append(indent).append("public override string ToString()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT) + .append("var buffer = new DirectBuffer(new byte[128], (ignored, newSize) => new byte[newSize]);\n") + .append(indent).append(INDENT).append("var codec = new ").append(codecClassName).append("();\n") + .append(indent).append(INDENT).append("codec."); + sb.append(wrapMethod).append("(buffer, 0"); + if (null != actingVersion) + { + sb.append(", ").append(actingVersion); + } + sb.append(");\n"); + sb.append(indent).append(INDENT).append("EncodeInto(codec);\n") + .append(indent).append(INDENT).append("StringBuilder sb = new StringBuilder();\n") + .append(indent).append(INDENT).append("codec.BuildString(sb);\n") + .append(indent).append(INDENT).append("return sb.ToString();\n") + .append(indent).append("}\n"); + } + + private void generateFields( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + final String propertyName = signalToken.name(); + + switch (encodingToken.signal()) + { + case ENCODING: + generatePrimitiveProperty(sb, propertyName, signalToken, encodingToken, indent); + break; + + case BEGIN_ENUM: + generateEnumProperty(sb, propertyName, signalToken, encodingToken, indent); + break; + + case BEGIN_SET: + generateBitSetProperty(sb, propertyName, signalToken, encodingToken, indent); + break; + + case BEGIN_COMPOSITE: + generateCompositeProperty(sb, propertyName, signalToken, encodingToken, indent); + break; + + default: + break; + } + } + } + } + + private void generateCompositeProperty( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String bitSetName = formatDtoClassName(typeToken.applicableTypeName()); + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(bitSetName).append(" ").append(formatPropertyName(propertyName)) + .append(" { get; set; } = new ").append(bitSetName).append("();\n"); + } + + private void generateBitSetProperty( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String enumName = formatClassName(typeToken.applicableTypeName()); + + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(enumName).append(" ") + .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + } + + private void generateEnumProperty( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String enumName = formatClassName(typeToken.applicableTypeName()); + + if (fieldToken.isConstantEncoding()) + { + final String constValue = fieldToken.encoding().constValue().toString(); + + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public static ").append(enumName).append(" ") + .append(formatPropertyName(propertyName)).append("\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("get { return ") + .append(formatNamespace(ir.packageName())).append(".").append(constValue) + .append("; }\n") + .append(indent).append("}\n"); + } + else + { + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(enumName).append(" ").append(formatPropertyName(propertyName)) + .append(" { get; set; }\n"); + } + } + + private void generatePrimitiveProperty( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + generateConstPropertyMethods(sb, propertyName, fieldToken, typeToken, indent); + } + else + { + generatePrimitivePropertyMethods(sb, propertyName, fieldToken, typeToken, indent); + } + } + + private void generatePrimitivePropertyMethods( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + generateSingleValueProperty(sb, propertyName, fieldToken, typeToken, indent); + } + else if (arrayLength > 1) + { + generateArrayProperty(sb, propertyName, fieldToken, typeToken, indent); + } + } + + private void generateArrayProperty( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public string ") + .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + } + else + { + final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); + + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(typeName).append("[] ") + .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + } + } + + private void generateSingleValueProperty( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); + + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(typeName).append(" ") + .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + } + + private void generateConstPropertyMethods( + final StringBuilder sb, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public static string ").append(toUpperFirstChar(propertyName)).append("\n") + .append(indent).append("{\n") + .append(indent).append(INDENT) + .append("get { return \"").append(typeToken.encoding().constValue().toString()).append("\"; }\n") + .append(indent).append("}\n"); + } + else + { + final String literalValue = + generateLiteral(typeToken.encoding().primitiveType(), typeToken.encoding().constValue().toString()); + + sb.append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public static ").append(cSharpTypeName(typeToken.encoding().primitiveType())) + .append(" ").append(formatPropertyName(propertyName)).append("\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("get { return ").append(literalValue).append("; }\n") + .append(indent).append("}\n"); + } + } + + private void generateVarData( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token token = tokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + final String dtoType = characterEncoding == null ? "byte[]" : "string"; + + sb.append("\n") + .append(indent).append("public ").append(dtoType).append(" ") + .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + } + } + } + + private String formatDtoClassName(final String name) + { + return formatClassName(name + "Dto"); + } + + private void generateDtosForTypes() throws IOException + { + for (final List tokens : ir.types()) + { + switch (tokens.get(0).signal()) + { + case BEGIN_COMPOSITE: + generateComposite(tokens); + break; + + default: + break; + } + } + } + + private void generateComposite(final List tokens) throws IOException + { + final String name = tokens.get(0).applicableTypeName(); + final String className = formatDtoClassName(name); + final String codecClassName = formatClassName(name); + + try (Writer out = outputManager.createOutput(className)) + { + out.append(generateFileHeader(ir.applicableNamespace())); + out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); + + final StringBuilder sb = new StringBuilder(); + + final List compositeTokens = tokens.subList(1, tokens.size() - 1); + generateCompositePropertyElements(sb, compositeTokens, BASE_INDENT + INDENT); + generateCompositeDecodeFrom(sb, codecClassName, compositeTokens, BASE_INDENT + INDENT); + generateCompositeEncodeInto(sb, codecClassName, compositeTokens, BASE_INDENT + INDENT); + generateDisplay(sb, codecClassName, "Wrap", codecClassName + ".SbeSchemaVersion", BASE_INDENT + INDENT); + + out.append(BASE_INDENT).append("public sealed partial class ").append(className).append("\n") + .append(BASE_INDENT).append("{") + .append(sb) + .append(BASE_INDENT).append("}\n") + .append("}\n"); + } + } + + private void generateCompositePropertyElements( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + final String propertyName = formatPropertyName(token.name()); + + switch (token.signal()) + { + case ENCODING: + generatePrimitiveProperty(sb, propertyName, token, token, indent); + break; + + case BEGIN_ENUM: + generateEnumProperty(sb, propertyName, token, token, indent); + break; + + case BEGIN_SET: + generateBitSetProperty(sb, propertyName, token, token, indent); + break; + + case BEGIN_COMPOSITE: + generateCompositeProperty(sb, propertyName, token, token, indent); + break; + + default: + break; + } + + i += tokens.get(i).componentTokenCount(); + } + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java new file mode 100644 index 0000000000..79859d6764 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java @@ -0,0 +1,35 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * Copyright 2017 MarketFactory Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.csharp; + +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.TargetCodeGenerator; +import uk.co.real_logic.sbe.ir.Ir; + +/** + * {@link CodeGenerator} factory for CSharp DTOs. + */ +public class CSharpDtos implements TargetCodeGenerator +{ + /** + * {@inheritDoc} + */ + public CodeGenerator newInstance(final Ir ir, final String outputDir) + { + return new CSharpDtoGenerator(ir, new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 8d15021814..530717c9c4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -786,40 +786,6 @@ private CharSequence generateEnumValues(final List tokens, final Token en return sb; } - private CharSequence generateFileHeader(final String packageName) - { - String[] tokens = packageName.split("\\."); - final StringBuilder sb = new StringBuilder(); - for (final String t : tokens) - { - sb.append(toUpperFirstChar(t)).append("."); - } - if (sb.length() > 0) - { - sb.setLength(sb.length() - 1); - } - - tokens = sb.toString().split("-"); - sb.setLength(0); - - for (final String t : tokens) - { - sb.append(toUpperFirstChar(t)); - } - - return String.format( - "// \n" + - "// Generated SBE (Simple Binary Encoding) message codec\n" + - "// \n\n" + - "#pragma warning disable 1591 // disable warning on missing comments\n" + - "using System;\n" + - "using System.Text;\n" + - "using Org.SbeTool.Sbe.Dll;\n\n" + - "namespace %s\n" + - "{\n", - sb); - } - private CharSequence generateClassDeclaration(final String className) { return String.format( @@ -828,20 +794,6 @@ private CharSequence generateClassDeclaration(final String className) className); } - private static String generateDocumentation(final String indent, final Token token) - { - final String description = token.description(); - if (null == description || description.isEmpty()) - { - return ""; - } - - return - indent + "/// \n" + - indent + "/// " + description + "\n" + - indent + "/// \n"; - } - private void generateMetaAttributeEnum() throws IOException { try (Writer out = outputManager.createOutput(META_ATTRIBUTE_ENUM)) @@ -1282,7 +1234,7 @@ private CharSequence generateConstPropertyMethods( final StringBuilder sb = new StringBuilder(); - final String javaTypeName = cSharpTypeName(token.encoding().primitiveType()); + final String csharpTypeName = cSharpTypeName(token.encoding().primitiveType()); final byte[] constantValue = token.encoding().constValue().byteArrayValue(token.encoding().primitiveType()); final CharSequence values = generateByteLiteralList( token.encoding().constValue().byteArrayValue(token.encoding().primitiveType())); @@ -1304,7 +1256,7 @@ private CharSequence generateConstPropertyMethods( indent + INDENT + "{\n" + indent + INDENT + INDENT + "return _%3$sValue[index];\n" + indent + INDENT + "}\n\n", - javaTypeName, + csharpTypeName, toUpperFirstChar(propertyName), propertyName)); @@ -2247,63 +2199,6 @@ private String generateByteOrder(final ByteOrder byteOrder, final int primitiveT return "LittleEndian"; } - private String generateLiteral(final PrimitiveType type, final String value) - { - String literal = ""; - - final String castType = cSharpTypeName(type); - switch (type) - { - case CHAR: - case UINT8: - case INT8: - case INT16: - case UINT16: - literal = "(" + castType + ")" + value; - break; - - case INT32: - literal = value; - break; - - case UINT32: - literal = value + "U"; - break; - - case FLOAT: - if (value.endsWith("NaN")) - { - literal = "float.NaN"; - } - else - { - literal = value + "f"; - } - break; - - case UINT64: - literal = "0x" + Long.toHexString(Long.parseLong(value)) + "UL"; - break; - - case INT64: - literal = value + "L"; - break; - - case DOUBLE: - if (value.endsWith("NaN")) - { - literal = "double.NaN"; - } - else - { - literal = value + "d"; - } - break; - } - - return literal; - } - private void appendGroupInstanceDisplay( final StringBuilder sb, final List fields, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index cac937c67f..124b352629 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -17,6 +17,8 @@ package uk.co.real_logic.sbe.generation.csharp; import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Token; import java.util.EnumMap; import java.util.Map; @@ -26,6 +28,118 @@ */ public class CSharpUtil { + static String generateLiteral(final PrimitiveType type, final String value) + { + String literal = ""; + + final String castType = cSharpTypeName(type); + switch (type) + { + case CHAR: + case UINT8: + case INT8: + case INT16: + case UINT16: + literal = "(" + castType + ")" + value; + break; + + case INT32: + literal = value; + break; + + case UINT32: + literal = value + "U"; + break; + + case FLOAT: + if (value.endsWith("NaN")) + { + literal = "float.NaN"; + } + else + { + literal = value + "f"; + } + break; + + case UINT64: + literal = "0x" + Long.toHexString(Long.parseLong(value)) + "UL"; + break; + + case INT64: + literal = value + "L"; + break; + + case DOUBLE: + if (value.endsWith("NaN")) + { + literal = "double.NaN"; + } + else + { + literal = value + "d"; + } + break; + } + + return literal; + } + + static CharSequence generateFileHeader(final String packageName, final String... imports) + { + return String.format( + "// \n" + + "// Generated SBE (Simple Binary Encoding) message codec\n" + + "// \n\n" + + "#pragma warning disable 1591 // disable warning on missing comments\n" + + "using System;\n" + + "using System.Text;\n" + + "%1$s" + + "using Org.SbeTool.Sbe.Dll;\n\n" + + "namespace %2$s\n" + + "{\n", + String.join("", imports), + formatNamespace(packageName)); + } + + static String formatNamespace(final String packageName) + { + String[] tokens = packageName.split("\\."); + final StringBuilder sb = new StringBuilder(); + for (final String t : tokens) + { + sb.append(Generators.toUpperFirstChar(t)).append("."); + } + if (sb.length() > 0) + { + sb.setLength(sb.length() - 1); + } + + tokens = sb.toString().split("-"); + sb.setLength(0); + + for (final String t : tokens) + { + sb.append(Generators.toUpperFirstChar(t)); + } + + return sb.toString(); + } + + static String generateDocumentation(final String indent, final Token token) + { + final String description = token.description(); + if (null == description || description.isEmpty()) + { + return ""; + } + + return + indent + "/// \n" + + indent + "/// " + description + "\n" + + indent + "/// \n"; + } + enum Separators { BEGIN_GROUP('['), @@ -89,7 +203,7 @@ public String toString() * @param primitiveType to map. * @return the name of the Java primitive that most closely maps. */ - public static String cSharpTypeName(final PrimitiveType primitiveType) + static String cSharpTypeName(final PrimitiveType primitiveType) { return PRIMITIVE_TYPE_STRING_ENUM_MAP.get(primitiveType); } From 68af4f64b24367d89d635fbff9246fe5eecd7e67 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 5 Oct 2023 18:45:53 +0100 Subject: [PATCH 339/805] [Java] Start to introduce property based testing (PBT). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this commit, I've: 1. Added a test dependency on JQwik. 2. Added a JQwik-based generator of arbitrary valid SBE message schemas. This generator exercises a lot of possibilities but not all. In particular, it is missing the generation of constants, min/max, and custom offsets. 3. Added a test that shows the parser parses any arbitrary SBE message schema. Why have I introduced PBT? My aim is to eventually test (an approximation of) the following property: ``` ∀ msgSchema ∈ PossibleMessageSchemas, ∀ bytes ∈ PossibleValidValues(msgSchema), DtoEncode(DtoDecode(bytes)) = bytes ``` I.e., that `DtoEncode` is the inverse of `DtoDecode` and that it preserves the information in an encoded message. --- .gitignore | 3 + build.gradle | 2 + .../sbe/properties/ParserPropertyTest.java | 48 ++ .../sbe/properties/SchemaDomain.java | 360 +++++++++++++++ .../sbe/properties/XmlSchemaWriter.java | 435 ++++++++++++++++++ 5 files changed, 848 insertions(+) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/SchemaDomain.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java diff --git a/.gitignore b/.gitignore index 6769c8db69..4ffe2537bc 100644 --- a/.gitignore +++ b/.gitignore @@ -119,4 +119,7 @@ rust/Cargo.lock .DS_Store /sbe-tool/src/main/golang/uk_co_real_logic_sbe_ir_generated/ +# JQwik +*.jqwik-database + /generated/ diff --git a/build.gradle b/build.gradle index 7dbd8d24fc..c71515f561 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,7 @@ def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.2' +def jqwikVersion = '1.8.0' def jmhVersion = '1.37' def agronaVersion = '1.21.2' def agronaVersionRange = '[1.21.2,2.0[' // allow any release >= 1.21.2 and < 2.0.0 @@ -251,6 +252,7 @@ project(':sbe-tool') { testImplementation files('build/classes/java/generated') testImplementation "org.hamcrest:hamcrest:${hamcrestVersion}" testImplementation "org.mockito:mockito-core:${mockitoVersion}" + testImplementation "net.jqwik:jqwik:${jqwikVersion}" testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java new file mode 100644 index 0000000000..7abb2b65ca --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties; + +import net.jqwik.api.Arbitrary; +import net.jqwik.api.ForAll; +import net.jqwik.api.Property; +import net.jqwik.api.Provide; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +public class ParserPropertyTest +{ + @Property + void shouldParseAnyValidSchema(@ForAll("schemas") final SchemaDomain.MessageSchema schema) throws Exception + { + final String xml = XmlSchemaWriter.writeString(schema); + try (InputStream in = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) + { + parse(in, ParserOptions.DEFAULT); + } + } + + @Provide + Arbitrary schemas() + { + return SchemaDomain.MessageSchema.arbitrary(); + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/SchemaDomain.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/SchemaDomain.java new file mode 100644 index 0000000000..1605d7d781 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/SchemaDomain.java @@ -0,0 +1,360 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties; + +import net.jqwik.api.Arbitraries; +import net.jqwik.api.Arbitrary; +import net.jqwik.api.Combinators; +import uk.co.real_logic.sbe.PrimitiveType; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public final class SchemaDomain +{ + private static final int MAX_COMPOSITE_DEPTH = 3; + private static final int MAX_GROUP_DEPTH = 3; + + private SchemaDomain() + { + } + + static final class EncodedDataTypeSchema implements TypeSchema + { + private final PrimitiveType primitiveType; + private final boolean isEmbedded; + + private EncodedDataTypeSchema( + final PrimitiveType primitiveType, + final boolean isEmbedded + ) + { + this.primitiveType = primitiveType; + this.isEmbedded = isEmbedded; + } + + public PrimitiveType primitiveType() + { + return primitiveType; + } + + @Override + public boolean isEmbedded() + { + return isEmbedded; + } + + @Override + public void accept(final TypeSchemaVisitor visitor) + { + visitor.onEncoded(this); + } + + static Arbitrary arbitrary() + { + return Combinators.combine( + Arbitraries.of(PrimitiveType.values()), + Arbitraries.of(true, false) + ).as(EncodedDataTypeSchema::new); + } + } + + static final class CompositeTypeSchema implements TypeSchema + { + private final List fields; + + private CompositeTypeSchema(final List fields) + { + this.fields = fields; + } + + public List fields() + { + return fields; + } + + static Arbitrary arbitrary(final int depth) + { + return TypeSchema.arbitrary(depth - 1) + .list() + .ofMinSize(1) + .ofMaxSize(3) + .injectDuplicates(0.2) + .map(CompositeTypeSchema::new); + } + + @Override + public void accept(final TypeSchemaVisitor visitor) + { + visitor.onComposite(this); + } + } + + static final class EnumTypeSchema implements TypeSchema + { + private final String encodingType; + private final List validValues; + + private EnumTypeSchema( + final String encodingType, + final List validValues) + { + this.encodingType = encodingType; + this.validValues = validValues; + } + + public String encodingType() + { + return encodingType; + } + + public List validValues() + { + return validValues; + } + + static Arbitrary arbitrary() + { + return Arbitraries.oneOf( + Arbitraries.chars().alpha() + .map(Character::toUpperCase) + .list() + .ofMaxSize(10) + .uniqueElements() + .map(values -> new EnumTypeSchema( + "char", + values.stream().map(String::valueOf).collect(Collectors.toList()) + )), + Arbitraries.integers() + .between(1, 254) + .list() + .ofMaxSize(254) + .uniqueElements() + .map(values -> new EnumTypeSchema( + "uint8", + values.stream().map(String::valueOf).collect(Collectors.toList()) + )) + ); + } + + @Override + public void accept(final TypeSchemaVisitor visitor) + { + visitor.onEnum(this); + } + } + + static final class SetSchema implements TypeSchema + { + private final String encodingType; + private final int choiceCount; + + private SetSchema( + final String encodingType, + final int choiceCount) + { + this.choiceCount = choiceCount; + this.encodingType = encodingType; + } + + public String encodingType() + { + return encodingType; + } + + public int choiceCount() + { + return choiceCount; + } + + @Override + public void accept(final TypeSchemaVisitor visitor) + { + visitor.onSet(this); + } + + static Arbitrary arbitrary() + { + return Combinators.combine( + Arbitraries.of( + "uint8", + "uint16", + "uint32", + "uint64" + ), + Arbitraries.integers().between(1, 4) + ).as(SetSchema::new); + } + } + + interface TypeSchema + { + static Arbitrary arbitrary(final int depth) + { + if (depth == 1) + { + return Arbitraries.oneOf( + EncodedDataTypeSchema.arbitrary(), + EnumTypeSchema.arbitrary(), + SetSchema.arbitrary() + ); + } + else + { + return Arbitraries.oneOf( + CompositeTypeSchema.arbitrary(depth), + EncodedDataTypeSchema.arbitrary(), + EnumTypeSchema.arbitrary(), + SetSchema.arbitrary() + ); + } + } + + default boolean isEmbedded() + { + return false; + } + + void accept(TypeSchemaVisitor visitor); + } + + interface TypeSchemaVisitor + { + void onEncoded(EncodedDataTypeSchema type); + + void onComposite(CompositeTypeSchema type); + + void onEnum(EnumTypeSchema type); + + void onSet(SetSchema type); + } + + static final class VarDataSchema + { + private final Encoding encoding; + + VarDataSchema(final Encoding encoding) + { + this.encoding = encoding; + } + + public Encoding encoding() + { + return encoding; + } + + static Arbitrary arbitrary() + { + return Arbitraries.of(Encoding.values()) + .map(VarDataSchema::new); + } + + enum Encoding + { + ASCII, + BYTES + } + } + + static final class GroupSchema + { + private final List blockFields; + private final List groups; + private final List varData; + + GroupSchema( + final List blockFields, + final List groups, + final List varData) + { + this.blockFields = blockFields; + this.groups = groups; + this.varData = varData; + } + + public List blockFields() + { + return blockFields; + } + + public List groups() + { + return groups; + } + + public List varData() + { + return varData; + } + + static Arbitrary arbitrary(final int depth) + { + final Arbitrary> subGroups = depth == 1 ? + Arbitraries.of(0).map(ignored -> new ArrayList<>()) : + arbitrary(depth - 1).list().ofMaxSize(3); + + return Combinators.combine( + TypeSchema.arbitrary(MAX_COMPOSITE_DEPTH).list().ofMaxSize(5), + subGroups, + VarDataSchema.arbitrary().list().ofMaxSize(3) + ).as(GroupSchema::new); + } + } + + static final class MessageSchema + { + private final List blockFields; + private final List groups; + private final List varData; + + MessageSchema( + final List blockFields, + final List groups, + final List varData + ) + { + this.blockFields = blockFields; + this.groups = groups; + this.varData = varData; + } + + public List blockFields() + { + return blockFields; + } + + public List groups() + { + return groups; + } + + public List varData() + { + return varData; + } + + static Arbitrary arbitrary() + { + return Combinators.combine( + TypeSchema.arbitrary(MAX_COMPOSITE_DEPTH).list().ofMaxSize(10), + GroupSchema.arbitrary(MAX_GROUP_DEPTH).list().ofMaxSize(3), + VarDataSchema.arbitrary().list().ofMaxSize(3) + ).as(MessageSchema::new); + } + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java new file mode 100644 index 0000000000..84ff1b2881 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java @@ -0,0 +1,435 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties; + +import org.agrona.collections.MutableInteger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.io.File; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import static java.util.Objects.requireNonNull; +import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; + +final class XmlSchemaWriter +{ + private XmlSchemaWriter() + { + } + + public static String writeString(final SchemaDomain.MessageSchema schema) + { + final StringWriter writer = new StringWriter(); + final StreamResult result = new StreamResult(writer); + writeTo(schema, result); + return writer.toString(); + } + + public static void writeFile( + final SchemaDomain.MessageSchema schema, + final File destination) + { + final StreamResult result = new StreamResult(destination); + writeTo(schema, result); + } + + private static void writeTo( + final SchemaDomain.MessageSchema schema, + final StreamResult destination) + { + try + { + final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + + final Element root = document.createElementNS("http://fixprotocol.io/2016/sbe", "sbe:messageSchema"); + root.setAttribute("id", "42"); + root.setAttribute("package", "uk.co.real_logic.sbe.properties"); + document.appendChild(root); + + final Element topLevelTypes = createTypesElement(document); + root.appendChild(topLevelTypes); + + final HashMap typeToName = new HashMap<>(); + + final TypeSchemaConverter typeSchemaConverter = new TypeSchemaConverter( + document, + topLevelTypes, + typeToName + ); + + appendTypes( + topLevelTypes, + typeSchemaConverter, + schema.blockFields(), + schema.groups()); + + final Element message = document.createElement("sbe:message"); + message.setAttribute("name", "TestMessage"); + message.setAttribute("id", "1"); + root.appendChild(message); + final MutableInteger nextMemberId = new MutableInteger(1); + appendMembers( + document, + typeToName, + schema.blockFields(), + schema.groups(), + schema.varData(), + nextMemberId, + message); + + try + { + final Transformer transformer = TransformerFactory.newInstance().newTransformer(); + + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + + final DOMSource source = new DOMSource(document); + + transformer.transform(source, destination); + } + catch (final Exception e) + { + throw new RuntimeException(e); + } + } + catch (final ParserConfigurationException e) + { + throw new RuntimeException(e); + } + } + + private static void appendMembers( + final Document document, + final HashMap typeToName, + final List blockFields, + final List groups, + final List varData, + final MutableInteger nextMemberId, + final Element parent) + { + for (final SchemaDomain.TypeSchema field : blockFields) + { + final int id = nextMemberId.getAndIncrement(); + + final boolean usePrimitiveName = field.isEmbedded() && field instanceof SchemaDomain.EncodedDataTypeSchema; + final String typeName = usePrimitiveName ? + ((SchemaDomain.EncodedDataTypeSchema)field).primitiveType().primitiveName() : + requireNonNull(typeToName.get(field)); + + final Element element = document.createElement("field"); + element.setAttribute("id", Integer.toString(id)); + element.setAttribute("name", "member" + id); + element.setAttribute("type", typeName); + parent.appendChild(element); + } + + for (final SchemaDomain.GroupSchema group : groups) + { + final int id = nextMemberId.getAndIncrement(); + + final Element element = document.createElement("group"); + element.setAttribute("id", Integer.toString(id)); + element.setAttribute("name", "member" + id); + appendMembers( + document, + typeToName, + group.blockFields(), + group.groups(), + group.varData(), + nextMemberId, + element); + parent.appendChild(element); + } + + for (final SchemaDomain.VarDataSchema data : varData) + { + final int id = nextMemberId.getAndIncrement(); + + final Element element = document.createElement("data"); + element.setAttribute("id", Integer.toString(id)); + element.setAttribute("name", "member" + id); + switch (data.encoding()) + { + case ASCII: + element.setAttribute("type", "varStringEncoding"); + break; + case BYTES: + element.setAttribute("type", "varDataEncoding"); + break; + default: + throw new IllegalStateException("Unknown encoding: " + data.encoding()); + } + parent.appendChild(element); + } + } + + private static Element createTypesElement(final Document document) + { + final Element types = document.createElement("types"); + + types.appendChild(createCompositeElement( + document, + "messageHeader", + createTypeElement(document, "blockLength", "uint16"), + createTypeElement(document, "templateId", "uint16"), + createTypeElement(document, "schemaId", "uint16"), + createTypeElement(document, "version", "uint16") + )); + + types.appendChild(createCompositeElement( + document, + "groupSizeEncoding", + createTypeElement(document, "blockLength", "uint16"), + createTypeElement(document, "numInGroup", "uint16") + )); + + final Element varString = createTypeElement(document, "varData", "uint8"); + varString.setAttribute("length", "0"); + varString.setAttribute("characterEncoding", "US-ASCII"); + types.appendChild(createCompositeElement( + document, + "varStringEncoding", + createTypeElement(document, "length", "uint16"), + varString + )); + + final Element varData = createTypeElement(document, "varData", "uint8"); + final Element varDataLength = createTypeElement(document, "length", "uint32"); + varDataLength.setAttribute("maxValue", "1000000"); + varData.setAttribute("length", "0"); + types.appendChild(createCompositeElement( + document, + "varDataEncoding", + varDataLength, + varData + )); + + return types; + } + + private static Element createSetElement( + final Document document, + final String name, + final String encodingType, + final int choiceCount) + { + final Element enumElement = document.createElement("set"); + enumElement.setAttribute("name", name); + enumElement.setAttribute("encodingType", encodingType); + + int caseId = 0; + for (int i = 0; i < choiceCount; i++) + { + final Element choice = document.createElement("choice"); + choice.setAttribute("name", "option" + caseId++); + choice.setTextContent(Integer.toString(i)); + enumElement.appendChild(choice); + } + + return enumElement; + } + + private static Element createEnumElement( + final Document document, + final String name, + final String encodingType, + final List validValues) + { + final Element enumElement = document.createElement("enum"); + enumElement.setAttribute("name", name); + enumElement.setAttribute("encodingType", encodingType); + + int caseId = 0; + for (final String value : validValues) + { + final Element validValue = document.createElement("validValue"); + validValue.setAttribute("name", "Case" + caseId++); + validValue.setTextContent(value); + enumElement.appendChild(validValue); + } + + return enumElement; + } + + private static Element createCompositeElement( + final Document document, + final String name, + final Element... types + ) + { + final Element composite = document.createElement("composite"); + composite.setAttribute("name", name); + + for (final Element type : types) + { + composite.appendChild(type); + } + + return composite; + } + + private static Element createTypeElement( + final Document document, + final String name, + final String primitiveType) + { + final Element blockLength = document.createElement("type"); + blockLength.setAttribute("name", name); + blockLength.setAttribute("primitiveType", primitiveType); + return blockLength; + } + + private static Element createRefElement( + final Document document, + final String name, + final String type) + { + final Element blockLength = document.createElement("ref"); + blockLength.setAttribute("name", name); + blockLength.setAttribute("type", type); + return blockLength; + } + + private static void appendTypes( + final Element topLevelTypes, + final TypeSchemaConverter typeSchemaConverter, + final List blockFields, + final List groups) + { + for (final SchemaDomain.TypeSchema field : blockFields) + { + if (!field.isEmbedded()) + { + topLevelTypes.appendChild(typeSchemaConverter.convert(field)); + } + } + + for (final SchemaDomain.GroupSchema group : groups) + { + appendTypes(topLevelTypes, typeSchemaConverter, group.blockFields(), group.groups()); + } + } + + private static final class TypeSchemaConverter implements SchemaDomain.TypeSchemaVisitor + { + private final Document document; + private final Element topLevelTypes; + private final Map typeToName; + private final Function nextName; + private Element result; + + private TypeSchemaConverter( + final Document document, + final Element topLevelTypes, + final Map typeToName) + { + this.document = document; + this.topLevelTypes = topLevelTypes; + this.typeToName = typeToName; + nextName = ignored -> "Type" + typeToName.size(); + } + + @Override + public void onEncoded(final SchemaDomain.EncodedDataTypeSchema type) + { + result = createTypeElement( + document, + typeToName.computeIfAbsent(type, nextName), + type.primitiveType().primitiveName() + ); + } + + @Override + public void onComposite(final SchemaDomain.CompositeTypeSchema type) + { + final Element[] parts = type.fields().stream() + .map(this::embedOrReference) + .toArray(Element[]::new); + result = createCompositeElement( + document, + typeToName.computeIfAbsent(type, nextName), + parts + ); + } + + @Override + public void onEnum(final SchemaDomain.EnumTypeSchema type) + { + result = createEnumElement( + document, + typeToName.computeIfAbsent(type, nextName), + type.encodingType(), + type.validValues() + ); + } + + @Override + public void onSet(final SchemaDomain.SetSchema type) + { + result = createSetElement( + document, + typeToName.computeIfAbsent(type, nextName), + type.encodingType(), + type.choiceCount() + ); + } + + private Element embedOrReference(final SchemaDomain.TypeSchema type) + { + if (type.isEmbedded()) + { + return convert(type); + } + else + { + final boolean hasWritten = typeToName.containsKey(type); + if (!hasWritten) + { + topLevelTypes.appendChild(convert(type)); + } + + final String typeName = requireNonNull(typeToName.get(type)); + return createRefElement( + document, + toLowerFirstChar(typeName), + typeName + ); + } + } + + public Element convert(final SchemaDomain.TypeSchema type) + { + result = null; + type.accept(this); + return requireNonNull(result); + } + } +} From 439ee4baada8d36f451e4d8c0c10b68df2308370 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 5 Oct 2023 19:08:49 +0100 Subject: [PATCH 340/805] [Java] Fix typos. --- .../src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index e7842ea47c..981bcaa8db 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -89,7 +89,7 @@ public EncodedDataType(final Node node, final String givenName, final String ref if (presence() != CONSTANT) { - handleError(node, "present must be constant when valueRef is set: " + valueRef); + handleError(node, "presence must be constant when valueRef is set: " + valueRef); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java index db25c1a291..9590c3e756 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java @@ -94,7 +94,7 @@ public Type( * @param presence of the type. * @param description of the type or null. * @param sinceVersion for the type - * @param deprecated version in which this wa.s deprecated. + * @param deprecated version in which this was deprecated. * @param semanticType of the type or null. */ public Type( From b94ef12eb404bd77b90f19a9b8028ec8f271d1b2 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 6 Oct 2023 00:43:37 +0100 Subject: [PATCH 341/805] [Java] Move property tests to their own source set. Gradle 8 complains about deprecations when using the "old style" test source set creation. Therefore, I have had to use `jvm-test-suites`, which is the Gradle 9 way of doing things. I have moved the property tests into their own source set and own test task: `propertyTest`, as they may be more expensive to run than the other unit tests. We may only wish to run them nightly in CI. I have also profiled the `propertyTest` task and removed usage of JQwik list item duplication, as it dominates the time taken during testing. The time taken is now dominated by compiling XPaths. --- build.gradle | 79 ++++++++++++++----- .../sbe/properties/ParserPropertyTest.java | 2 +- .../sbe/properties/SchemaDomain.java | 64 +++++++++++++-- .../sbe/properties/XmlSchemaWriter.java | 25 +++--- .../resources/junit-platform.properties | 3 + 5 files changed, 135 insertions(+), 38 deletions(-) rename sbe-tool/src/{test => propertyTest}/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java (97%) rename sbe-tool/src/{test => propertyTest}/java/uk/co/real_logic/sbe/properties/SchemaDomain.java (81%) rename sbe-tool/src/{test => propertyTest}/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java (95%) create mode 100644 sbe-tool/src/propertyTest/resources/junit-platform.properties diff --git a/build.gradle b/build.gradle index c71515f561..191c4c156a 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,7 @@ buildscript { plugins { id 'java-library' + id 'jvm-test-suite' id 'com.github.johnrengelman.shadow' version '8.1.1' apply false id 'com.github.ben-manes.versions' version '0.51.0' } @@ -165,6 +166,7 @@ jar.enabled = false subprojects { apply plugin: 'java-library' + apply plugin: 'jvm-test-suite' apply plugin: 'checkstyle' group = sbeGroup @@ -217,22 +219,34 @@ subprojects { } } - test { - useJUnitPlatform() + testing { + suites { + test { + useJUnitJupiter junitVersion - testLogging { - for (def level : LogLevel.values()) - { - def testLogging = get(level) - testLogging.exceptionFormat = 'full' - testLogging.events = ["FAILED", "STANDARD_OUT", "STANDARD_ERROR"] - } - } + targets { + all { + testTask.configure { + useJUnitPlatform() - javaLauncher.set(toolchainLauncher) + testLogging { + for (def level : LogLevel.values()) + { + def testLogging = get(level) + testLogging.exceptionFormat = 'full' + testLogging.events = ["FAILED", "STANDARD_OUT", "STANDARD_ERROR"] + } + } + + javaLauncher.set(toolchainLauncher) - systemProperty 'sbe.enable.ir.precedence.checks', 'true' - systemProperty 'sbe.enable.test.precedence.checks', 'true' + systemProperty 'sbe.enable.ir.precedence.checks', 'true' + systemProperty 'sbe.enable.test.precedence.checks', 'true' + } + } + } + } + } } } @@ -249,12 +263,6 @@ project(':sbe-tool') { prefer(agronaVersion) } } - testImplementation files('build/classes/java/generated') - testImplementation "org.hamcrest:hamcrest:${hamcrestVersion}" - testImplementation "org.mockito:mockito-core:${mockitoVersion}" - testImplementation "net.jqwik:jqwik:${jqwikVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" } def generatedDir = 'build/generated-src' @@ -276,6 +284,39 @@ project(':sbe-tool') { compileTestJava.dependsOn compileGeneratedJava + testing { + suites { + test { + dependencies { + implementation files('build/classes/java/generated') + implementation "org.hamcrest:hamcrest:${hamcrestVersion}" + implementation "org.mockito:mockito-core:${mockitoVersion}" + implementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" + } + } + + propertyTest(JvmTestSuite) { + useJUnitJupiter junitVersion + + dependencies { + implementation project() + implementation "net.jqwik:jqwik:${jqwikVersion}" + } + + targets { + all { + testTask.configure { + minHeapSize = '2g' + maxHeapSize = '2g' + + javaLauncher.set(toolchainLauncher) + } + } + } + } + } + } + tasks.register('generateTestCodecs', JavaExec) { dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.SbeTool') diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java similarity index 97% rename from sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java rename to sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java index 7abb2b65ca..5781777274 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java @@ -28,7 +28,7 @@ import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -public class ParserPropertyTest +class ParserPropertyTest { @Property void shouldParseAnyValidSchema(@ForAll("schemas") final SchemaDomain.MessageSchema schema) throws Exception diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/SchemaDomain.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/SchemaDomain.java similarity index 81% rename from sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/SchemaDomain.java rename to sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/SchemaDomain.java index 1605d7d781..ab2d58db15 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/SchemaDomain.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/SchemaDomain.java @@ -19,13 +19,14 @@ import net.jqwik.api.Arbitraries; import net.jqwik.api.Arbitrary; import net.jqwik.api.Combinators; +import net.jqwik.api.arbitraries.ListArbitrary; import uk.co.real_logic.sbe.PrimitiveType; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -public final class SchemaDomain +final class SchemaDomain { private static final int MAX_COMPOSITE_DEPTH = 3; private static final int MAX_GROUP_DEPTH = 3; @@ -34,6 +35,57 @@ private SchemaDomain() { } + /** + * This combinator adds duplicates to an arbitrary list. We prefer this to JQwik's built-in functionality, + * as that is inefficient and dominates test runs. + *

    + * This method works by generating a list of integers, which represent, in an alternating manner, + * the number of items to skip before selecting an item to duplicate + * and the number of items to skip before inserting the duplicate. + * + * @param maxDuplicates the maximum number of duplicates to add + * @param arbitrary the arbitrary list to duplicate items in + * @param the type of the list + * @return an arbitrary list with duplicates + */ + private static Arbitrary> withDuplicates( + final int maxDuplicates, + final ListArbitrary arbitrary) + { + return Combinators.combine( + Arbitraries.integers().list().ofMaxSize(2 * maxDuplicates), + arbitrary + ).as((positions, originalItems) -> + { + if (originalItems.isEmpty()) + { + return originalItems; + } + + final List items = new ArrayList<>(originalItems); + T itemToDupe = null; + int j = 0; + + for (final int position : positions) + { + j += position; + j %= items.size(); + j = Math.abs(j); + if (itemToDupe == null) + { + itemToDupe = items.get(j); + } + else + { + items.add(j, itemToDupe); + itemToDupe = null; + } + } + + return items; + }); + } + static final class EncodedDataTypeSchema implements TypeSchema { private final PrimitiveType primitiveType; @@ -90,11 +142,7 @@ public List fields() static Arbitrary arbitrary(final int depth) { - return TypeSchema.arbitrary(depth - 1) - .list() - .ofMinSize(1) - .ofMaxSize(3) - .injectDuplicates(0.2) + return withDuplicates(2, TypeSchema.arbitrary(depth - 1).list().ofMinSize(1).ofMaxSize(3)) .map(CompositeTypeSchema::new); } @@ -309,7 +357,7 @@ static Arbitrary arbitrary(final int depth) arbitrary(depth - 1).list().ofMaxSize(3); return Combinators.combine( - TypeSchema.arbitrary(MAX_COMPOSITE_DEPTH).list().ofMaxSize(5), + withDuplicates(2, TypeSchema.arbitrary(MAX_COMPOSITE_DEPTH).list().ofMaxSize(5)), subGroups, VarDataSchema.arbitrary().list().ofMaxSize(3) ).as(GroupSchema::new); @@ -351,7 +399,7 @@ public List varData() static Arbitrary arbitrary() { return Combinators.combine( - TypeSchema.arbitrary(MAX_COMPOSITE_DEPTH).list().ofMaxSize(10), + withDuplicates(3, TypeSchema.arbitrary(MAX_COMPOSITE_DEPTH).list().ofMaxSize(10)), GroupSchema.arbitrary(MAX_GROUP_DEPTH).list().ofMaxSize(3), VarDataSchema.arbitrary().list().ofMaxSize(3) ).as(MessageSchema::new); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java similarity index 95% rename from sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java rename to sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java index 84ff1b2881..2572bb69ca 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java @@ -22,9 +22,7 @@ import java.io.File; import java.io.StringWriter; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Function; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -35,7 +33,6 @@ import javax.xml.transform.stream.StreamResult; import static java.util.Objects.requireNonNull; -import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; final class XmlSchemaWriter { @@ -83,7 +80,9 @@ private static void writeTo( typeToName ); + final Set visitedTypes = new HashSet<>(); appendTypes( + visitedTypes, topLevelTypes, typeSchemaConverter, schema.blockFields(), @@ -93,7 +92,7 @@ private static void writeTo( message.setAttribute("name", "TestMessage"); message.setAttribute("id", "1"); root.appendChild(message); - final MutableInteger nextMemberId = new MutableInteger(1); + final MutableInteger nextMemberId = new MutableInteger(0); appendMembers( document, typeToName, @@ -319,6 +318,7 @@ private static Element createRefElement( } private static void appendTypes( + final Set visitedTypes, final Element topLevelTypes, final TypeSchemaConverter typeSchemaConverter, final List blockFields, @@ -326,7 +326,7 @@ private static void appendTypes( { for (final SchemaDomain.TypeSchema field : blockFields) { - if (!field.isEmbedded()) + if (!field.isEmbedded() && visitedTypes.add(field)) { topLevelTypes.appendChild(typeSchemaConverter.convert(field)); } @@ -334,7 +334,7 @@ private static void appendTypes( for (final SchemaDomain.GroupSchema group : groups) { - appendTypes(topLevelTypes, typeSchemaConverter, group.blockFields(), group.groups()); + appendTypes(visitedTypes, topLevelTypes, typeSchemaConverter, group.blockFields(), group.groups()); } } @@ -370,13 +370,18 @@ public void onEncoded(final SchemaDomain.EncodedDataTypeSchema type) @Override public void onComposite(final SchemaDomain.CompositeTypeSchema type) { - final Element[] parts = type.fields().stream() + final Element[] members = type.fields().stream() .map(this::embedOrReference) .toArray(Element[]::new); + for (int i = 0; i < members.length; i++) + { + final Element member = members[i]; + member.setAttribute("name", "member" + i + "Of" + member.getAttribute("name")); + } result = createCompositeElement( document, typeToName.computeIfAbsent(type, nextName), - parts + members ); } @@ -419,7 +424,7 @@ private Element embedOrReference(final SchemaDomain.TypeSchema type) final String typeName = requireNonNull(typeToName.get(type)); return createRefElement( document, - toLowerFirstChar(typeName), + typeName, typeName ); } diff --git a/sbe-tool/src/propertyTest/resources/junit-platform.properties b/sbe-tool/src/propertyTest/resources/junit-platform.properties new file mode 100644 index 0000000000..8a3fb086c1 --- /dev/null +++ b/sbe-tool/src/propertyTest/resources/junit-platform.properties @@ -0,0 +1,3 @@ +jqwik.edgecases.default=MIXIN +jqwik.tries.default=5000 +jqwik.failures.runfirst=true \ No newline at end of file From ea7e84bacb42a4de44087ec78bb359b628a40be2 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 6 Oct 2023 09:24:01 +0100 Subject: [PATCH 342/805] [Java] Suppress javadoc warnings in propertyTest source set. --- config/checkstyle/suppressions.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 84e7e82814..2823a9547e 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -6,5 +6,6 @@ + From 526eac24d96245e4d4ca64b21e3aa9e9368d248e Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 6 Oct 2023 09:24:32 +0100 Subject: [PATCH 343/805] [Java] Split apart schema generation files. I think separate files improves the readability of the arbitrary message schema generation. --- .../sbe/properties/ParserPropertyTest.java | 9 +- .../sbe/properties/SchemaDomain.java | 408 ------------------ .../arbitraries/SbeArbitraries.java | 189 ++++++++ .../schema/CompositeTypeSchema.java | 40 ++ .../schema/EncodedDataTypeSchema.java | 52 +++ .../sbe/properties/schema/EnumTypeSchema.java | 49 +++ .../sbe/properties/schema/GroupSchema.java | 52 +++ .../sbe/properties/schema/MessageSchema.java | 52 +++ .../sbe/properties/schema/SetSchema.java | 48 +++ .../sbe/properties/schema/TypeSchema.java | 27 ++ .../properties/schema/TypeSchemaVisitor.java | 28 ++ .../sbe/properties/schema/VarDataSchema.java | 38 ++ .../{ => schema}/XmlSchemaWriter.java | 62 +-- 13 files changed, 612 insertions(+), 442 deletions(-) delete mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/SchemaDomain.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java rename sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/{ => schema}/XmlSchemaWriter.java (86%) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java index 5781777274..9f0517c5b8 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java @@ -20,6 +20,9 @@ import net.jqwik.api.ForAll; import net.jqwik.api.Property; import net.jqwik.api.Provide; +import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; +import uk.co.real_logic.sbe.properties.schema.MessageSchema; +import uk.co.real_logic.sbe.properties.schema.XmlSchemaWriter; import uk.co.real_logic.sbe.xml.ParserOptions; import java.io.ByteArrayInputStream; @@ -31,7 +34,7 @@ class ParserPropertyTest { @Property - void shouldParseAnyValidSchema(@ForAll("schemas") final SchemaDomain.MessageSchema schema) throws Exception + void shouldParseAnyValidSchema(@ForAll("schemas") final MessageSchema schema) throws Exception { final String xml = XmlSchemaWriter.writeString(schema); try (InputStream in = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) @@ -41,8 +44,8 @@ void shouldParseAnyValidSchema(@ForAll("schemas") final SchemaDomain.MessageSche } @Provide - Arbitrary schemas() + Arbitrary schemas() { - return SchemaDomain.MessageSchema.arbitrary(); + return SbeArbitraries.message(); } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/SchemaDomain.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/SchemaDomain.java deleted file mode 100644 index ab2d58db15..0000000000 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/SchemaDomain.java +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright 2013-2023 Real Logic Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.co.real_logic.sbe.properties; - -import net.jqwik.api.Arbitraries; -import net.jqwik.api.Arbitrary; -import net.jqwik.api.Combinators; -import net.jqwik.api.arbitraries.ListArbitrary; -import uk.co.real_logic.sbe.PrimitiveType; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -final class SchemaDomain -{ - private static final int MAX_COMPOSITE_DEPTH = 3; - private static final int MAX_GROUP_DEPTH = 3; - - private SchemaDomain() - { - } - - /** - * This combinator adds duplicates to an arbitrary list. We prefer this to JQwik's built-in functionality, - * as that is inefficient and dominates test runs. - *

    - * This method works by generating a list of integers, which represent, in an alternating manner, - * the number of items to skip before selecting an item to duplicate - * and the number of items to skip before inserting the duplicate. - * - * @param maxDuplicates the maximum number of duplicates to add - * @param arbitrary the arbitrary list to duplicate items in - * @param the type of the list - * @return an arbitrary list with duplicates - */ - private static Arbitrary> withDuplicates( - final int maxDuplicates, - final ListArbitrary arbitrary) - { - return Combinators.combine( - Arbitraries.integers().list().ofMaxSize(2 * maxDuplicates), - arbitrary - ).as((positions, originalItems) -> - { - if (originalItems.isEmpty()) - { - return originalItems; - } - - final List items = new ArrayList<>(originalItems); - T itemToDupe = null; - int j = 0; - - for (final int position : positions) - { - j += position; - j %= items.size(); - j = Math.abs(j); - if (itemToDupe == null) - { - itemToDupe = items.get(j); - } - else - { - items.add(j, itemToDupe); - itemToDupe = null; - } - } - - return items; - }); - } - - static final class EncodedDataTypeSchema implements TypeSchema - { - private final PrimitiveType primitiveType; - private final boolean isEmbedded; - - private EncodedDataTypeSchema( - final PrimitiveType primitiveType, - final boolean isEmbedded - ) - { - this.primitiveType = primitiveType; - this.isEmbedded = isEmbedded; - } - - public PrimitiveType primitiveType() - { - return primitiveType; - } - - @Override - public boolean isEmbedded() - { - return isEmbedded; - } - - @Override - public void accept(final TypeSchemaVisitor visitor) - { - visitor.onEncoded(this); - } - - static Arbitrary arbitrary() - { - return Combinators.combine( - Arbitraries.of(PrimitiveType.values()), - Arbitraries.of(true, false) - ).as(EncodedDataTypeSchema::new); - } - } - - static final class CompositeTypeSchema implements TypeSchema - { - private final List fields; - - private CompositeTypeSchema(final List fields) - { - this.fields = fields; - } - - public List fields() - { - return fields; - } - - static Arbitrary arbitrary(final int depth) - { - return withDuplicates(2, TypeSchema.arbitrary(depth - 1).list().ofMinSize(1).ofMaxSize(3)) - .map(CompositeTypeSchema::new); - } - - @Override - public void accept(final TypeSchemaVisitor visitor) - { - visitor.onComposite(this); - } - } - - static final class EnumTypeSchema implements TypeSchema - { - private final String encodingType; - private final List validValues; - - private EnumTypeSchema( - final String encodingType, - final List validValues) - { - this.encodingType = encodingType; - this.validValues = validValues; - } - - public String encodingType() - { - return encodingType; - } - - public List validValues() - { - return validValues; - } - - static Arbitrary arbitrary() - { - return Arbitraries.oneOf( - Arbitraries.chars().alpha() - .map(Character::toUpperCase) - .list() - .ofMaxSize(10) - .uniqueElements() - .map(values -> new EnumTypeSchema( - "char", - values.stream().map(String::valueOf).collect(Collectors.toList()) - )), - Arbitraries.integers() - .between(1, 254) - .list() - .ofMaxSize(254) - .uniqueElements() - .map(values -> new EnumTypeSchema( - "uint8", - values.stream().map(String::valueOf).collect(Collectors.toList()) - )) - ); - } - - @Override - public void accept(final TypeSchemaVisitor visitor) - { - visitor.onEnum(this); - } - } - - static final class SetSchema implements TypeSchema - { - private final String encodingType; - private final int choiceCount; - - private SetSchema( - final String encodingType, - final int choiceCount) - { - this.choiceCount = choiceCount; - this.encodingType = encodingType; - } - - public String encodingType() - { - return encodingType; - } - - public int choiceCount() - { - return choiceCount; - } - - @Override - public void accept(final TypeSchemaVisitor visitor) - { - visitor.onSet(this); - } - - static Arbitrary arbitrary() - { - return Combinators.combine( - Arbitraries.of( - "uint8", - "uint16", - "uint32", - "uint64" - ), - Arbitraries.integers().between(1, 4) - ).as(SetSchema::new); - } - } - - interface TypeSchema - { - static Arbitrary arbitrary(final int depth) - { - if (depth == 1) - { - return Arbitraries.oneOf( - EncodedDataTypeSchema.arbitrary(), - EnumTypeSchema.arbitrary(), - SetSchema.arbitrary() - ); - } - else - { - return Arbitraries.oneOf( - CompositeTypeSchema.arbitrary(depth), - EncodedDataTypeSchema.arbitrary(), - EnumTypeSchema.arbitrary(), - SetSchema.arbitrary() - ); - } - } - - default boolean isEmbedded() - { - return false; - } - - void accept(TypeSchemaVisitor visitor); - } - - interface TypeSchemaVisitor - { - void onEncoded(EncodedDataTypeSchema type); - - void onComposite(CompositeTypeSchema type); - - void onEnum(EnumTypeSchema type); - - void onSet(SetSchema type); - } - - static final class VarDataSchema - { - private final Encoding encoding; - - VarDataSchema(final Encoding encoding) - { - this.encoding = encoding; - } - - public Encoding encoding() - { - return encoding; - } - - static Arbitrary arbitrary() - { - return Arbitraries.of(Encoding.values()) - .map(VarDataSchema::new); - } - - enum Encoding - { - ASCII, - BYTES - } - } - - static final class GroupSchema - { - private final List blockFields; - private final List groups; - private final List varData; - - GroupSchema( - final List blockFields, - final List groups, - final List varData) - { - this.blockFields = blockFields; - this.groups = groups; - this.varData = varData; - } - - public List blockFields() - { - return blockFields; - } - - public List groups() - { - return groups; - } - - public List varData() - { - return varData; - } - - static Arbitrary arbitrary(final int depth) - { - final Arbitrary> subGroups = depth == 1 ? - Arbitraries.of(0).map(ignored -> new ArrayList<>()) : - arbitrary(depth - 1).list().ofMaxSize(3); - - return Combinators.combine( - withDuplicates(2, TypeSchema.arbitrary(MAX_COMPOSITE_DEPTH).list().ofMaxSize(5)), - subGroups, - VarDataSchema.arbitrary().list().ofMaxSize(3) - ).as(GroupSchema::new); - } - } - - static final class MessageSchema - { - private final List blockFields; - private final List groups; - private final List varData; - - MessageSchema( - final List blockFields, - final List groups, - final List varData - ) - { - this.blockFields = blockFields; - this.groups = groups; - this.varData = varData; - } - - public List blockFields() - { - return blockFields; - } - - public List groups() - { - return groups; - } - - public List varData() - { - return varData; - } - - static Arbitrary arbitrary() - { - return Combinators.combine( - withDuplicates(3, TypeSchema.arbitrary(MAX_COMPOSITE_DEPTH).list().ofMaxSize(10)), - GroupSchema.arbitrary(MAX_GROUP_DEPTH).list().ofMaxSize(3), - VarDataSchema.arbitrary().list().ofMaxSize(3) - ).as(MessageSchema::new); - } - } -} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java new file mode 100644 index 0000000000..a892a27a57 --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -0,0 +1,189 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.arbitraries; + +import net.jqwik.api.Arbitraries; +import net.jqwik.api.Arbitrary; +import net.jqwik.api.Combinators; +import net.jqwik.api.arbitraries.ListArbitrary; +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.properties.schema.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public final class SbeArbitraries +{ + private static final int MAX_COMPOSITE_DEPTH = 3; + private static final int MAX_GROUP_DEPTH = 3; + + private SbeArbitraries() + { + } + + /** + * This combinator adds duplicates to an arbitrary list. We prefer this to JQwik's built-in functionality, + * as that is inefficient and dominates test runs. + *

    + * This method works by generating a list of integers, which represent, in an alternating manner, + * the number of items to skip before selecting an item to duplicate + * and the number of items to skip before inserting the duplicate. + * + * @param maxDuplicates the maximum number of duplicates to add + * @param arbitrary the arbitrary list to duplicate items in + * @param the type of the list + * @return an arbitrary list with duplicates + */ + private static Arbitrary> withDuplicates( + final int maxDuplicates, + final ListArbitrary arbitrary) + { + return Combinators.combine( + Arbitraries.integers().list().ofMaxSize(2 * maxDuplicates), + arbitrary + ).as((positions, originalItems) -> + { + if (originalItems.isEmpty()) + { + return originalItems; + } + + final List items = new ArrayList<>(originalItems); + T itemToDupe = null; + int j = 0; + + for (final int position : positions) + { + j += position; + j %= items.size(); + j = Math.abs(j); + if (itemToDupe == null) + { + itemToDupe = items.get(j); + } + else + { + items.add(j, itemToDupe); + itemToDupe = null; + } + } + + return items; + }); + } + + private static Arbitrary encodedDataType() + { + return Combinators.combine( + Arbitraries.of(PrimitiveType.values()), + Arbitraries.of(true, false) + ).as(EncodedDataTypeSchema::new); + } + + private static Arbitrary enumType() + { + return Arbitraries.oneOf( + Arbitraries.chars().alpha() + .map(Character::toUpperCase) + .list() + .ofMaxSize(10) + .uniqueElements() + .map(values -> new EnumTypeSchema( + "char", + values.stream().map(String::valueOf).collect(Collectors.toList()) + )), + Arbitraries.integers() + .between(1, 254) + .list() + .ofMaxSize(254) + .uniqueElements() + .map(values -> new EnumTypeSchema( + "uint8", + values.stream().map(String::valueOf).collect(Collectors.toList()) + )) + ); + } + + private static Arbitrary setType() + { + return Combinators.combine( + Arbitraries.of( + "uint8", + "uint16", + "uint32", + "uint64" + ), + Arbitraries.integers().between(1, 4) + ).as(SetSchema::new); + } + + private static Arbitrary compositeType(final int depth) + { + return withDuplicates(2, type(depth - 1).list().ofMinSize(1).ofMaxSize(3)) + .map(CompositeTypeSchema::new); + } + + private static Arbitrary type(final int depth) + { + if (depth == 1) + { + return Arbitraries.oneOf( + encodedDataType(), + enumType(), + setType() + ); + } + else + { + return Arbitraries.oneOf( + compositeType(depth), + encodedDataType(), + enumType(), + setType() + ); + } + } + + private static Arbitrary group(final int depth) + { + final Arbitrary> subGroups = depth == 1 ? + Arbitraries.of(0).map(ignored -> new ArrayList<>()) : + group(depth - 1).list().ofMaxSize(3); + + return Combinators.combine( + withDuplicates(2, type(MAX_COMPOSITE_DEPTH).list().ofMaxSize(5)), + subGroups, + varData().list().ofMaxSize(3) + ).as(GroupSchema::new); + } + + private static Arbitrary varData() + { + return Arbitraries.of(VarDataSchema.Encoding.values()) + .map(VarDataSchema::new); + } + + public static Arbitrary message() + { + return Combinators.combine( + withDuplicates(3, type(MAX_COMPOSITE_DEPTH).list().ofMaxSize(10)), + group(MAX_GROUP_DEPTH).list().ofMaxSize(3), + varData().list().ofMaxSize(3) + ).as(MessageSchema::new); + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java new file mode 100644 index 0000000000..a6df53d778 --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +import java.util.List; + +public final class CompositeTypeSchema implements TypeSchema +{ + private final List fields; + + public CompositeTypeSchema(final List fields) + { + this.fields = fields; + } + + public List fields() + { + return fields; + } + + @Override + public void accept(final TypeSchemaVisitor visitor) + { + visitor.onComposite(this); + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java new file mode 100644 index 0000000000..b5fe76941d --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +import uk.co.real_logic.sbe.PrimitiveType; + +public final class EncodedDataTypeSchema implements TypeSchema +{ + private final PrimitiveType primitiveType; + private final boolean isEmbedded; + + public EncodedDataTypeSchema( + final PrimitiveType primitiveType, + final boolean isEmbedded + ) + { + this.primitiveType = primitiveType; + this.isEmbedded = isEmbedded; + } + + public PrimitiveType primitiveType() + { + return primitiveType; + } + + @Override + public boolean isEmbedded() + { + return isEmbedded; + } + + @Override + public void accept(final TypeSchemaVisitor visitor) + { + visitor.onEncoded(this); + } + +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java new file mode 100644 index 0000000000..fa669fe04a --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java @@ -0,0 +1,49 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +import java.util.List; + +public final class EnumTypeSchema implements TypeSchema +{ + private final String encodingType; + private final List validValues; + + public EnumTypeSchema( + final String encodingType, + final List validValues) + { + this.encodingType = encodingType; + this.validValues = validValues; + } + + public String encodingType() + { + return encodingType; + } + + public List validValues() + { + return validValues; + } + + @Override + public void accept(final TypeSchemaVisitor visitor) + { + visitor.onEnum(this); + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java new file mode 100644 index 0000000000..df34e0a9b6 --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +import java.util.List; + +public final class GroupSchema +{ + private final List blockFields; + private final List groups; + private final List varData; + + public GroupSchema( + final List blockFields, + final List groups, + final List varData) + { + this.blockFields = blockFields; + this.groups = groups; + this.varData = varData; + } + + public List blockFields() + { + return blockFields; + } + + public List groups() + { + return groups; + } + + public List varData() + { + return varData; + } + +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java new file mode 100644 index 0000000000..c275defe3d --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java @@ -0,0 +1,52 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +import java.util.List; + +public final class MessageSchema +{ + private final List blockFields; + private final List groups; + private final List varData; + + public MessageSchema( + final List blockFields, + final List groups, + final List varData + ) + { + this.blockFields = blockFields; + this.groups = groups; + this.varData = varData; + } + + public List blockFields() + { + return blockFields; + } + + public List groups() + { + return groups; + } + + public List varData() + { + return varData; + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java new file mode 100644 index 0000000000..95874e8381 --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java @@ -0,0 +1,48 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +public final class SetSchema implements TypeSchema +{ + private final String encodingType; + private final int choiceCount; + + public SetSchema( + final String encodingType, + final int choiceCount) + { + this.choiceCount = choiceCount; + this.encodingType = encodingType; + } + + public String encodingType() + { + return encodingType; + } + + public int choiceCount() + { + return choiceCount; + } + + @Override + public void accept(final TypeSchemaVisitor visitor) + { + visitor.onSet(this); + } + +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java new file mode 100644 index 0000000000..311521e697 --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java @@ -0,0 +1,27 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +public interface TypeSchema +{ + default boolean isEmbedded() + { + return false; + } + + void accept(TypeSchemaVisitor visitor); +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java new file mode 100644 index 0000000000..830a2e1cf7 --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java @@ -0,0 +1,28 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +public interface TypeSchemaVisitor +{ + void onEncoded(EncodedDataTypeSchema type); + + void onComposite(CompositeTypeSchema type); + + void onEnum(EnumTypeSchema type); + + void onSet(SetSchema type); +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java new file mode 100644 index 0000000000..c6b39db56b --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +public final class VarDataSchema +{ + private final Encoding encoding; + + public VarDataSchema(final Encoding encoding) + { + this.encoding = encoding; + } + + public Encoding encoding() + { + return encoding; + } + + public enum Encoding + { + ASCII, + BYTES + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/XmlSchemaWriter.java similarity index 86% rename from sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java rename to sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/XmlSchemaWriter.java index 2572bb69ca..63a10903ca 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/XmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/XmlSchemaWriter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package uk.co.real_logic.sbe.properties; +package uk.co.real_logic.sbe.properties.schema; import org.agrona.collections.MutableInteger; import org.w3c.dom.Document; @@ -34,13 +34,13 @@ import static java.util.Objects.requireNonNull; -final class XmlSchemaWriter +public final class XmlSchemaWriter { private XmlSchemaWriter() { } - public static String writeString(final SchemaDomain.MessageSchema schema) + public static String writeString(final MessageSchema schema) { final StringWriter writer = new StringWriter(); final StreamResult result = new StreamResult(writer); @@ -49,7 +49,7 @@ public static String writeString(final SchemaDomain.MessageSchema schema) } public static void writeFile( - final SchemaDomain.MessageSchema schema, + final MessageSchema schema, final File destination) { final StreamResult result = new StreamResult(destination); @@ -57,7 +57,7 @@ public static void writeFile( } private static void writeTo( - final SchemaDomain.MessageSchema schema, + final MessageSchema schema, final StreamResult destination) { try @@ -72,7 +72,7 @@ private static void writeTo( final Element topLevelTypes = createTypesElement(document); root.appendChild(topLevelTypes); - final HashMap typeToName = new HashMap<>(); + final HashMap typeToName = new HashMap<>(); final TypeSchemaConverter typeSchemaConverter = new TypeSchemaConverter( document, @@ -80,7 +80,7 @@ private static void writeTo( typeToName ); - final Set visitedTypes = new HashSet<>(); + final Set visitedTypes = new HashSet<>(); appendTypes( visitedTypes, topLevelTypes, @@ -127,20 +127,20 @@ private static void writeTo( private static void appendMembers( final Document document, - final HashMap typeToName, - final List blockFields, - final List groups, - final List varData, + final HashMap typeToName, + final List blockFields, + final List groups, + final List varData, final MutableInteger nextMemberId, final Element parent) { - for (final SchemaDomain.TypeSchema field : blockFields) + for (final TypeSchema field : blockFields) { final int id = nextMemberId.getAndIncrement(); - final boolean usePrimitiveName = field.isEmbedded() && field instanceof SchemaDomain.EncodedDataTypeSchema; + final boolean usePrimitiveName = field.isEmbedded() && field instanceof EncodedDataTypeSchema; final String typeName = usePrimitiveName ? - ((SchemaDomain.EncodedDataTypeSchema)field).primitiveType().primitiveName() : + ((EncodedDataTypeSchema)field).primitiveType().primitiveName() : requireNonNull(typeToName.get(field)); final Element element = document.createElement("field"); @@ -150,7 +150,7 @@ private static void appendMembers( parent.appendChild(element); } - for (final SchemaDomain.GroupSchema group : groups) + for (final GroupSchema group : groups) { final int id = nextMemberId.getAndIncrement(); @@ -168,7 +168,7 @@ private static void appendMembers( parent.appendChild(element); } - for (final SchemaDomain.VarDataSchema data : varData) + for (final VarDataSchema data : varData) { final int id = nextMemberId.getAndIncrement(); @@ -318,13 +318,13 @@ private static Element createRefElement( } private static void appendTypes( - final Set visitedTypes, + final Set visitedTypes, final Element topLevelTypes, final TypeSchemaConverter typeSchemaConverter, - final List blockFields, - final List groups) + final List blockFields, + final List groups) { - for (final SchemaDomain.TypeSchema field : blockFields) + for (final TypeSchema field : blockFields) { if (!field.isEmbedded() && visitedTypes.add(field)) { @@ -332,24 +332,24 @@ private static void appendTypes( } } - for (final SchemaDomain.GroupSchema group : groups) + for (final GroupSchema group : groups) { appendTypes(visitedTypes, topLevelTypes, typeSchemaConverter, group.blockFields(), group.groups()); } } - private static final class TypeSchemaConverter implements SchemaDomain.TypeSchemaVisitor + private static final class TypeSchemaConverter implements TypeSchemaVisitor { private final Document document; private final Element topLevelTypes; - private final Map typeToName; - private final Function nextName; + private final Map typeToName; + private final Function nextName; private Element result; private TypeSchemaConverter( final Document document, final Element topLevelTypes, - final Map typeToName) + final Map typeToName) { this.document = document; this.topLevelTypes = topLevelTypes; @@ -358,7 +358,7 @@ private TypeSchemaConverter( } @Override - public void onEncoded(final SchemaDomain.EncodedDataTypeSchema type) + public void onEncoded(final EncodedDataTypeSchema type) { result = createTypeElement( document, @@ -368,7 +368,7 @@ public void onEncoded(final SchemaDomain.EncodedDataTypeSchema type) } @Override - public void onComposite(final SchemaDomain.CompositeTypeSchema type) + public void onComposite(final CompositeTypeSchema type) { final Element[] members = type.fields().stream() .map(this::embedOrReference) @@ -386,7 +386,7 @@ public void onComposite(final SchemaDomain.CompositeTypeSchema type) } @Override - public void onEnum(final SchemaDomain.EnumTypeSchema type) + public void onEnum(final EnumTypeSchema type) { result = createEnumElement( document, @@ -397,7 +397,7 @@ public void onEnum(final SchemaDomain.EnumTypeSchema type) } @Override - public void onSet(final SchemaDomain.SetSchema type) + public void onSet(final SetSchema type) { result = createSetElement( document, @@ -407,7 +407,7 @@ public void onSet(final SchemaDomain.SetSchema type) ); } - private Element embedOrReference(final SchemaDomain.TypeSchema type) + private Element embedOrReference(final TypeSchema type) { if (type.isEmbedded()) { @@ -430,7 +430,7 @@ private Element embedOrReference(final SchemaDomain.TypeSchema type) } } - public Element convert(final SchemaDomain.TypeSchema type) + public Element convert(final TypeSchema type) { result = null; type.accept(this); From 0a2a6e43e0cdfbc60f47ff9c078cfe74148dbd2d Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Sat, 7 Oct 2023 00:06:46 +0100 Subject: [PATCH 344/805] [Java] Extend PBT to generate arbitrary encoded messages. In this commit, I've also demonstrated the usage of arbitrary encoded messages in a JsonPrinter test. In the test, I print an arbitrary value of an arbitrary schema and check that it is valid JSON. The test passes as long as we constrain the generation of strings, as JsonPrinter currently does not do any escaping. I also noted that it uses `'` rather than `"`, which AFAICS is not permitted by the JSON specification, but is permitted by our (less strict) JSON testing tool. --- build.gradle | 2 + .../sbe/properties/JsonPropertyTest.java | 56 ++ .../sbe/properties/ParserPropertyTest.java | 6 +- .../arbitraries/SbeArbitraries.java | 622 +++++++++++++++++- .../sbe/properties/schema/MessageSchema.java | 10 + ...maWriter.java => TestXmlSchemaWriter.java} | 8 +- .../resources/junit-platform.properties | 5 +- 7 files changed, 678 insertions(+), 31 deletions(-) create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java rename sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/{XmlSchemaWriter.java => TestXmlSchemaWriter.java} (98%) diff --git a/build.gradle b/build.gradle index 191c4c156a..2ccfad6010 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.2' def jqwikVersion = '1.8.0' +def jsonVersion = '20230618' def jmhVersion = '1.37' def agronaVersion = '1.21.2' def agronaVersionRange = '[1.21.2,2.0[' // allow any release >= 1.21.2 and < 2.0.0 @@ -301,6 +302,7 @@ project(':sbe-tool') { dependencies { implementation project() implementation "net.jqwik:jqwik:${jqwikVersion}" + implementation "org.json:json:${jsonVersion}" } targets { diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java new file mode 100644 index 0000000000..ab5c8d955e --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties; + +import net.jqwik.api.Arbitrary; +import net.jqwik.api.ForAll; +import net.jqwik.api.Property; +import net.jqwik.api.Provide; +import uk.co.real_logic.sbe.json.JsonPrinter; +import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; +import org.agrona.concurrent.UnsafeBuffer; +import org.json.JSONException; +import org.json.JSONObject; + +public class JsonPropertyTest +{ + @Property + void shouldGenerateValidJson( + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage + ) + { + final StringBuilder output = new StringBuilder(); + final JsonPrinter printer = new JsonPrinter(encodedMessage.ir()); + printer.print(output, new UnsafeBuffer(encodedMessage.buffer()), 0); + try + { + new JSONObject(output.toString()); + } + catch (final JSONException e) + { + throw new AssertionError("Invalid JSON: " + output + "\n\nSchema:\n" + encodedMessage.schema(), e); + } + } + + @Provide + Arbitrary encodedMessage() + { + final SbeArbitraries.CharGenerationMode mode = + SbeArbitraries.CharGenerationMode.JSON_PRINTER_COMPATIBLE; + return SbeArbitraries.encodedMessage(mode); + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java index 9f0517c5b8..b6ce84ef3a 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java @@ -22,7 +22,7 @@ import net.jqwik.api.Provide; import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; import uk.co.real_logic.sbe.properties.schema.MessageSchema; -import uk.co.real_logic.sbe.properties.schema.XmlSchemaWriter; +import uk.co.real_logic.sbe.properties.schema.TestXmlSchemaWriter; import uk.co.real_logic.sbe.xml.ParserOptions; import java.io.ByteArrayInputStream; @@ -36,7 +36,7 @@ class ParserPropertyTest @Property void shouldParseAnyValidSchema(@ForAll("schemas") final MessageSchema schema) throws Exception { - final String xml = XmlSchemaWriter.writeString(schema); + final String xml = TestXmlSchemaWriter.writeString(schema); try (InputStream in = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { parse(in, ParserOptions.DEFAULT); @@ -46,6 +46,6 @@ void shouldParseAnyValidSchema(@ForAll("schemas") final MessageSchema schema) th @Provide Arbitrary schemas() { - return SbeArbitraries.message(); + return SbeArbitraries.messageSchema(); } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index a892a27a57..eb6ef0603f 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -19,18 +19,38 @@ import net.jqwik.api.Arbitraries; import net.jqwik.api.Arbitrary; import net.jqwik.api.Combinators; +import net.jqwik.api.arbitraries.CharacterArbitrary; import net.jqwik.api.arbitraries.ListArbitrary; import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.PrimitiveValue; +import uk.co.real_logic.sbe.ir.Encoding; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.Token; import uk.co.real_logic.sbe.properties.schema.*; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.ParserOptions; +import org.agrona.BitUtil; +import org.agrona.ExpandableArrayBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.collections.MutableInteger; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.stream.Collectors; +import static uk.co.real_logic.sbe.ir.Signal.*; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +@SuppressWarnings("EnhancedSwitchMigration") public final class SbeArbitraries { private static final int MAX_COMPOSITE_DEPTH = 3; private static final int MAX_GROUP_DEPTH = 3; + public static final int NULL_VALUE = Integer.MIN_VALUE; private SbeArbitraries() { @@ -87,7 +107,7 @@ private static Arbitrary> withDuplicates( }); } - private static Arbitrary encodedDataType() + private static Arbitrary encodedDataTypeSchema() { return Combinators.combine( Arbitraries.of(PrimitiveType.values()), @@ -95,7 +115,13 @@ private static Arbitrary encodedDataType() ).as(EncodedDataTypeSchema::new); } - private static Arbitrary enumType() + public enum CharGenerationMode + { + UNRESTRICTED, + JSON_PRINTER_COMPATIBLE + } + + private static Arbitrary enumTypeSchema() { return Arbitraries.oneOf( Arbitraries.chars().alpha() @@ -119,7 +145,7 @@ private static Arbitrary enumType() ); } - private static Arbitrary setType() + private static Arbitrary setTypeSchema() { return Combinators.combine( Arbitraries.of( @@ -132,58 +158,610 @@ private static Arbitrary setType() ).as(SetSchema::new); } - private static Arbitrary compositeType(final int depth) + private static Arbitrary compositeTypeSchema(final int depth) { - return withDuplicates(2, type(depth - 1).list().ofMinSize(1).ofMaxSize(3)) + return withDuplicates(2, typeSchema(depth - 1).list().ofMinSize(1).ofMaxSize(3)) .map(CompositeTypeSchema::new); } - private static Arbitrary type(final int depth) + private static Arbitrary typeSchema(final int depth) { if (depth == 1) { return Arbitraries.oneOf( - encodedDataType(), - enumType(), - setType() + encodedDataTypeSchema(), + enumTypeSchema(), + setTypeSchema() ); } else { return Arbitraries.oneOf( - compositeType(depth), - encodedDataType(), - enumType(), - setType() + compositeTypeSchema(depth), + encodedDataTypeSchema(), + enumTypeSchema(), + setTypeSchema() ); } } - private static Arbitrary group(final int depth) + private static Arbitrary groupSchema(final int depth) { final Arbitrary> subGroups = depth == 1 ? Arbitraries.of(0).map(ignored -> new ArrayList<>()) : - group(depth - 1).list().ofMaxSize(3); + groupSchema(depth - 1).list().ofMaxSize(3); return Combinators.combine( - withDuplicates(2, type(MAX_COMPOSITE_DEPTH).list().ofMaxSize(5)), + withDuplicates(2, typeSchema(MAX_COMPOSITE_DEPTH).list().ofMaxSize(5)), subGroups, - varData().list().ofMaxSize(3) + varDataSchema().list().ofMaxSize(3) ).as(GroupSchema::new); } - private static Arbitrary varData() + private static Arbitrary varDataSchema() { return Arbitraries.of(VarDataSchema.Encoding.values()) .map(VarDataSchema::new); } - public static Arbitrary message() + public static Arbitrary messageSchema() { return Combinators.combine( - withDuplicates(3, type(MAX_COMPOSITE_DEPTH).list().ofMaxSize(10)), - group(MAX_GROUP_DEPTH).list().ofMaxSize(3), - varData().list().ofMaxSize(3) + withDuplicates(3, typeSchema(MAX_COMPOSITE_DEPTH).list().ofMaxSize(10)), + groupSchema(MAX_GROUP_DEPTH).list().ofMaxSize(3), + varDataSchema().list().ofMaxSize(3) ).as(MessageSchema::new); } + + public interface Encoder + { + void encode(MutableDirectBuffer buffer, int offset, MutableInteger limit); + } + + private static Encoder combineEncoders(final Collection encoders) + { + return (buffer, offset, limit) -> + { + for (final Encoder encoder : encoders) + { + encoder.encode(buffer, offset, limit); + } + }; + } + + private static Arbitrary combineArbitraryEncoders(final List> encoders) + { + if (encoders.isEmpty()) + { + return Arbitraries.of(emptyEncoder()); + } + else + { + return Combinators.combine(encoders).as(SbeArbitraries::combineEncoders); + } + } + + public static CharacterArbitrary chars(final CharGenerationMode mode) + { + switch (mode) + { + case UNRESTRICTED: + return Arbitraries.chars(); + case JSON_PRINTER_COMPATIBLE: + return Arbitraries.chars().alpha(); + default: + throw new IllegalArgumentException("Unsupported mode: " + mode); + } + } + + private static Arbitrary encodedTypeEncoder( + final Encoding encoding, + final CharGenerationMode charGenerationMode) + { + final PrimitiveValue minValue = encoding.applicableMinValue(); + final PrimitiveValue maxValue = encoding.applicableMaxValue(); + + switch (encoding.primitiveType()) + { + case CHAR: + assert minValue.longValue() <= maxValue.longValue(); + return chars(charGenerationMode).map(c -> + (buffer, offset, limit) -> buffer.putChar(offset, c, encoding.byteOrder())); + + case UINT8: + case INT8: + assert (short)minValue.longValue() <= (short)maxValue.longValue(); + return Arbitraries.shorts() + .between((short)minValue.longValue(), (short)maxValue.longValue()) + .map(b -> (buffer, offset, limit) -> buffer.putByte(offset, (byte)(short)b)); + + case UINT16: + case INT16: + assert (int)minValue.longValue() <= (int)maxValue.longValue(); + return Arbitraries.integers() + .between((int)minValue.longValue(), (int)maxValue.longValue()) + .map(s -> (buffer, offset, limit) -> buffer.putShort(offset, (short)(int)s, encoding.byteOrder())); + + case UINT32: + case INT32: + assert minValue.longValue() <= maxValue.longValue(); + return Arbitraries.longs() + .between(minValue.longValue(), maxValue.longValue()) + .map(i -> (buffer, offset, limit) -> buffer.putInt(offset, (int)(long)i, encoding.byteOrder())); + + case UINT64: + return Arbitraries.longs() + .map(l -> (buffer, offset, limit) -> buffer.putLong(offset, l, encoding.byteOrder())); + + case INT64: + assert minValue.longValue() <= maxValue.longValue(); + return Arbitraries.longs() + .between(minValue.longValue(), maxValue.longValue()) + .map(l -> (buffer, offset, limit) -> buffer.putLong(offset, l, encoding.byteOrder())); + + case FLOAT: + return Arbitraries.floats() + .map(f -> (buffer, offset, limit) -> buffer.putFloat(offset, f, encoding.byteOrder())); + + case DOUBLE: + return Arbitraries.doubles() + .map(d -> (buffer, offset, limit) -> buffer.putDouble(offset, d, encoding.byteOrder())); + + default: + throw new IllegalArgumentException("Unsupported type: " + encoding.primitiveType()); + } + } + + private static Arbitrary encodedTypeEncoder( + final int offset, + final Token typeToken, + final CharGenerationMode charGenerationMode) + { + final Encoding encoding = typeToken.encoding(); + final Arbitrary arbEncoder = encodedTypeEncoder(encoding, charGenerationMode); + + if (typeToken.arrayLength() == 1) + { + return arbEncoder.map(encoder -> (buffer, bufferOffset, limit) -> + encoder.encode(buffer, bufferOffset + offset, limit)); + } + else + { + return arbEncoder.map(encoder -> (buffer, bufferOffset, limit) -> + { + for (int i = 0; i < typeToken.arrayLength(); i++) + { + encoder.encode(buffer, bufferOffset + offset + i * encoding.primitiveType().size(), limit); + } + }); + } + } + + private static Encoder emptyEncoder() + { + return (buffer, offset, limit) -> + { + }; + } + + private static Encoder integerValueEncoder(final Encoding encoding, final long value) + { + final PrimitiveType type = encoding.primitiveType(); + switch (type) + { + case CHAR: + case UINT8: + case INT8: + return (buffer, offset, limit) -> buffer.putByte(offset, (byte)value); + + case UINT16: + case INT16: + return (buffer, offset, limit) -> buffer.putShort(offset, (short)value, encoding.byteOrder()); + + case UINT32: + case INT32: + return (buffer, offset, limit) -> buffer.putInt(offset, (int)value, encoding.byteOrder()); + + case UINT64: + case INT64: + return (buffer, offset, limit) -> buffer.putLong(offset, value, encoding.byteOrder()); + + default: + throw new IllegalArgumentException("Unsupported type: " + type); + } + } + + private static Arbitrary enumEncoder( + final int offset, + final List tokens, + final Token typeToken, + final MutableInteger cursor, + final int endIdxInclusive) + { + cursor.increment(); + + final List encoders = new ArrayList<>(); + for (; cursor.get() <= endIdxInclusive; cursor.increment()) + { + final Token token = tokens.get(cursor.get()); + + if (VALID_VALUE != token.signal()) + { + throw new IllegalArgumentException("Expected VALID_VALUE token"); + } + + final Encoding encoding = token.encoding(); + final Encoder caseEncoder = integerValueEncoder(encoding, encoding.constValue().longValue()); + encoders.add(caseEncoder); + } + + if (encoders.isEmpty()) + { + final Encoder nullEncoder = integerValueEncoder( + typeToken.encoding(), + typeToken.encoding().nullValue().longValue()); + encoders.add(nullEncoder); + } + + return Arbitraries.of(encoders).map(encoder -> + (buffer, bufferOffset, limit) -> encoder.encode(buffer, bufferOffset + offset, limit)); + } + + private static Encoder choiceEncoder(final Encoding encoding) + { + final long choiceBitIdx = encoding.constValue().longValue(); + final PrimitiveType type = encoding.primitiveType(); + switch (type) + { + case UINT8: + case INT8: + return (buffer, offset, limit) -> + { + buffer.checkLimit(offset + BitUtil.SIZE_OF_BYTE); + final byte oldValue = buffer.getByte(offset); + final byte newValue = (byte)(oldValue | (1 << choiceBitIdx)); + buffer.putByte(offset, newValue); + }; + + case UINT16: + case INT16: + return (buffer, offset, limit) -> + { + buffer.checkLimit(offset + BitUtil.SIZE_OF_SHORT); + final short oldValue = buffer.getShort(offset, encoding.byteOrder()); + final short newValue = (short)(oldValue | (1 << choiceBitIdx)); + buffer.putShort(offset, newValue, encoding.byteOrder()); + }; + + case UINT32: + case INT32: + return (buffer, offset, limit) -> + { + buffer.checkLimit(offset + BitUtil.SIZE_OF_INT); + final int oldValue = buffer.getInt(offset, encoding.byteOrder()); + final int newValue = oldValue | (1 << choiceBitIdx); + buffer.putInt(offset, newValue, encoding.byteOrder()); + }; + + case UINT64: + case INT64: + return (buffer, offset, limit) -> + { + buffer.checkLimit(offset + BitUtil.SIZE_OF_LONG); + final long oldValue = buffer.getLong(offset, encoding.byteOrder()); + final long newValue = oldValue | (1L << choiceBitIdx); + buffer.putLong(offset, newValue, encoding.byteOrder()); + }; + + default: + throw new IllegalArgumentException("Unsupported type: " + type); + } + } + + private static Arbitrary bitSetEncoder( + final int offset, + final List tokens, + final MutableInteger cursor, + final int endIdxInclusive) + { + cursor.increment(); + + final List encoders = new ArrayList<>(); + for (; cursor.get() <= endIdxInclusive; cursor.increment()) + { + final Token token = tokens.get(cursor.get()); + + if (CHOICE != token.signal()) + { + throw new IllegalArgumentException("Expected CHOICE token"); + } + + final Encoding encoding = token.encoding(); + final Encoder choiceEncoder = choiceEncoder(encoding); + encoders.add(choiceEncoder); + } + + return Arbitraries.subsetOf(encoders) + .map(SbeArbitraries::combineEncoders) + .map(encoder -> (buffer, bufferOffset, limit) -> encoder.encode(buffer, bufferOffset + offset, limit)); + } + + private static Arbitrary fieldsEncoder( + final List tokens, + final MutableInteger cursor, + final int endIdxInclusive, + final boolean expectFields, + final CharGenerationMode charGenerationMode) + { + final List> encoders = new ArrayList<>(); + while (cursor.get() <= endIdxInclusive) + { + final Token memberToken = tokens.get(cursor.get()); + final int nextFieldIdx = cursor.get() + memberToken.componentTokenCount(); + + Token typeToken = memberToken; + int endFieldTokenCount = 0; + + if (BEGIN_FIELD == memberToken.signal()) + { + cursor.increment(); + typeToken = tokens.get(cursor.get()); + endFieldTokenCount = 1; + } + else if (expectFields) + { + break; + } + + final int offset = typeToken.offset(); + + if (!memberToken.isConstantEncoding()) + { + switch (typeToken.signal()) + { + case BEGIN_COMPOSITE: + cursor.increment(); + final int endCompositeTokenCount = 1; + final int lastMemberIdx = nextFieldIdx - endCompositeTokenCount - endFieldTokenCount - 1; + final Arbitrary encoder = fieldsEncoder( + tokens, cursor, lastMemberIdx, false, charGenerationMode); + final Arbitrary positionedEncoder = encoder.map(e -> + (buffer, bufferOffset, limit) -> e.encode(buffer, bufferOffset + offset, limit)); + encoders.add(positionedEncoder); + break; + + case BEGIN_ENUM: + final int endEnumTokenCount = 1; + final int lastValidValueIdx = nextFieldIdx - endFieldTokenCount - endEnumTokenCount - 1; + encoders.add(enumEncoder(offset, tokens, typeToken, cursor, lastValidValueIdx)); + break; + + case BEGIN_SET: + final int endSetTokenCount = 1; + final int lastChoiceIdx = nextFieldIdx - endFieldTokenCount - endSetTokenCount - 1; + encoders.add(bitSetEncoder(offset, tokens, cursor, lastChoiceIdx)); + break; + + case ENCODING: + encoders.add(encodedTypeEncoder(offset, typeToken, charGenerationMode)); + break; + + default: + break; + } + } + + cursor.set(nextFieldIdx); + } + + return combineArbitraryEncoders(encoders); + } + + + private static Arbitrary groupsEncoder( + final List tokens, + final MutableInteger cursor, + final int endIdxInclusive, + final CharGenerationMode charGenerationMode) + { + final List> encoders = new ArrayList<>(); + + while (cursor.get() <= endIdxInclusive) + { + final Token token = tokens.get(cursor.get()); + if (BEGIN_GROUP != token.signal()) + { + break; + } + final int nextFieldIdx = cursor.get() + token.componentTokenCount(); + + cursor.increment(); // consume BEGIN_GROUP + cursor.increment(); // consume BEGIN_COMPOSITE + final Token blockLengthToken = tokens.get(cursor.get()); + final int blockLength = token.encodedLength(); + final Encoder blockLengthEncoder = integerValueEncoder(blockLengthToken.encoding(), blockLength); + cursor.increment(); // consume ENCODED + final Token numInGroupToken = tokens.get(cursor.get()); + cursor.increment(); // consume ENCODED + cursor.increment(); // consume END_COMPOSITE + final int headerLength = blockLengthToken.encodedLength() + numInGroupToken.encodedLength(); + + + final Arbitrary groupElement = Combinators.combine( + fieldsEncoder(tokens, cursor, nextFieldIdx - 1, true, charGenerationMode), + groupsEncoder(tokens, cursor, nextFieldIdx - 1, charGenerationMode), + varDataEncoder(tokens, cursor, nextFieldIdx - 1, charGenerationMode) + ).as((fieldsEncoder, groupsEncoder, varDataEncoder) -> + (buffer, ignored, limit) -> + { + final int offset = limit.get(); + fieldsEncoder.encode(buffer, offset, null); + limit.set(offset + blockLength); + groupsEncoder.encode(buffer, NULL_VALUE, limit); + varDataEncoder.encode(buffer, NULL_VALUE, limit); + }); + + final Arbitrary repeatingGroupEncoder = groupElement.list() + .ofMaxSize(10) + .map(elements -> (buffer, ignored, limit) -> + { + final int offset = limit.get(); + limit.set(offset + headerLength); + blockLengthEncoder.encode(buffer, offset, null); + integerValueEncoder(numInGroupToken.encoding(), elements.size()) + .encode(buffer, offset + blockLengthToken.encodedLength(), null); + + for (final Encoder element : elements) + { + element.encode(buffer, NULL_VALUE, limit); + } + }); + + encoders.add(repeatingGroupEncoder); + + cursor.set(nextFieldIdx); + } + + return combineArbitraryEncoders(encoders); + } + + private static Arbitrary varDataEncoder( + final List tokens, + final MutableInteger cursor, + final int endIdxInclusive, + final CharGenerationMode charGenerationMode) + { + final List> encoders = new ArrayList<>(); + + while (cursor.get() <= endIdxInclusive) + { + final Token token = tokens.get(cursor.get()); + if (BEGIN_VAR_DATA != token.signal()) + { + break; + } + final int nextFieldIdx = cursor.get() + token.componentTokenCount(); + + cursor.increment(); // BEGIN_COMPOSITE + cursor.increment(); // ENCODED + final Token lengthToken = tokens.get(cursor.get()); + cursor.increment(); // ENCODED + final Token varDataToken = tokens.get(cursor.get()); + cursor.increment(); // END_COMPOSITE + + final String characterEncoding = varDataToken.encoding().characterEncoding(); + final Arbitrary arbitraryByte = null == characterEncoding ? + Arbitraries.bytes() : + chars(charGenerationMode).map(c -> (byte)c.charValue()); + encoders.add(arbitraryByte.list().map(bytes -> + (buffer, ignored, limit) -> + { + final int offset = limit.get(); + final int elementLength = varDataToken.encoding().primitiveType().size(); + limit.set(offset + lengthToken.encodedLength() + bytes.size() * elementLength); + integerValueEncoder(lengthToken.encoding(), bytes.size()) + .encode(buffer, offset, null); + for (int i = 0; i < bytes.size(); i++) + { + final int dataOffset = offset + lengthToken.encodedLength() + i * elementLength; + integerValueEncoder(varDataToken.encoding(), bytes.get(i)) + .encode(buffer, dataOffset, null); + } + })); + + cursor.set(nextFieldIdx); + } + + return combineArbitraryEncoders(encoders); + } + + public static Arbitrary messageValueEncoder( + final Ir ir, + final short messageId, + final CharGenerationMode charGenerationMode) + { + final List tokens = ir.getMessage(messageId); + final MutableInteger cursor = new MutableInteger(1); + + final Token token = tokens.get(0); + if (BEGIN_MESSAGE != token.signal()) + { + throw new IllegalArgumentException("Expected BEGIN_MESSAGE token"); + } + + final Arbitrary fieldsEncoder = fieldsEncoder( + tokens, cursor, tokens.size() - 1, true, charGenerationMode); + final Arbitrary groupsEncoder = groupsEncoder( + tokens, cursor, tokens.size() - 1, charGenerationMode); + final Arbitrary varDataEncoder = varDataEncoder( + tokens, cursor, tokens.size() - 1, charGenerationMode); + return Combinators.combine(fieldsEncoder, groupsEncoder, varDataEncoder) + .as((fields, groups, varData) -> (buffer, offset, limit) -> + { + final int blockLength = token.encodedLength(); + buffer.putShort(0, (short)blockLength, ir.byteOrder()); + buffer.putShort(2, messageId, ir.byteOrder()); + buffer.putShort(4, (short)ir.id(), ir.byteOrder()); + buffer.putShort(6, (short)0, ir.byteOrder()); + final int headerLength = 8; + fields.encode(buffer, offset + headerLength, null); + limit.set(offset + headerLength + blockLength); + groups.encode(buffer, NULL_VALUE, limit); + varData.encode(buffer, NULL_VALUE, limit); + }); + } + + public static final class EncodedMessage + { + private final String schema; + private final Ir ir; + private final ExpandableArrayBuffer buffer; + + private EncodedMessage(final String schema, final Ir ir, final ExpandableArrayBuffer buffer) + { + this.schema = schema; + this.ir = ir; + this.buffer = buffer; + } + + public String schema() + { + return schema; + } + + public Ir ir() + { + return ir; + } + + public ExpandableArrayBuffer buffer() + { + return buffer; + } + } + + public static Arbitrary encodedMessage(final CharGenerationMode mode) + { + return SbeArbitraries.messageSchema().flatMap(testSchema -> + { + final String xml = TestXmlSchemaWriter.writeString(testSchema); + try (InputStream in = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) + { + final uk.co.real_logic.sbe.xml.MessageSchema parsedSchema = parse(in, ParserOptions.DEFAULT); + final Ir ir = new IrGenerator().generate(parsedSchema); + return SbeArbitraries.messageValueEncoder(ir, testSchema.templateId(), mode) + .map(encoder -> + { + final ExpandableArrayBuffer buffer = new ExpandableArrayBuffer(); + final MutableInteger limit = new MutableInteger(); + encoder.encode(buffer, 0, limit); + return new EncodedMessage(xml, ir, buffer); + }); + } + catch (final Exception e) + { + throw new RuntimeException(e); + } + }).withoutEdgeCases(); + } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java index c275defe3d..451f61a34f 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java @@ -35,6 +35,16 @@ public MessageSchema( this.varData = varData; } + public short schemaId() + { + return 42; + } + + public short templateId() + { + return 1; + } + public List blockFields() { return blockFields; diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/XmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java similarity index 98% rename from sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/XmlSchemaWriter.java rename to sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index 63a10903ca..242f7c9946 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/XmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -34,9 +34,9 @@ import static java.util.Objects.requireNonNull; -public final class XmlSchemaWriter +public final class TestXmlSchemaWriter { - private XmlSchemaWriter() + private TestXmlSchemaWriter() { } @@ -65,7 +65,7 @@ private static void writeTo( final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); final Element root = document.createElementNS("http://fixprotocol.io/2016/sbe", "sbe:messageSchema"); - root.setAttribute("id", "42"); + root.setAttribute("id", Short.toString(schema.schemaId())); root.setAttribute("package", "uk.co.real_logic.sbe.properties"); document.appendChild(root); @@ -90,7 +90,7 @@ private static void writeTo( final Element message = document.createElement("sbe:message"); message.setAttribute("name", "TestMessage"); - message.setAttribute("id", "1"); + message.setAttribute("id", Short.toString(schema.templateId())); root.appendChild(message); final MutableInteger nextMemberId = new MutableInteger(0); appendMembers( diff --git a/sbe-tool/src/propertyTest/resources/junit-platform.properties b/sbe-tool/src/propertyTest/resources/junit-platform.properties index 8a3fb086c1..8194cc7e80 100644 --- a/sbe-tool/src/propertyTest/resources/junit-platform.properties +++ b/sbe-tool/src/propertyTest/resources/junit-platform.properties @@ -1,3 +1,4 @@ jqwik.edgecases.default=MIXIN -jqwik.tries.default=5000 -jqwik.failures.runfirst=true \ No newline at end of file +jqwik.tries.default=500 +jqwik.failures.runfirst=true +jqwik.shrinking.bounded.seconds=90 \ No newline at end of file From 5af0274372a8a8498fa7ee2b2fdcafcca745856e Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Sat, 7 Oct 2023 03:15:25 +0100 Subject: [PATCH 345/805] [Java] Test DTOs preserve information. In this commit, I've added a round trip property test, where I show `dto.EncodeInto(...)` is the inverse of `dto.DecodeFrom(...)` and that the original encoded value is preserved through the transformation. --- .../generation/csharp/CSharpDtoGenerator.java | 7 +- .../properties/CSharpDtosPropertyTest.java | 130 ++++++++++++++++++ .../CSharpDtosPropertyTest/Program.cs | 31 +++++ .../SbePropertyTest.csproj | 14 ++ 4 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java create mode 100644 sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs create mode 100644 sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index a0f1e21d9d..e7ceeeb155 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -266,7 +266,7 @@ private void generateFieldDecodeFrom( break; case BEGIN_COMPOSITE: - generateComplexDecodeFrom(sb, fieldToken, indent); + generateComplexDecodeFrom(sb, fieldToken, typeToken, indent); break; default: @@ -389,10 +389,12 @@ private void generatePropertyDecodeFrom( private void generateComplexDecodeFrom( final StringBuilder sb, final Token fieldToken, + final Token typeToken, final String indent) { final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); + final String dtoClassName = formatDtoClassName(typeToken.applicableTypeName()); wrapInActingVersionCheck( sb, @@ -401,7 +403,7 @@ private void generateComplexDecodeFrom( (blkSb, blkIndent) -> { blkSb.append(blkIndent).append(formattedPropertyName).append(" = new ") - .append(formatDtoClassName(propertyName)).append("();\n") + .append(dtoClassName).append("();\n") .append(blkIndent).append(formattedPropertyName).append(".DecodeFrom(codec.") .append(formattedPropertyName).append(");\n"); }, @@ -577,7 +579,6 @@ private void generateFieldEncodeInto( final Token typeToken, final String indent) { - switch (typeToken.signal()) { case ENCODING: diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java new file mode 100644 index 0000000000..2c3cc814e1 --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java @@ -0,0 +1,130 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties; + +import net.jqwik.api.Arbitrary; +import net.jqwik.api.ForAll; +import net.jqwik.api.Property; +import net.jqwik.api.Provide; +import uk.co.real_logic.sbe.generation.csharp.CSharpDtoGenerator; +import uk.co.real_logic.sbe.generation.csharp.CSharpGenerator; +import uk.co.real_logic.sbe.generation.csharp.CSharpNamespaceOutputManager; +import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; +import org.agrona.IoUtil; +import org.agrona.io.DirectBufferInputStream; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; + +public class CSharpDtosPropertyTest +{ + @Property + void dtoEncodeShouldBeTheInverseOfDtoDecode( + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage + ) throws IOException, InterruptedException + { + final Path tempDir = Files.createTempDirectory("sbe-csharp-dto-test"); + try + { + final CSharpNamespaceOutputManager outputManager = new CSharpNamespaceOutputManager( + tempDir.toString(), + "SbePropertyTest" + ); + new CSharpGenerator(encodedMessage.ir(), outputManager) + .generate(); + new CSharpDtoGenerator(encodedMessage.ir(), outputManager) + .generate(); + copyResourceToFile("/CSharpDtosPropertyTest/SbePropertyTest.csproj", tempDir); + copyResourceToFile("/CSharpDtosPropertyTest/Program.cs", tempDir); + try ( + DirectBufferInputStream inputStream = new DirectBufferInputStream(encodedMessage.buffer()); + OutputStream outputStream = Files.newOutputStream(tempDir.resolve("input.dat"))) + { + final byte[] buffer = new byte[2048]; + int read; + while ((read = inputStream.read(buffer, 0, buffer.length)) >= 0) + { + outputStream.write(buffer, 0, read); + } + } + + final Path stdout = tempDir.resolve("stdout.txt"); + final Path stderr = tempDir.resolve("stderr.txt"); + final ProcessBuilder processBuilder = new ProcessBuilder("dotnet", "run", "--", "input.dat") + .directory(tempDir.toFile()) + .redirectOutput(stdout.toFile()) + .redirectError(stderr.toFile()); + + final Process process = processBuilder.start(); + if (0 != process.waitFor()) + { + throw new AssertionError( + "Process failed with exit code: " + process.exitValue() + "\n\n" + + "STDOUT:\n" + new String(Files.readAllBytes(stdout)) + "\n\n" + + "STDERR:\n" + new String(Files.readAllBytes(stderr)) + "\n\n" + + "SCHEMA:\n" + encodedMessage.schema()); + } + + final byte[] inputBytes = encodedMessage.buffer().byteArray(); + final byte[] outputBytes = Files.readAllBytes(tempDir.resolve("output.dat")); + if (!Arrays.equals(inputBytes, outputBytes)) + { + throw new AssertionError( + "Input and output files differ\n\n" + + "SCHEMA:\n" + encodedMessage.schema()); + } + } + finally + { + IoUtil.delete(tempDir.toFile(), true); + } + } + + @Provide + Arbitrary encodedMessage() + { + final SbeArbitraries.CharGenerationMode mode = + SbeArbitraries.CharGenerationMode.JSON_PRINTER_COMPATIBLE; + return SbeArbitraries.encodedMessage(mode); + } + + private static void copyResourceToFile( + final String resourcePath, + final Path outputDir) + { + try (InputStream inputStream = CSharpDtosPropertyTest.class.getResourceAsStream(resourcePath)) + { + if (inputStream == null) + { + throw new IOException("Resource not found: " + resourcePath); + } + + final int resourceNameIndex = resourcePath.lastIndexOf('/') + 1; + final String resourceName = resourcePath.substring(resourceNameIndex); + final Path outputFilePath = outputDir.resolve(resourceName); + Files.copy(inputStream, outputFilePath); + } + catch (final IOException e) + { + throw new RuntimeException(e); + } + } +} diff --git a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs new file mode 100644 index 0000000000..1efcf4bfa7 --- /dev/null +++ b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; +using Org.SbeTool.Sbe.Dll; +using Uk.Co.Real_logic.Sbe.Properties; + +namespace SbePropertyTest { + static class Test { + static int Main(string[] args) { + if (args.Length != 1) { + Console.WriteLine("Usage: dotnet run -- $BINARY_FILE"); + return 1; + } + var binaryFile = args[0]; + var inputBytes = File.ReadAllBytes(binaryFile); + var buffer = new DirectBuffer(inputBytes); + var messageHeader = new MessageHeader(); + messageHeader.Wrap(buffer, 0, 0); + var decoder = new TestMessage(); + decoder.WrapForDecode(buffer, 8, messageHeader.BlockLength, messageHeader.Version); + var dto = new TestMessageDto(); + dto.DecodeFrom(decoder); + var outputBytes = new byte[inputBytes.Length]; + var outputBuffer = new DirectBuffer(outputBytes); + var encoder = new TestMessage(); + encoder.WrapForEncodeAndApplyHeader(outputBuffer, 0, new MessageHeader()); + dto.EncodeInto(encoder); + File.WriteAllBytes("output.dat", outputBytes); + return 0; + } + } +} diff --git a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj new file mode 100644 index 0000000000..a1bbc69f1c --- /dev/null +++ b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + + + + + /home/zach/src/real-logic/simple-binary-encoding/csharp/sbe-dll/bin/Release/netstandard2.0/SBE.dll + + + + From fdf77422434e6a2c81c1e8f426cc83451f9e3fcb Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Tue, 10 Oct 2023 11:36:17 +0100 Subject: [PATCH 346/805] [Java,C#] Make dotnet executable customisable in tests. Addresses CodeQL comment. --- .../co/real_logic/sbe/properties/CSharpDtosPropertyTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java index 2c3cc814e1..3834b86e11 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java @@ -36,6 +36,8 @@ public class CSharpDtosPropertyTest { + private static final String DOTNET_EXECUTABLE = System.getProperty("sbe.tests.dotnet.executable", "dotnet"); + @Property void dtoEncodeShouldBeTheInverseOfDtoDecode( @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage @@ -68,7 +70,7 @@ void dtoEncodeShouldBeTheInverseOfDtoDecode( final Path stdout = tempDir.resolve("stdout.txt"); final Path stderr = tempDir.resolve("stderr.txt"); - final ProcessBuilder processBuilder = new ProcessBuilder("dotnet", "run", "--", "input.dat") + final ProcessBuilder processBuilder = new ProcessBuilder(DOTNET_EXECUTABLE, "run", "--", "input.dat") .directory(tempDir.toFile()) .redirectOutput(stdout.toFile()) .redirectError(stderr.toFile()); From 852a0fe38989d8de7f224405c7551c208a83ea68 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Tue, 10 Oct 2023 12:08:09 +0100 Subject: [PATCH 347/805] [Java] Extend schema generation to include bitsets with gaps. --- .../properties/arbitraries/SbeArbitraries.java | 15 ++++++--------- .../sbe/properties/schema/SetSchema.java | 13 +++++++------ .../properties/schema/TestXmlSchemaWriter.java | 11 +++++------ 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index eb6ef0603f..1efd68e7c0 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -147,15 +147,12 @@ private static Arbitrary enumTypeSchema() private static Arbitrary setTypeSchema() { - return Combinators.combine( - Arbitraries.of( - "uint8", - "uint16", - "uint32", - "uint64" - ), - Arbitraries.integers().between(1, 4) - ).as(SetSchema::new); + return Arbitraries.oneOf( + Arbitraries.integers().between(0, 7).set().map(choices -> new SetSchema("uint8", choices)), + Arbitraries.integers().between(0, 15).set().map(choices -> new SetSchema("uint16", choices)), + Arbitraries.integers().between(0, 31).set().map(choices -> new SetSchema("uint32", choices)), + Arbitraries.integers().between(0, 63).set().map(choices -> new SetSchema("uint64", choices)) + ); } private static Arbitrary compositeTypeSchema(final int depth) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java index 95874e8381..4ed41fc013 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java @@ -16,17 +16,19 @@ package uk.co.real_logic.sbe.properties.schema; +import java.util.Set; + public final class SetSchema implements TypeSchema { private final String encodingType; - private final int choiceCount; + private final Set choices; public SetSchema( final String encodingType, - final int choiceCount) + final Set choices) { - this.choiceCount = choiceCount; this.encodingType = encodingType; + this.choices = choices; } public String encodingType() @@ -34,9 +36,9 @@ public String encodingType() return encodingType; } - public int choiceCount() + public Set choices() { - return choiceCount; + return choices; } @Override @@ -44,5 +46,4 @@ public void accept(final TypeSchemaVisitor visitor) { visitor.onSet(this); } - } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index 242f7c9946..c7c23533bd 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -238,18 +238,17 @@ private static Element createSetElement( final Document document, final String name, final String encodingType, - final int choiceCount) + final Set choices) { final Element enumElement = document.createElement("set"); enumElement.setAttribute("name", name); enumElement.setAttribute("encodingType", encodingType); - int caseId = 0; - for (int i = 0; i < choiceCount; i++) + for (final Integer value : choices) { final Element choice = document.createElement("choice"); - choice.setAttribute("name", "option" + caseId++); - choice.setTextContent(Integer.toString(i)); + choice.setAttribute("name", "option" + value); + choice.setTextContent(value.toString()); enumElement.appendChild(choice); } @@ -403,7 +402,7 @@ public void onSet(final SetSchema type) document, typeToName.computeIfAbsent(type, nextName), type.encodingType(), - type.choiceCount() + type.choices() ); } From 92588c0433373590fd18a6d561fef1b886028d3f Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Tue, 10 Oct 2023 16:23:23 +0100 Subject: [PATCH 348/805] [Java] Use arbitrary fixed-length arrays in property tests. Previously, we were only generating non-array fields in blocks. Now, we can exercise more possibly specifications in our property-based tests. --- .../arbitraries/SbeArbitraries.java | 20 +++++++++++++------ .../schema/EncodedDataTypeSchema.java | 8 ++++++++ .../schema/TestXmlSchemaWriter.java | 20 ++++++++++++++++++- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index 1efd68e7c0..4750da7c19 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -111,6 +111,7 @@ private static Arbitrary encodedDataTypeSchema() { return Combinators.combine( Arbitraries.of(PrimitiveType.values()), + Arbitraries.of(1, 1, 1, 2, 13), Arbitraries.of(true, false) ).as(EncodedDataTypeSchema::new); } @@ -324,13 +325,15 @@ private static Arbitrary encodedTypeEncoder( } else { - return arbEncoder.map(encoder -> (buffer, bufferOffset, limit) -> - { - for (int i = 0; i < typeToken.arrayLength(); i++) + return arbEncoder.list().ofSize(typeToken.arrayLength()) + .map(encoders -> (buffer, bufferOffset, limit) -> { - encoder.encode(buffer, bufferOffset + offset + i * encoding.primitiveType().size(), limit); - } - }); + for (int i = 0; i < typeToken.arrayLength(); i++) + { + final int elementOffset = bufferOffset + offset + i * encoding.primitiveType().size(); + encoders.get(i).encode(buffer, elementOffset, limit); + } + }); } } @@ -478,6 +481,11 @@ private static Arbitrary bitSetEncoder( encoders.add(choiceEncoder); } + if (encoders.isEmpty()) + { + return Arbitraries.of(emptyEncoder()); + } + return Arbitraries.subsetOf(encoders) .map(SbeArbitraries::combineEncoders) .map(encoder -> (buffer, bufferOffset, limit) -> encoder.encode(buffer, bufferOffset + offset, limit)); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java index b5fe76941d..5eb092150f 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java @@ -21,14 +21,17 @@ public final class EncodedDataTypeSchema implements TypeSchema { private final PrimitiveType primitiveType; + private final int length; private final boolean isEmbedded; public EncodedDataTypeSchema( final PrimitiveType primitiveType, + final int length, final boolean isEmbedded ) { this.primitiveType = primitiveType; + this.length = length; this.isEmbedded = isEmbedded; } @@ -37,6 +40,11 @@ public PrimitiveType primitiveType() return primitiveType; } + public int length() + { + return length; + } + @Override public boolean isEmbedded() { diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index c7c23533bd..2211c31860 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -305,6 +305,23 @@ private static Element createTypeElement( return blockLength; } + private static Element createTypeElement( + final Document document, + final String name, + final String primitiveType, + final int length) + { + final Element blockLength = document.createElement("type"); + blockLength.setAttribute("name", name); + blockLength.setAttribute("primitiveType", primitiveType); + if (length > 1) + { + blockLength.setAttribute("length", Integer.toString(length)); + } + + return blockLength; + } + private static Element createRefElement( final Document document, final String name, @@ -362,7 +379,8 @@ public void onEncoded(final EncodedDataTypeSchema type) result = createTypeElement( document, typeToName.computeIfAbsent(type, nextName), - type.primitiveType().primitiveName() + type.primitiveType().primitiveName(), + type.length() ); } From b205c4b919ed5f84bef110fad1c6be3cd8c142cb Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 11 Oct 2023 10:00:17 +0100 Subject: [PATCH 349/805] [Java] Model optional fields in property-based tests. Previously, we were only supplying required fields in the schema. Now, we allow fields and primitive types to be marked as optional. Note that they can be marked as optional in two places. Optional => null value. There are some oddities around specifying `nullValue`s: https://github.com/real-logic/simple-binary-encoding/issues/429 We currently use the default `nullValue`s for types rather than generating arbitrary ones. --- .../arbitraries/SbeArbitraries.java | 33 ++++++++++- .../schema/EncodedDataTypeSchema.java | 9 +++ .../sbe/properties/schema/FieldSchema.java | 44 +++++++++++++++ .../sbe/properties/schema/GroupSchema.java | 6 +- .../sbe/properties/schema/MessageSchema.java | 6 +- .../schema/TestXmlSchemaWriter.java | 56 ++++++++++++++----- 6 files changed, 131 insertions(+), 23 deletions(-) create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index 4750da7c19..2a3d2bd9b3 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -112,6 +112,7 @@ private static Arbitrary encodedDataTypeSchema() return Combinators.combine( Arbitraries.of(PrimitiveType.values()), Arbitraries.of(1, 1, 1, 2, 13), + presence(), Arbitraries.of(true, false) ).as(EncodedDataTypeSchema::new); } @@ -190,12 +191,26 @@ private static Arbitrary groupSchema(final int depth) groupSchema(depth - 1).list().ofMaxSize(3); return Combinators.combine( - withDuplicates(2, typeSchema(MAX_COMPOSITE_DEPTH).list().ofMaxSize(5)), + withDuplicates( + 2, + Combinators.combine( + typeSchema(MAX_COMPOSITE_DEPTH), + presence() + ).as(FieldSchema::new).list().ofMaxSize(5) + ), subGroups, varDataSchema().list().ofMaxSize(3) ).as(GroupSchema::new); } + private static Arbitrary presence() + { + return Arbitraries.of( + Encoding.Presence.REQUIRED, + Encoding.Presence.OPTIONAL + ); + } + private static Arbitrary varDataSchema() { return Arbitraries.of(VarDataSchema.Encoding.values()) @@ -205,7 +220,14 @@ private static Arbitrary varDataSchema() public static Arbitrary messageSchema() { return Combinators.combine( - withDuplicates(3, typeSchema(MAX_COMPOSITE_DEPTH).list().ofMaxSize(10)), + + withDuplicates( + 3, + Combinators.combine( + typeSchema(MAX_COMPOSITE_DEPTH), + presence() + ).as(FieldSchema::new).list().ofMaxSize(10) + ), groupSchema(MAX_GROUP_DEPTH).list().ofMaxSize(3), varDataSchema().list().ofMaxSize(3) ).as(MessageSchema::new); @@ -752,7 +774,12 @@ public static Arbitrary encodedMessage(final CharGenerationMode final String xml = TestXmlSchemaWriter.writeString(testSchema); try (InputStream in = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { - final uk.co.real_logic.sbe.xml.MessageSchema parsedSchema = parse(in, ParserOptions.DEFAULT); + final ParserOptions options = ParserOptions.builder() + .suppressOutput(false) + .warningsFatal(true) + .stopOnError(true) + .build(); + final uk.co.real_logic.sbe.xml.MessageSchema parsedSchema = parse(in, options); final Ir ir = new IrGenerator().generate(parsedSchema); return SbeArbitraries.messageValueEncoder(ir, testSchema.templateId(), mode) .map(encoder -> diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java index 5eb092150f..a1bbeba14e 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java @@ -17,21 +17,25 @@ package uk.co.real_logic.sbe.properties.schema; import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.ir.Encoding; public final class EncodedDataTypeSchema implements TypeSchema { private final PrimitiveType primitiveType; private final int length; + private final Encoding.Presence presence; private final boolean isEmbedded; public EncodedDataTypeSchema( final PrimitiveType primitiveType, final int length, + final Encoding.Presence presence, final boolean isEmbedded ) { this.primitiveType = primitiveType; this.length = length; + this.presence = presence; this.isEmbedded = isEmbedded; } @@ -45,6 +49,11 @@ public int length() return length; } + public Encoding.Presence presence() + { + return presence; + } + @Override public boolean isEmbedded() { diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java new file mode 100644 index 0000000000..406ee65cdd --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java @@ -0,0 +1,44 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.schema; + +import uk.co.real_logic.sbe.ir.Encoding; + +public final class FieldSchema +{ + private final TypeSchema type; + private final Encoding.Presence presence; + + public FieldSchema( + final TypeSchema type, + final Encoding.Presence presence + ) + { + this.type = type; + this.presence = presence; + } + + public TypeSchema type() + { + return type; + } + + public Encoding.Presence presence() + { + return presence; + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java index df34e0a9b6..53c3c81df7 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java @@ -20,12 +20,12 @@ public final class GroupSchema { - private final List blockFields; + private final List blockFields; private final List groups; private final List varData; public GroupSchema( - final List blockFields, + final List blockFields, final List groups, final List varData) { @@ -34,7 +34,7 @@ public GroupSchema( this.varData = varData; } - public List blockFields() + public List blockFields() { return blockFields; } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java index 451f61a34f..a0decb2d6b 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java @@ -20,12 +20,12 @@ public final class MessageSchema { - private final List blockFields; + private final List blockFields; private final List groups; private final List varData; public MessageSchema( - final List blockFields, + final List blockFields, final List groups, final List varData ) @@ -45,7 +45,7 @@ public short templateId() return 1; } - public List blockFields() + public List blockFields() { return blockFields; } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index 2211c31860..1481126646 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -16,6 +16,7 @@ package uk.co.real_logic.sbe.properties.schema; +import uk.co.real_logic.sbe.ir.Encoding; import org.agrona.collections.MutableInteger; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -24,6 +25,7 @@ import java.io.StringWriter; import java.util.*; import java.util.function.Function; +import java.util.stream.Collectors; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; @@ -85,7 +87,7 @@ private static void writeTo( visitedTypes, topLevelTypes, typeSchemaConverter, - schema.blockFields(), + schema.blockFields().stream().map(FieldSchema::type).collect(Collectors.toList()), schema.groups()); final Element message = document.createElement("sbe:message"); @@ -128,25 +130,26 @@ private static void writeTo( private static void appendMembers( final Document document, final HashMap typeToName, - final List blockFields, + final List blockFields, final List groups, final List varData, final MutableInteger nextMemberId, final Element parent) { - for (final TypeSchema field : blockFields) + for (final FieldSchema field : blockFields) { final int id = nextMemberId.getAndIncrement(); - final boolean usePrimitiveName = field.isEmbedded() && field instanceof EncodedDataTypeSchema; + final boolean usePrimitiveName = field.type().isEmbedded() && field.type() instanceof EncodedDataTypeSchema; final String typeName = usePrimitiveName ? - ((EncodedDataTypeSchema)field).primitiveType().primitiveName() : - requireNonNull(typeToName.get(field)); + ((EncodedDataTypeSchema)field.type()).primitiveType().primitiveName() : + requireNonNull(typeToName.get(field.type())); final Element element = document.createElement("field"); element.setAttribute("id", Integer.toString(id)); element.setAttribute("name", "member" + id); element.setAttribute("type", typeName); + element.setAttribute("presence", field.presence().name().toLowerCase()); parent.appendChild(element); } @@ -309,17 +312,35 @@ private static Element createTypeElement( final Document document, final String name, final String primitiveType, - final int length) + final int length, + final Encoding.Presence presence) { - final Element blockLength = document.createElement("type"); - blockLength.setAttribute("name", name); - blockLength.setAttribute("primitiveType", primitiveType); + final Element typeElement = document.createElement("type"); + typeElement.setAttribute("name", name); + typeElement.setAttribute("primitiveType", primitiveType); + if (length > 1) { - blockLength.setAttribute("length", Integer.toString(length)); + typeElement.setAttribute("length", Integer.toString(length)); } - return blockLength; + switch (presence) + { + + case REQUIRED: + typeElement.setAttribute("presence", "required"); + break; + case OPTIONAL: + typeElement.setAttribute("presence", "optional"); + break; + case CONSTANT: + typeElement.setAttribute("presence", "constant"); + break; + default: + throw new IllegalArgumentException("Unknown presence: " + presence); + } + + return typeElement; } private static Element createRefElement( @@ -350,7 +371,13 @@ private static void appendTypes( for (final GroupSchema group : groups) { - appendTypes(visitedTypes, topLevelTypes, typeSchemaConverter, group.blockFields(), group.groups()); + appendTypes( + visitedTypes, + topLevelTypes, + typeSchemaConverter, + group.blockFields().stream().map(FieldSchema::type).collect(Collectors.toList()), + group.groups() + ); } } @@ -380,7 +407,8 @@ public void onEncoded(final EncodedDataTypeSchema type) document, typeToName.computeIfAbsent(type, nextName), type.primitiveType().primitiveName(), - type.length() + type.length(), + type.presence() ); } From 58b0e927615750902cece9c62a5b9d18f1c95bbc Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 11 Oct 2023 10:17:38 +0100 Subject: [PATCH 350/805] [Java, C#] Add a GitHub workflow for slow checks. This workflow is configured to run once per day or when manually requested. At the moment, the slow checks include several property-based tests. These tests take a significant amount of time to execute; therefore, we decided it was better to keep them out of the CI build. --- .github/workflows/slow.yml | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/slow.yml diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml new file mode 100644 index 0000000000..9a22c1f415 --- /dev/null +++ b/.github/workflows/slow.yml @@ -0,0 +1,58 @@ +name: Slow checks + +on: + workflow_dispatch: + branches: + - '**' + schedule: + - cron: '0 12 * * *' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' + +permissions: + contents: read + +jobs: + property-tests: + name: Property tests + runs-on: ubuntu-22.04 + strategy: + matrix: + java: [ '21' ] + dotnet: [ '3.1.301' ] + env: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Setup java + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: ${{ matrix.java }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV + - name: Setup java 8 to run the Gradle script + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 8 + - name: Setup dotnet + uses: actions/setup-dotnet@v2 + with: + dotnet-version: ${{ matrix.dotnet }} + - name: Build SbeTool + run: ./gradlew + - name: Build .NET library + run: ./csharp/build.sh + - name: Run property tests + run: ./gradlew propertyTest From 4f9d51b18607ace0e4297dd6c38a8bc3300409d6 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 11 Oct 2023 19:41:37 +0100 Subject: [PATCH 351/805] [Java] Extend arbitrary varData encodings. We now explore more of the "schema space", as we generate lengths of different encodings. It surfaces an issue, reported in #955, which was fixed in another outstanding PR's commit: 3885a63d3103ac52406c660147ee929fa9aaee63. --- .../arbitraries/SbeArbitraries.java | 27 ++++-- .../schema/TestXmlSchemaWriter.java | 87 ++++++++++--------- .../sbe/properties/schema/VarDataSchema.java | 21 +++-- 3 files changed, 81 insertions(+), 54 deletions(-) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index 2a3d2bd9b3..cc2f5ff9ab 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -150,10 +150,18 @@ private static Arbitrary enumTypeSchema() private static Arbitrary setTypeSchema() { return Arbitraries.oneOf( - Arbitraries.integers().between(0, 7).set().map(choices -> new SetSchema("uint8", choices)), - Arbitraries.integers().between(0, 15).set().map(choices -> new SetSchema("uint16", choices)), - Arbitraries.integers().between(0, 31).set().map(choices -> new SetSchema("uint32", choices)), - Arbitraries.integers().between(0, 63).set().map(choices -> new SetSchema("uint64", choices)) + Arbitraries.integers().between(0, 7).set() + .ofMaxSize(8) + .map(choices -> new SetSchema("uint8", choices)), + Arbitraries.integers().between(0, 15).set() + .ofMaxSize(16) + .map(choices -> new SetSchema("uint16", choices)), + Arbitraries.integers().between(0, 31).set() + .ofMaxSize(32) + .map(choices -> new SetSchema("uint32", choices)), + Arbitraries.integers().between(0, 63).set() + .ofMaxSize(64) + .map(choices -> new SetSchema("uint64", choices)) ); } @@ -213,14 +221,19 @@ private static Arbitrary presence() private static Arbitrary varDataSchema() { - return Arbitraries.of(VarDataSchema.Encoding.values()) - .map(VarDataSchema::new); + return Combinators.combine( + Arbitraries.of(VarDataSchema.Encoding.values()), + Arbitraries.of( + PrimitiveType.UINT8, + PrimitiveType.UINT16, + PrimitiveType.UINT32 + ) + ).as(VarDataSchema::new); } public static Arbitrary messageSchema() { return Combinators.combine( - withDuplicates( 3, Combinators.combine( diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index 1481126646..7ccd273017 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -20,6 +20,7 @@ import org.agrona.collections.MutableInteger; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.Node; import java.io.File; import java.io.StringWriter; @@ -74,7 +75,7 @@ private static void writeTo( final Element topLevelTypes = createTypesElement(document); root.appendChild(topLevelTypes); - final HashMap typeToName = new HashMap<>(); + final HashMap typeToName = new HashMap<>(); final TypeSchemaConverter typeSchemaConverter = new TypeSchemaConverter( document, @@ -88,7 +89,8 @@ private static void writeTo( topLevelTypes, typeSchemaConverter, schema.blockFields().stream().map(FieldSchema::type).collect(Collectors.toList()), - schema.groups()); + schema.groups(), + schema.varData()); final Element message = document.createElement("sbe:message"); message.setAttribute("name", "TestMessage"); @@ -129,7 +131,7 @@ private static void writeTo( private static void appendMembers( final Document document, - final HashMap typeToName, + final HashMap typeToName, final List blockFields, final List groups, final List varData, @@ -174,21 +176,10 @@ private static void appendMembers( for (final VarDataSchema data : varData) { final int id = nextMemberId.getAndIncrement(); - final Element element = document.createElement("data"); element.setAttribute("id", Integer.toString(id)); element.setAttribute("name", "member" + id); - switch (data.encoding()) - { - case ASCII: - element.setAttribute("type", "varStringEncoding"); - break; - case BYTES: - element.setAttribute("type", "varDataEncoding"); - break; - default: - throw new IllegalStateException("Unknown encoding: " + data.encoding()); - } + element.setAttribute("type", requireNonNull(typeToName.get(data))); parent.appendChild(element); } } @@ -213,27 +204,6 @@ private static Element createTypesElement(final Document document) createTypeElement(document, "numInGroup", "uint16") )); - final Element varString = createTypeElement(document, "varData", "uint8"); - varString.setAttribute("length", "0"); - varString.setAttribute("characterEncoding", "US-ASCII"); - types.appendChild(createCompositeElement( - document, - "varStringEncoding", - createTypeElement(document, "length", "uint16"), - varString - )); - - final Element varData = createTypeElement(document, "varData", "uint8"); - final Element varDataLength = createTypeElement(document, "length", "uint32"); - varDataLength.setAttribute("maxValue", "1000000"); - varData.setAttribute("length", "0"); - types.appendChild(createCompositeElement( - document, - "varDataEncoding", - varDataLength, - varData - )); - return types; } @@ -359,7 +329,8 @@ private static void appendTypes( final Element topLevelTypes, final TypeSchemaConverter typeSchemaConverter, final List blockFields, - final List groups) + final List groups, + final List varDataFields) { for (final TypeSchema field : blockFields) { @@ -376,23 +347,29 @@ private static void appendTypes( topLevelTypes, typeSchemaConverter, group.blockFields().stream().map(FieldSchema::type).collect(Collectors.toList()), - group.groups() - ); + group.groups(), + group.varData()); + } + + for (final VarDataSchema varData : varDataFields) + { + topLevelTypes.appendChild(typeSchemaConverter.convert(varData)); } } + @SuppressWarnings("EnhancedSwitchMigration") private static final class TypeSchemaConverter implements TypeSchemaVisitor { private final Document document; private final Element topLevelTypes; - private final Map typeToName; - private final Function nextName; + private final Map typeToName; + private final Function nextName; private Element result; private TypeSchemaConverter( final Document document, final Element topLevelTypes, - final Map typeToName) + final Map typeToName) { this.document = document; this.topLevelTypes = topLevelTypes; @@ -481,5 +458,31 @@ public Element convert(final TypeSchema type) type.accept(this); return requireNonNull(result); } + + public Node convert(final VarDataSchema varData) + { + final Element lengthElement = createTypeElement(document, "length", + varData.lengthEncoding().primitiveName()); + + if (varData.lengthEncoding().size() >= 4) + { + lengthElement.setAttribute("maxValue", Integer.toString(1_000_000)); + } + + final Element varDataElement = createTypeElement(document, "varData", "uint8"); + varDataElement.setAttribute("length", "0"); + + if (varData.dataEncoding().equals(VarDataSchema.Encoding.ASCII)) + { + varDataElement.setAttribute("characterEncoding", "US-ASCII"); + } + + return createCompositeElement( + document, + typeToName.computeIfAbsent(varData, nextName), + lengthElement, + varDataElement + ); + } } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java index c6b39db56b..b5e98c02c7 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java @@ -16,18 +16,29 @@ package uk.co.real_logic.sbe.properties.schema; +import uk.co.real_logic.sbe.PrimitiveType; + public final class VarDataSchema { - private final Encoding encoding; + private final Encoding dataEncoding; + private final PrimitiveType lengthEncoding; + + public VarDataSchema( + final Encoding dataEncoding, + final PrimitiveType lengthEncoding) + { + this.dataEncoding = dataEncoding; + this.lengthEncoding = lengthEncoding; + } - public VarDataSchema(final Encoding encoding) + public Encoding dataEncoding() { - this.encoding = encoding; + return dataEncoding; } - public Encoding encoding() + public PrimitiveType lengthEncoding() { - return encoding; + return lengthEncoding; } public enum Encoding From 77711dd7e6285c2763794f0ee048745b250d6f4e Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 12 Oct 2023 13:27:22 +0100 Subject: [PATCH 352/805] [Java, C#] Tidy up encoded message writing in tests. Previously, we were writing all bytes in a buffer rather than just those used for encoding the message. Now, we keep track of the "limit" of the message and only use the bytes in the buffer up to the limit. --- .../sbe/properties/CSharpDtosPropertyTest.java | 9 +++++++-- .../properties/arbitraries/SbeArbitraries.java | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java index 3834b86e11..7a4dde3f49 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java @@ -57,7 +57,11 @@ void dtoEncodeShouldBeTheInverseOfDtoDecode( copyResourceToFile("/CSharpDtosPropertyTest/SbePropertyTest.csproj", tempDir); copyResourceToFile("/CSharpDtosPropertyTest/Program.cs", tempDir); try ( - DirectBufferInputStream inputStream = new DirectBufferInputStream(encodedMessage.buffer()); + DirectBufferInputStream inputStream = new DirectBufferInputStream( + encodedMessage.buffer(), + 0, + encodedMessage.length() + ); OutputStream outputStream = Files.newOutputStream(tempDir.resolve("input.dat"))) { final byte[] buffer = new byte[2048]; @@ -85,7 +89,8 @@ void dtoEncodeShouldBeTheInverseOfDtoDecode( "SCHEMA:\n" + encodedMessage.schema()); } - final byte[] inputBytes = encodedMessage.buffer().byteArray(); + final byte[] inputBytes = new byte[encodedMessage.length()]; + encodedMessage.buffer().getBytes(0, inputBytes); final byte[] outputBytes = Files.readAllBytes(tempDir.resolve("output.dat")); if (!Arrays.equals(inputBytes, outputBytes)) { diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index cc2f5ff9ab..2e3db4bda0 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -756,12 +756,18 @@ public static final class EncodedMessage private final String schema; private final Ir ir; private final ExpandableArrayBuffer buffer; + private final int length; - private EncodedMessage(final String schema, final Ir ir, final ExpandableArrayBuffer buffer) + private EncodedMessage( + final String schema, + final Ir ir, + final ExpandableArrayBuffer buffer, + final int length) { this.schema = schema; this.ir = ir; this.buffer = buffer; + this.length = length; } public String schema() @@ -778,6 +784,11 @@ public ExpandableArrayBuffer buffer() { return buffer; } + + public int length() + { + return length; + } } public static Arbitrary encodedMessage(final CharGenerationMode mode) @@ -800,7 +811,7 @@ public static Arbitrary encodedMessage(final CharGenerationMode final ExpandableArrayBuffer buffer = new ExpandableArrayBuffer(); final MutableInteger limit = new MutableInteger(); encoder.encode(buffer, 0, limit); - return new EncodedMessage(xml, ir, buffer); + return new EncodedMessage(xml, ir, buffer, limit.get()); }); } catch (final Exception e) From 19f69a9fae941dd5018e68c546bc7d60528a2683 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 13 Oct 2023 00:00:41 +0100 Subject: [PATCH 353/805] [C#] Upgrade to latest LTS .NET version. To support records in DTOs, we require C# 9+. This is not supported by .NET 3. Also, this old version is no longer supported by Microsoft. Therefore, I have upgraded to the latest LTS release. --- .github/workflows/codeql.yml | 2 +- .github/workflows/slow.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index db70001ed7..44a604749a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -88,7 +88,7 @@ jobs: fail-fast: false matrix: language: [ 'csharp' ] - dotnet: [ '3.1.x' ] + dotnet: [ '8.0.x' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 9a22c1f415..a5f007f6bf 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: java: [ '21' ] - dotnet: [ '3.1.301' ] + dotnet: [ '8.0.x' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 From 520cdb1c5eb7156b68a7789819fd4c9e2b332987 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 12 Oct 2023 23:20:21 +0100 Subject: [PATCH 354/805] [C#] Generate DTOs using C# 9+ records. The reason behind this change is to support equality and comparison of DTOs in tests by leveraging records. --- .../sbe/generation/csharp/CSharpDtoGenerator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index e7ceeeb155..ad6c68db38 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -103,7 +103,7 @@ public void generate() throws IOException out.append(generateFileHeader(ir.applicableNamespace(), "using System.Collections.Generic;\n")); out.append(generateDocumentation(BASE_INDENT, msgToken)); - out.append(BASE_INDENT).append("public sealed partial class ").append(className).append("\n") + out.append(BASE_INDENT).append("public sealed partial record ").append(className).append("\n") .append(BASE_INDENT).append("{") .append(sb) .append(BASE_INDENT).append("}\n") @@ -136,7 +136,7 @@ private void generateGroups( sb.append("\n") .append(generateDocumentation(indent, groupToken)) - .append(indent).append("public sealed partial class ").append(groupClassName).append("\n") + .append(indent).append("public sealed partial record ").append(groupClassName).append("\n") .append(indent).append("{"); i++; @@ -1031,7 +1031,7 @@ private void generateComposite(final List tokens) throws IOException generateCompositeEncodeInto(sb, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "Wrap", codecClassName + ".SbeSchemaVersion", BASE_INDENT + INDENT); - out.append(BASE_INDENT).append("public sealed partial class ").append(className).append("\n") + out.append(BASE_INDENT).append("public sealed partial record ").append(className).append("\n") .append(BASE_INDENT).append("{") .append(sb) .append(BASE_INDENT).append("}\n") From c1afd033456fc7d264dad9ce22a188e877271ae4 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Tue, 17 Oct 2023 17:04:37 +0100 Subject: [PATCH 355/805] [C#] Use more-idiomatic null representations. Also, make records immutable, as it is more idiomatic to use `with` expressions. In the future, it may be preferable to declare record fields in the constructor rather than as init-only properties; however, this would be a much larger change. This is the current mapping of optional fields: - Primitives: as nullable value types - Composites: as nullable references - Enums: we already generate a `NULL_VALUE` case and we use that - Bitsets: as a flags enum where `0` is the null value - Strings: as empty string - Arrays: as empty read-only lists --- csharp/sbe-tests/DtoTests.cs | 5 +- .../generation/csharp/CSharpDtoGenerator.java | 286 ++++++++++-------- .../sbe/generation/csharp/CSharpUtil.java | 6 +- .../CSharpDtosPropertyTest/Program.cs | 3 +- .../SbePropertyTest.csproj | 2 +- 5 files changed, 169 insertions(+), 133 deletions(-) diff --git a/csharp/sbe-tests/DtoTests.cs b/csharp/sbe-tests/DtoTests.cs index 99fbcadc74..fcd0007bf7 100644 --- a/csharp/sbe-tests/DtoTests.cs +++ b/csharp/sbe-tests/DtoTests.cs @@ -16,14 +16,13 @@ public void ShouldRoundTripCar() var decoder = new Car(); decoder.WrapForDecode(inputBuffer, 0, Car.BlockLength, Car.SchemaVersion); var decoderString = decoder.ToString(); - var dto = new CarDto(); - dto.DecodeFrom(decoder); + var dto = CarDto.DecodeFrom(decoder); var outputByteArray = new byte[1024]; var outputBuffer = new DirectBuffer(outputByteArray); var encoder = new Car(); encoder.WrapForEncode(outputBuffer, 0); dto.EncodeInto(encoder); - var dtoString = dto.ToString(); + var dtoString = dto.ToSbeString(); CollectionAssert.AreEqual(inputByteArray, outputByteArray); Assert.AreEqual(decoderString, dtoString); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index ad6c68db38..b6ab8638d9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -30,7 +30,6 @@ import java.io.Writer; import java.util.ArrayList; import java.util.List; -import java.util.function.BiConsumer; import static uk.co.real_logic.sbe.generation.csharp.CSharpUtil.*; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; @@ -40,7 +39,6 @@ /** * DTO generator for the CSharp programming language. */ -@SuppressWarnings("CodeBlock2Expr") public class CSharpDtoGenerator implements CodeGenerator { private static final String INDENT = " "; @@ -94,13 +92,17 @@ public void generate() throws IOException collectVarData(messageBody, offset, varData); generateVarData(sb, varData, BASE_INDENT + INDENT); - generateDecodeFrom(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); + generateDecodeFrom(sb, className, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); generateEncodeInto(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "WrapForEncode", null, BASE_INDENT + INDENT); try (Writer out = outputManager.createOutput(className)) { - out.append(generateFileHeader(ir.applicableNamespace(), "using System.Collections.Generic;\n")); + out.append(generateFileHeader( + ir.applicableNamespace(), + "#nullable enable\n\n", + "using System.Collections.Generic;\n", + "using System.Linq;\n")); out.append(generateDocumentation(BASE_INDENT, msgToken)); out.append(BASE_INDENT).append("public sealed partial record ").append(className).append("\n") @@ -130,9 +132,9 @@ private void generateGroups( sb.append("\n") .append(generateDocumentation(indent, groupToken)) - .append(indent).append("public List<").append(groupClassName).append("> ") + .append(indent).append("public IReadOnlyList<").append(groupClassName).append("> ") .append(formatPropertyName(groupName)) - .append(" { get; set; } = new List<").append(groupClassName).append(">();\n"); + .append(" { get; init; }\n"); sb.append("\n") .append(generateDocumentation(indent, groupToken)) @@ -155,7 +157,8 @@ private void generateGroups( i = collectVarData(tokens, i, varData); generateVarData(sb, varData, indent + INDENT); - generateDecodeFrom(sb, codecClassName, fields, groups, varData, indent + INDENT); + generateDecodeListFrom(sb, groupClassName, codecClassName, indent + INDENT); + generateDecodeFrom(sb, groupClassName, codecClassName, fields, groups, varData, indent + INDENT); generateEncodeInto(sb, codecClassName, fields, groups, varData, indent + INDENT); sb.append(indent).append("}\n"); @@ -164,23 +167,29 @@ private void generateGroups( private void generateCompositeDecodeFrom( final StringBuilder sb, + final String dtoClassName, final String codecClassName, final List tokens, final String indent) { sb.append("\n") - .append(indent).append("public void DecodeFrom(").append(codecClassName).append(" codec)\n") + .append(indent).append("public static ").append(dtoClassName).append(" DecodeFrom(") + .append(codecClassName).append(" codec)\n") .append(indent).append("{\n"); + sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("()\n") + .append(indent).append(INDENT).append("{\n"); + for (int i = 0; i < tokens.size(); ) { final Token token = tokens.get(i); - generateFieldDecodeFrom(sb, token, token, codecClassName, indent + INDENT); + generateFieldDecodeFrom(sb, token, token, codecClassName, indent + INDENT + INDENT); i += tokens.get(i).componentTokenCount(); } + sb.append(indent).append(INDENT).append("};\n"); sb.append(indent).append("}\n"); } @@ -198,7 +207,7 @@ private void generateCompositeEncodeInto( { final Token token = tokens.get(i); - generateFieldEncodeInto(sb, token, token, indent + INDENT); + generateFieldEncodeInto(sb, codecClassName, token, token, indent + INDENT); i += tokens.get(i).componentTokenCount(); } @@ -206,8 +215,36 @@ private void generateCompositeEncodeInto( sb.append(indent).append("}\n"); } + private void generateDecodeListFrom( + final StringBuilder sb, + final String dtoClassName, + final String codecClassName, + final String indent) + { + sb.append("\n") + .append(indent).append("public static IReadOnlyList<").append(dtoClassName).append("> DecodeListFrom(") + .append(codecClassName).append(" codec)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("var ").append("list = new List<").append(dtoClassName) + .append(">(codec.Count);\n") + .append(indent).append(INDENT) + .append("while (codec.HasNext)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("var element = ").append(dtoClassName).append(".DecodeFrom(codec.Next());\n") + .append(indent).append(INDENT).append(INDENT) + .append("list.Add(element);\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append(INDENT) + .append("return list.AsReadOnly();\n") + .append(indent).append("}\n"); + } + private void generateDecodeFrom( final StringBuilder sb, + final String dtoClassName, final String codecClassName, final List fields, final List groups, @@ -215,12 +252,16 @@ private void generateDecodeFrom( final String indent) { sb.append("\n") - .append(indent).append("public void DecodeFrom(").append(codecClassName).append(" codec)\n") + .append(indent).append("public static ").append(dtoClassName) + .append(" DecodeFrom(").append(codecClassName).append(" codec)\n") .append(indent).append("{\n"); - generateFieldsDecodeFrom(sb, fields, codecClassName, indent + INDENT); - generateGroupsDecodeFrom(sb, groups, indent + INDENT); - generateVarDataDecodeFrom(sb, varData, indent + INDENT); + sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("()\n") + .append(indent).append(INDENT).append("{\n"); + generateFieldsDecodeFrom(sb, fields, codecClassName, indent + INDENT + INDENT); + generateGroupsDecodeFrom(sb, groups, indent + INDENT + INDENT); + generateVarDataDecodeFrom(sb, varData, indent + INDENT + INDENT); + sb.append(indent).append(INDENT).append("};\n"); sb.append(indent).append("}\n"); } @@ -256,13 +297,13 @@ private void generateFieldDecodeFrom( break; case BEGIN_SET: - generatePropertyDecodeFrom(sb, fieldToken, "0", indent); + generatePropertyDecodeFrom(sb, codecClassName, fieldToken, "0", indent); break; case BEGIN_ENUM: final String enumName = formatClassName(typeToken.applicableTypeName()); final String nullValue = formatNamespace(ir.packageName()) + "." + enumName + ".NULL_VALUE"; - generatePropertyDecodeFrom(sb, fieldToken, nullValue, indent); + generatePropertyDecodeFrom(sb, codecClassName, fieldToken, nullValue, indent); break; case BEGIN_COMPOSITE: @@ -291,7 +332,7 @@ private void generatePrimitiveDecodeFrom( if (arrayLength == 1) { final String nullValue = codecClassName + "." + formatPropertyName(fieldToken.name()) + "NullValue"; - generatePropertyDecodeFrom(sb, fieldToken, nullValue, indent); + generatePropertyDecodeFrom(sb, codecClassName, fieldToken, nullValue, indent); } else if (arrayLength > 1) { @@ -319,44 +360,27 @@ private void generateArrayDecodeFrom( sb, fieldToken, indent, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName) - .append(" = codec.Get").append(formattedPropertyName).append("();\n"); - }, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName).append(" = null;\n"); - } + "codec.Get" + formattedPropertyName + "()", + "null", + null ); } else { - final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); - wrapInActingVersionCheck( sb, fieldToken, indent, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName) - .append(" = new ").append(typeName).append("[") - .append(typeToken.arrayLength()).append("];\n") - .append(blkIndent).append("codec.").append(formattedPropertyName) - .append(".CopyTo(new Span<").append(typeName).append(">(") - .append(formattedPropertyName).append("));\n"); - }, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName).append(" = null;\n"); - } + "codec." + formattedPropertyName + "AsSpan().ToArray()", + "null", + null ); } } private void generatePropertyDecodeFrom( final StringBuilder sb, + final String codecClassName, final Token fieldToken, final String nullValue, final String indent) @@ -374,15 +398,9 @@ private void generatePropertyDecodeFrom( sb, fieldToken, indent, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName).append(" = codec.") - .append(formattedPropertyName).append(";\n"); - }, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName).append(" = ").append(nullValue).append(";\n"); - } + "codec." + formattedPropertyName, + nullValue, + codecClassName + "." + formattedPropertyName + "NullValue" ); } @@ -400,17 +418,9 @@ private void generateComplexDecodeFrom( sb, fieldToken, indent, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName).append(" = new ") - .append(dtoClassName).append("();\n") - .append(blkIndent).append(formattedPropertyName).append(".DecodeFrom(codec.") - .append(formattedPropertyName).append(");\n"); - }, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName).append(" = null;\n"); - } + dtoClassName + ".DecodeFrom(codec." + formattedPropertyName + ")", + "null", + "null" ); } @@ -429,30 +439,13 @@ private void generateGroupsDecodeFrom( final String groupName = groupToken.name(); final String formattedPropertyName = formatPropertyName(groupName); final String groupDtoClassName = formatDtoClassName(groupName); - final String groupCodecVarName = groupName + "Codec"; - - sb.append("\n") - .append(indent) - .append(formattedPropertyName).append(" = new List<").append(groupDtoClassName).append(">();\n"); wrapInActingVersionCheck( sb, groupToken, indent, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append("var ").append(groupCodecVarName).append(" = codec.") - .append(formattedPropertyName).append(";\n") - .append(blkIndent).append("while (").append(groupCodecVarName).append(".HasNext)\n") - .append(blkIndent).append("{\n") - .append(blkIndent).append(INDENT) - .append("var element = new ").append(groupDtoClassName).append("();\n") - .append(blkIndent).append(INDENT) - .append("element.DecodeFrom(").append(groupCodecVarName).append(".Next());\n") - .append(blkIndent).append(INDENT) - .append(formattedPropertyName).append(".Add(element);\n") - .append(blkIndent).append("}\n"); - }, + groupDtoClassName + ".DecodeListFrom(codec." + formattedPropertyName + ")", + "new List<" + groupDtoClassName + ">(0).AsReadOnly()", null ); @@ -493,15 +486,9 @@ private void generateVarDataDecodeFrom( sb, token, indent, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName) - .append(" = codec.").append(accessor).append("();\n"); - }, - (blkSb, blkIndent) -> - { - blkSb.append(blkIndent).append(formattedPropertyName).append(" = null;\n"); - } + "codec." + accessor + "()", + "null", + null ); } } @@ -511,30 +498,31 @@ private void wrapInActingVersionCheck( final StringBuilder sb, final Token token, final String indent, - final BiConsumer generatePresentBlock, - final BiConsumer generateNotPresentBlock) + final String presentExpression, + final String notPresentExpression, + final String nullCodecValueOrNull) { final String propertyName = token.name(); final String formattedPropertyName = formatPropertyName(propertyName); + sb.append(indent).append(formattedPropertyName).append(" = "); + if (token.version() > 0) { - sb.append("\n").append(indent).append("if (codec.").append(formattedPropertyName) - .append("InActingVersion())\n") - .append(indent).append("{\n"); - generatePresentBlock.accept(sb, indent + INDENT); - sb.append(indent).append("}\n"); - if (null != generateNotPresentBlock) + sb.append("codec.").append(formattedPropertyName).append("InActingVersion()"); + + if (null != nullCodecValueOrNull) { - sb.append(indent).append("else\n") - .append(indent).append("{\n"); - generateNotPresentBlock.accept(sb, indent + INDENT); - sb.append(indent).append("}\n"); + sb.append(" && codec.").append(formattedPropertyName).append(" != ").append(nullCodecValueOrNull); } + + sb.append(" ?\n"); + sb.append(indent).append(INDENT).append(presentExpression).append(" :\n") + .append(indent).append(INDENT).append(notPresentExpression).append(",\n"); } else { - generatePresentBlock.accept(sb, indent); + sb.append(presentExpression).append(",\n"); } } @@ -550,7 +538,7 @@ private void generateEncodeInto( .append(indent).append("public void EncodeInto(").append(codecClassName).append(" codec)\n") .append(indent).append("{\n"); - generateFieldsEncodeInto(sb, fields, indent + INDENT); + generateFieldsEncodeInto(sb, codecClassName, fields, indent + INDENT); generateGroupsEncodeInto(sb, groups, indent + INDENT); generateVarDataEncodeInto(sb, varData, indent + INDENT); @@ -559,6 +547,7 @@ private void generateEncodeInto( private void generateFieldsEncodeInto( final StringBuilder sb, + final String codecClassName, final List tokens, final String indent) { @@ -568,13 +557,14 @@ private void generateFieldsEncodeInto( if (signalToken.signal() == Signal.BEGIN_FIELD) { final Token encodingToken = tokens.get(i + 1); - generateFieldEncodeInto(sb, signalToken, encodingToken, indent); + generateFieldEncodeInto(sb, codecClassName, signalToken, encodingToken, indent); } } } private void generateFieldEncodeInto( final StringBuilder sb, + final String codecClassName, final Token fieldToken, final Token typeToken, final String indent) @@ -582,12 +572,12 @@ private void generateFieldEncodeInto( switch (typeToken.signal()) { case ENCODING: - generatePrimitiveEncodeInto(sb, fieldToken, typeToken, indent); + generatePrimitiveEncodeInto(sb, codecClassName, fieldToken, typeToken, indent); break; case BEGIN_SET: case BEGIN_ENUM: - generatePropertyEncodeInto(sb, fieldToken, indent); + generateEnumEncodeInto(sb, fieldToken, indent); break; case BEGIN_COMPOSITE: @@ -601,6 +591,7 @@ private void generateFieldEncodeInto( private void generatePrimitiveEncodeInto( final StringBuilder sb, + final String codecClassName, final Token fieldToken, final Token typeToken, final String indent) @@ -614,7 +605,7 @@ private void generatePrimitiveEncodeInto( if (arrayLength == 1) { - generatePropertyEncodeInto(sb, fieldToken, indent); + generatePropertyEncodeInto(sb, codecClassName, fieldToken, indent); } else if (arrayLength > 1) { @@ -638,19 +629,53 @@ private void generateArrayEncodeInto( if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { + final String value = nullableConvertedExpression(fieldToken, formattedPropertyName, "\"\""); sb.append(indent).append("codec.Set").append(formattedPropertyName).append("(") - .append(formattedPropertyName).append(");\n"); + .append(value).append(");\n"); } else { final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); sb.append(indent).append("new Span<").append(typeName).append(">(").append(formattedPropertyName) - .append(").CopyTo(codec.").append(formattedPropertyName).append("AsSpan());\n"); + .append("?.ToArray()).CopyTo(codec.").append(formattedPropertyName).append("AsSpan());\n"); } } + private String nullableConvertedExpression( + final Token fieldToken, + final String expression, + final String nullValue) + { + return fieldToken.version() > 0 || fieldToken.isOptionalEncoding() ? + expression + " ?? " + nullValue : + expression; + } + private void generatePropertyEncodeInto( + final StringBuilder sb, + final String codecClassName, + final Token fieldToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + final String value = nullableConvertedExpression( + fieldToken, + formattedPropertyName, + codecClassName + "." + formattedPropertyName + "NullValue"); + + sb.append(indent).append("codec.").append(formattedPropertyName).append(" = ") + .append(value).append(";\n"); + } + + private void generateEnumEncodeInto( final StringBuilder sb, final Token fieldToken, final String indent) @@ -743,7 +768,7 @@ private void generateDisplay( final String indent) { sb.append("\n") - .append(indent).append("public override string ToString()\n") + .append(indent).append("public string ToSbeString()\n") .append(indent).append("{\n") .append(indent).append(INDENT) .append("var buffer = new DirectBuffer(new byte[128], (ignored, newSize) => new byte[newSize]);\n") @@ -800,6 +825,11 @@ private void generateFields( } } + private String optionality(final Token fieldToken, final Token typeToken) + { + return fieldToken.isOptionalEncoding() ? "?" : ""; + } + private void generateCompositeProperty( final StringBuilder sb, final String propertyName, @@ -807,11 +837,12 @@ private void generateCompositeProperty( final Token typeToken, final String indent) { - final String bitSetName = formatDtoClassName(typeToken.applicableTypeName()); + final String compositeName = formatDtoClassName(typeToken.applicableTypeName()); sb.append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("public ").append(bitSetName).append(" ").append(formatPropertyName(propertyName)) - .append(" { get; set; } = new ").append(bitSetName).append("();\n"); + .append(indent).append("public ").append(compositeName) + .append(optionality(fieldToken, typeToken)).append(" ").append(formatPropertyName(propertyName)) + .append(" { get; init; }\n"); } private void generateBitSetProperty( @@ -826,7 +857,7 @@ private void generateBitSetProperty( sb.append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("public ").append(enumName).append(" ") - .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); } private void generateEnumProperty( @@ -856,8 +887,8 @@ private void generateEnumProperty( { sb.append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("public ").append(enumName).append(" ").append(formatPropertyName(propertyName)) - .append(" { get; set; }\n"); + .append(indent).append("public ").append(enumName).append(" ") + .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); } } @@ -909,7 +940,7 @@ private void generateArrayProperty( sb.append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("public string ") - .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); } else { @@ -917,8 +948,9 @@ private void generateArrayProperty( sb.append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("public ").append(typeName).append("[] ") - .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + .append(indent).append("public IReadOnlyList<").append(typeName).append(">") + .append(optionality(fieldToken, typeToken)).append(" ") + .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); } } @@ -933,8 +965,9 @@ private void generateSingleValueProperty( sb.append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("public ").append(typeName).append(" ") - .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + .append(indent).append("public ").append(typeName) + .append(optionality(fieldToken, typeToken)).append(" ") + .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); } private void generateConstPropertyMethods( @@ -984,9 +1017,11 @@ private void generateVarData( final String characterEncoding = varDataToken.encoding().characterEncoding(); final String dtoType = characterEncoding == null ? "byte[]" : "string"; + final String optionality = token.version() > 0 ? "?" : ""; + sb.append("\n") .append(indent).append("public ").append(dtoType).append(" ") - .append(formatPropertyName(propertyName)).append(" { get; set; }\n"); + .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); } } } @@ -1020,14 +1055,17 @@ private void generateComposite(final List tokens) throws IOException try (Writer out = outputManager.createOutput(className)) { - out.append(generateFileHeader(ir.applicableNamespace())); + out.append(generateFileHeader(ir.applicableNamespace(), + "#nullable enable\n", + "using System.Collections.Generic;\n", + "using System.Linq;\n")); out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); final StringBuilder sb = new StringBuilder(); final List compositeTokens = tokens.subList(1, tokens.size() - 1); generateCompositePropertyElements(sb, compositeTokens, BASE_INDENT + INDENT); - generateCompositeDecodeFrom(sb, codecClassName, compositeTokens, BASE_INDENT + INDENT); + generateCompositeDecodeFrom(sb, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateCompositeEncodeInto(sb, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "Wrap", codecClassName + ".SbeSchemaVersion", BASE_INDENT + INDENT); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index 124b352629..1fc1cb64b2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -85,20 +85,20 @@ static String generateLiteral(final PrimitiveType type, final String value) return literal; } - static CharSequence generateFileHeader(final String packageName, final String... imports) + static CharSequence generateFileHeader(final String packageName, final String... topLevelStatements) { return String.format( "// \n" + "// Generated SBE (Simple Binary Encoding) message codec\n" + "// \n\n" + "#pragma warning disable 1591 // disable warning on missing comments\n" + + "%1$s" + "using System;\n" + "using System.Text;\n" + - "%1$s" + "using Org.SbeTool.Sbe.Dll;\n\n" + "namespace %2$s\n" + "{\n", - String.join("", imports), + String.join("", topLevelStatements), formatNamespace(packageName)); } diff --git a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs index 1efcf4bfa7..60bdc22616 100644 --- a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs +++ b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs @@ -17,8 +17,7 @@ static int Main(string[] args) { messageHeader.Wrap(buffer, 0, 0); var decoder = new TestMessage(); decoder.WrapForDecode(buffer, 8, messageHeader.BlockLength, messageHeader.Version); - var dto = new TestMessageDto(); - dto.DecodeFrom(decoder); + var dto = TestMessageDto.DecodeFrom(decoder); var outputBytes = new byte[inputBytes.Length]; var outputBuffer = new DirectBuffer(outputBytes); var encoder = new TestMessage(); diff --git a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj index a1bbc69f1c..8b0b167d2b 100644 --- a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj +++ b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net6.0 From 207ab1f3be2e28c9d3aa867f8dedf82191a6ebb9 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 18 Oct 2023 14:23:08 +0100 Subject: [PATCH 356/805] [IR] Change default float and double values to minimum representable values. Previously, we were using the minimum positive value as the `minValue`. --- .../src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java index 27411749b5..0754d9a485 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java @@ -197,7 +197,7 @@ public enum Representation /** * Maximum value representation for a single precision 32-bit floating point type. */ - public static final float MIN_VALUE_FLOAT = Float.MIN_VALUE; + public static final float MIN_VALUE_FLOAT = -Float.MAX_VALUE; /** * Maximum value representation for a single precision 32-bit floating point type. @@ -212,7 +212,7 @@ public enum Representation /** * Minimum value representation for a double precision 64-bit floating point type. */ - public static final double MIN_VALUE_DOUBLE = Double.MIN_VALUE; + public static final double MIN_VALUE_DOUBLE = -Double.MAX_VALUE; /** * Maximum value representation for a double precision 64-bit floating point type. From 4201789439cd009daa73683231485bc6dc0295de Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 18 Oct 2023 15:57:17 +0100 Subject: [PATCH 357/805] [C#] Add validation to DTOs and improve use of records. The aim of these changes are to avoid multiple representations in DTOs and to support read-only views over data. The new validation includes: - Checking null values "idiomatic null values" rather than the reserved null value, to prevent against multiple kinds of null in DTOs. - Checking primitive field values are at least `minValue` and at most `maxValue`. Note that this validation is not applied to fixed-size arrays as the specification says, "Data range attributes minValue and maxValue do not apply", under the "Fixed-length data" section. Records are now immutable. Record expressions, i.e., using `with`, are supported and will apply validation, as we have customised the `init` property accessor. I have not included support for encoding null composite values from DTOs; however, in theory, this could be added later. --- .../generation/csharp/CSharpDtoGenerator.java | 347 ++++++++++++++---- .../arbitraries/SbeArbitraries.java | 7 +- 2 files changed, 278 insertions(+), 76 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index b6ab8638d9..d50030351a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -79,23 +79,26 @@ public void generate() throws IOException int offset = 0; final StringBuilder sb = new StringBuilder(); + final StringBuilder ctorArgs = new StringBuilder(); final List fields = new ArrayList<>(); offset = collectFields(messageBody, offset, fields); - generateFields(sb, fields, BASE_INDENT + INDENT); + generateFields(sb, ctorArgs, codecClassName, fields, BASE_INDENT + INDENT); final List groups = new ArrayList<>(); offset = collectGroups(messageBody, offset, groups); - generateGroups(sb, codecClassName, groups, BASE_INDENT + INDENT); + generateGroups(sb, ctorArgs, className, codecClassName, groups, BASE_INDENT + INDENT); final List varData = new ArrayList<>(); collectVarData(messageBody, offset, varData); - generateVarData(sb, varData, BASE_INDENT + INDENT); + generateVarData(sb, ctorArgs, varData, BASE_INDENT + INDENT); generateDecodeFrom(sb, className, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); generateEncodeInto(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "WrapForEncode", null, BASE_INDENT + INDENT); + removeTrailingComma(ctorArgs); + try (Writer out = outputManager.createOutput(className)) { out.append(generateFileHeader( @@ -105,7 +108,9 @@ public void generate() throws IOException "using System.Linq;\n")); out.append(generateDocumentation(BASE_INDENT, msgToken)); - out.append(BASE_INDENT).append("public sealed partial record ").append(className).append("\n") + out.append(BASE_INDENT).append("public sealed partial record ").append(className).append("(\n") + .append(ctorArgs) + .append(BASE_INDENT).append(")\n") .append(BASE_INDENT).append("{") .append(sb) .append(BASE_INDENT).append("}\n") @@ -116,7 +121,9 @@ public void generate() throws IOException private void generateGroups( final StringBuilder sb, - final String parentMessageClassName, + final StringBuilder ctorArgs, + final String qualifiedParentDtoClassName, + final String qualifiedParentCodecClassName, final List tokens, final String indent) { @@ -130,38 +137,58 @@ private void generateGroups( final String groupName = groupToken.name(); final String groupClassName = formatDtoClassName(groupName); + final String formattedPropertyName = formatPropertyName(groupName); + + ctorArgs.append(indent).append("IReadOnlyList<") + .append(qualifiedParentDtoClassName).append(".").append(groupClassName).append("> ") + .append(formattedPropertyName).append(",\n"); + sb.append("\n") .append(generateDocumentation(indent, groupToken)) .append(indent).append("public IReadOnlyList<").append(groupClassName).append("> ") - .append(formatPropertyName(groupName)) - .append(" { get; init; }\n"); + .append(formattedPropertyName) + .append(" { get; init; } = ").append(formattedPropertyName).append(";\n"); - sb.append("\n") - .append(generateDocumentation(indent, groupToken)) - .append(indent).append("public sealed partial record ").append(groupClassName).append("\n") - .append(indent).append("{"); + final StringBuilder groupCtorArgs = new StringBuilder(); + final StringBuilder groupRecordBody = new StringBuilder(); i++; i += tokens.get(i).componentTokenCount(); + final String qualifiedDtoClassName = qualifiedParentDtoClassName + "." + groupClassName; + final String qualifiedCodecClassName = + qualifiedParentCodecClassName + "." + formatClassName(groupName) + "Group"; + final List fields = new ArrayList<>(); i = collectFields(tokens, i, fields); - generateFields(sb, fields, indent + INDENT); + generateFields(groupRecordBody, groupCtorArgs, qualifiedCodecClassName, fields, indent + INDENT); final List groups = new ArrayList<>(); i = collectGroups(tokens, i, groups); - final String codecClassName = parentMessageClassName + "." + formatClassName(groupName) + "Group"; - generateGroups(sb, codecClassName, groups, indent + INDENT); + generateGroups(groupRecordBody, groupCtorArgs, qualifiedDtoClassName, + qualifiedCodecClassName, groups, indent + INDENT); final List varData = new ArrayList<>(); i = collectVarData(tokens, i, varData); - generateVarData(sb, varData, indent + INDENT); + generateVarData(groupRecordBody, groupCtorArgs, varData, indent + INDENT); - generateDecodeListFrom(sb, groupClassName, codecClassName, indent + INDENT); - generateDecodeFrom(sb, groupClassName, codecClassName, fields, groups, varData, indent + INDENT); - generateEncodeInto(sb, codecClassName, fields, groups, varData, indent + INDENT); + generateDecodeListFrom( + groupRecordBody, groupClassName, qualifiedCodecClassName, indent + INDENT); + generateDecodeFrom( + groupRecordBody, groupClassName, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); + generateEncodeInto( + groupRecordBody, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); - sb.append(indent).append("}\n"); + removeTrailingComma(groupCtorArgs); + + sb.append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("public sealed partial record ").append(groupClassName).append("(\n") + .append(groupCtorArgs) + .append(indent).append(")\n") + .append(indent).append("{\n") + .append(groupRecordBody) + .append(indent).append("}\n"); } } @@ -177,8 +204,7 @@ private void generateCompositeDecodeFrom( .append(codecClassName).append(" codec)\n") .append(indent).append("{\n"); - sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("()\n") - .append(indent).append(INDENT).append("{\n"); + sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("(\n"); for (int i = 0; i < tokens.size(); ) { @@ -189,7 +215,9 @@ private void generateCompositeDecodeFrom( i += tokens.get(i).componentTokenCount(); } - sb.append(indent).append(INDENT).append("};\n"); + removeTrailingComma(sb); + + sb.append(indent).append(INDENT).append(");\n"); sb.append(indent).append("}\n"); } @@ -256,12 +284,12 @@ private void generateDecodeFrom( .append(" DecodeFrom(").append(codecClassName).append(" codec)\n") .append(indent).append("{\n"); - sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("()\n") - .append(indent).append(INDENT).append("{\n"); + sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("(\n"); generateFieldsDecodeFrom(sb, fields, codecClassName, indent + INDENT + INDENT); generateGroupsDecodeFrom(sb, groups, indent + INDENT + INDENT); generateVarDataDecodeFrom(sb, varData, indent + INDENT + INDENT); - sb.append(indent).append(INDENT).append("};\n"); + removeTrailingComma(sb); + sb.append(indent).append(INDENT).append(");\n"); sb.append(indent).append("}\n"); } @@ -297,13 +325,13 @@ private void generateFieldDecodeFrom( break; case BEGIN_SET: - generatePropertyDecodeFrom(sb, codecClassName, fieldToken, "0", indent); + generatePropertyDecodeFrom(sb, fieldToken, "0", null, indent); break; case BEGIN_ENUM: final String enumName = formatClassName(typeToken.applicableTypeName()); final String nullValue = formatNamespace(ir.packageName()) + "." + enumName + ".NULL_VALUE"; - generatePropertyDecodeFrom(sb, codecClassName, fieldToken, nullValue, indent); + generatePropertyDecodeFrom(sb, fieldToken, nullValue, null, indent); break; case BEGIN_COMPOSITE: @@ -331,8 +359,8 @@ private void generatePrimitiveDecodeFrom( if (arrayLength == 1) { - final String nullValue = codecClassName + "." + formatPropertyName(fieldToken.name()) + "NullValue"; - generatePropertyDecodeFrom(sb, codecClassName, fieldToken, nullValue, indent); + final String codecNullValue = codecClassName + "." + formatPropertyName(fieldToken.name()) + "NullValue"; + generatePropertyDecodeFrom(sb, fieldToken, "null", codecNullValue, indent); } else if (arrayLength > 1) { @@ -356,7 +384,7 @@ private void generateArrayDecodeFrom( if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { - wrapInActingVersionCheck( + generateRecordPropertyAssignment( sb, fieldToken, indent, @@ -367,7 +395,7 @@ private void generateArrayDecodeFrom( } else { - wrapInActingVersionCheck( + generateRecordPropertyAssignment( sb, fieldToken, indent, @@ -380,12 +408,11 @@ private void generateArrayDecodeFrom( private void generatePropertyDecodeFrom( final StringBuilder sb, - final String codecClassName, final Token fieldToken, - final String nullValue, + final String dtoNullValue, + final String codecNullValue, final String indent) { - if (fieldToken.isConstantEncoding()) { return; @@ -394,13 +421,13 @@ private void generatePropertyDecodeFrom( final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); - wrapInActingVersionCheck( + generateRecordPropertyAssignment( sb, fieldToken, indent, "codec." + formattedPropertyName, - nullValue, - codecClassName + "." + formattedPropertyName + "NullValue" + dtoNullValue, + codecNullValue ); } @@ -414,7 +441,7 @@ private void generateComplexDecodeFrom( final String formattedPropertyName = formatPropertyName(propertyName); final String dtoClassName = formatDtoClassName(typeToken.applicableTypeName()); - wrapInActingVersionCheck( + generateRecordPropertyAssignment( sb, fieldToken, indent, @@ -440,7 +467,7 @@ private void generateGroupsDecodeFrom( final String formattedPropertyName = formatPropertyName(groupName); final String groupDtoClassName = formatDtoClassName(groupName); - wrapInActingVersionCheck( + generateRecordPropertyAssignment( sb, groupToken, indent, @@ -482,7 +509,7 @@ private void generateVarDataDecodeFrom( "Get" + formattedPropertyName + "Bytes" : "Get" + formattedPropertyName; - wrapInActingVersionCheck( + generateRecordPropertyAssignment( sb, token, indent, @@ -494,7 +521,7 @@ private void generateVarDataDecodeFrom( } } - private void wrapInActingVersionCheck( + private void generateRecordPropertyAssignment( final StringBuilder sb, final Token token, final String indent, @@ -505,7 +532,7 @@ private void wrapInActingVersionCheck( final String propertyName = token.name(); final String formattedPropertyName = formatPropertyName(propertyName); - sb.append(indent).append(formattedPropertyName).append(" = "); + sb.append(indent).append(formattedPropertyName).append(": "); if (token.version() > 0) { @@ -699,6 +726,17 @@ private void generateComplexEncodeInto( { final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); + + if (fieldToken.isOptionalEncoding()) + { + sb.append(indent).append("if (null == ").append(formattedPropertyName).append(")\n") + .append(indent).append("{") + .append(indent).append(INDENT).append("throw new System.InvalidOperationException(\"") + .append("Null composite value encoding (").append(formattedPropertyName) + .append(") is not supported via DTOs\");\n") + .append(indent).append("}\n\n"); + } + sb.append(indent).append(formattedPropertyName).append(".EncodeInto(codec.") .append(formattedPropertyName).append(");\n"); } @@ -789,6 +827,8 @@ private void generateDisplay( private void generateFields( final StringBuilder sb, + final StringBuilder ctorArgs, + final String codecClassName, final List tokens, final String indent) { @@ -803,19 +843,20 @@ private void generateFields( switch (encodingToken.signal()) { case ENCODING: - generatePrimitiveProperty(sb, propertyName, signalToken, encodingToken, indent); + generatePrimitiveProperty( + sb, ctorArgs, codecClassName, propertyName, signalToken, encodingToken, indent); break; case BEGIN_ENUM: - generateEnumProperty(sb, propertyName, signalToken, encodingToken, indent); + generateEnumProperty(sb, ctorArgs, propertyName, signalToken, encodingToken, indent); break; case BEGIN_SET: - generateBitSetProperty(sb, propertyName, signalToken, encodingToken, indent); + generateBitSetProperty(sb, ctorArgs, propertyName, signalToken, encodingToken, indent); break; case BEGIN_COMPOSITE: - generateCompositeProperty(sb, propertyName, signalToken, encodingToken, indent); + generateCompositeProperty(sb, ctorArgs, propertyName, signalToken, encodingToken, indent); break; default: @@ -825,28 +866,30 @@ private void generateFields( } } - private String optionality(final Token fieldToken, final Token typeToken) - { - return fieldToken.isOptionalEncoding() ? "?" : ""; - } - private void generateCompositeProperty( final StringBuilder sb, + final StringBuilder ctorArgs, final String propertyName, final Token fieldToken, final Token typeToken, final String indent) { final String compositeName = formatDtoClassName(typeToken.applicableTypeName()); + final String nullableSuffix = fieldToken.isOptionalEncoding() ? "?" : ""; + final String formattedPropertyName = formatPropertyName(propertyName); + + ctorArgs.append(indent).append(compositeName).append(" ").append(formattedPropertyName).append(",\n"); + sb.append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("public ").append(compositeName) - .append(optionality(fieldToken, typeToken)).append(" ").append(formatPropertyName(propertyName)) - .append(" { get; init; }\n"); + .append(nullableSuffix).append(" ").append(formattedPropertyName) + .append(" { get; init; } = ").append(formattedPropertyName).append(";\n"); } private void generateBitSetProperty( final StringBuilder sb, + final StringBuilder ctorArgs, final String propertyName, final Token fieldToken, final Token typeToken, @@ -854,14 +897,20 @@ private void generateBitSetProperty( { final String enumName = formatClassName(typeToken.applicableTypeName()); + final String formattedPropertyName = formatPropertyName(propertyName); + + ctorArgs.append(indent).append(enumName).append(" ").append(formattedPropertyName).append(",\n"); + sb.append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("public ").append(enumName).append(" ") - .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); + .append(formattedPropertyName).append(" { get; init; } = ") + .append(formattedPropertyName).append(";\n"); } private void generateEnumProperty( final StringBuilder sb, + final StringBuilder ctorArgs, final String propertyName, final Token fieldToken, final Token typeToken, @@ -869,6 +918,8 @@ private void generateEnumProperty( { final String enumName = formatClassName(typeToken.applicableTypeName()); + final String formattedPropertyName = formatPropertyName(propertyName); + if (fieldToken.isConstantEncoding()) { final String constValue = fieldToken.encoding().constValue().toString(); @@ -876,7 +927,7 @@ private void generateEnumProperty( sb.append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("public static ").append(enumName).append(" ") - .append(formatPropertyName(propertyName)).append("\n") + .append(formattedPropertyName).append("\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("get { return ") .append(formatNamespace(ir.packageName())).append(".").append(constValue) @@ -885,15 +936,19 @@ private void generateEnumProperty( } else { + ctorArgs.append(indent).append(enumName).append(" ").append(formattedPropertyName).append(",\n"); + sb.append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("public ").append(enumName).append(" ") - .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); + .append(formattedPropertyName).append(" { get; init; } = ").append(formattedPropertyName).append(";\n"); } } private void generatePrimitiveProperty( final StringBuilder sb, + final StringBuilder ctorArgs, + final String codecClassName, final String propertyName, final Token fieldToken, final Token typeToken, @@ -905,12 +960,14 @@ private void generatePrimitiveProperty( } else { - generatePrimitivePropertyMethods(sb, propertyName, fieldToken, typeToken, indent); + generatePrimitivePropertyMethods(sb, ctorArgs, codecClassName, propertyName, fieldToken, typeToken, indent); } } private void generatePrimitivePropertyMethods( final StringBuilder sb, + final StringBuilder ctorArgs, + final String codecClassName, final String propertyName, final Token fieldToken, final Token typeToken, @@ -920,54 +977,162 @@ private void generatePrimitivePropertyMethods( if (arrayLength == 1) { - generateSingleValueProperty(sb, propertyName, fieldToken, typeToken, indent); + generateSingleValueProperty(sb, ctorArgs, codecClassName, propertyName, fieldToken, typeToken, indent); } else if (arrayLength > 1) { - generateArrayProperty(sb, propertyName, fieldToken, typeToken, indent); + generateArrayProperty(sb, ctorArgs, codecClassName, propertyName, fieldToken, typeToken, indent); } } private void generateArrayProperty( final StringBuilder sb, + final StringBuilder ctorArgs, + final String codecClassName, final String propertyName, final Token fieldToken, final Token typeToken, final String indent) { + final String formattedPropertyName = formatPropertyName(propertyName); + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { + ctorArgs.append(indent).append("string ").append(formattedPropertyName).append(",\n"); + sb.append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("public string ") - .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); + .append(formattedPropertyName).append(" { get; init; } = ") + .append(formattedPropertyName).append(";\n"); } else { final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); + final String fieldName = "_" + toLowerFirstChar(propertyName); + final String nullableSuffix = fieldToken.isOptionalEncoding() ? "?" : ""; + final String listTypeName = "IReadOnlyList<" + typeName + ">" + nullableSuffix; + + ctorArgs.append(indent).append(listTypeName).append(" ").append(formattedPropertyName).append(",\n"); + + sb.append("\n") + .append(indent).append("private ").append(listTypeName).append(" ").append(fieldName) + .append(" = Validate").append(formattedPropertyName).append("(").append(formattedPropertyName) + .append(");\n"); sb.append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("public IReadOnlyList<").append(typeName).append(">") - .append(optionality(fieldToken, typeToken)).append(" ") - .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); + .append(indent).append("public ").append(listTypeName).append(" ") + .append(formattedPropertyName).append("\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("get => ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("init => ").append(fieldName).append(" = Validate") + .append(formattedPropertyName).append("(value);\n") + .append(indent).append("}\n"); + + sb.append("\n") + .append(indent).append("private static ").append(listTypeName).append(" Validate") + .append(formattedPropertyName).append("(").append(listTypeName).append(" value)\n") + .append(indent).append("{\n"); + + if (fieldToken.isOptionalEncoding()) + { + sb.append(indent).append(INDENT) + .append("if (value == null)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("return null;\n") + .append(indent).append(INDENT) + .append("}\n"); + } + + sb.append(indent).append(INDENT) + .append("if (value.Count > ").append(codecClassName).append(".") + .append(formattedPropertyName).append("Length)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw new ArgumentException(\"too many elements: \" + value.Count);\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append(INDENT) + .append("return value;\n") + .append(indent).append("}\n"); } } private void generateSingleValueProperty( final StringBuilder sb, + final StringBuilder ctorArgs, + final String codecClassName, final String propertyName, final Token fieldToken, final Token typeToken, final String indent) { - final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); + final String nullableSuffix = fieldToken.isOptionalEncoding() ? "?" : ""; + final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()) + nullableSuffix; + final String formattedPropertyName = formatPropertyName(propertyName); + final String fieldName = "_" + toLowerFirstChar(propertyName); + + ctorArgs.append(indent).append(typeName).append(" ").append(formattedPropertyName).append(",\n"); + + sb.append("\n") + .append(indent).append("private ").append(typeName).append(" ").append(fieldName) + .append(" = Validate").append(formattedPropertyName) + .append("(").append(formattedPropertyName).append(");\n"); sb.append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("public ").append(typeName) - .append(optionality(fieldToken, typeToken)).append(" ") - .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); + .append(indent).append("public ").append(typeName).append(" ") + .append(formattedPropertyName).append("\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("get => ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("init => ").append(fieldName).append(" = Validate") + .append(formattedPropertyName).append("(value);\n") + .append(indent).append("}\n"); + + sb.append("\n") + .append(indent).append("private static ").append(typeName).append(" Validate") + .append(formattedPropertyName).append("(").append(typeName).append(" value)\n") + .append(indent).append("{\n"); + + if (fieldToken.isOptionalEncoding()) + { + sb.append(indent).append(INDENT) + .append("if (value == null)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("return null;\n") + .append(indent).append(INDENT) + .append("}\n"); + + sb.append(indent).append(INDENT) + .append("if (value == ").append(codecClassName).append(".") + .append(formattedPropertyName).append("NullValue)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw new ArgumentException(\"null value is reserved: \" + value);\n") + .append(indent).append(INDENT) + .append("}\n"); + } + + sb.append(indent).append(INDENT) + .append("if (value < ") + .append(codecClassName).append(".").append(formattedPropertyName).append("MinValue || value > ") + .append(codecClassName).append(".").append(formattedPropertyName).append("MaxValue)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw new ArgumentException(\"value is out of allowed range: \" + value);\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append(INDENT) + .append("return value;\n") + .append(indent).append("}\n"); } private void generateConstPropertyMethods( @@ -1004,6 +1169,7 @@ private void generateConstPropertyMethods( private void generateVarData( final StringBuilder sb, + final StringBuilder ctorArgs, final List tokens, final String indent) { @@ -1017,11 +1183,14 @@ private void generateVarData( final String characterEncoding = varDataToken.encoding().characterEncoding(); final String dtoType = characterEncoding == null ? "byte[]" : "string"; - final String optionality = token.version() > 0 ? "?" : ""; + final String formattedPropertyName = formatPropertyName(propertyName); + + ctorArgs.append(indent).append(dtoType).append(" ").append(formattedPropertyName).append(",\n"); sb.append("\n") .append(indent).append("public ").append(dtoType).append(" ") - .append(formatPropertyName(propertyName)).append(" { get; init; }\n"); + .append(formattedPropertyName).append(" { get; init; } = ") + .append(formattedPropertyName).append(";\n"); } } } @@ -1062,14 +1231,19 @@ private void generateComposite(final List tokens) throws IOException out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); final StringBuilder sb = new StringBuilder(); + final StringBuilder ctorArgs = new StringBuilder(); final List compositeTokens = tokens.subList(1, tokens.size() - 1); - generateCompositePropertyElements(sb, compositeTokens, BASE_INDENT + INDENT); + generateCompositePropertyElements(sb, ctorArgs, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateCompositeDecodeFrom(sb, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateCompositeEncodeInto(sb, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "Wrap", codecClassName + ".SbeSchemaVersion", BASE_INDENT + INDENT); - out.append(BASE_INDENT).append("public sealed partial record ").append(className).append("\n") + removeTrailingComma(ctorArgs); + + out.append(BASE_INDENT).append("public sealed partial record ").append(className).append("(\n") + .append(ctorArgs) + .append(BASE_INDENT).append(")\n") .append(BASE_INDENT).append("{") .append(sb) .append(BASE_INDENT).append("}\n") @@ -1077,8 +1251,31 @@ private void generateComposite(final List tokens) throws IOException } } + private static void removeTrailingComma(final StringBuilder ctorArgs) + { + if (ctorArgs.length() < 2) + { + return; + } + + if (ctorArgs.charAt(ctorArgs.length() - 1) != '\n') + { + return; + } + + if (ctorArgs.charAt(ctorArgs.length() - 2) != ',') + { + return; + } + + ctorArgs.setLength(ctorArgs.length() - 2); + ctorArgs.append("\n"); + } + private void generateCompositePropertyElements( final StringBuilder sb, + final StringBuilder ctorArgs, + final String codecClassName, final List tokens, final String indent) { @@ -1090,19 +1287,19 @@ private void generateCompositePropertyElements( switch (token.signal()) { case ENCODING: - generatePrimitiveProperty(sb, propertyName, token, token, indent); + generatePrimitiveProperty(sb, ctorArgs, codecClassName, propertyName, token, token, indent); break; case BEGIN_ENUM: - generateEnumProperty(sb, propertyName, token, token, indent); + generateEnumProperty(sb, ctorArgs, propertyName, token, token, indent); break; case BEGIN_SET: - generateBitSetProperty(sb, propertyName, token, token, indent); + generateBitSetProperty(sb, ctorArgs, propertyName, token, token, indent); break; case BEGIN_COMPOSITE: - generateCompositeProperty(sb, propertyName, token, token, indent); + generateCompositeProperty(sb, ctorArgs, propertyName, token, token, indent); break; default: diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index 2e3db4bda0..b1b025d4d9 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -324,7 +324,12 @@ private static Arbitrary encodedTypeEncoder( case UINT64: return Arbitraries.longs() - .map(l -> (buffer, offset, limit) -> buffer.putLong(offset, l, encoding.byteOrder())); + .map(l -> (buffer, offset, limit) -> + { + final long nullValue = encoding.applicableNullValue().longValue(); + final long nonNullValue = l == nullValue ? minValue.longValue() : l; + buffer.putLong(offset, nonNullValue, encoding.byteOrder()); + }); case INT64: assert minValue.longValue() <= maxValue.longValue(); From bc17a46ba35ed5c8adc175d95fac952325be14d5 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 18 Oct 2023 16:57:47 +0100 Subject: [PATCH 358/805] [C#] Support DTO generation via system property. Previously, you had to pass the `CSharpDtos` FQN as the `TargetCodeGenerator` when running sbe-tool; however, that means the XML schema was parsed multiple times, as DTOs depend on flyweights, which seems wasteful. Therefore, I have introduced a system property, `sbe.csharp.generate.dtos` that also controls the generation of DTOs when targetting `CSharp`. --- .../sbe/generation/csharp/CSharp.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java index 157309f319..8a88cbce56 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java @@ -26,14 +26,30 @@ */ public class CSharp implements TargetCodeGenerator { + private static final boolean GENERATE_DTOS = Boolean.getBoolean("sbe.csharp.generate.dtos"); + /** * {@inheritDoc} */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new CSharpGenerator( + final CSharpGenerator flyweightGenerator = new CSharpGenerator( ir, TargetCodeGeneratorLoader.precedenceChecks(), new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); + + if (GENERATE_DTOS) + { + final CSharpDtoGenerator dtoGenerator = + new CSharpDtoGenerator(ir, new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); + + return () -> + { + flyweightGenerator.generate(); + dtoGenerator.generate(); + }; + } + + return flyweightGenerator; } } From 248eae90e8c67111e1888a7f7fd9dec0c90a9da2 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 19 Oct 2023 16:49:33 +0100 Subject: [PATCH 359/805] [C#] Extend tests to cover extended schemas. These tests showed some deficiencies in the DTO generation. For example, added variable-length data was not represented as nullable nor properly handled in `EncodeInto(...)`. During this work, I noticed composite "field" tokens (i.e., types) take their `token.version()` from their containing message/group field. I had to adjust some code that was using `token.version() > 0` to determine whether a field had been added, as this only works with message/group fields. --- .../generation/csharp/CSharpDtoGenerator.java | 87 ++++++++++++++----- .../properties/CSharpDtosPropertyTest.java | 11 +++ .../arbitraries/SbeArbitraries.java | 55 +++++++++--- .../sbe/properties/schema/FieldSchema.java | 11 ++- .../sbe/properties/schema/GroupSchema.java | 10 ++- .../sbe/properties/schema/MessageSchema.java | 35 +++++++- .../schema/TestXmlSchemaWriter.java | 3 + .../sbe/properties/schema/VarDataSchema.java | 10 ++- 8 files changed, 184 insertions(+), 38 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index d50030351a..9335295663 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -93,8 +93,8 @@ public void generate() throws IOException collectVarData(messageBody, offset, varData); generateVarData(sb, ctorArgs, varData, BASE_INDENT + INDENT); - generateDecodeFrom(sb, className, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); - generateEncodeInto(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); + generateMessageDecodeFrom(sb, className, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); + generateMessageEncodeInto(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "WrapForEncode", null, BASE_INDENT + INDENT); removeTrailingComma(ctorArgs); @@ -119,6 +119,12 @@ public void generate() throws IOException } } + private enum DefinitionKind + { + Composite, + Message + } + private void generateGroups( final StringBuilder sb, final StringBuilder ctorArgs, @@ -174,9 +180,9 @@ private void generateGroups( generateDecodeListFrom( groupRecordBody, groupClassName, qualifiedCodecClassName, indent + INDENT); - generateDecodeFrom( + generateMessageDecodeFrom( groupRecordBody, groupClassName, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); - generateEncodeInto( + generateMessageEncodeInto( groupRecordBody, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); removeTrailingComma(groupCtorArgs); @@ -210,7 +216,8 @@ private void generateCompositeDecodeFrom( { final Token token = tokens.get(i); - generateFieldDecodeFrom(sb, token, token, codecClassName, indent + INDENT + INDENT); + generateFieldDecodeFrom( + sb, DefinitionKind.Composite, token, token, codecClassName, indent + INDENT + INDENT); i += tokens.get(i).componentTokenCount(); } @@ -270,7 +277,7 @@ private void generateDecodeListFrom( .append(indent).append("}\n"); } - private void generateDecodeFrom( + private void generateMessageDecodeFrom( final StringBuilder sb, final String dtoClassName, final String codecClassName, @@ -285,7 +292,7 @@ private void generateDecodeFrom( .append(indent).append("{\n"); sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("(\n"); - generateFieldsDecodeFrom(sb, fields, codecClassName, indent + INDENT + INDENT); + generateMessageFieldsDecodeFrom(sb, fields, codecClassName, indent + INDENT + INDENT); generateGroupsDecodeFrom(sb, groups, indent + INDENT + INDENT); generateVarDataDecodeFrom(sb, varData, indent + INDENT + INDENT); removeTrailingComma(sb); @@ -294,7 +301,7 @@ private void generateDecodeFrom( sb.append(indent).append("}\n"); } - private void generateFieldsDecodeFrom( + private void generateMessageFieldsDecodeFrom( final StringBuilder sb, final List tokens, final String codecClassName, @@ -307,35 +314,37 @@ private void generateFieldsDecodeFrom( { final Token encodingToken = tokens.get(i + 1); - generateFieldDecodeFrom(sb, signalToken, encodingToken, codecClassName, indent); + generateFieldDecodeFrom(sb, DefinitionKind.Message, signalToken, encodingToken, codecClassName, indent); } } } private void generateFieldDecodeFrom( final StringBuilder sb, + final DefinitionKind rootKind, final Token fieldToken, final Token typeToken, - final String codecClassName, final String indent) + final String codecClassName, + final String indent) { switch (typeToken.signal()) { case ENCODING: - generatePrimitiveDecodeFrom(sb, fieldToken, typeToken, codecClassName, indent); + generatePrimitiveDecodeFrom(sb, rootKind, fieldToken, typeToken, codecClassName, indent); break; case BEGIN_SET: - generatePropertyDecodeFrom(sb, fieldToken, "0", null, indent); + generatePropertyDecodeFrom(sb, rootKind, fieldToken, "0", null, indent); break; case BEGIN_ENUM: final String enumName = formatClassName(typeToken.applicableTypeName()); final String nullValue = formatNamespace(ir.packageName()) + "." + enumName + ".NULL_VALUE"; - generatePropertyDecodeFrom(sb, fieldToken, nullValue, null, indent); + generatePropertyDecodeFrom(sb, rootKind, fieldToken, nullValue, null, indent); break; case BEGIN_COMPOSITE: - generateComplexDecodeFrom(sb, fieldToken, typeToken, indent); + generateComplexDecodeFrom(sb, rootKind, fieldToken, typeToken, indent); break; default: @@ -345,6 +354,7 @@ private void generateFieldDecodeFrom( private void generatePrimitiveDecodeFrom( final StringBuilder sb, + final DefinitionKind rootKind, final Token fieldToken, final Token typeToken, final String codecClassName, @@ -360,16 +370,17 @@ private void generatePrimitiveDecodeFrom( if (arrayLength == 1) { final String codecNullValue = codecClassName + "." + formatPropertyName(fieldToken.name()) + "NullValue"; - generatePropertyDecodeFrom(sb, fieldToken, "null", codecNullValue, indent); + generatePropertyDecodeFrom(sb, rootKind, fieldToken, "null", codecNullValue, indent); } else if (arrayLength > 1) { - generateArrayDecodeFrom(sb, fieldToken, typeToken, indent); + generateArrayDecodeFrom(sb, rootKind, fieldToken, typeToken, indent); } } private void generateArrayDecodeFrom( final StringBuilder sb, + final DefinitionKind rootKind, final Token fieldToken, final Token typeToken, final String indent) @@ -386,6 +397,7 @@ private void generateArrayDecodeFrom( { generateRecordPropertyAssignment( sb, + rootKind, fieldToken, indent, "codec.Get" + formattedPropertyName + "()", @@ -397,6 +409,7 @@ private void generateArrayDecodeFrom( { generateRecordPropertyAssignment( sb, + rootKind, fieldToken, indent, "codec." + formattedPropertyName + "AsSpan().ToArray()", @@ -408,6 +421,7 @@ private void generateArrayDecodeFrom( private void generatePropertyDecodeFrom( final StringBuilder sb, + final DefinitionKind rootKind, final Token fieldToken, final String dtoNullValue, final String codecNullValue, @@ -423,6 +437,7 @@ private void generatePropertyDecodeFrom( generateRecordPropertyAssignment( sb, + rootKind, fieldToken, indent, "codec." + formattedPropertyName, @@ -433,6 +448,7 @@ private void generatePropertyDecodeFrom( private void generateComplexDecodeFrom( final StringBuilder sb, + final DefinitionKind rootKind, final Token fieldToken, final Token typeToken, final String indent) @@ -443,6 +459,7 @@ private void generateComplexDecodeFrom( generateRecordPropertyAssignment( sb, + rootKind, fieldToken, indent, dtoClassName + ".DecodeFrom(codec." + formattedPropertyName + ")", @@ -469,6 +486,7 @@ private void generateGroupsDecodeFrom( generateRecordPropertyAssignment( sb, + DefinitionKind.Message, groupToken, indent, groupDtoClassName + ".DecodeListFrom(codec." + formattedPropertyName + ")", @@ -511,6 +529,7 @@ private void generateVarDataDecodeFrom( generateRecordPropertyAssignment( sb, + DefinitionKind.Message, token, indent, "codec." + accessor + "()", @@ -523,6 +542,7 @@ private void generateVarDataDecodeFrom( private void generateRecordPropertyAssignment( final StringBuilder sb, + final DefinitionKind rootKind, final Token token, final String indent, final String presentExpression, @@ -534,8 +554,20 @@ private void generateRecordPropertyAssignment( sb.append(indent).append(formattedPropertyName).append(": "); - if (token.version() > 0) + // N.B., in the IR, the composite information is "embedded" into each message/group field. + // When we are looking at a composite "field" (i.e., a type) the `token.version()` method + // returns the "sinceVersion" of the containing field. Therefore, we cannot decide presence + // based on `token.version()` when dealing with composites. + if (rootKind.equals(DefinitionKind.Message) && token.version() > 0) { + if (token.signal() != Signal.BEGIN_VAR_DATA && !token.isOptionalEncoding()) + { + throw new IllegalStateException( + "Expected added field " + propertyName + + " (sinceVersion=" + token.version() + ") to have optional presence." + ); + } + sb.append("codec.").append(formattedPropertyName).append("InActingVersion()"); if (null != nullCodecValueOrNull) @@ -553,7 +585,7 @@ private void generateRecordPropertyAssignment( } } - private void generateEncodeInto( + private void generateMessageEncodeInto( final StringBuilder sb, final String codecClassName, final List fields, @@ -674,7 +706,7 @@ private String nullableConvertedExpression( final String expression, final String nullValue) { - return fieldToken.version() > 0 || fieldToken.isOptionalEncoding() ? + return fieldToken.isOptionalEncoding() ? expression + " ?? " + nullValue : expression; } @@ -791,9 +823,19 @@ private void generateVarDataEncodeInto( if (token.signal() == Signal.BEGIN_VAR_DATA) { final String propertyName = token.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (token.version() > 0) + { + sb.append(indent).append("if (null == ").append(formattedPropertyName).append(")\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("throw new System.InvalidOperationException(\"") + .append(formattedPropertyName).append(" must not be null.\");\n") + .append(indent).append("}\n\n"); + } - sb.append(indent).append("codec.Set").append(formatPropertyName(propertyName)) - .append("(").append(formatPropertyName(propertyName)).append(");\n"); + sb.append(indent).append("codec.Set").append(formattedPropertyName) + .append("(").append(formattedPropertyName).append(");\n"); } } } @@ -1181,7 +1223,8 @@ private void generateVarData( final String propertyName = token.name(); final Token varDataToken = Generators.findFirst("varData", tokens, i); final String characterEncoding = varDataToken.encoding().characterEncoding(); - final String dtoType = characterEncoding == null ? "byte[]" : "string"; + final String nullableSuffix = token.version() > 0 ? "?" : ""; + final String dtoType = (characterEncoding == null ? "byte[]" : "string") + nullableSuffix; final String formattedPropertyName = formatPropertyName(propertyName); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java index 7a4dde3f49..8a8be0fdde 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java @@ -89,6 +89,17 @@ void dtoEncodeShouldBeTheInverseOfDtoDecode( "SCHEMA:\n" + encodedMessage.schema()); } + final byte[] errorBytes = Files.readAllBytes(stderr); + if (errorBytes.length != 0) + { + throw new AssertionError( + "Process wrote to stderr.\n\n" + + "STDOUT:\n" + new String(Files.readAllBytes(stdout)) + "\n\n" + + "STDERR:\n" + new String(errorBytes) + "\n\n" + + "SCHEMA:\n" + encodedMessage.schema() + "\n\n" + ); + } + final byte[] inputBytes = new byte[encodedMessage.length()]; encodedMessage.buffer().getBytes(0, inputBytes); final byte[] outputBytes = Files.readAllBytes(tempDir.resolve("output.dat")); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index b1b025d4d9..13f027fb30 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -192,6 +192,37 @@ private static Arbitrary typeSchema(final int depth) } } + private static Arbitrary addedField() + { + return Combinators.combine( + typeSchema(MAX_COMPOSITE_DEPTH), + Arbitraries.of(Encoding.Presence.OPTIONAL), + Arbitraries.of((short)1, (short)2) + ).as(FieldSchema::new); + } + + private static Arbitrary originalField() + { + return Combinators.combine( + typeSchema(MAX_COMPOSITE_DEPTH), + presence(), + Arbitraries.of((short)0) + ).as(FieldSchema::new); + } + + private static Arbitrary skewedFieldDistribution() + { + final Arbitrary originalField = originalField(); + final Arbitrary addedField = addedField(); + + return Arbitraries.oneOf( + originalField, + originalField, + originalField, + addedField + ); + } + private static Arbitrary groupSchema(final int depth) { final Arbitrary> subGroups = depth == 1 ? @@ -201,10 +232,7 @@ private static Arbitrary groupSchema(final int depth) return Combinators.combine( withDuplicates( 2, - Combinators.combine( - typeSchema(MAX_COMPOSITE_DEPTH), - presence() - ).as(FieldSchema::new).list().ofMaxSize(5) + skewedFieldDistribution().list().ofMaxSize(5) ), subGroups, varDataSchema().list().ofMaxSize(3) @@ -227,6 +255,13 @@ private static Arbitrary varDataSchema() PrimitiveType.UINT8, PrimitiveType.UINT16, PrimitiveType.UINT32 + ), + Arbitraries.of( + (short)0, + (short)0, + (short)0, + (short)1, + (short)2 ) ).as(VarDataSchema::new); } @@ -236,10 +271,7 @@ public static Arbitrary messageSchema() return Combinators.combine( withDuplicates( 3, - Combinators.combine( - typeSchema(MAX_COMPOSITE_DEPTH), - presence() - ).as(FieldSchema::new).list().ofMaxSize(10) + skewedFieldDistribution().list().ofMaxSize(10) ), groupSchema(MAX_GROUP_DEPTH).list().ofMaxSize(3), varDataSchema().list().ofMaxSize(3) @@ -747,7 +779,7 @@ public static Arbitrary messageValueEncoder( buffer.putShort(0, (short)blockLength, ir.byteOrder()); buffer.putShort(2, messageId, ir.byteOrder()); buffer.putShort(4, (short)ir.id(), ir.byteOrder()); - buffer.putShort(6, (short)0, ir.byteOrder()); + buffer.putShort(6, (short)ir.version(), ir.byteOrder()); final int headerLength = 8; fields.encode(buffer, offset + headerLength, null); limit.set(offset + headerLength + blockLength); @@ -821,7 +853,10 @@ public static Arbitrary encodedMessage(final CharGenerationMode } catch (final Exception e) { - throw new RuntimeException(e); + throw new AssertionError( + "Failed to generate encoded value for schema.\n\n" + + "SCHEMA:\n" + xml, + e); } }).withoutEdgeCases(); } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java index 406ee65cdd..c1fad8abc4 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java @@ -22,14 +22,18 @@ public final class FieldSchema { private final TypeSchema type; private final Encoding.Presence presence; + private final short sinceVersion; public FieldSchema( final TypeSchema type, - final Encoding.Presence presence + final Encoding.Presence presence, + final short sinceVersion ) { + assert sinceVersion == 0 || presence.equals(Encoding.Presence.OPTIONAL); this.type = type; this.presence = presence; + this.sinceVersion = sinceVersion; } public TypeSchema type() @@ -41,4 +45,9 @@ public Encoding.Presence presence() { return presence; } + + public short sinceVersion() + { + return sinceVersion; + } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java index 53c3c81df7..47cfe343a7 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java @@ -16,7 +16,9 @@ package uk.co.real_logic.sbe.properties.schema; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; public final class GroupSchema { @@ -29,9 +31,13 @@ public GroupSchema( final List groups, final List varData) { - this.blockFields = blockFields; + this.blockFields = blockFields.stream() + .sorted(Comparator.comparing(FieldSchema::sinceVersion)) + .collect(Collectors.toList()); this.groups = groups; - this.varData = varData; + this.varData = varData.stream() + .sorted(Comparator.comparing(VarDataSchema::sinceVersion)) + .collect(Collectors.toList()); } public List blockFields() diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java index a0decb2d6b..2095628c39 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java @@ -16,13 +16,16 @@ package uk.co.real_logic.sbe.properties.schema; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; public final class MessageSchema { private final List blockFields; private final List groups; private final List varData; + private final short version; public MessageSchema( final List blockFields, @@ -30,9 +33,14 @@ public MessageSchema( final List varData ) { - this.blockFields = blockFields; + this.blockFields = blockFields.stream() + .sorted(Comparator.comparing(FieldSchema::sinceVersion)) + .collect(Collectors.toList()); this.groups = groups; - this.varData = varData; + this.varData = varData.stream() + .sorted(Comparator.comparing(VarDataSchema::sinceVersion)) + .collect(Collectors.toList()); + this.version = findMaxVersion(blockFields, groups, varData); } public short schemaId() @@ -45,6 +53,11 @@ public short templateId() return 1; } + public short version() + { + return version; + } + public List blockFields() { return blockFields; @@ -59,4 +72,22 @@ public List varData() { return varData; } + + private static short findMaxVersion( + final List fields, + final List groups, + final List varData + ) + { + final int maxFieldVersion = fields.stream() + .mapToInt(FieldSchema::sinceVersion) + .max().orElse(0); + final int maxGroupVersion = groups.stream() + .mapToInt(group -> findMaxVersion(group.blockFields(), group.groups(), group.varData())) + .max().orElse(0); + final int maxVarDataVersion = varData.stream() + .mapToInt(VarDataSchema::sinceVersion) + .max().orElse(0); + return (short)Math.max(maxFieldVersion, Math.max(maxGroupVersion, maxVarDataVersion)); + } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index 7ccd273017..3c43228099 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -70,6 +70,7 @@ private static void writeTo( final Element root = document.createElementNS("http://fixprotocol.io/2016/sbe", "sbe:messageSchema"); root.setAttribute("id", Short.toString(schema.schemaId())); root.setAttribute("package", "uk.co.real_logic.sbe.properties"); + root.setAttribute("version", Short.toString(schema.version())); document.appendChild(root); final Element topLevelTypes = createTypesElement(document); @@ -152,6 +153,7 @@ private static void appendMembers( element.setAttribute("name", "member" + id); element.setAttribute("type", typeName); element.setAttribute("presence", field.presence().name().toLowerCase()); + element.setAttribute("sinceVersion", Short.toString(field.sinceVersion())); parent.appendChild(element); } @@ -180,6 +182,7 @@ private static void appendMembers( element.setAttribute("id", Integer.toString(id)); element.setAttribute("name", "member" + id); element.setAttribute("type", requireNonNull(typeToName.get(data))); + element.setAttribute("sinceVersion", Short.toString(data.sinceVersion())); parent.appendChild(element); } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java index b5e98c02c7..db3d5900a1 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java @@ -22,13 +22,16 @@ public final class VarDataSchema { private final Encoding dataEncoding; private final PrimitiveType lengthEncoding; + private final short sinceVersion; public VarDataSchema( final Encoding dataEncoding, - final PrimitiveType lengthEncoding) + final PrimitiveType lengthEncoding, + final short sinceVersion) { this.dataEncoding = dataEncoding; this.lengthEncoding = lengthEncoding; + this.sinceVersion = sinceVersion; } public Encoding dataEncoding() @@ -41,6 +44,11 @@ public PrimitiveType lengthEncoding() return lengthEncoding; } + public short sinceVersion() + { + return sinceVersion; + } + public enum Encoding { ASCII, From 7ee92651a2471aa7ee4fe087283397c4ac5b697d Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 9 Nov 2023 15:25:34 +0000 Subject: [PATCH 360/805] [C#] Address some of Martin's feedback re "added" var data representation. The SBE spec doesn't explicitly allow variable-length data or groups to be added to existing message schemas, i.e., only block-level fields may be added; however in practice the encoders/decoders for some languages do support the addition of var data fields. Previously, I had represented these "added" var data fields as optional strings or byte arrays, but having chatted with Martin, we think it is better to mimick the existing decoder representation, i.e., use empty strings/arrays to represent missing elements. In this commit, I've also fixed some instances where I was checking `token.version() > 0` where I should have been checking `token.version() > sinceVersionOfParentContainer`. Ideally, I would have liked to remove such checks entirely, but the C# and C++ codecs do not give sensible responses when decoding older versions in some cases, i.e., you _must_ check the presence of the field before accessing it. --- .../generation/csharp/CSharpDtoGenerator.java | 196 ++++++++++-------- .../properties/CSharpDtosPropertyTest.java | 19 +- .../arbitraries/SbeArbitraries.java | 14 +- 3 files changed, 131 insertions(+), 98 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index 9335295663..6f25151a56 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -30,6 +30,7 @@ import java.io.Writer; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import static uk.co.real_logic.sbe.generation.csharp.CSharpUtil.*; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; @@ -43,6 +44,7 @@ public class CSharpDtoGenerator implements CodeGenerator { private static final String INDENT = " "; private static final String BASE_INDENT = INDENT; + private static final Predicate CANNOT_EXTEND = ignored -> false; private final Ir ir; private final OutputManager outputManager; @@ -93,8 +95,10 @@ public void generate() throws IOException collectVarData(messageBody, offset, varData); generateVarData(sb, ctorArgs, varData, BASE_INDENT + INDENT); - generateMessageDecodeFrom(sb, className, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); - generateMessageEncodeInto(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); + generateDecodeFrom(sb, className, codecClassName, fields, groups, varData, + token -> token.version() > msgToken.version(), + BASE_INDENT + INDENT); + generateEncodeInto(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "WrapForEncode", null, BASE_INDENT + INDENT); removeTrailingComma(ctorArgs); @@ -119,12 +123,6 @@ public void generate() throws IOException } } - private enum DefinitionKind - { - Composite, - Message - } - private void generateGroups( final StringBuilder sb, final StringBuilder ctorArgs, @@ -142,9 +140,15 @@ private void generateGroups( } final String groupName = groupToken.name(); final String groupClassName = formatDtoClassName(groupName); - final String formattedPropertyName = formatPropertyName(groupName); + final Token dimToken = tokens.get(i + 1); + if (dimToken.signal() != Signal.BEGIN_COMPOSITE) + { + throw new IllegalStateException("groups must start with BEGIN_COMPOSITE: token=" + dimToken); + } + final int sinceVersion = dimToken.version(); + ctorArgs.append(indent).append("IReadOnlyList<") .append(qualifiedParentDtoClassName).append(".").append(groupClassName).append("> ") .append(formattedPropertyName).append(",\n"); @@ -167,22 +171,40 @@ private void generateGroups( final List fields = new ArrayList<>(); i = collectFields(tokens, i, fields); + generateFields(groupRecordBody, groupCtorArgs, qualifiedCodecClassName, fields, indent + INDENT); final List groups = new ArrayList<>(); i = collectGroups(tokens, i, groups); + generateGroups(groupRecordBody, groupCtorArgs, qualifiedDtoClassName, qualifiedCodecClassName, groups, indent + INDENT); final List varData = new ArrayList<>(); i = collectVarData(tokens, i, varData); + generateVarData(groupRecordBody, groupCtorArgs, varData, indent + INDENT); generateDecodeListFrom( groupRecordBody, groupClassName, qualifiedCodecClassName, indent + INDENT); - generateMessageDecodeFrom( - groupRecordBody, groupClassName, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); - generateMessageEncodeInto( + + final Predicate wasAddedAfterGroup = token -> + { + final boolean addedAfterParent = token.version() > sinceVersion; + + if (addedAfterParent && token.signal() == Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("Cannot extend var data inside a group."); + } + + return addedAfterParent; + }; + + generateDecodeFrom( + groupRecordBody, groupClassName, qualifiedCodecClassName, fields, groups, varData, + wasAddedAfterGroup, indent + INDENT); + + generateEncodeInto( groupRecordBody, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); removeTrailingComma(groupCtorArgs); @@ -217,7 +239,7 @@ private void generateCompositeDecodeFrom( final Token token = tokens.get(i); generateFieldDecodeFrom( - sb, DefinitionKind.Composite, token, token, codecClassName, indent + INDENT + INDENT); + sb, CANNOT_EXTEND, token, token, codecClassName, indent + INDENT + INDENT); i += tokens.get(i).componentTokenCount(); } @@ -277,13 +299,14 @@ private void generateDecodeListFrom( .append(indent).append("}\n"); } - private void generateMessageDecodeFrom( + private void generateDecodeFrom( final StringBuilder sb, final String dtoClassName, final String codecClassName, final List fields, final List groups, final List varData, + final Predicate wasAddedAfterParent, final String indent) { sb.append("\n") @@ -292,9 +315,9 @@ private void generateMessageDecodeFrom( .append(indent).append("{\n"); sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("(\n"); - generateMessageFieldsDecodeFrom(sb, fields, codecClassName, indent + INDENT + INDENT); + generateMessageFieldsDecodeFrom(sb, wasAddedAfterParent, fields, codecClassName, indent + INDENT + INDENT); generateGroupsDecodeFrom(sb, groups, indent + INDENT + INDENT); - generateVarDataDecodeFrom(sb, varData, indent + INDENT + INDENT); + generateVarDataDecodeFrom(sb, varData, wasAddedAfterParent, indent + INDENT + INDENT); removeTrailingComma(sb); sb.append(indent).append(INDENT).append(");\n"); @@ -303,6 +326,7 @@ private void generateMessageDecodeFrom( private void generateMessageFieldsDecodeFrom( final StringBuilder sb, + final Predicate wasAddedAfterParent, final List tokens, final String codecClassName, final String indent) @@ -314,14 +338,15 @@ private void generateMessageFieldsDecodeFrom( { final Token encodingToken = tokens.get(i + 1); - generateFieldDecodeFrom(sb, DefinitionKind.Message, signalToken, encodingToken, codecClassName, indent); + generateFieldDecodeFrom( + sb, wasAddedAfterParent, signalToken, encodingToken, codecClassName, indent); } } } private void generateFieldDecodeFrom( final StringBuilder sb, - final DefinitionKind rootKind, + final Predicate wasAddedAfterParent, final Token fieldToken, final Token typeToken, final String codecClassName, @@ -330,21 +355,21 @@ private void generateFieldDecodeFrom( switch (typeToken.signal()) { case ENCODING: - generatePrimitiveDecodeFrom(sb, rootKind, fieldToken, typeToken, codecClassName, indent); + generatePrimitiveDecodeFrom(sb, fieldToken, typeToken, wasAddedAfterParent, codecClassName, indent); break; case BEGIN_SET: - generatePropertyDecodeFrom(sb, rootKind, fieldToken, "0", null, indent); + generatePropertyDecodeFrom(sb, fieldToken, wasAddedAfterParent, "0", null, indent); break; case BEGIN_ENUM: final String enumName = formatClassName(typeToken.applicableTypeName()); final String nullValue = formatNamespace(ir.packageName()) + "." + enumName + ".NULL_VALUE"; - generatePropertyDecodeFrom(sb, rootKind, fieldToken, nullValue, null, indent); + generatePropertyDecodeFrom(sb, fieldToken, wasAddedAfterParent, nullValue, null, indent); break; case BEGIN_COMPOSITE: - generateComplexDecodeFrom(sb, rootKind, fieldToken, typeToken, indent); + generateComplexDecodeFrom(sb, fieldToken, typeToken, indent); break; default: @@ -354,9 +379,9 @@ private void generateFieldDecodeFrom( private void generatePrimitiveDecodeFrom( final StringBuilder sb, - final DefinitionKind rootKind, final Token fieldToken, final Token typeToken, + final Predicate wasAddedAfterParent, final String codecClassName, final String indent) { @@ -370,19 +395,19 @@ private void generatePrimitiveDecodeFrom( if (arrayLength == 1) { final String codecNullValue = codecClassName + "." + formatPropertyName(fieldToken.name()) + "NullValue"; - generatePropertyDecodeFrom(sb, rootKind, fieldToken, "null", codecNullValue, indent); + generatePropertyDecodeFrom(sb, fieldToken, wasAddedAfterParent, "null", codecNullValue, indent); } else if (arrayLength > 1) { - generateArrayDecodeFrom(sb, rootKind, fieldToken, typeToken, indent); + generateArrayDecodeFrom(sb, fieldToken, typeToken, wasAddedAfterParent, indent); } } private void generateArrayDecodeFrom( final StringBuilder sb, - final DefinitionKind rootKind, final Token fieldToken, final Token typeToken, + final Predicate wasAddedAfterParent, final String indent) { if (fieldToken.isConstantEncoding()) @@ -397,8 +422,8 @@ private void generateArrayDecodeFrom( { generateRecordPropertyAssignment( sb, - rootKind, fieldToken, + wasAddedAfterParent, indent, "codec.Get" + formattedPropertyName + "()", "null", @@ -409,8 +434,8 @@ private void generateArrayDecodeFrom( { generateRecordPropertyAssignment( sb, - rootKind, fieldToken, + wasAddedAfterParent, indent, "codec." + formattedPropertyName + "AsSpan().ToArray()", "null", @@ -421,8 +446,8 @@ private void generateArrayDecodeFrom( private void generatePropertyDecodeFrom( final StringBuilder sb, - final DefinitionKind rootKind, final Token fieldToken, + final Predicate wasAddedAfterParent, final String dtoNullValue, final String codecNullValue, final String indent) @@ -437,8 +462,8 @@ private void generatePropertyDecodeFrom( generateRecordPropertyAssignment( sb, - rootKind, fieldToken, + wasAddedAfterParent, indent, "codec." + formattedPropertyName, dtoNullValue, @@ -448,7 +473,6 @@ private void generatePropertyDecodeFrom( private void generateComplexDecodeFrom( final StringBuilder sb, - final DefinitionKind rootKind, final Token fieldToken, final Token typeToken, final String indent) @@ -457,15 +481,9 @@ private void generateComplexDecodeFrom( final String formattedPropertyName = formatPropertyName(propertyName); final String dtoClassName = formatDtoClassName(typeToken.applicableTypeName()); - generateRecordPropertyAssignment( - sb, - rootKind, - fieldToken, - indent, - dtoClassName + ".DecodeFrom(codec." + formattedPropertyName + ")", - "null", - "null" - ); + sb.append(indent).append(formattedPropertyName).append(": ") + .append(dtoClassName).append(".DecodeFrom(codec.") + .append(formattedPropertyName).append(")").append(",\n"); } private void generateGroupsDecodeFrom( @@ -484,10 +502,17 @@ private void generateGroupsDecodeFrom( final String formattedPropertyName = formatPropertyName(groupName); final String groupDtoClassName = formatDtoClassName(groupName); + final Token dimToken = tokens.get(i + 1); + if (dimToken.signal() != Signal.BEGIN_COMPOSITE) + { + throw new IllegalStateException("groups must start with BEGIN_COMPOSITE: token=" + dimToken); + } + final int sinceVersion = dimToken.version(); + generateRecordPropertyAssignment( sb, - DefinitionKind.Message, groupToken, + token -> token.version() > sinceVersion, indent, groupDtoClassName + ".DecodeListFrom(codec." + formattedPropertyName + ")", "new List<" + groupDtoClassName + ">(0).AsReadOnly()", @@ -511,6 +536,7 @@ private void generateGroupsDecodeFrom( private void generateVarDataDecodeFrom( final StringBuilder sb, final List tokens, + final Predicate wasAddedAfterParent, final String indent) { for (int i = 0; i < tokens.size(); i++) @@ -526,24 +552,32 @@ private void generateVarDataDecodeFrom( final String accessor = characterEncoding == null ? "Get" + formattedPropertyName + "Bytes" : "Get" + formattedPropertyName; + final String missingValue = characterEncoding == null ? + "new byte[0]" : + "\"\""; + + sb.append(indent).append(formattedPropertyName).append(": "); - generateRecordPropertyAssignment( - sb, - DefinitionKind.Message, - token, - indent, - "codec." + accessor + "()", - "null", - null - ); + if (wasAddedAfterParent.test(token)) + { + sb.append("codec.").append(formattedPropertyName).append("InActingVersion()"); + sb.append(" ?\n"); + sb.append(indent).append(INDENT).append("codec.").append(accessor).append("()") + .append(" :\n") + .append(indent).append(INDENT).append(missingValue).append(",\n"); + } + else + { + sb.append("codec.").append(accessor).append("()").append(",\n"); + } } } } private void generateRecordPropertyAssignment( final StringBuilder sb, - final DefinitionKind rootKind, final Token token, + final Predicate wasAddedAfterParent, final String indent, final String presentExpression, final String notPresentExpression, @@ -554,27 +588,29 @@ private void generateRecordPropertyAssignment( sb.append(indent).append(formattedPropertyName).append(": "); - // N.B., in the IR, the composite information is "embedded" into each message/group field. - // When we are looking at a composite "field" (i.e., a type) the `token.version()` method - // returns the "sinceVersion" of the containing field. Therefore, we cannot decide presence - // based on `token.version()` when dealing with composites. - if (rootKind.equals(DefinitionKind.Message) && token.version() > 0) - { - if (token.signal() != Signal.BEGIN_VAR_DATA && !token.isOptionalEncoding()) - { - throw new IllegalStateException( - "Expected added field " + propertyName + - " (sinceVersion=" + token.version() + ") to have optional presence." - ); - } + boolean hasPresenceCondition = false; + // Unfortunately, we need to check whether the field is in the acting version, + // as the codec may incorrectly decode data for missing fields. + if (wasAddedAfterParent.test(token)) + { sb.append("codec.").append(formattedPropertyName).append("InActingVersion()"); + hasPresenceCondition = true; + } - if (null != nullCodecValueOrNull) + if (token.isOptionalEncoding() && null != nullCodecValueOrNull) + { + if (hasPresenceCondition) { - sb.append(" && codec.").append(formattedPropertyName).append(" != ").append(nullCodecValueOrNull); + sb.append(" && "); } + sb.append("codec.").append(formattedPropertyName).append(" != ").append(nullCodecValueOrNull); + hasPresenceCondition = true; + } + + if (hasPresenceCondition) + { sb.append(" ?\n"); sb.append(indent).append(INDENT).append(presentExpression).append(" :\n") .append(indent).append(INDENT).append(notPresentExpression).append(",\n"); @@ -585,7 +621,7 @@ private void generateRecordPropertyAssignment( } } - private void generateMessageEncodeInto( + private void generateEncodeInto( final StringBuilder sb, final String codecClassName, final List fields, @@ -758,17 +794,6 @@ private void generateComplexEncodeInto( { final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); - - if (fieldToken.isOptionalEncoding()) - { - sb.append(indent).append("if (null == ").append(formattedPropertyName).append(")\n") - .append(indent).append("{") - .append(indent).append(INDENT).append("throw new System.InvalidOperationException(\"") - .append("Null composite value encoding (").append(formattedPropertyName) - .append(") is not supported via DTOs\");\n") - .append(indent).append("}\n\n"); - } - sb.append(indent).append(formattedPropertyName).append(".EncodeInto(codec.") .append(formattedPropertyName).append(");\n"); } @@ -825,15 +850,6 @@ private void generateVarDataEncodeInto( final String propertyName = token.name(); final String formattedPropertyName = formatPropertyName(propertyName); - if (token.version() > 0) - { - sb.append(indent).append("if (null == ").append(formattedPropertyName).append(")\n") - .append(indent).append("{\n") - .append(indent).append(INDENT).append("throw new System.InvalidOperationException(\"") - .append(formattedPropertyName).append(" must not be null.\");\n") - .append(indent).append("}\n\n"); - } - sb.append(indent).append("codec.Set").append(formattedPropertyName) .append("(").append(formattedPropertyName).append(");\n"); } @@ -917,7 +933,6 @@ private void generateCompositeProperty( final String indent) { final String compositeName = formatDtoClassName(typeToken.applicableTypeName()); - final String nullableSuffix = fieldToken.isOptionalEncoding() ? "?" : ""; final String formattedPropertyName = formatPropertyName(propertyName); ctorArgs.append(indent).append(compositeName).append(" ").append(formattedPropertyName).append(",\n"); @@ -925,7 +940,7 @@ private void generateCompositeProperty( sb.append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("public ").append(compositeName) - .append(nullableSuffix).append(" ").append(formattedPropertyName) + .append(" ").append(formattedPropertyName) .append(" { get; init; } = ").append(formattedPropertyName).append(";\n"); } @@ -1223,8 +1238,7 @@ private void generateVarData( final String propertyName = token.name(); final Token varDataToken = Generators.findFirst("varData", tokens, i); final String characterEncoding = varDataToken.encoding().characterEncoding(); - final String nullableSuffix = token.version() > 0 ? "?" : ""; - final String dtoType = (characterEncoding == null ? "byte[]" : "string") + nullableSuffix; + final String dtoType = characterEncoding == null ? "byte[]" : "string"; final String formattedPropertyName = formatPropertyName(propertyName); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java index 8a8be0fdde..701ca2fcf4 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java @@ -50,10 +50,21 @@ void dtoEncodeShouldBeTheInverseOfDtoDecode( tempDir.toString(), "SbePropertyTest" ); - new CSharpGenerator(encodedMessage.ir(), outputManager) - .generate(); - new CSharpDtoGenerator(encodedMessage.ir(), outputManager) - .generate(); + + try + { + new CSharpGenerator(encodedMessage.ir(), outputManager) + .generate(); + new CSharpDtoGenerator(encodedMessage.ir(), outputManager) + .generate(); + } + catch (final Exception generationException) + { + throw new AssertionError( + "Code generation failed.\n\nSCHEMA:\n" + encodedMessage.schema(), + generationException); + } + copyResourceToFile("/CSharpDtosPropertyTest/SbePropertyTest.csproj", tempDir); copyResourceToFile("/CSharpDtosPropertyTest/Program.cs", tempDir); try ( diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index 13f027fb30..25207cdf96 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -21,6 +21,7 @@ import net.jqwik.api.Combinators; import net.jqwik.api.arbitraries.CharacterArbitrary; import net.jqwik.api.arbitraries.ListArbitrary; +import net.jqwik.api.arbitraries.ShortArbitrary; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.PrimitiveValue; import uk.co.real_logic.sbe.ir.Encoding; @@ -235,7 +236,7 @@ private static Arbitrary groupSchema(final int depth) skewedFieldDistribution().list().ofMaxSize(5) ), subGroups, - varDataSchema().list().ofMaxSize(3) + varDataSchema(Arbitraries.of((short)0)).list().ofMaxSize(3) ).as(GroupSchema::new); } @@ -247,7 +248,7 @@ private static Arbitrary presence() ); } - private static Arbitrary varDataSchema() + private static Arbitrary varDataSchema(final Arbitrary sinceVersion) { return Combinators.combine( Arbitraries.of(VarDataSchema.Encoding.values()), @@ -256,6 +257,13 @@ private static Arbitrary varDataSchema() PrimitiveType.UINT16, PrimitiveType.UINT32 ), + sinceVersion + ).as(VarDataSchema::new); + } + + private static Arbitrary varDataSchema() + { + return varDataSchema( Arbitraries.of( (short)0, (short)0, @@ -263,7 +271,7 @@ private static Arbitrary varDataSchema() (short)1, (short)2 ) - ).as(VarDataSchema::new); + ); } public static Arbitrary messageSchema() From 1b98e1de06346eb350045fd6bdb253774e15a22d Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 10 Nov 2023 19:06:29 +0000 Subject: [PATCH 361/805] [C#] Address feedback around encode/decode methods. This commit addresses some feedback from Martin: - Makes encode and decode methods static - Improves naming: - `EncodeInto(codec)` -> `EncodeWith` - `DecodeFrom(codec)` -> `DecodeWith` - Introduces version that works directly with buffer --- csharp/sbe-tests/DtoTests.cs | 27 ++- .../generation/csharp/CSharpDtoGenerator.java | 215 ++++++++++++------ .../CSharpDtosPropertyTest/Program.cs | 4 +- 3 files changed, 163 insertions(+), 83 deletions(-) diff --git a/csharp/sbe-tests/DtoTests.cs b/csharp/sbe-tests/DtoTests.cs index fcd0007bf7..1986db5738 100644 --- a/csharp/sbe-tests/DtoTests.cs +++ b/csharp/sbe-tests/DtoTests.cs @@ -8,29 +8,42 @@ namespace Org.SbeTool.Sbe.Tests public class DtoTests { [TestMethod] - public void ShouldRoundTripCar() + public void ShouldRoundTripCar1() { var inputByteArray = new byte[1024]; var inputBuffer = new DirectBuffer(inputByteArray); - EncodeCar(inputBuffer); + EncodeCar(inputBuffer, 0); var decoder = new Car(); decoder.WrapForDecode(inputBuffer, 0, Car.BlockLength, Car.SchemaVersion); var decoderString = decoder.ToString(); - var dto = CarDto.DecodeFrom(decoder); + var dto = CarDto.DecodeWith(decoder); var outputByteArray = new byte[1024]; var outputBuffer = new DirectBuffer(outputByteArray); var encoder = new Car(); encoder.WrapForEncode(outputBuffer, 0); - dto.EncodeInto(encoder); + CarDto.EncodeWith(encoder, dto); var dtoString = dto.ToSbeString(); CollectionAssert.AreEqual(inputByteArray, outputByteArray); Assert.AreEqual(decoderString, dtoString); } + + [TestMethod] + public void ShouldRoundTripCar2() + { + var inputByteArray = new byte[1024]; + var inputBuffer = new DirectBuffer(inputByteArray); + var length = EncodeCar(inputBuffer, 0); + var dto = CarDto.DecodeFrom(inputBuffer, 0, length, Car.BlockLength, Car.SchemaVersion); + var outputByteArray = new byte[1024]; + var outputBuffer = new DirectBuffer(outputByteArray); + CarDto.EncodeInto(outputBuffer, 0, dto); + CollectionAssert.AreEqual(inputByteArray, outputByteArray); + } - private static void EncodeCar(DirectBuffer buffer) + private static int EncodeCar(DirectBuffer buffer, int offset) { var car = new Car(); - car.WrapForEncode(buffer, 0); + car.WrapForEncode(buffer, offset); car.SerialNumber = 1234; car.ModelYear = 2013; car.Available = BooleanType.T; @@ -104,6 +117,8 @@ private static void EncodeCar(DirectBuffer buffer) car.SetManufacturer("Ford"); car.SetModel("Fiesta"); car.SetActivationCode("1234"); + + return car.Limit - offset; } } } \ No newline at end of file diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index 6f25151a56..a132e751d6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -75,7 +75,7 @@ public void generate() throws IOException { final Token msgToken = tokens.get(0); final String codecClassName = formatClassName(msgToken.name()); - final String className = formatDtoClassName(msgToken.name()); + final String dtoClassName = formatDtoClassName(msgToken.name()); final List messageBody = tokens.subList(1, tokens.size() - 1); int offset = 0; @@ -89,21 +89,24 @@ public void generate() throws IOException final List groups = new ArrayList<>(); offset = collectGroups(messageBody, offset, groups); - generateGroups(sb, ctorArgs, className, codecClassName, groups, BASE_INDENT + INDENT); + generateGroups(sb, ctorArgs, dtoClassName, codecClassName, groups, BASE_INDENT + INDENT); final List varData = new ArrayList<>(); collectVarData(messageBody, offset, varData); generateVarData(sb, ctorArgs, varData, BASE_INDENT + INDENT); - generateDecodeFrom(sb, className, codecClassName, fields, groups, varData, + generateDecodeWith(sb, dtoClassName, codecClassName, fields, groups, varData, token -> token.version() > msgToken.version(), BASE_INDENT + INDENT); - generateEncodeInto(sb, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); + generateDecodeFrom(sb, dtoClassName, codecClassName, BASE_INDENT + INDENT); + generateEncodeWith(sb, dtoClassName, codecClassName, fields, groups, varData, + BASE_INDENT + INDENT); + generateEncodeInto(sb, dtoClassName, codecClassName, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "WrapForEncode", null, BASE_INDENT + INDENT); removeTrailingComma(ctorArgs); - try (Writer out = outputManager.createOutput(className)) + try (Writer out = outputManager.createOutput(dtoClassName)) { out.append(generateFileHeader( ir.applicableNamespace(), @@ -112,7 +115,7 @@ public void generate() throws IOException "using System.Linq;\n")); out.append(generateDocumentation(BASE_INDENT, msgToken)); - out.append(BASE_INDENT).append("public sealed partial record ").append(className).append("(\n") + out.append(BASE_INDENT).append("public sealed partial record ").append(dtoClassName).append("(\n") .append(ctorArgs) .append(BASE_INDENT).append(")\n") .append(BASE_INDENT).append("{") @@ -185,7 +188,7 @@ private void generateGroups( generateVarData(groupRecordBody, groupCtorArgs, varData, indent + INDENT); - generateDecodeListFrom( + generateDecodeListWith( groupRecordBody, groupClassName, qualifiedCodecClassName, indent + INDENT); final Predicate wasAddedAfterGroup = token -> @@ -200,12 +203,13 @@ private void generateGroups( return addedAfterParent; }; - generateDecodeFrom( + generateDecodeWith( groupRecordBody, groupClassName, qualifiedCodecClassName, fields, groups, varData, wasAddedAfterGroup, indent + INDENT); - generateEncodeInto( - groupRecordBody, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); + generateEncodeWith( + groupRecordBody, groupClassName, qualifiedCodecClassName, fields, groups, varData, + indent + INDENT); removeTrailingComma(groupCtorArgs); @@ -220,7 +224,7 @@ private void generateGroups( } } - private void generateCompositeDecodeFrom( + private void generateCompositeDecodeWith( final StringBuilder sb, final String dtoClassName, final String codecClassName, @@ -228,7 +232,7 @@ private void generateCompositeDecodeFrom( final String indent) { sb.append("\n") - .append(indent).append("public static ").append(dtoClassName).append(" DecodeFrom(") + .append(indent).append("public static ").append(dtoClassName).append(" DecodeWith(") .append(codecClassName).append(" codec)\n") .append(indent).append("{\n"); @@ -238,7 +242,7 @@ private void generateCompositeDecodeFrom( { final Token token = tokens.get(i); - generateFieldDecodeFrom( + generateFieldDecodeWith( sb, CANNOT_EXTEND, token, token, codecClassName, indent + INDENT + INDENT); i += tokens.get(i).componentTokenCount(); @@ -250,21 +254,24 @@ private void generateCompositeDecodeFrom( sb.append(indent).append("}\n"); } - private void generateCompositeEncodeInto( + private void generateCompositeEncodeWith( final StringBuilder sb, + final String dtoClassName, final String codecClassName, final List tokens, final String indent) { sb.append("\n") - .append(indent).append("public void EncodeInto(").append(codecClassName).append(" codec)\n") + .append(indent).append("public static void EncodeWith(") + .append(codecClassName).append(" codec, ") + .append(dtoClassName).append(" dto)\n") .append(indent).append("{\n"); for (int i = 0; i < tokens.size(); ) { final Token token = tokens.get(i); - generateFieldEncodeInto(sb, codecClassName, token, token, indent + INDENT); + generateFieldEncodeWith(sb, codecClassName, token, token, indent + INDENT); i += tokens.get(i).componentTokenCount(); } @@ -272,14 +279,14 @@ private void generateCompositeEncodeInto( sb.append(indent).append("}\n"); } - private void generateDecodeListFrom( + private void generateDecodeListWith( final StringBuilder sb, final String dtoClassName, final String codecClassName, final String indent) { sb.append("\n") - .append(indent).append("public static IReadOnlyList<").append(dtoClassName).append("> DecodeListFrom(") + .append(indent).append("public static IReadOnlyList<").append(dtoClassName).append("> DecodeListWith(") .append(codecClassName).append(" codec)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("var ").append("list = new List<").append(dtoClassName) @@ -289,7 +296,7 @@ private void generateDecodeListFrom( .append(indent).append(INDENT) .append("{\n") .append(indent).append(INDENT).append(INDENT) - .append("var element = ").append(dtoClassName).append(".DecodeFrom(codec.Next());\n") + .append("var element = ").append(dtoClassName).append(".DecodeWith(codec.Next());\n") .append(indent).append(INDENT).append(INDENT) .append("list.Add(element);\n") .append(indent).append(INDENT) @@ -299,7 +306,7 @@ private void generateDecodeListFrom( .append(indent).append("}\n"); } - private void generateDecodeFrom( + private void generateDecodeWith( final StringBuilder sb, final String dtoClassName, final String codecClassName, @@ -311,20 +318,40 @@ private void generateDecodeFrom( { sb.append("\n") .append(indent).append("public static ").append(dtoClassName) - .append(" DecodeFrom(").append(codecClassName).append(" codec)\n") + .append(" DecodeWith(").append(codecClassName).append(" codec)\n") .append(indent).append("{\n"); sb.append(indent).append(INDENT).append("return new ").append(dtoClassName).append("(\n"); - generateMessageFieldsDecodeFrom(sb, wasAddedAfterParent, fields, codecClassName, indent + INDENT + INDENT); - generateGroupsDecodeFrom(sb, groups, indent + INDENT + INDENT); - generateVarDataDecodeFrom(sb, varData, wasAddedAfterParent, indent + INDENT + INDENT); + generateMessageFieldsDecodeWith(sb, wasAddedAfterParent, fields, codecClassName, indent + INDENT + INDENT); + generateGroupsDecodeWith(sb, groups, indent + INDENT + INDENT); + generateVarDataDecodeWith(sb, varData, wasAddedAfterParent, indent + INDENT + INDENT); removeTrailingComma(sb); sb.append(indent).append(INDENT).append(");\n"); sb.append(indent).append("}\n"); } - private void generateMessageFieldsDecodeFrom( + private void generateDecodeFrom( + final StringBuilder sb, + final String dtoClassName, + final String codecClassName, + final String indent) + { + sb.append("\n") + .append(indent).append("public static ").append(dtoClassName) + .append(" DecodeFrom(DirectBuffer buffer, int offset, int length, ") + .append("int actingBlockLength, int actingVersion)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT) + .append("var decoder = new ").append(codecClassName).append("();\n") + .append(indent).append(INDENT) + .append("decoder.WrapForDecode(buffer, offset, actingBlockLength, actingVersion);\n") + .append(indent).append(INDENT) + .append("return DecodeWith(decoder);\n") + .append(indent).append("}\n"); + } + + private void generateMessageFieldsDecodeWith( final StringBuilder sb, final Predicate wasAddedAfterParent, final List tokens, @@ -338,13 +365,13 @@ private void generateMessageFieldsDecodeFrom( { final Token encodingToken = tokens.get(i + 1); - generateFieldDecodeFrom( + generateFieldDecodeWith( sb, wasAddedAfterParent, signalToken, encodingToken, codecClassName, indent); } } } - private void generateFieldDecodeFrom( + private void generateFieldDecodeWith( final StringBuilder sb, final Predicate wasAddedAfterParent, final Token fieldToken, @@ -355,21 +382,21 @@ private void generateFieldDecodeFrom( switch (typeToken.signal()) { case ENCODING: - generatePrimitiveDecodeFrom(sb, fieldToken, typeToken, wasAddedAfterParent, codecClassName, indent); + generatePrimitiveDecodeWith(sb, fieldToken, typeToken, wasAddedAfterParent, codecClassName, indent); break; case BEGIN_SET: - generatePropertyDecodeFrom(sb, fieldToken, wasAddedAfterParent, "0", null, indent); + generatePropertyDecodeWith(sb, fieldToken, wasAddedAfterParent, "0", null, indent); break; case BEGIN_ENUM: final String enumName = formatClassName(typeToken.applicableTypeName()); final String nullValue = formatNamespace(ir.packageName()) + "." + enumName + ".NULL_VALUE"; - generatePropertyDecodeFrom(sb, fieldToken, wasAddedAfterParent, nullValue, null, indent); + generatePropertyDecodeWith(sb, fieldToken, wasAddedAfterParent, nullValue, null, indent); break; case BEGIN_COMPOSITE: - generateComplexDecodeFrom(sb, fieldToken, typeToken, indent); + generateComplexDecodeWith(sb, fieldToken, typeToken, indent); break; default: @@ -377,7 +404,7 @@ private void generateFieldDecodeFrom( } } - private void generatePrimitiveDecodeFrom( + private void generatePrimitiveDecodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -395,15 +422,15 @@ private void generatePrimitiveDecodeFrom( if (arrayLength == 1) { final String codecNullValue = codecClassName + "." + formatPropertyName(fieldToken.name()) + "NullValue"; - generatePropertyDecodeFrom(sb, fieldToken, wasAddedAfterParent, "null", codecNullValue, indent); + generatePropertyDecodeWith(sb, fieldToken, wasAddedAfterParent, "null", codecNullValue, indent); } else if (arrayLength > 1) { - generateArrayDecodeFrom(sb, fieldToken, typeToken, wasAddedAfterParent, indent); + generateArrayDecodeWith(sb, fieldToken, typeToken, wasAddedAfterParent, indent); } } - private void generateArrayDecodeFrom( + private void generateArrayDecodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -444,7 +471,7 @@ private void generateArrayDecodeFrom( } } - private void generatePropertyDecodeFrom( + private void generatePropertyDecodeWith( final StringBuilder sb, final Token fieldToken, final Predicate wasAddedAfterParent, @@ -471,7 +498,7 @@ private void generatePropertyDecodeFrom( ); } - private void generateComplexDecodeFrom( + private void generateComplexDecodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -482,11 +509,11 @@ private void generateComplexDecodeFrom( final String dtoClassName = formatDtoClassName(typeToken.applicableTypeName()); sb.append(indent).append(formattedPropertyName).append(": ") - .append(dtoClassName).append(".DecodeFrom(codec.") + .append(dtoClassName).append(".DecodeWith(codec.") .append(formattedPropertyName).append(")").append(",\n"); } - private void generateGroupsDecodeFrom( + private void generateGroupsDecodeWith( final StringBuilder sb, final List tokens, final String indent) @@ -514,7 +541,7 @@ private void generateGroupsDecodeFrom( groupToken, token -> token.version() > sinceVersion, indent, - groupDtoClassName + ".DecodeListFrom(codec." + formattedPropertyName + ")", + groupDtoClassName + ".DecodeListWith(codec." + formattedPropertyName + ")", "new List<" + groupDtoClassName + ">(0).AsReadOnly()", null ); @@ -533,7 +560,7 @@ private void generateGroupsDecodeFrom( } } - private void generateVarDataDecodeFrom( + private void generateVarDataDecodeWith( final StringBuilder sb, final List tokens, final Predicate wasAddedAfterParent, @@ -621,8 +648,9 @@ private void generateRecordPropertyAssignment( } } - private void generateEncodeInto( + private void generateEncodeWith( final StringBuilder sb, + final String dtoClassName, final String codecClassName, final List fields, final List groups, @@ -630,17 +658,49 @@ private void generateEncodeInto( final String indent) { sb.append("\n") - .append(indent).append("public void EncodeInto(").append(codecClassName).append(" codec)\n") + .append(indent).append("public static void EncodeWith(") + .append(codecClassName).append(" codec, ") + .append(dtoClassName).append(" dto)\n") .append(indent).append("{\n"); - generateFieldsEncodeInto(sb, codecClassName, fields, indent + INDENT); - generateGroupsEncodeInto(sb, groups, indent + INDENT); - generateVarDataEncodeInto(sb, varData, indent + INDENT); + generateFieldsEncodeWith(sb, codecClassName, fields, indent + INDENT); + generateGroupsEncodeWith(sb, groups, indent + INDENT); + generateVarDataEncodeWith(sb, varData, indent + INDENT); sb.append(indent).append("}\n"); } - private void generateFieldsEncodeInto( + private void generateEncodeInto( + final StringBuilder sb, + final String dtoClassName, + final String codecClassName, + final String indent) + { + sb.append("\n") + .append(indent).append("public static int EncodeInto(") + .append("DirectBuffer buffer, int offset, ") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("var encoder = new ").append(codecClassName).append("();\n") + .append(indent).append(INDENT).append("encoder.WrapForEncode(buffer, offset);\n") + .append(indent).append(INDENT).append("EncodeWith(encoder, dto);\n") + .append(indent).append(INDENT).append("return encoder.Limit - offset;\n") + .append(indent).append("}\n"); + + sb.append("\n") + .append(indent).append("public static int EncodeWithHeaderInto(") + .append("DirectBuffer buffer, int offset, ") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("var encoder = new ").append(codecClassName).append("();\n") + .append(indent).append(INDENT) + .append("encoder.WrapForEncodeAndApplyHeader(buffer, offset, new MessageHeader());\n") + .append(indent).append(INDENT).append("EncodeWith(encoder, dto);\n") + .append(indent).append(INDENT).append("return encoder.Limit - offset;\n") + .append(indent).append("}\n"); + } + + private void generateFieldsEncodeWith( final StringBuilder sb, final String codecClassName, final List tokens, @@ -652,12 +712,12 @@ private void generateFieldsEncodeInto( if (signalToken.signal() == Signal.BEGIN_FIELD) { final Token encodingToken = tokens.get(i + 1); - generateFieldEncodeInto(sb, codecClassName, signalToken, encodingToken, indent); + generateFieldEncodeWith(sb, codecClassName, signalToken, encodingToken, indent); } } } - private void generateFieldEncodeInto( + private void generateFieldEncodeWith( final StringBuilder sb, final String codecClassName, final Token fieldToken, @@ -667,16 +727,16 @@ private void generateFieldEncodeInto( switch (typeToken.signal()) { case ENCODING: - generatePrimitiveEncodeInto(sb, codecClassName, fieldToken, typeToken, indent); + generatePrimitiveEncodeWith(sb, codecClassName, fieldToken, typeToken, indent); break; case BEGIN_SET: case BEGIN_ENUM: - generateEnumEncodeInto(sb, fieldToken, indent); + generateEnumEncodeWith(sb, fieldToken, indent); break; case BEGIN_COMPOSITE: - generateComplexEncodeInto(sb, fieldToken, indent); + generateComplexEncodeWith(sb, fieldToken, typeToken, indent); break; default: @@ -684,7 +744,7 @@ private void generateFieldEncodeInto( } } - private void generatePrimitiveEncodeInto( + private void generatePrimitiveEncodeWith( final StringBuilder sb, final String codecClassName, final Token fieldToken, @@ -700,15 +760,15 @@ private void generatePrimitiveEncodeInto( if (arrayLength == 1) { - generatePropertyEncodeInto(sb, codecClassName, fieldToken, indent); + generatePropertyEncodeWith(sb, codecClassName, fieldToken, indent); } else if (arrayLength > 1) { - generateArrayEncodeInto(sb, fieldToken, typeToken, indent); + generateArrayEncodeWith(sb, fieldToken, typeToken, indent); } } - private void generateArrayEncodeInto( + private void generateArrayEncodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -724,7 +784,7 @@ private void generateArrayEncodeInto( if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { - final String value = nullableConvertedExpression(fieldToken, formattedPropertyName, "\"\""); + final String value = nullableConvertedExpression(fieldToken, "dto." + formattedPropertyName, "\"\""); sb.append(indent).append("codec.Set").append(formattedPropertyName).append("(") .append(value).append(");\n"); } @@ -732,7 +792,7 @@ private void generateArrayEncodeInto( { final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()); - sb.append(indent).append("new Span<").append(typeName).append(">(").append(formattedPropertyName) + sb.append(indent).append("new Span<").append(typeName).append(">(dto.").append(formattedPropertyName) .append("?.ToArray()).CopyTo(codec.").append(formattedPropertyName).append("AsSpan());\n"); } } @@ -747,7 +807,7 @@ private String nullableConvertedExpression( expression; } - private void generatePropertyEncodeInto( + private void generatePropertyEncodeWith( final StringBuilder sb, final String codecClassName, final Token fieldToken, @@ -763,14 +823,14 @@ private void generatePropertyEncodeInto( final String value = nullableConvertedExpression( fieldToken, - formattedPropertyName, + "dto." + formattedPropertyName, codecClassName + "." + formattedPropertyName + "NullValue"); sb.append(indent).append("codec.").append(formattedPropertyName).append(" = ") .append(value).append(";\n"); } - private void generateEnumEncodeInto( + private void generateEnumEncodeWith( final StringBuilder sb, final Token fieldToken, final String indent) @@ -783,22 +843,25 @@ private void generateEnumEncodeInto( final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); - sb.append(indent).append("codec.").append(formattedPropertyName).append(" = ") + sb.append(indent).append("codec.").append(formattedPropertyName).append(" = dto.") .append(formattedPropertyName).append(";\n"); } - private void generateComplexEncodeInto( + private void generateComplexEncodeWith( final StringBuilder sb, final Token fieldToken, + final Token typeToken, final String indent) { final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); - sb.append(indent).append(formattedPropertyName).append(".EncodeInto(codec.") - .append(formattedPropertyName).append(");\n"); + final String dtoClassName = formatDtoClassName(typeToken.applicableTypeName()); + sb.append(indent) + .append(dtoClassName).append(".EncodeWith(codec.").append(formattedPropertyName) + .append(", dto.").append(formattedPropertyName).append(");\n"); } - private void generateGroupsEncodeInto( + private void generateGroupsEncodeWith( final StringBuilder sb, final List tokens, final String indent) @@ -813,15 +876,17 @@ private void generateGroupsEncodeInto( final String groupName = groupToken.name(); final String formattedPropertyName = formatPropertyName(groupName); final String groupCodecVarName = groupName + "Codec"; + final String groupDtoClassName = formatDtoClassName(groupName); sb.append("\n") .append(indent).append("var ").append(groupCodecVarName) .append(" = codec.").append(formattedPropertyName) - .append("Count(").append(formattedPropertyName).append(".Count);\n\n") - .append(indent).append("foreach (var group in ").append(formattedPropertyName).append(")\n") + .append("Count(dto.").append(formattedPropertyName).append(".Count);\n\n") + .append(indent).append("foreach (var group in dto.").append(formattedPropertyName).append(")\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("group.EncodeInto(").append(groupCodecVarName) - .append(".Next()").append(");\n") + .append(indent).append(INDENT).append(groupDtoClassName).append(".EncodeWith(") + .append(groupCodecVarName) + .append(".Next()").append(", group);\n") .append(indent).append("}\n\n"); i++; @@ -838,7 +903,7 @@ private void generateGroupsEncodeInto( } } - private void generateVarDataEncodeInto( + private void generateVarDataEncodeWith( final StringBuilder sb, final List tokens, final String indent) @@ -851,7 +916,7 @@ private void generateVarDataEncodeInto( final String formattedPropertyName = formatPropertyName(propertyName); sb.append(indent).append("codec.Set").append(formattedPropertyName) - .append("(").append(formattedPropertyName).append(");\n"); + .append("(dto.").append(formattedPropertyName).append(");\n"); } } } @@ -876,7 +941,7 @@ private void generateDisplay( sb.append(", ").append(actingVersion); } sb.append(");\n"); - sb.append(indent).append(INDENT).append("EncodeInto(codec);\n") + sb.append(indent).append(INDENT).append("EncodeWith(codec, this);\n") .append(indent).append(INDENT).append("StringBuilder sb = new StringBuilder();\n") .append(indent).append(INDENT).append("codec.BuildString(sb);\n") .append(indent).append(INDENT).append("return sb.ToString();\n") @@ -1292,8 +1357,8 @@ private void generateComposite(final List tokens) throws IOException final List compositeTokens = tokens.subList(1, tokens.size() - 1); generateCompositePropertyElements(sb, ctorArgs, codecClassName, compositeTokens, BASE_INDENT + INDENT); - generateCompositeDecodeFrom(sb, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); - generateCompositeEncodeInto(sb, codecClassName, compositeTokens, BASE_INDENT + INDENT); + generateCompositeDecodeWith(sb, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); + generateCompositeEncodeWith(sb, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateDisplay(sb, codecClassName, "Wrap", codecClassName + ".SbeSchemaVersion", BASE_INDENT + INDENT); removeTrailingComma(ctorArgs); diff --git a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs index 60bdc22616..fa73cd118d 100644 --- a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs +++ b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/Program.cs @@ -17,12 +17,12 @@ static int Main(string[] args) { messageHeader.Wrap(buffer, 0, 0); var decoder = new TestMessage(); decoder.WrapForDecode(buffer, 8, messageHeader.BlockLength, messageHeader.Version); - var dto = TestMessageDto.DecodeFrom(decoder); + var dto = TestMessageDto.DecodeWith(decoder); var outputBytes = new byte[inputBytes.Length]; var outputBuffer = new DirectBuffer(outputBytes); var encoder = new TestMessage(); encoder.WrapForEncodeAndApplyHeader(outputBuffer, 0, new MessageHeader()); - dto.EncodeInto(encoder); + TestMessageDto.EncodeWith(encoder, dto); File.WriteAllBytes("output.dat", outputBytes); return 0; } From 96b70326c33c1f1756aca7e5f5746022d8aee72c Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 2 Nov 2023 11:55:35 +0000 Subject: [PATCH 362/805] [C++] Generate DTOs for non-perf-sensitive usecases. In some applications performance is not cricital. Some users would like to use SBE across their whole "estate", but don't want the "sharp edges" associated with using flyweight codecs, e.g., accidental escape. In this commit, I've added a first cut of DTO generation for C++ and a simple test based on the Car Example. The DTOs support encoding and decoding via the generated codecs using `DtoT::encode(CodecT& codec, const DtoT& dto)` and `DtoT::decode(CodecT& codec, Dto& dto)` methods. Generation can be enabled specifying the target code generator class, `uk.co.real_logic.sbe.generation.cpp.CppDtos`, or by passing a system property `-Dsbe.cpp.generate.dtos=true`. --- .../java/uk/co/real_logic/sbe/SbeTool.java | 5 + .../generation/TargetCodeGeneratorLoader.java | 21 +- .../sbe/generation/cpp/CppDtoGenerator.java | 1824 +++++++++++++++++ .../sbe/generation/cpp/CppDtos.java | 36 + .../sbe/generation/cpp/CppGenerator.java | 58 - .../sbe/generation/cpp/CppUtil.java | 58 + sbe-tool/src/test/cpp/CMakeLists.txt | 6 + sbe-tool/src/test/cpp/DtoTest.cpp | 195 ++ .../src/test/resources/dto-test-schema.xml | 110 + 9 files changed, 2250 insertions(+), 63 deletions(-) create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java create mode 100644 sbe-tool/src/test/cpp/DtoTest.cpp create mode 100644 sbe-tool/src/test/resources/dto-test-schema.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index aae460dc2b..a6958a12bf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -192,6 +192,11 @@ public class SbeTool */ public static final String DECODE_UNKNOWN_ENUM_VALUES = "sbe.decode.unknown.enum.values"; + /** + * Should generate C++ DTOs. Defaults to false. + */ + public static final String GENERATE_CPP_DTOS = "sbe.cpp.generate.dtos"; + /** * Configuration option used to manage sinceVersion based transformations. When set, parsed schemas will be * transformed to discard messages and types higher than the specified version. This can be useful when needing diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 54a9766449..6f872cd55e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -18,6 +18,7 @@ import uk.co.real_logic.sbe.generation.c.CGenerator; import uk.co.real_logic.sbe.generation.c.COutputManager; import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; +import uk.co.real_logic.sbe.generation.cpp.CppDtoGenerator; import uk.co.real_logic.sbe.generation.cpp.CppGenerator; import uk.co.real_logic.sbe.generation.cpp.NamespaceOutputManager; import uk.co.real_logic.sbe.generation.golang.GolangGenerator; @@ -83,11 +84,21 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new CppGenerator( - ir, - "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)), - precedenceChecks(), - new NamespaceOutputManager(outputDir, ir.applicableNamespace())); + final NamespaceOutputManager outputManager = new NamespaceOutputManager( + outputDir, ir.applicableNamespace()); + final boolean decodeUnknownEnumValues = "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)); + + final CodeGenerator codecGenerator = new CppGenerator(ir, decodeUnknownEnumValues, precedenceChecks(), + outputManager); + final CodeGenerator dtoGenerator = new CppDtoGenerator(ir, outputManager); + final CodeGenerator combinedGenerator = () -> + { + codecGenerator.generate(); + dtoGenerator.generate(); + }; + + final boolean generateDtos = "true".equals(System.getProperty(GENERATE_CPP_DTOS)); + return generateDtos ? combinedGenerator : codecGenerator; } }, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java new file mode 100644 index 0000000000..e1e3793da8 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -0,0 +1,1824 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * Copyright (C) 2017 MarketFactory, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.generation.cpp; + +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.Signal; +import uk.co.real_logic.sbe.ir.Token; +import org.agrona.LangUtil; +import org.agrona.Verify; +import org.agrona.generation.OutputManager; + +import java.io.IOException; +import java.io.Writer; +import java.util.*; +import java.util.stream.Collectors; + +import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; +import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; +import static uk.co.real_logic.sbe.generation.cpp.CppUtil.*; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; + +/** + * DTO generator for the CSharp programming language. + */ +public class CppDtoGenerator implements CodeGenerator +{ + private static final String INDENT = " "; + private static final String BASE_INDENT = INDENT; + + private final Ir ir; + private final OutputManager outputManager; + + /** + * Create a new C# DTO {@link CodeGenerator}. + * + * @param ir for the messages and types. + * @param outputManager for generating the DTOs to. + */ + public CppDtoGenerator(final Ir ir, final OutputManager outputManager) + { + Verify.notNull(ir, "ir"); + Verify.notNull(outputManager, "outputManager"); + + this.ir = ir; + this.outputManager = outputManager; + } + + /** + * {@inheritDoc} + */ + public void generate() throws IOException + { + generateDtosForTypes(); + + for (final List tokens : ir.messages()) + { + final Token msgToken = tokens.get(0); + final String codecClassName = formatClassName(msgToken.name()); + final String className = formatDtoClassName(msgToken.name()); + + final List messageBody = tokens.subList(1, tokens.size() - 1); + int offset = 0; + + final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT); + + final List fields = new ArrayList<>(); + offset = collectFields(messageBody, offset, fields); + generateFields(classBuilder, codecClassName, fields, BASE_INDENT + INDENT); + + final List groups = new ArrayList<>(); + offset = collectGroups(messageBody, offset, groups); + generateGroups(classBuilder, className, codecClassName, groups, + BASE_INDENT + INDENT); + + final List varData = new ArrayList<>(); + collectVarData(messageBody, offset, varData); + generateVarData(classBuilder, varData, BASE_INDENT + INDENT); + + generateMessageDecodeFrom(classBuilder, className, codecClassName, fields, + groups, varData, BASE_INDENT + INDENT); + generateMessageEncodeInto(classBuilder, className, codecClassName, fields, groups, varData, + BASE_INDENT + INDENT); + generateDisplay(classBuilder, codecClassName, "wrapForEncode", null, BASE_INDENT + INDENT); + + try (Writer out = outputManager.createOutput(className)) + { + final List beginTypeTokensInSchema = ir.types().stream() + .map(t -> t.get(0)) + .collect(Collectors.toList()); + + final Set referencedTypes = generateTypesToIncludes(beginTypeTokensInSchema); + referencedTypes.add(codecClassName); + + out.append(generateDtoFileHeader( + ir.namespaces(), + className, + referencedTypes)); + out.append(generateDocumentation(BASE_INDENT, msgToken)); + classBuilder.appendTo(out); + out.append("} // namespace\n"); + out.append("#endif\n"); + } + } + } + + private static final class ClassBuilder + { + private final StringBuilder publicSb = new StringBuilder(); + private final StringBuilder privateSb = new StringBuilder(); + private final StringBuilder fieldSb = new StringBuilder(); + private final String className; + private final String indent; + + private ClassBuilder(final String className, final String indent) + { + this.className = className; + this.indent = indent; + } + + public StringBuilder appendPublic() + { + return publicSb; + } + + public StringBuilder appendPrivate() + { + return privateSb; + } + + public StringBuilder appendField() + { + return fieldSb; + } + + public void appendTo(final Appendable out) + { + try + { + out.append(indent).append("class ").append(className).append("\n") + .append(indent).append("{\n") + .append(indent).append("private:\n") + .append(privateSb) + .append("\n") + .append(indent).append("public:\n") + .append(publicSb) + .append("\n") + .append(indent).append("private:\n") + .append(fieldSb) + .append(indent).append("};\n"); + } + catch (final IOException exception) + { + LangUtil.rethrowUnchecked(exception); + } + } + } + + private void generateGroups( + final ClassBuilder classBuilder, + final String qualifiedParentDtoClassName, + final String qualifiedParentCodecClassName, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String groupClassName = formatDtoClassName(groupName); + final String qualifiedDtoClassName = qualifiedParentDtoClassName + "::" + groupClassName; + + final String fieldName = "m_" + toLowerFirstChar(groupName); + final String formattedPropertyName = formatPropertyName(groupName); + + classBuilder.appendField().append(indent).append("std::vector<") + .append(qualifiedDtoClassName).append("> ") + .append(fieldName).append(";\n"); + + final ClassBuilder groupClassBuilder = new ClassBuilder(groupClassName, indent); + + i++; + i += tokens.get(i).componentTokenCount(); + + final String qualifiedCodecClassName = + qualifiedParentCodecClassName + "::" + formatClassName(groupName); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + generateFields(groupClassBuilder, qualifiedCodecClassName, fields, indent + INDENT); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + generateGroups(groupClassBuilder, qualifiedDtoClassName, + qualifiedCodecClassName, groups, indent + INDENT); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + generateVarData(groupClassBuilder, varData, indent + INDENT); + + generateDecodeListFrom( + groupClassBuilder, groupClassName, qualifiedCodecClassName, indent + INDENT); + generateMessageDecodeFrom(groupClassBuilder, groupClassName, qualifiedCodecClassName, + fields, groups, varData, indent + INDENT); + generateMessageEncodeInto( + groupClassBuilder, groupClassName, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); + + groupClassBuilder.appendTo( + classBuilder.appendPublic().append("\n").append(generateDocumentation(indent, groupToken)) + ); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("[[nodiscard]] const std::vector<").append(qualifiedDtoClassName).append(">& ") + .append(formattedPropertyName).append("() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("[[nodiscard]] std::vector<").append(qualifiedDtoClassName).append(">& ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("void ").append(formattedPropertyName).append("(") + .append("const std::vector<").append(qualifiedDtoClassName).append(">& values)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = values;\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("void ").append(formattedPropertyName).append("(") + .append("std::vector<").append(qualifiedDtoClassName).append(">&& values)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = std::move(values);\n") + .append(indent).append("}\n"); + } + } + + private void generateCompositeDecodeFrom( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final List tokens, + final String indent) + { + final StringBuilder decodeBuilder = classBuilder.appendPublic().append("\n") + .append(indent).append("static void decode(").append(codecClassName).append("& codec, ") + .append(dtoClassName).append("& dto)\n") + .append(indent).append("{\n"); + + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + + generateFieldDecodeFrom( + decodeBuilder, token, token, codecClassName, indent + INDENT); + + i += tokens.get(i).componentTokenCount(); + } + + decodeBuilder.append(indent).append("}\n"); + } + + private void generateCompositeEncodeInto( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final List tokens, + final String indent) + { + final StringBuilder encodeBuilder = classBuilder.appendPublic().append("\n") + .append(indent).append("static void encode(").append(codecClassName).append("& codec,") + .append("const ").append(dtoClassName).append("& dto)\n") + .append(indent).append("{\n"); + + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + + generateFieldEncodeInto(encodeBuilder, codecClassName, token, token, indent + INDENT); + + i += tokens.get(i).componentTokenCount(); + } + + encodeBuilder.append(indent).append("}\n"); + } + + private void generateDecodeListFrom( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final String indent) + { + classBuilder.appendPublic().append("\n") + .append(indent).append("static std::vector<").append(dtoClassName).append("> decodeMany(") + .append(codecClassName).append("& codec)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("std::vector<").append(dtoClassName) + .append("> dtos(codec.count());\n") + .append(indent).append(INDENT) + .append("for (std::size_t i = 0; i < dtos.size(); i++)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append(dtoClassName).append(" dto;\n") + .append(indent).append(INDENT).append(INDENT) + .append(dtoClassName).append("::decode(codec.next(), dto);\n") + .append(indent).append(INDENT).append(INDENT) + .append("dtos[i] = dto;\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append(INDENT) + .append("return dtos;\n") + .append(indent).append("}\n"); + } + + private void generateMessageDecodeFrom( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final List fields, + final List groups, + final List varData, + final String indent) + { + final StringBuilder decodeBuilder = classBuilder.appendPublic().append("\n") + .append(indent).append("static void decode(").append(codecClassName).append("& codec, ") + .append(dtoClassName).append("& dto)\n") + .append(indent).append("{\n"); + + generateMessageFieldsDecodeFrom(decodeBuilder, fields, codecClassName, indent + INDENT); + generateGroupsDecodeFrom(decodeBuilder, groups, indent + INDENT); + generateVarDataDecodeFrom(decodeBuilder, varData, indent + INDENT); + decodeBuilder.append(indent).append("}\n"); + } + + private void generateMessageFieldsDecodeFrom( + final StringBuilder sb, + final List tokens, + final String codecClassName, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + + generateFieldDecodeFrom(sb, signalToken, encodingToken, codecClassName, indent); + } + } + } + + private void generateFieldDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String codecClassName, + final String indent) + { + switch (typeToken.signal()) + { + case ENCODING: + generatePrimitiveDecodeFrom(sb, fieldToken, typeToken, codecClassName, indent); + break; + + case BEGIN_SET: + final String bitSetName = formatDtoClassName(typeToken.applicableTypeName()); + generateBitSetDecodeFrom(sb, fieldToken, bitSetName, indent); + break; + + case BEGIN_ENUM: + generateEnumDecodeFrom(sb, fieldToken, indent); + break; + + case BEGIN_COMPOSITE: + generateCompositePropertyDecodeFrom(sb, fieldToken, typeToken, indent); + break; + + default: + break; + } + } + + private void generatePrimitiveDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String codecClassName, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + return; + } + + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + final String typeName = cppTypeName(typeToken.encoding().primitiveType()); + final String codecNullValue = codecClassName + "::" + formatPropertyName(fieldToken.name()) + "NullValue()"; + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + generateRecordPropertyAssignment( + sb, + fieldToken, + indent, + "codec." + formattedPropertyName + "()", + codecNullValue, + typeName + ); + } + else if (arrayLength > 1) + { + generateArrayDecodeFrom(sb, fieldToken, typeToken, codecClassName, indent); + } + } + + private void generateArrayDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String codecClassName, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + generateRecordPropertyAssignment( + sb, + fieldToken, + indent, + "std::string(codec." + formattedPropertyName + "(), " + + codecClassName + "::" + formattedPropertyName + "Length())", + null, + "std::string" + ); + } + else + { + final StringBuilder initializerList = new StringBuilder(); + initializerList.append("{ "); + final int arrayLength = typeToken.arrayLength(); + for (int i = 0; i < arrayLength; i++) + { + initializerList.append("codec.").append(formattedPropertyName).append("(").append(i).append("),"); + } + assert arrayLength > 0; + initializerList.setLength(initializerList.length() - 1); + initializerList.append(" }"); + + generateRecordPropertyAssignment( + sb, + fieldToken, + indent, + initializerList, + null, + "std::vector<" + cppTypeName(typeToken.encoding().primitiveType()) + ">" + ); + } + } + + private void generateBitSetDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final String dtoTypeName, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (fieldToken.isOptionalEncoding()) + { + sb.append(indent).append("if (codec.").append(formattedPropertyName).append("InActingVersion()"); + + sb.append(")\n") + .append(indent).append("{\n"); + + sb.append(indent).append(INDENT).append(dtoTypeName).append("::decode(codec.") + .append(formattedPropertyName).append("(), ") + .append("dto.").append(formattedPropertyName).append("());\n"); + + sb.append(indent).append("}\n") + .append(indent).append("else\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("().clear();\n") + .append(indent).append("}\n"); + } + else + { + sb.append(indent).append(dtoTypeName).append("::decode(codec.") + .append(formattedPropertyName).append("(), ") + .append("dto.").append(formattedPropertyName).append("());\n"); + } + } + + private void generateEnumDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + sb.append(indent).append("dto.").append(formattedPropertyName).append("(") + .append("codec.").append(formattedPropertyName).append("());\n"); + } + + private void generateCompositePropertyDecodeFrom( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + final String dtoClassName = formatDtoClassName(typeToken.applicableTypeName()); + + sb.append(indent).append(dtoClassName).append("::decode(codec.") + .append(formattedPropertyName).append("(), ") + .append("dto.").append(formattedPropertyName).append("());\n"); + } + + private void generateGroupsDecodeFrom( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String formattedPropertyName = formatPropertyName(groupName); + final String groupDtoClassName = formatDtoClassName(groupName); + + sb.append(indent).append("dto.").append(formattedPropertyName).append("(") + .append(groupDtoClassName).append("::decodeMany(codec.") + .append(formattedPropertyName).append("()));\n"); + + i++; + i += tokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + } + } + + private void generateVarDataDecodeFrom( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0; i < tokens.size(); i++) + { + final Token token = tokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + final String formattedPropertyName = formatPropertyName(propertyName); + + final boolean isOptional = token.version() > 0; + + final String dataVar = toLowerFirstChar(propertyName) + "Data"; + final String lengthVar = toLowerFirstChar(propertyName) + "Length"; + final String blockIndent = isOptional ? indent + INDENT : indent; + final StringBuilder codecValueExtraction = new StringBuilder() + .append(blockIndent).append("std::size_t ").append(lengthVar) + .append(" = codec.").append(formattedPropertyName).append("Length();\n") + .append(blockIndent).append("const char* ").append(dataVar) + .append(" = codec.").append(formattedPropertyName).append("();\n"); + + final String dtoValue; + final String nullDtoValue; + + if (characterEncoding == null) + { + dtoValue = "std::vector(" + dataVar + ", " + dataVar + " + " + lengthVar + ")"; + nullDtoValue = "std::vector()"; + } + else + { + dtoValue = "std::string(" + dataVar + ", " + lengthVar + ")"; + nullDtoValue = "\"\""; + } + + if (isOptional) + { + sb.append(indent).append("if (codec.").append(formattedPropertyName).append("InActingVersion()"); + + sb.append(")\n") + .append(indent).append("{\n"); + + sb.append(codecValueExtraction); + + sb.append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(") + .append(dtoValue).append(");\n"); + + sb.append(indent).append("}\n") + .append(indent).append("else\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("dto.") + .append(formattedPropertyName).append("(").append(nullDtoValue).append(");\n") + .append(indent).append("}\n"); + } + else + { + sb.append(codecValueExtraction); + + sb.append(indent).append("dto.").append(formattedPropertyName).append("(") + .append(dtoValue).append(");\n"); + } + } + } + } + + private void generateRecordPropertyAssignment( + final StringBuilder sb, + final Token token, + final String indent, + final CharSequence presentExpression, + final String nullCodecValueOrNull, + final String dtoTypeName) + { + final String propertyName = token.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (token.isOptionalEncoding()) + { + sb.append(indent).append("if (codec.").append(formattedPropertyName).append("InActingVersion()"); + + if (null != nullCodecValueOrNull) + { + sb.append(" && codec.").append(formattedPropertyName).append("() != ").append(nullCodecValueOrNull); + } + + sb.append(")\n") + .append(indent).append("{\n"); + + sb.append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(std::make_optional<") + .append(dtoTypeName).append(">(").append(presentExpression).append("));\n"); + + sb.append(indent).append("}\n") + .append(indent).append("else\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(std::nullopt);\n") + .append(indent).append("}\n"); + } + else + { + sb.append(indent).append("dto.").append(formattedPropertyName).append("(") + .append(presentExpression).append(");\n"); + } + } + + private void generateMessageEncodeInto( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final List fields, + final List groups, + final List varData, + final String indent) + { + final StringBuilder encodeBuilder = classBuilder.appendPublic().append("\n") + .append(indent).append("static void encode(").append(codecClassName).append("& codec, const ") + .append(dtoClassName).append("& dto)\n") + .append(indent).append("{\n"); + + generateFieldsEncodeInto(encodeBuilder, codecClassName, fields, indent + INDENT); + generateGroupsEncodeInto(encodeBuilder, groups, indent + INDENT); + generateVarDataEncodeInto(encodeBuilder, varData, indent + INDENT); + + encodeBuilder.append(indent).append("}\n"); + } + + private void generateFieldsEncodeInto( + final StringBuilder sb, + final String codecClassName, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + generateFieldEncodeInto(sb, codecClassName, signalToken, encodingToken, indent); + } + } + } + + private void generateFieldEncodeInto( + final StringBuilder sb, + final String codecClassName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + switch (typeToken.signal()) + { + case ENCODING: + generatePrimitiveEncodeInto(sb, codecClassName, fieldToken, typeToken, indent); + break; + + case BEGIN_ENUM: + generateEnumEncodeInto(sb, fieldToken, indent); + break; + + case BEGIN_SET: + case BEGIN_COMPOSITE: + generateComplexPropertyEncodeInto(sb, fieldToken, typeToken, indent); + break; + + default: + break; + } + } + + private void generatePrimitiveEncodeInto( + final StringBuilder sb, + final String codecClassName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + return; + } + + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + generatePrimitiveValueEncodeInto(sb, codecClassName, fieldToken, indent); + } + else if (arrayLength > 1) + { + generateArrayEncodeInto(sb, fieldToken, typeToken, indent); + } + } + + private void generateArrayEncodeInto( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + final String accessor = "dto." + formattedPropertyName + "()"; + final String value = fieldToken.isOptionalEncoding() ? + accessor + ".value_or(" + "\"\"" + ")" : + accessor; + sb.append(indent).append("codec.put").append(toUpperFirstChar(propertyName)).append("(") + .append(value).append(".c_str());\n"); + } + else + { + final String typeName = cppTypeName(typeToken.encoding().primitiveType()); + final String vectorVar = toLowerFirstChar(propertyName) + "Vector"; + + final String accessor = "dto." + formattedPropertyName + "()"; + final String value = fieldToken.isOptionalEncoding() ? + accessor + ".value_or(std::vector<" + typeName + ">())" : + accessor; + + sb.append(indent).append("std::vector<").append(typeName).append("> ").append(vectorVar) + .append(" = ").append(value).append(";\n\n"); + + sb.append(indent).append("if (").append(vectorVar).append(".size() != ") + .append(typeToken.arrayLength()).append(")\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("throw std::invalid_argument(\"") + .append(propertyName) + .append(": array length != ") + .append(typeToken.arrayLength()) + .append("\");\n") + .append(indent).append("}\n\n"); + + sb.append(indent).append("for (std::uint64_t i = 0; i < ").append(typeToken.arrayLength()) + .append("; i++)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("codec.").append(formattedPropertyName).append("(i, ") + .append(vectorVar).append("[i]);\n") + .append(indent).append("}\n"); + } + } + + private void generatePrimitiveValueEncodeInto( + final StringBuilder sb, + final String codecClassName, + final Token fieldToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + final String nullValue = codecClassName + "::" + formattedPropertyName + "NullValue()"; + final String accessor = "dto." + formattedPropertyName + "()"; + final String value = fieldToken.isOptionalEncoding() ? + accessor + ".value_or(" + nullValue + ")" : + accessor; + + sb.append(indent).append("codec.").append(formattedPropertyName).append("(") + .append(value).append(");\n"); + } + + private void generateEnumEncodeInto( + final StringBuilder sb, + final Token fieldToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + sb.append(indent).append("codec.").append(formattedPropertyName).append("(dto.") + .append(formattedPropertyName).append("());\n"); + } + + private void generateComplexPropertyEncodeInto( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + final String typeName = formatDtoClassName(typeToken.applicableTypeName()); + + sb.append(indent).append(typeName).append("::encode(codec.") + .append(formattedPropertyName).append("(), dto.") + .append(formattedPropertyName).append("());\n"); + } + + private void generateGroupsEncodeInto( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String formattedPropertyName = formatPropertyName(groupName); + final String groupCodecVarName = groupName + "Codec"; + final String groupDtoTypeName = formatDtoClassName(groupName); + + sb.append("\n") + .append(indent).append("const std::vector<").append(groupDtoTypeName).append(">& ") + .append(formattedPropertyName).append(" = dto.").append(formattedPropertyName).append("();\n\n") + .append(indent).append("auto&").append(" ").append(groupCodecVarName) + .append(" = codec.").append(formattedPropertyName) + .append("Count(").append(formattedPropertyName).append(".size());\n\n") + .append(indent).append("for (const auto& group: ").append(formattedPropertyName).append(")\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(groupDtoTypeName).append("::encode(").append(groupCodecVarName) + .append(".next(), group);\n") + .append(indent).append("}\n\n"); + + i++; + i += tokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + } + } + + private void generateVarDataEncodeInto( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0; i < tokens.size(); i++) + { + final Token token = tokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final Token lengthToken = Generators.findFirst("length", tokens, i); + final String lengthTypeName = cppTypeName(lengthToken.encoding().primitiveType()); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + final String formattedPropertyName = formatPropertyName(propertyName); + final String varName = toLowerFirstChar(propertyName) + "Vector"; + + sb.append(indent).append("auto& ").append(varName).append(" = dto.") + .append(formattedPropertyName).append("();\n") + .append(indent).append("codec.put").append(toUpperFirstChar(propertyName)) + .append("("); + + if (null == characterEncoding) + { + sb.append("reinterpret_cast(").append(varName).append(".data()), ") + .append("static_cast<").append(lengthTypeName).append(">(").append(varName).append(".size())"); + } + else + { + sb.append(varName); + } + + sb.append(");\n"); + } + } + } + + private void generateDisplay( + final ClassBuilder classBuilder, + final String codecClassName, + final String wrapMethod, + final String actingVersion, + final String indent) + { + final StringBuilder toStringBuilder = classBuilder.appendPublic() + .append("\n") + .append(indent).append( + "std::string string(char* tempBuffer, std::uint64_t offset, std::uint64_t length) const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(codecClassName).append(" codec;\n") + .append(indent).append(INDENT).append("codec."); + + toStringBuilder.append(wrapMethod).append("(tempBuffer, offset"); + + if (null != actingVersion) + { + toStringBuilder.append(", ").append(actingVersion); + } + + toStringBuilder.append(", ").append("length);\n"); + + toStringBuilder.append(indent).append(INDENT).append("encode(codec, *this);\n") + .append(indent).append(INDENT).append("std::ostringstream oss;\n") + .append(indent).append(INDENT).append("oss << codec;\n") + .append(indent).append(INDENT).append("return oss.str();\n") + .append(indent).append("}\n"); + } + + private void generateFields( + final ClassBuilder classBuilder, + final String codecClassName, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + final String propertyName = signalToken.name(); + + switch (encodingToken.signal()) + { + case ENCODING: + generatePrimitiveProperty( + classBuilder, codecClassName, propertyName, signalToken, encodingToken, indent); + break; + + case BEGIN_ENUM: + generateEnumProperty(classBuilder, propertyName, signalToken, encodingToken, indent); + break; + + case BEGIN_SET: + case BEGIN_COMPOSITE: + generateComplexProperty(classBuilder, propertyName, signalToken, encodingToken, indent); + break; + + default: + break; + } + } + } + } + + private void generateComplexProperty( + final ClassBuilder classBuilder, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String typeName = formatDtoClassName(typeToken.applicableTypeName()); + final String formattedPropertyName = formatPropertyName(propertyName); + final String fieldName = "m_" + toLowerFirstChar(propertyName); + + classBuilder.appendField() + .append(indent).append(typeName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("[[nodiscard]] const ").append(typeName).append("& ") + .append(formattedPropertyName).append("() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("[[nodiscard]] ").append(typeName).append("& ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + } + + private void generateEnumProperty( + final ClassBuilder classBuilder, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String enumName = formatClassName(typeToken.applicableTypeName()) + "::Value"; + + final String formattedPropertyName = formatPropertyName(propertyName); + + if (fieldToken.isConstantEncoding()) + { + final String constValue = fieldToken.encoding().constValue().toString(); + final String caseName = constValue.substring(constValue.indexOf(".") + 1); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("[[nodiscard]] static ").append(enumName).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(enumName).append("::") + .append(caseName).append(";\n") + .append(indent).append("}\n"); + } + else + { + final String fieldName = "m_" + toLowerFirstChar(propertyName); + + classBuilder.appendField() + .append(indent).append(enumName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("[[nodiscard]] ").append(enumName).append(" ") + .append(formattedPropertyName).append("() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("void ").append(formattedPropertyName) + .append("(").append(enumName).append(" value)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + } + } + + private void generatePrimitiveProperty( + final ClassBuilder classBuilder, + final String codecClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + generateConstPropertyMethods(classBuilder, propertyName, fieldToken, typeToken, indent); + } + else + { + generatePrimitivePropertyMethods(classBuilder, codecClassName, propertyName, fieldToken, typeToken, indent); + } + } + + private void generatePrimitivePropertyMethods( + final ClassBuilder classBuilder, + final String codecClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + generateSingleValueProperty(classBuilder, codecClassName, propertyName, fieldToken, typeToken, indent); + } + else if (arrayLength > 1) + { + generateArrayProperty(classBuilder, codecClassName, propertyName, fieldToken, typeToken, indent); + } + } + + private void generateArrayProperty( + final ClassBuilder classBuilder, + final String codecClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String fieldName = "m_" + toLowerFirstChar(propertyName); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + classBuilder.appendField() + .append(indent).append("std::string ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("[[nodiscard]] const std::string& ") + .append(formattedPropertyName).append("() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("void ").append(formattedPropertyName) + .append("(const std::string& borrowedValue)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = borrowedValue;\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("void ").append(formattedPropertyName) + .append("(std::string&& ownedValue)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = std::move(ownedValue);\n") + .append(indent).append("}\n"); + } + else + { + final String validateMethod = "validate" + toUpperFirstChar(propertyName); + final String elementTypeName = cppTypeName(typeToken.encoding().primitiveType()); + final String vectorTypeName = "std::vector<" + elementTypeName + ">"; + final CharSequence typeName = typeWithFieldOptionality( + fieldToken, + vectorTypeName + ); + + classBuilder.appendField() + .append(indent).append(typeName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("[[nodiscard]] ").append(typeName).append(" ") + .append(formattedPropertyName).append("() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("void ").append(formattedPropertyName).append("(") + .append(typeName).append("& borrowedValue").append(")\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(validateMethod).append("(borrowedValue);\n") + .append(indent).append(INDENT).append(fieldName).append(" = borrowedValue;\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("void ").append(formattedPropertyName).append("(") + .append(typeName).append("&& ownedValue").append(")\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(validateMethod).append("(ownedValue);\n") + .append(indent).append(INDENT).append(fieldName).append(" = std::move(ownedValue);\n") + .append(indent).append("}\n"); + + generateArrayValidateMethod( + classBuilder, + codecClassName, + fieldToken, + indent, + validateMethod, + typeName, + vectorTypeName, + formattedPropertyName); + } + } + + private static void generateArrayValidateMethod( + final ClassBuilder classBuilder, + final String codecClassName, + final Token fieldToken, + final String indent, + final String validateMethod, + final CharSequence typeName, + final String vectorTypeName, + final String formattedPropertyName) + { + final StringBuilder validateBuilder = classBuilder.appendPrivate().append("\n") + .append(indent).append("static void ").append(validateMethod).append("(") + .append(typeName).append(" value)\n") + .append(indent).append("{\n"); + + String value = "value"; + + if (fieldToken.isOptionalEncoding()) + { + validateBuilder.append(indent).append(INDENT) + .append("if (!value.has_value())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("return;\n") + .append(indent).append(INDENT) + .append("}\n"); + + validateBuilder.append(indent).append(INDENT) + .append(vectorTypeName).append(" actualValue = value.value();\n"); + + value = "actualValue"; + } + + validateBuilder.append(indent).append(INDENT) + .append("if (").append(value).append(".size() > ").append(codecClassName).append("::") + .append(formattedPropertyName).append("Length())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw std::invalid_argument(\"") + .append(formattedPropertyName) + .append(": too many elements: \" + std::to_string(") + .append(value).append(".size()));\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append("}\n"); + } + + private void generateSingleValueProperty( + final ClassBuilder classBuilder, + final String codecClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String elementTypeName = cppTypeName(typeToken.encoding().primitiveType()); + final CharSequence typeName = typeWithFieldOptionality( + fieldToken, + elementTypeName + ); + final String formattedPropertyName = formatPropertyName(propertyName); + final String fieldName = "m_" + toLowerFirstChar(propertyName); + final String validateMethod = "validate" + toUpperFirstChar(propertyName); + + classBuilder.appendField() + .append(indent).append(typeName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("[[nodiscard]] ").append(typeName).append(" ") + .append(formattedPropertyName).append("() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("void ").append(formattedPropertyName).append("(") + .append(typeName).append(" value)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(validateMethod).append("(value);\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + + final StringBuilder validateBuilder = classBuilder.appendPrivate().append("\n") + .append(indent).append("static void ").append(validateMethod).append("(") + .append(typeName).append(" value)\n") + .append(indent).append("{\n"); + + String value = "value"; + + if (fieldToken.isOptionalEncoding()) + { + validateBuilder.append(indent).append(INDENT) + .append("if (!value.has_value())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("return;\n") + .append(indent).append(INDENT) + .append("}\n"); + + validateBuilder.append(indent).append(INDENT) + .append("if (value.value() == ").append(codecClassName).append("::") + .append(formattedPropertyName).append("NullValue())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw std::invalid_argument(\"") + .append(propertyName) + .append(": null value is reserved: \" + std::to_string(value.value()));\n") + .append(indent).append(INDENT) + .append("}\n"); + + validateBuilder.append(indent).append(INDENT) + .append(elementTypeName).append(" actualValue = value.value();\n"); + + value = "actualValue"; + } + + validateBuilder.append(indent).append(INDENT) + .append("if (").append(value).append(" < ") + .append(codecClassName).append("::").append(formattedPropertyName).append("MinValue() || ") + .append(value).append(" > ") + .append(codecClassName).append("::").append(formattedPropertyName).append("MaxValue())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw std::invalid_argument(\"") + .append(propertyName) + .append(": value is out of allowed range: \" + std::to_string(") + .append(value).append("));\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append("}\n"); + } + + private void generateConstPropertyMethods( + final ClassBuilder classBuilder, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("static std::string ").append(toLowerFirstChar(propertyName)).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT) + .append("return \"").append(typeToken.encoding().constValue().toString()).append("\";\n") + .append(indent).append("}\n"); + } + else + { + final CharSequence literalValue = + generateLiteral(typeToken.encoding().primitiveType(), typeToken.encoding().constValue().toString()); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("[[nodiscard]] static ") + .append(cppTypeName(typeToken.encoding().primitiveType())) + .append(" ").append(formatPropertyName(propertyName)).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(literalValue).append(";\n") + .append(indent).append("}\n"); + } + } + + private void generateVarData( + final ClassBuilder classBuilder, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token token = tokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + final String dtoType = characterEncoding == null ? "std::vector" : "std::string"; + + final String fieldName = "m_" + toLowerFirstChar(propertyName); + final String formattedPropertyName = formatPropertyName(propertyName); + + classBuilder.appendField() + .append(indent).append(dtoType).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(indent).append("[[nodiscard]] const ").append(dtoType).append("& ") + .append(formattedPropertyName).append("() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(indent).append("[[nodiscard]] ").append(dtoType).append("& ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(indent).append("void ").append(formattedPropertyName) + .append("(const ").append(dtoType).append("& borrowedValue)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = borrowedValue;\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(indent).append("void ").append(formattedPropertyName) + .append("(").append(dtoType).append("&& ownedValue)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = std::move(ownedValue);\n") + .append(indent).append("}\n"); + } + } + } + + private static String formatDtoClassName(final String name) + { + return formatClassName(name + "Dto"); + } + + private void generateDtosForTypes() throws IOException + { + for (final List tokens : ir.types()) + { + switch (tokens.get(0).signal()) + { + case BEGIN_COMPOSITE: + generateComposite(tokens); + break; + + case BEGIN_SET: + generateChoiceSet(tokens); + break; + + default: + break; + } + } + } + + private void generateComposite(final List tokens) throws IOException + { + final String name = tokens.get(0).applicableTypeName(); + final String className = formatDtoClassName(name); + final String codecClassName = formatClassName(name); + + try (Writer out = outputManager.createOutput(className)) + { + final List compositeTokens = tokens.subList(1, tokens.size() - 1); + final Set referencedTypes = generateTypesToIncludes(compositeTokens); + referencedTypes.add(codecClassName); + out.append(generateDtoFileHeader(ir.namespaces(), className, referencedTypes)); + out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); + + final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT); + + generateCompositePropertyElements(classBuilder, codecClassName, compositeTokens, BASE_INDENT + INDENT); + generateCompositeDecodeFrom(classBuilder, className, codecClassName, compositeTokens, + BASE_INDENT + INDENT); + generateCompositeEncodeInto(classBuilder, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); + generateDisplay(classBuilder, codecClassName, "wrap", + codecClassName + "::sbeSchemaVersion()", BASE_INDENT + INDENT); + + classBuilder.appendTo(out); + out.append("} // namespace\n"); + out.append("#endif\n"); + } + } + + private void generateChoiceSet(final List tokens) throws IOException + { + final String name = tokens.get(0).applicableTypeName(); + final String className = formatDtoClassName(name); + final String codecClassName = formatClassName(name); + + try (Writer out = outputManager.createOutput(className)) + { + final List setTokens = tokens.subList(1, tokens.size() - 1); + final Set referencedTypes = generateTypesToIncludes(setTokens); + referencedTypes.add(codecClassName); + out.append(generateDtoFileHeader(ir.namespaces(), className, referencedTypes)); + out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); + + final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT); + + generateChoices(classBuilder, className, setTokens, BASE_INDENT + INDENT); + generateChoiceSetDecodeFrom(classBuilder, className, codecClassName, setTokens, BASE_INDENT + INDENT); + generateChoiceSetEncodeInto(classBuilder, className, codecClassName, setTokens, BASE_INDENT + INDENT); + + classBuilder.appendTo(out); + out.append("} // namespace\n"); + out.append("#endif\n"); + } + } + + private void generateChoiceSetEncodeInto( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final List setTokens, + final String indent) + { + final StringBuilder encodeBuilder = classBuilder.appendPublic() + .append("\n") + .append(indent).append("static void encode(\n") + .append(indent).append(INDENT).append(codecClassName).append("& codec, ") + .append("const ").append(dtoClassName).append("& dto)\n") + .append(indent).append("{\n"); + + encodeBuilder.append(indent).append(INDENT).append("codec.clear();\n"); + + for (final Token token : setTokens) + { + if (token.signal() == Signal.CHOICE) + { + final String formattedPropertyName = formatPropertyName(token.name()); + encodeBuilder.append(indent).append(INDENT).append("codec.").append(formattedPropertyName) + .append("(dto.").append(formattedPropertyName).append("());\n"); + } + } + + encodeBuilder.append(indent).append("}\n"); + } + + private void generateChoiceSetDecodeFrom( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final List setTokens, + final String indent) + { + final StringBuilder decodeBuilder = classBuilder.appendPublic() + .append("\n") + .append(indent).append("static void decode(\n") + .append(indent).append(INDENT).append("const ").append(codecClassName).append("& codec, ") + .append(dtoClassName).append("& dto)\n") + .append(indent).append("{\n"); + + for (final Token token : setTokens) + { + if (token.signal() == Signal.CHOICE) + { + final String formattedPropertyName = formatPropertyName(token.name()); + decodeBuilder.append(indent).append(INDENT).append("dto.").append(formattedPropertyName) + .append("(codec.").append(formattedPropertyName).append("());\n"); + } + } + + decodeBuilder.append(indent).append("}\n"); + } + + private void generateChoices( + final ClassBuilder classBuilder, + final String dtoClassName, + final List setTokens, + final String indent) + { + final List fields = new ArrayList<>(); + + for (final Token token : setTokens) + { + if (token.signal() == Signal.CHOICE) + { + final String fieldName = "m_" + toLowerFirstChar(token.name()); + final String formattedPropertyName = formatPropertyName(token.name()); + + fields.add(fieldName); + + classBuilder.appendField() + .append(indent).append("bool ").append(fieldName).append(";\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append("[[nodiscard]] bool ").append(formattedPropertyName).append("() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append(dtoClassName).append("& ") + .append(formattedPropertyName).append("(bool value)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("return *this;\n") + .append(indent).append("}\n"); + } + } + + final StringBuilder clearBuilder = classBuilder.appendPublic() + .append(indent).append(dtoClassName).append("& clear()\n") + .append(indent).append("{\n"); + + for (final String field : fields) + { + clearBuilder.append(indent).append(INDENT).append(field).append(" = false;\n"); + } + + clearBuilder.append(indent).append(INDENT).append("return *this;\n") + .append(indent).append("}\n"); + } + + private void generateCompositePropertyElements( + final ClassBuilder classBuilder, + final String codecClassName, + final List tokens, + final String indent) + { + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + final String propertyName = formatPropertyName(token.name()); + + switch (token.signal()) + { + case ENCODING: + generatePrimitiveProperty(classBuilder, codecClassName, propertyName, token, token, indent); + break; + + case BEGIN_ENUM: + generateEnumProperty(classBuilder, propertyName, token, token, indent); + break; + + case BEGIN_SET: + case BEGIN_COMPOSITE: + generateComplexProperty(classBuilder, propertyName, token, token, indent); + break; + + default: + break; + } + + i += tokens.get(i).componentTokenCount(); + } + } + + private static Set generateTypesToIncludes(final List tokens) + { + final Set typesToInclude = new HashSet<>(); + + for (final Token token : tokens) + { + switch (token.signal()) + { + case BEGIN_ENUM: + typesToInclude.add(formatClassName(token.applicableTypeName())); + break; + + case BEGIN_SET: + case BEGIN_COMPOSITE: + typesToInclude.add(formatDtoClassName(token.applicableTypeName())); + break; + + default: + break; + } + } + + return typesToInclude; + } + + private static CharSequence typeWithFieldOptionality( + final Token fieldToken, + final String typeName) + { + if (fieldToken.isOptionalEncoding()) + { + return "std::optional<" + typeName + ">"; + } + else + { + return typeName; + } + } + + private static CharSequence generateDtoFileHeader( + final CharSequence[] namespaces, + final String className, + final Collection typesToInclude) + { + final StringBuilder sb = new StringBuilder(); + + sb.append("/* Generated SBE (Simple Binary Encoding) message DTO */\n"); + + sb.append(String.format( + "#ifndef _%1$s_%2$s_CXX_H_\n" + + "#define _%1$s_%2$s_CXX_H_\n\n", + String.join("_", namespaces).toUpperCase(), + className.toUpperCase())); + + sb.append("#if __cplusplus < 201703L\n") + .append("#error DTO code requires at least C++17.\n") + .append("#endif\n\n"); + + sb.append("#include \n") + .append("#include \n") + .append("#include \n") + .append("#include \n") + .append("#include \n") + .append("#include \n") + .append("#include \n") + .append("#include \n") + .append("#include \n") + .append("#include \n"); + + if (typesToInclude != null && !typesToInclude.isEmpty()) + { + sb.append("\n"); + for (final String incName : typesToInclude) + { + sb.append("#include \"").append(incName).append(".h\"\n"); + } + } + + sb.append("\nnamespace "); + sb.append(String.join(" {\nnamespace ", namespaces)); + sb.append(" {\n\n"); + + return sb; + } + + private static String generateDocumentation(final String indent, final Token token) + { + final String description = token.description(); + if (null == description || description.isEmpty()) + { + return ""; + } + + return + indent + "/**\n" + + indent + " * " + description + "\n" + + indent + " */\n"; + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java new file mode 100644 index 0000000000..dfe00b449e --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java @@ -0,0 +1,36 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * Copyright 2017 MarketFactory Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.generation.cpp; + +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.TargetCodeGenerator; +import uk.co.real_logic.sbe.ir.Ir; + +/** + * {@link CodeGenerator} factory for CSharp DTOs. + */ +public class CppDtos implements TargetCodeGenerator +{ + /** + * {@inheritDoc} + */ + public CodeGenerator newInstance(final Ir ir, final String outputDir) + { + return new CppDtoGenerator(ir, new NamespaceOutputManager(outputDir, ir.applicableNamespace())); + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 5b5e6f0721..99f5498e38 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -3503,64 +3503,6 @@ private CharSequence generateNullValueLiteral(final PrimitiveType primitiveType, return generateLiteral(primitiveType, encoding.applicableNullValue().toString()); } - private static CharSequence generateLiteral(final PrimitiveType type, final String value) - { - String literal = ""; - - switch (type) - { - case CHAR: - case UINT8: - case UINT16: - case INT8: - case INT16: - literal = "static_cast<" + cppTypeName(type) + ">(" + value + ")"; - break; - - case UINT32: - literal = "UINT32_C(0x" + Integer.toHexString((int)Long.parseLong(value)) + ")"; - break; - - case INT32: - final long intValue = Long.parseLong(value); - if (intValue == Integer.MIN_VALUE) - { - literal = "INT32_MIN"; - } - else - { - literal = "INT32_C(" + value + ")"; - } - break; - - case FLOAT: - literal = value.endsWith("NaN") ? "SBE_FLOAT_NAN" : value + "f"; - break; - - case INT64: - final long longValue = Long.parseLong(value); - if (longValue == Long.MIN_VALUE) - { - literal = "INT64_MIN"; - } - else - { - literal = "INT64_C(" + value + ")"; - } - break; - - case UINT64: - literal = "UINT64_C(0x" + Long.toHexString(Long.parseLong(value)) + ")"; - break; - - case DOUBLE: - literal = value.endsWith("NaN") ? "SBE_DOUBLE_NAN" : value; - break; - } - - return literal; - } - private void generateDisplay( final StringBuilder sb, final String name, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java index 76b75687d2..6ac6d8afa8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java @@ -137,4 +137,62 @@ public static String closingBraces(final int count) return sb.toString(); } + + static CharSequence generateLiteral(final PrimitiveType type, final String value) + { + String literal = ""; + + switch (type) + { + case CHAR: + case UINT8: + case UINT16: + case INT8: + case INT16: + literal = "static_cast<" + cppTypeName(type) + ">(" + value + ")"; + break; + + case UINT32: + literal = "UINT32_C(0x" + Integer.toHexString((int)Long.parseLong(value)) + ")"; + break; + + case INT32: + final long intValue = Long.parseLong(value); + if (intValue == Integer.MIN_VALUE) + { + literal = "INT32_MIN"; + } + else + { + literal = "INT32_C(" + value + ")"; + } + break; + + case FLOAT: + literal = value.endsWith("NaN") ? "SBE_FLOAT_NAN" : value + "f"; + break; + + case INT64: + final long longValue = Long.parseLong(value); + if (longValue == Long.MIN_VALUE) + { + literal = "INT64_MIN"; + } + else + { + literal = "INT64_C(" + value + ")"; + } + break; + + case UINT64: + literal = "UINT64_C(0x" + Long.toHexString(Long.parseLong(value)) + ")"; + break; + + case DOUBLE: + literal = value.endsWith("NaN") ? "SBE_DOUBLE_NAN" : value; + break; + } + + return literal; + } } diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index b1319e2389..92f061d2ef 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -39,6 +39,7 @@ set(COMPOSITE_ELEMENTS_SCHEMA ${CODEC_SCHEMA_DIR}/composite-elements-schema.xml) set(COMPOSITE_OFFSETS_SCHEMA ${CODEC_SCHEMA_DIR}/composite-offsets-schema.xml) set(MESSAGE_BLOCK_LENGTH_TEST ${CODEC_SCHEMA_DIR}/message-block-length-test.xml) set(GROUP_WITH_DATA_SCHEMA ${CODEC_SCHEMA_DIR}/group-with-data-schema.xml) +set(DTO_SCHEMA ${CODEC_SCHEMA_DIR}/dto-test-schema.xml) set(ISSUE835_SCHEMA ${CODEC_SCHEMA_DIR}/issue835.xml) set(ISSUE889_SCHEMA ${CODEC_SCHEMA_DIR}/issue889.xml) set(ACCESS_ORDER_SCHEMA ${CODEC_SCHEMA_DIR}/field-order-check-schema.xml) @@ -54,6 +55,7 @@ add_custom_command( ${COMPOSITE_OFFSETS_SCHEMA} ${MESSAGE_BLOCK_LENGTH_TEST} ${GROUP_WITH_DATA_SCHEMA} + ${DTO_SCHEMA} ${ISSUE835_SCHEMA} ${ISSUE889_SCHEMA} ${ACCESS_ORDER_SCHEMA} @@ -66,12 +68,14 @@ add_custom_command( -Dsbe.generate.precedence.checks="true" -Dsbe.precedence.checks.flag.name="SBE_ENABLE_PRECEDENCE_CHECKS_IN_TESTS" -Dsbe.cpp.disable.implicit.copying="true" + -Dsbe.cpp.generate.dtos="true" -jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${COMPOSITE_OFFSETS_SCHEMA} ${MESSAGE_BLOCK_LENGTH_TEST} ${GROUP_WITH_DATA_SCHEMA} ${COMPOSITE_ELEMENTS_SCHEMA} + ${DTO_SCHEMA} ${ISSUE835_SCHEMA} ${ISSUE889_SCHEMA} ${ACCESS_ORDER_SCHEMA} @@ -92,3 +96,5 @@ sbe_test(Issue835Test codecs) sbe_test(Issue889Test codecs) sbe_test(FieldAccessOrderCheckTest codecs) target_compile_definitions(FieldAccessOrderCheckTest PRIVATE SBE_ENABLE_PRECEDENCE_CHECKS_IN_TESTS) +sbe_test(DtoTest codecs) +target_compile_features(DtoTest PRIVATE cxx_std_17) diff --git a/sbe-tool/src/test/cpp/DtoTest.cpp b/sbe-tool/src/test/cpp/DtoTest.cpp new file mode 100644 index 0000000000..59f46fe149 --- /dev/null +++ b/sbe-tool/src/test/cpp/DtoTest.cpp @@ -0,0 +1,195 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if __cplusplus < 201703L +#error DTO code requires at least C++17. +#endif + +#include +#include "dto_test/ExtendedCar.h" +#include "dto_test/ExtendedCarDto.h" + +using namespace dto_test; + +static const std::size_t BUFFER_LEN = 2048; + +static const std::uint32_t SERIAL_NUMBER = 1234; +static const std::uint16_t MODEL_YEAR = 2013; +static const BooleanType::Value AVAILABLE = BooleanType::T; +static const Model::Value CODE = Model::A; +static const bool CRUISE_CONTROL = true; +static const bool SPORTS_PACK = true; +static const bool SUNROOF = false; +static const BoostType::Value BOOST_TYPE = BoostType::NITROUS; +static const std::uint8_t BOOSTER_HORSEPOWER = 200; +static const std::int32_t ADDED1 = 7; +static const std::int8_t ADDED6_1 = 11; +static const std::int8_t ADDED6_2 = 13; + +static char VEHICLE_CODE[] = { 'a', 'b', 'c', 'd', 'e', 'f' }; +static char MANUFACTURER_CODE[] = { '1', '2', '3' }; +static const char *FUEL_FIGURES_1_USAGE_DESCRIPTION = "Urban Cycle"; +static const char *FUEL_FIGURES_2_USAGE_DESCRIPTION = "Combined Cycle"; +static const char *FUEL_FIGURES_3_USAGE_DESCRIPTION = "Highway Cycle"; +static const char *MANUFACTURER = "Honda"; +static const char *MODEL = "Civic VTi"; +static const char *ACTIVATION_CODE = "deadbeef"; +static const char *ADDED5 = "feedface"; + +static const std::uint8_t PERFORMANCE_FIGURES_COUNT = 2; +static const std::uint8_t FUEL_FIGURES_COUNT = 3; +static const std::uint8_t ACCELERATION_COUNT = 3; + +static const std::uint16_t fuel1Speed = 30; +static const float fuel1Mpg = 35.9f; +static const std::int8_t fuel1Added2Element1 = 42; +static const std::int8_t fuel1Added2Element2 = 43; +static const std::int8_t fuel1Added3 = 44; +static const std::uint16_t fuel2Speed = 55; +static const float fuel2Mpg = 49.0f; +static const std::int8_t fuel2Added2Element1 = 45; +static const std::int8_t fuel2Added2Element2 = 46; +static const std::int8_t fuel2Added3 = 47; +static const std::uint16_t fuel3Speed = 75; +static const float fuel3Mpg = 40.0f; +static const std::int8_t fuel3Added2Element1 = 48; +static const std::int8_t fuel3Added2Element2 = 49; +static const std::int8_t fuel3Added3 = 50; + +static const std::uint8_t perf1Octane = 95; +static const std::uint16_t perf1aMph = 30; +static const float perf1aSeconds = 4.0f; +static const std::uint16_t perf1bMph = 60; +static const float perf1bSeconds = 7.5f; +static const std::uint16_t perf1cMph = 100; +static const float perf1cSeconds = 12.2f; + +static const std::uint8_t perf2Octane = 99; +static const std::uint16_t perf2aMph = 30; +static const float perf2aSeconds = 3.8f; +static const std::uint16_t perf2bMph = 60; +static const float perf2bSeconds = 7.1f; +static const std::uint16_t perf2cMph = 100; +static const float perf2cSeconds = 11.8f; + +static const std::uint16_t engineCapacity = 2000; +static const std::uint8_t engineNumCylinders = 4; + +class DtoTest : public testing::Test +{ + +public: + static std::uint64_t encodeCar(ExtendedCar &car) + { + car.serialNumber(SERIAL_NUMBER) + .modelYear(MODEL_YEAR) + .available(AVAILABLE) + .code(CODE) + .putVehicleCode(VEHICLE_CODE); + + car.extras().clear() + .cruiseControl(CRUISE_CONTROL) + .sportsPack(SPORTS_PACK) + .sunRoof(SUNROOF); + + car.engine() + .capacity(engineCapacity) + .numCylinders(engineNumCylinders) + .putManufacturerCode(MANUFACTURER_CODE) + .efficiency(50) + .boosterEnabled(BooleanType::Value::T) + .booster().boostType(BOOST_TYPE).horsePower(BOOSTER_HORSEPOWER); + + car.added1(ADDED1); + + car.added4(BooleanType::Value::T); + + car.added6().one(ADDED6_1).two(ADDED6_2); + + ExtendedCar::FuelFigures &fuelFigures = car.fuelFiguresCount(FUEL_FIGURES_COUNT); + + fuelFigures + .next().speed(fuel1Speed).mpg(fuel1Mpg) + .putAdded2(fuel1Added2Element1, fuel1Added2Element2) + .added3(fuel1Added3) + .putUsageDescription( + FUEL_FIGURES_1_USAGE_DESCRIPTION, static_cast(strlen(FUEL_FIGURES_1_USAGE_DESCRIPTION))); + + fuelFigures + .next().speed(fuel2Speed).mpg(fuel2Mpg) + .putAdded2(fuel2Added2Element1, fuel2Added2Element2) + .added3(fuel2Added3) + .putUsageDescription( + FUEL_FIGURES_2_USAGE_DESCRIPTION, static_cast(strlen(FUEL_FIGURES_2_USAGE_DESCRIPTION))); + + fuelFigures + .next().speed(fuel3Speed).mpg(fuel3Mpg) + .putAdded2(fuel3Added2Element1, fuel3Added2Element2) + .added3(fuel3Added3) + .putUsageDescription( + FUEL_FIGURES_3_USAGE_DESCRIPTION, static_cast(strlen(FUEL_FIGURES_3_USAGE_DESCRIPTION))); + + ExtendedCar::PerformanceFigures &perfFigs = car.performanceFiguresCount(PERFORMANCE_FIGURES_COUNT); + + perfFigs.next() + .octaneRating(perf1Octane) + .accelerationCount(ACCELERATION_COUNT) + .next().mph(perf1aMph).seconds(perf1aSeconds) + .next().mph(perf1bMph).seconds(perf1bSeconds) + .next().mph(perf1cMph).seconds(perf1cSeconds); + + perfFigs.next() + .octaneRating(perf2Octane) + .accelerationCount(ACCELERATION_COUNT) + .next().mph(perf2aMph).seconds(perf2aSeconds) + .next().mph(perf2bMph).seconds(perf2bSeconds) + .next().mph(perf2cMph).seconds(perf2cSeconds); + + car.putManufacturer(MANUFACTURER, static_cast(strlen(MANUFACTURER))) + .putModel(MODEL, static_cast(strlen(MODEL))) + .putActivationCode(ACTIVATION_CODE, static_cast(strlen(ACTIVATION_CODE))) + .putAdded5(ADDED5, static_cast(strlen(ADDED5))); + + return car.encodedLength(); + } +}; + +TEST_F(DtoTest, shouldRoundTripCar) +{ + char input[BUFFER_LEN]; + std::memset(input, 0, BUFFER_LEN); + ExtendedCar encoder1; + encoder1.wrapForEncode(input, 0, BUFFER_LEN); + const std::uint64_t encodedCarLength = encodeCar(encoder1); + ExtendedCar decoder; + decoder.wrapForDecode( + input, + 0, + ExtendedCar::sbeBlockLength(), + ExtendedCar::sbeSchemaVersion(), + encodedCarLength); + ExtendedCarDto dto; + ExtendedCarDto::decode(decoder, dto); + char output[BUFFER_LEN]; + std::memset(output, 0, BUFFER_LEN); + ExtendedCar encoder2; + encoder2.wrapForEncode(output, 0, BUFFER_LEN); + ExtendedCarDto::encode(encoder2, dto); + const std::uint64_t encodedCarLength2 = encoder2.encodedLength(); + + EXPECT_EQ(encodedCarLength, encodedCarLength2); + EXPECT_EQ(0, std::memcmp(input, output, encodedCarLength2)); +} diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml new file mode 100644 index 0000000000..f6f832e990 --- /dev/null +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T + S + N + K + + + + + + + 9000 + + Petrol + + + + + + 0 + 1 + + + A + B + C + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 029fb2573432fe44fa2b9f0855614242f8511ade Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 2 Nov 2023 15:09:35 +0000 Subject: [PATCH 363/805] [C++] Only build DTOs with compilers that support C++ 17. --- .../sbe/generation/cpp/CppDtoGenerator.java | 6 +++-- sbe-tool/src/test/cpp/CMakeLists.txt | 26 +++++++++++++++++-- sbe-tool/src/test/cpp/DtoTest.cpp | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index e1e3793da8..60924dd8f2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -1777,7 +1777,8 @@ private static CharSequence generateDtoFileHeader( String.join("_", namespaces).toUpperCase(), className.toUpperCase())); - sb.append("#if __cplusplus < 201703L\n") + sb.append("#if (defined(_MSVC_LANG) && _MSVC_LANG < 201703L) || ") + .append("(!defined(_MSVC_LANG) && defined(__cplusplus) && __cplusplus < 201703L)\n") .append("#error DTO code requires at least C++17.\n") .append("#endif\n\n"); @@ -1790,7 +1791,8 @@ private static CharSequence generateDtoFileHeader( .append("#include \n") .append("#include \n") .append("#include \n") - .append("#include \n"); + .append("#include \n") + .append("#include \n"); if (typesToInclude != null && !typesToInclude.isEmpty()) { diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 92f061d2ef..1de7412623 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -96,5 +96,27 @@ sbe_test(Issue835Test codecs) sbe_test(Issue889Test codecs) sbe_test(FieldAccessOrderCheckTest codecs) target_compile_definitions(FieldAccessOrderCheckTest PRIVATE SBE_ENABLE_PRECEDENCE_CHECKS_IN_TESTS) -sbe_test(DtoTest codecs) -target_compile_features(DtoTest PRIVATE cxx_std_17) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # Check if the GCC version supports C++17 + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0") + sbe_test(DtoTest codecs) + target_compile_features(DtoTest PRIVATE cxx_std_17) + endif() +endif() + +if (CMAKE_CXX_COMPILER_ID STREQUAL "CLang") + # Check if CLang version supports C++17 + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "4.0") + sbe_test(DtoTest codecs) + target_compile_features(DtoTest PRIVATE cxx_std_17) + endif() +endif() + +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + # Check if MSVC version supports C++17 + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "19.14") + sbe_test(DtoTest codecs) + target_compile_options(DtoTest PRIVATE /std:c++17) + endif() +endif() diff --git a/sbe-tool/src/test/cpp/DtoTest.cpp b/sbe-tool/src/test/cpp/DtoTest.cpp index 59f46fe149..3c8f675051 100644 --- a/sbe-tool/src/test/cpp/DtoTest.cpp +++ b/sbe-tool/src/test/cpp/DtoTest.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#if __cplusplus < 201703L +#if (defined(_MSVC_LANG) && _MSVC_LANG < 201703L) || (!defined(_MSVC_LANG) && defined(__cplusplus) && __cplusplus < 201703L) #error DTO code requires at least C++17. #endif From 246e6f77a0405435881666835be2c01b73ce891c Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 3 Nov 2023 09:57:00 +0000 Subject: [PATCH 364/805] [C++] Improve naming conventions in DTOs. Changes: - `encode` -> `encodeWith` - `decode` -> `decodeWith` --- .../sbe/generation/cpp/CppDtoGenerator.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 60924dd8f2..651a3aa676 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -274,7 +274,7 @@ private void generateCompositeDecodeFrom( final String indent) { final StringBuilder decodeBuilder = classBuilder.appendPublic().append("\n") - .append(indent).append("static void decode(").append(codecClassName).append("& codec, ") + .append(indent).append("static void decodeWith(").append(codecClassName).append("& codec, ") .append(dtoClassName).append("& dto)\n") .append(indent).append("{\n"); @@ -299,7 +299,7 @@ private void generateCompositeEncodeInto( final String indent) { final StringBuilder encodeBuilder = classBuilder.appendPublic().append("\n") - .append(indent).append("static void encode(").append(codecClassName).append("& codec,") + .append(indent).append("static void encodeWith(").append(codecClassName).append("& codec,") .append("const ").append(dtoClassName).append("& dto)\n") .append(indent).append("{\n"); @@ -322,7 +322,7 @@ private void generateDecodeListFrom( final String indent) { classBuilder.appendPublic().append("\n") - .append(indent).append("static std::vector<").append(dtoClassName).append("> decodeMany(") + .append(indent).append("static std::vector<").append(dtoClassName).append("> decodeManyWith(") .append(codecClassName).append("& codec)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("std::vector<").append(dtoClassName) @@ -334,7 +334,7 @@ private void generateDecodeListFrom( .append(indent).append(INDENT).append(INDENT) .append(dtoClassName).append(" dto;\n") .append(indent).append(INDENT).append(INDENT) - .append(dtoClassName).append("::decode(codec.next(), dto);\n") + .append(dtoClassName).append("::decodeWith(codec.next(), dto);\n") .append(indent).append(INDENT).append(INDENT) .append("dtos[i] = dto;\n") .append(indent).append(INDENT) @@ -354,7 +354,7 @@ private void generateMessageDecodeFrom( final String indent) { final StringBuilder decodeBuilder = classBuilder.appendPublic().append("\n") - .append(indent).append("static void decode(").append(codecClassName).append("& codec, ") + .append(indent).append("static void decodeWith(").append(codecClassName).append("& codec, ") .append(dtoClassName).append("& dto)\n") .append(indent).append("{\n"); @@ -526,7 +526,7 @@ private void generateBitSetDecodeFrom( sb.append(")\n") .append(indent).append("{\n"); - sb.append(indent).append(INDENT).append(dtoTypeName).append("::decode(codec.") + sb.append(indent).append(INDENT).append(dtoTypeName).append("::decodeWith(codec.") .append(formattedPropertyName).append("(), ") .append("dto.").append(formattedPropertyName).append("());\n"); @@ -538,7 +538,7 @@ private void generateBitSetDecodeFrom( } else { - sb.append(indent).append(dtoTypeName).append("::decode(codec.") + sb.append(indent).append(dtoTypeName).append("::decodeWith(codec.") .append(formattedPropertyName).append("(), ") .append("dto.").append(formattedPropertyName).append("());\n"); } @@ -571,7 +571,7 @@ private void generateCompositePropertyDecodeFrom( final String formattedPropertyName = formatPropertyName(propertyName); final String dtoClassName = formatDtoClassName(typeToken.applicableTypeName()); - sb.append(indent).append(dtoClassName).append("::decode(codec.") + sb.append(indent).append(dtoClassName).append("::decodeWith(codec.") .append(formattedPropertyName).append("(), ") .append("dto.").append(formattedPropertyName).append("());\n"); } @@ -593,7 +593,7 @@ private void generateGroupsDecodeFrom( final String groupDtoClassName = formatDtoClassName(groupName); sb.append(indent).append("dto.").append(formattedPropertyName).append("(") - .append(groupDtoClassName).append("::decodeMany(codec.") + .append(groupDtoClassName).append("::decodeManyWith(codec.") .append(formattedPropertyName).append("()));\n"); i++; @@ -729,7 +729,7 @@ private void generateMessageEncodeInto( final String indent) { final StringBuilder encodeBuilder = classBuilder.appendPublic().append("\n") - .append(indent).append("static void encode(").append(codecClassName).append("& codec, const ") + .append(indent).append("static void encodeWith(").append(codecClassName).append("& codec, const ") .append(dtoClassName).append("& dto)\n") .append(indent).append("{\n"); @@ -914,7 +914,7 @@ private void generateComplexPropertyEncodeInto( final String formattedPropertyName = formatPropertyName(propertyName); final String typeName = formatDtoClassName(typeToken.applicableTypeName()); - sb.append(indent).append(typeName).append("::encode(codec.") + sb.append(indent).append(typeName).append("::encodeWith(codec.") .append(formattedPropertyName).append("(), dto.") .append(formattedPropertyName).append("());\n"); } @@ -944,7 +944,7 @@ private void generateGroupsEncodeInto( .append("Count(").append(formattedPropertyName).append(".size());\n\n") .append(indent).append("for (const auto& group: ").append(formattedPropertyName).append(")\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append(groupDtoTypeName).append("::encode(").append(groupCodecVarName) + .append(indent).append(INDENT).append(groupDtoTypeName).append("::encodeWith(").append(groupCodecVarName) .append(".next(), group);\n") .append(indent).append("}\n\n"); @@ -1024,7 +1024,7 @@ private void generateDisplay( toStringBuilder.append(", ").append("length);\n"); - toStringBuilder.append(indent).append(INDENT).append("encode(codec, *this);\n") + toStringBuilder.append(indent).append(INDENT).append("encodeWith(codec, *this);\n") .append(indent).append(INDENT).append("std::ostringstream oss;\n") .append(indent).append(INDENT).append("oss << codec;\n") .append(indent).append(INDENT).append("return oss.str();\n") @@ -1591,7 +1591,7 @@ private void generateChoiceSetEncodeInto( { final StringBuilder encodeBuilder = classBuilder.appendPublic() .append("\n") - .append(indent).append("static void encode(\n") + .append(indent).append("static void encodeWith(\n") .append(indent).append(INDENT).append(codecClassName).append("& codec, ") .append("const ").append(dtoClassName).append("& dto)\n") .append(indent).append("{\n"); @@ -1620,7 +1620,7 @@ private void generateChoiceSetDecodeFrom( { final StringBuilder decodeBuilder = classBuilder.appendPublic() .append("\n") - .append(indent).append("static void decode(\n") + .append(indent).append("static void decodeWith(\n") .append(indent).append(INDENT).append("const ").append(codecClassName).append("& codec, ") .append(dtoClassName).append("& dto)\n") .append(indent).append("{\n"); From e33c6a86affbed5a8b976483f667bb4d4e72c93f Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 3 Nov 2023 11:31:02 +0000 Subject: [PATCH 365/805] [C++] Support "to string" without specification of buffer length. As we use the generated codecs to create a string representation of our DTOs, we don't use Agrona buffers in C++, and there is no concept of resizing, it is necessary to size a temporary buffer during the construction of the string data. Previously, we were letting the user supply this value, which wasn't a very friendly API. Now, we use the `computeLength` methods on the codec to determine how big of a temporary buffer we need. Perhaps the methods will also be useful for avoiding a buffer copy when used in conjunction with Aeron. For example, a developer could use `dto.computeEncodedLength()` to initialise a buffer claim rather than copying via the `offer(...)` API. --- .../sbe/generation/cpp/CppDtoGenerator.java | 145 ++++++++++++++++-- sbe-tool/src/test/cpp/DtoTest.cpp | 16 +- 2 files changed, 143 insertions(+), 18 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 651a3aa676..8ee894cf08 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -100,7 +100,9 @@ public void generate() throws IOException groups, varData, BASE_INDENT + INDENT); generateMessageEncodeInto(classBuilder, className, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); - generateDisplay(classBuilder, codecClassName, "wrapForEncode", null, BASE_INDENT + INDENT); + generateComputeEncodedLength(classBuilder, codecClassName, groups, varData, BASE_INDENT + INDENT); + generateDisplay(classBuilder, className, codecClassName, "dto.computeEncodedLength()", + "wrapForEncode", null, BASE_INDENT + INDENT); try (Writer out = outputManager.createOutput(className)) { @@ -227,6 +229,8 @@ private void generateGroups( fields, groups, varData, indent + INDENT); generateMessageEncodeInto( groupClassBuilder, groupClassName, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); + generateComputeEncodedLength(groupClassBuilder, qualifiedCodecClassName, groups, varData, + indent + INDENT); groupClassBuilder.appendTo( classBuilder.appendPublic().append("\n").append(generateDocumentation(indent, groupToken)) @@ -266,6 +270,103 @@ private void generateGroups( } } + private void generateComputeEncodedLength( + final ClassBuilder classBuilder, + final String qualifiedCodecClassName, + final List groupTokens, + final List varDataTokens, + final String indent) + { + final StringBuilder lengthBuilder = classBuilder.appendPublic() + .append("\n") + .append(indent).append("[[nodiscard]] std::size_t computeEncodedLength() const\n") + .append(indent).append("{\n"); + + final StringBuilder arguments = new StringBuilder(); + + for (int i = 0, size = groupTokens.size(); i < size; i++) + { + final Token groupToken = groupTokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + i++; + i += groupTokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(groupTokens, i, fields); + final List subGroups = new ArrayList<>(); + i = collectGroups(groupTokens, i, subGroups); + final List subVarData = new ArrayList<>(); + i = collectVarData(groupTokens, i, subVarData); + + final String groupName = groupToken.name(); + final String fieldName = "m_" + toLowerFirstChar(groupName); + + final boolean isConstLength = subGroups.isEmpty() && subVarData.isEmpty(); + final String argumentName = isConstLength ? + toLowerFirstChar(groupName) + "Count" : + toLowerFirstChar(groupName) + "Lengths"; + + if (isConstLength) + { + lengthBuilder + .append(indent).append(INDENT).append("std::size_t ").append(argumentName) + .append(" = ").append(fieldName).append(".size();\n"); + } + else + { + final String countName = argumentName + "Count"; + + lengthBuilder + .append(indent).append(INDENT).append("std::size_t ").append(countName).append(" = ") + .append(fieldName).append(".size();\n") + .append(indent).append(INDENT).append("std::vector> ") + .append(argumentName).append("(").append(countName).append(");\n") + .append(indent).append(INDENT).append("for (std::size_t i = 0; i < ").append(countName) + .append("; i++)\n") + .append(indent).append(INDENT).append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("auto& group = ").append(fieldName).append("[i];\n") + .append(indent).append(INDENT).append(INDENT) + .append(argumentName).append("[i] = group.computeEncodedLength();\n") + .append(indent).append(INDENT).append("}\n") + .append("\n"); + } + + arguments.append(argumentName).append(", "); + } + + for (int i = 0, size = varDataTokens.size(); i < size; i++) + { + final Token token = varDataTokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final Token varDataToken = Generators.findFirst("varData", varDataTokens, i); + final String fieldName = "m_" + toLowerFirstChar(propertyName); + final String argumentName = toLowerFirstChar(propertyName) + "Length"; + + lengthBuilder.append(indent).append(INDENT).append("std::size_t ").append(argumentName) + .append(" = ").append(fieldName).append(".size() * sizeof(") + .append(cppTypeName(varDataToken.encoding().primitiveType())).append(");\n"); + + arguments.append(argumentName).append(", "); + } + } + + if (arguments.length() >= 2) + { + arguments.setLength(arguments.length() - 2); + } + + lengthBuilder.append(indent).append(INDENT).append("return ").append(qualifiedCodecClassName) + .append("::computeLength(").append(arguments).append(");\n") + .append(indent).append("}\n"); + } + private void generateCompositeDecodeFrom( final ClassBuilder classBuilder, final String dtoClassName, @@ -944,8 +1045,8 @@ private void generateGroupsEncodeInto( .append("Count(").append(formattedPropertyName).append(".size());\n\n") .append(indent).append("for (const auto& group: ").append(formattedPropertyName).append(")\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append(groupDtoTypeName).append("::encodeWith(").append(groupCodecVarName) - .append(".next(), group);\n") + .append(indent).append(INDENT).append(groupDtoTypeName) + .append("::encodeWith(").append(groupCodecVarName).append(".next(), group);\n") .append(indent).append("}\n\n"); i++; @@ -1002,32 +1103,44 @@ private void generateVarDataEncodeInto( private void generateDisplay( final ClassBuilder classBuilder, + final String dtoClassName, final String codecClassName, + final String lengthExpression, final String wrapMethod, final String actingVersion, final String indent) { - final StringBuilder toStringBuilder = classBuilder.appendPublic() + final StringBuilder streamBuilder = classBuilder.appendPublic() .append("\n") - .append(indent).append( - "std::string string(char* tempBuffer, std::uint64_t offset, std::uint64_t length) const\n") + .append(indent).append("friend std::ostream& operator << (std::ostream& stream, const ") + .append(dtoClassName).append("& dto)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(codecClassName).append(" codec;\n") - .append(indent).append(INDENT).append("codec."); - - toStringBuilder.append(wrapMethod).append("(tempBuffer, offset"); + .append(indent).append(INDENT).append("const std::size_t length = ") + .append(lengthExpression).append(";\n") + .append(indent).append(INDENT).append("std::vector buffer(length);\n") + .append(indent).append(INDENT).append("codec.").append(wrapMethod) + .append("(buffer.data(), 0"); if (null != actingVersion) { - toStringBuilder.append(", ").append(actingVersion); + streamBuilder.append(", ").append(actingVersion); } - toStringBuilder.append(", ").append("length);\n"); + streamBuilder.append(", ").append("length);\n"); + + streamBuilder.append(indent).append(INDENT).append("encodeWith(codec, dto);\n") + .append(indent).append(INDENT).append("stream << codec;\n") + .append(indent).append(INDENT).append("return stream;\n") + .append(indent).append("}\n"); - toStringBuilder.append(indent).append(INDENT).append("encodeWith(codec, *this);\n") - .append(indent).append(INDENT).append("std::ostringstream oss;\n") - .append(indent).append(INDENT).append("oss << codec;\n") - .append(indent).append(INDENT).append("return oss.str();\n") + classBuilder.appendPublic() + .append("\n") + .append(indent).append("[[nodiscard]] std::string string() const\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("std::ostringstream stream;\n") + .append(indent).append(INDENT).append("stream << *this;\n") + .append(indent).append(INDENT).append("return stream.str();\n") .append(indent).append("}\n"); } @@ -1547,7 +1660,7 @@ private void generateComposite(final List tokens) throws IOException generateCompositeDecodeFrom(classBuilder, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateCompositeEncodeInto(classBuilder, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); - generateDisplay(classBuilder, codecClassName, "wrap", + generateDisplay(classBuilder, className, codecClassName, codecClassName + "::encodedLength()", "wrap", codecClassName + "::sbeSchemaVersion()", BASE_INDENT + INDENT); classBuilder.appendTo(out); diff --git a/sbe-tool/src/test/cpp/DtoTest.cpp b/sbe-tool/src/test/cpp/DtoTest.cpp index 3c8f675051..2b37c6b910 100644 --- a/sbe-tool/src/test/cpp/DtoTest.cpp +++ b/sbe-tool/src/test/cpp/DtoTest.cpp @@ -174,6 +174,7 @@ TEST_F(DtoTest, shouldRoundTripCar) ExtendedCar encoder1; encoder1.wrapForEncode(input, 0, BUFFER_LEN); const std::uint64_t encodedCarLength = encodeCar(encoder1); + ExtendedCar decoder; decoder.wrapForDecode( input, @@ -182,14 +183,25 @@ TEST_F(DtoTest, shouldRoundTripCar) ExtendedCar::sbeSchemaVersion(), encodedCarLength); ExtendedCarDto dto; - ExtendedCarDto::decode(decoder, dto); + ExtendedCarDto::decodeWith(decoder, dto); + char output[BUFFER_LEN]; std::memset(output, 0, BUFFER_LEN); ExtendedCar encoder2; encoder2.wrapForEncode(output, 0, BUFFER_LEN); - ExtendedCarDto::encode(encoder2, dto); + ExtendedCarDto::encodeWith(encoder2, dto); const std::uint64_t encodedCarLength2 = encoder2.encodedLength(); + decoder.sbeRewind(); + std::ostringstream originalStringStream; + originalStringStream << decoder; + std::string originalString = originalStringStream.str(); + + std::ostringstream dtoStringStream; + dtoStringStream << dto; + std::string dtoString = dtoStringStream.str(); + EXPECT_EQ(encodedCarLength, encodedCarLength2); EXPECT_EQ(0, std::memcmp(input, output, encodedCarLength2)); + EXPECT_EQ(originalString, dtoString); } From f88d345519583d4ea84a496c71ae59bbcdc0324e Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 3 Nov 2023 15:34:09 +0000 Subject: [PATCH 366/805] [C++] Fix issues with length computation. I had incorrectly assumed that the `Flyweight::computeLength` method took _encoded lengths_ of groups etc., but actually it takes a complicated structure of group counts and variable lengths. As it was hard to build this list, I've opted for a simpler approach: do the length calculation within the generated DTO message and its groups. In this commit, I've also added some convenience methods for converting between DTOs and "byte arrays". --- .../sbe/generation/cpp/CppDtoGenerator.java | 251 +++++++++++------- sbe-tool/src/test/cpp/DtoTest.cpp | 34 ++- 2 files changed, 186 insertions(+), 99 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 8ee894cf08..c13a3211b1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -96,10 +96,12 @@ public void generate() throws IOException collectVarData(messageBody, offset, varData); generateVarData(classBuilder, varData, BASE_INDENT + INDENT); - generateMessageDecodeFrom(classBuilder, className, codecClassName, fields, + generateDecodeWith(classBuilder, className, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); - generateMessageEncodeInto(classBuilder, className, codecClassName, fields, groups, varData, + generateDecodeFrom(classBuilder, className, codecClassName, BASE_INDENT + INDENT); + generateEncodeWith(classBuilder, className, codecClassName, fields, groups, varData, BASE_INDENT + INDENT); + generateEncodeInto(classBuilder, className, codecClassName, BASE_INDENT + INDENT); generateComputeEncodedLength(classBuilder, codecClassName, groups, varData, BASE_INDENT + INDENT); generateDisplay(classBuilder, className, codecClassName, "dto.computeEncodedLength()", "wrapForEncode", null, BASE_INDENT + INDENT); @@ -225,9 +227,9 @@ private void generateGroups( generateDecodeListFrom( groupClassBuilder, groupClassName, qualifiedCodecClassName, indent + INDENT); - generateMessageDecodeFrom(groupClassBuilder, groupClassName, qualifiedCodecClassName, + generateDecodeWith(groupClassBuilder, groupClassName, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); - generateMessageEncodeInto( + generateEncodeWith( groupClassBuilder, groupClassName, qualifiedCodecClassName, fields, groups, varData, indent + INDENT); generateComputeEncodedLength(groupClassBuilder, qualifiedCodecClassName, groups, varData, indent + INDENT); @@ -282,7 +284,11 @@ private void generateComputeEncodedLength( .append(indent).append("[[nodiscard]] std::size_t computeEncodedLength() const\n") .append(indent).append("{\n"); - final StringBuilder arguments = new StringBuilder(); + lengthBuilder + .append(indent).append(INDENT).append("std::size_t encodedLength = 0;\n"); + + lengthBuilder.append(indent).append(INDENT).append("encodedLength += ").append(qualifiedCodecClassName) + .append("::sbeBlockLength();\n\n"); for (int i = 0, size = groupTokens.size(); i < size; i++) { @@ -304,39 +310,17 @@ private void generateComputeEncodedLength( final String groupName = groupToken.name(); final String fieldName = "m_" + toLowerFirstChar(groupName); - - final boolean isConstLength = subGroups.isEmpty() && subVarData.isEmpty(); - final String argumentName = isConstLength ? - toLowerFirstChar(groupName) + "Count" : - toLowerFirstChar(groupName) + "Lengths"; - - if (isConstLength) - { - lengthBuilder - .append(indent).append(INDENT).append("std::size_t ").append(argumentName) - .append(" = ").append(fieldName).append(".size();\n"); - } - else - { - final String countName = argumentName + "Count"; - - lengthBuilder - .append(indent).append(INDENT).append("std::size_t ").append(countName).append(" = ") - .append(fieldName).append(".size();\n") - .append(indent).append(INDENT).append("std::vector> ") - .append(argumentName).append("(").append(countName).append(");\n") - .append(indent).append(INDENT).append("for (std::size_t i = 0; i < ").append(countName) - .append("; i++)\n") - .append(indent).append(INDENT).append("{\n") - .append(indent).append(INDENT).append(INDENT) - .append("auto& group = ").append(fieldName).append("[i];\n") - .append(indent).append(INDENT).append(INDENT) - .append(argumentName).append("[i] = group.computeEncodedLength();\n") - .append(indent).append(INDENT).append("}\n") - .append("\n"); - } - - arguments.append(argumentName).append(", "); + final String groupCodecClassName = qualifiedCodecClassName + "::" + formatClassName(groupName); + + lengthBuilder + .append(indent).append(INDENT).append("encodedLength += ") + .append(groupCodecClassName).append("::sbeHeaderSize();\n\n") + .append(indent).append(INDENT).append("for (auto& group : ") + .append(fieldName).append(")\n") + .append(indent).append(INDENT).append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("encodedLength += group.computeEncodedLength();\n") + .append(indent).append(INDENT).append("}\n\n"); } for (int i = 0, size = varDataTokens.size(); i < size; i++) @@ -347,27 +331,23 @@ private void generateComputeEncodedLength( final String propertyName = token.name(); final Token varDataToken = Generators.findFirst("varData", varDataTokens, i); final String fieldName = "m_" + toLowerFirstChar(propertyName); - final String argumentName = toLowerFirstChar(propertyName) + "Length"; - lengthBuilder.append(indent).append(INDENT).append("std::size_t ").append(argumentName) - .append(" = ").append(fieldName).append(".size() * sizeof(") - .append(cppTypeName(varDataToken.encoding().primitiveType())).append(");\n"); + lengthBuilder.append(indent).append(INDENT).append("encodedLength += ") + .append(qualifiedCodecClassName).append("::") + .append(formatPropertyName(propertyName)).append("HeaderLength();\n"); - arguments.append(argumentName).append(", "); - } - } + lengthBuilder.append(indent).append(INDENT).append("encodedLength += ") + .append(fieldName).append(".size() * sizeof(") + .append(cppTypeName(varDataToken.encoding().primitiveType())).append(");\n\n"); - if (arguments.length() >= 2) - { - arguments.setLength(arguments.length() - 2); + } } - lengthBuilder.append(indent).append(INDENT).append("return ").append(qualifiedCodecClassName) - .append("::computeLength(").append(arguments).append(");\n") + lengthBuilder.append(indent).append(INDENT).append("return encodedLength;\n") .append(indent).append("}\n"); } - private void generateCompositeDecodeFrom( + private void generateCompositeDecodeWith( final ClassBuilder classBuilder, final String dtoClassName, final String codecClassName, @@ -383,7 +363,7 @@ private void generateCompositeDecodeFrom( { final Token token = tokens.get(i); - generateFieldDecodeFrom( + generateFieldDecodeWith( decodeBuilder, token, token, codecClassName, indent + INDENT); i += tokens.get(i).componentTokenCount(); @@ -392,7 +372,7 @@ private void generateCompositeDecodeFrom( decodeBuilder.append(indent).append("}\n"); } - private void generateCompositeEncodeInto( + private void generateCompositeEncodeWith( final ClassBuilder classBuilder, final String dtoClassName, final String codecClassName, @@ -408,7 +388,7 @@ private void generateCompositeEncodeInto( { final Token token = tokens.get(i); - generateFieldEncodeInto(encodeBuilder, codecClassName, token, token, indent + INDENT); + generateFieldEncodeWith(encodeBuilder, codecClassName, token, token, indent + INDENT); i += tokens.get(i).componentTokenCount(); } @@ -445,7 +425,7 @@ private void generateDecodeListFrom( .append(indent).append("}\n"); } - private void generateMessageDecodeFrom( + private void generateDecodeWith( final ClassBuilder classBuilder, final String dtoClassName, final String codecClassName, @@ -459,13 +439,35 @@ private void generateMessageDecodeFrom( .append(dtoClassName).append("& dto)\n") .append(indent).append("{\n"); - generateMessageFieldsDecodeFrom(decodeBuilder, fields, codecClassName, indent + INDENT); - generateGroupsDecodeFrom(decodeBuilder, groups, indent + INDENT); - generateVarDataDecodeFrom(decodeBuilder, varData, indent + INDENT); + generateMessageFieldsDecodeWith(decodeBuilder, fields, codecClassName, indent + INDENT); + generateGroupsDecodeWith(decodeBuilder, groups, indent + INDENT); + generateVarDataDecodeWith(decodeBuilder, varData, indent + INDENT); decodeBuilder.append(indent).append("}\n"); } - private void generateMessageFieldsDecodeFrom( + private static void generateDecodeFrom( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final String indent) + { + classBuilder.appendPublic() + .append("\n") + .append(indent).append("static ").append(dtoClassName).append(" decodeFrom(") + .append("char* buffer, std::uint64_t offset, ") + .append("std::uint64_t actingBlockLength, std::uint64_t actingVersion, ") + .append("std::uint64_t bufferLength)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(codecClassName).append(" codec;\n") + .append(indent).append(INDENT) + .append("codec.wrapForDecode(buffer, offset, actingBlockLength, actingVersion, bufferLength);\n") + .append(indent).append(INDENT).append(dtoClassName).append(" dto;\n") + .append(indent).append(INDENT).append(dtoClassName).append("::decodeWith(codec, dto);\n") + .append(indent).append(INDENT).append("return dto;\n") + .append(indent).append("}\n"); + } + + private void generateMessageFieldsDecodeWith( final StringBuilder sb, final List tokens, final String codecClassName, @@ -478,12 +480,12 @@ private void generateMessageFieldsDecodeFrom( { final Token encodingToken = tokens.get(i + 1); - generateFieldDecodeFrom(sb, signalToken, encodingToken, codecClassName, indent); + generateFieldDecodeWith(sb, signalToken, encodingToken, codecClassName, indent); } } } - private void generateFieldDecodeFrom( + private void generateFieldDecodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -493,20 +495,20 @@ private void generateFieldDecodeFrom( switch (typeToken.signal()) { case ENCODING: - generatePrimitiveDecodeFrom(sb, fieldToken, typeToken, codecClassName, indent); + generatePrimitiveDecodeWith(sb, fieldToken, typeToken, codecClassName, indent); break; case BEGIN_SET: final String bitSetName = formatDtoClassName(typeToken.applicableTypeName()); - generateBitSetDecodeFrom(sb, fieldToken, bitSetName, indent); + generateBitSetDecodeWith(sb, fieldToken, bitSetName, indent); break; case BEGIN_ENUM: - generateEnumDecodeFrom(sb, fieldToken, indent); + generateEnumDecodeWith(sb, fieldToken, indent); break; case BEGIN_COMPOSITE: - generateCompositePropertyDecodeFrom(sb, fieldToken, typeToken, indent); + generateCompositePropertyDecodeWith(sb, fieldToken, typeToken, indent); break; default: @@ -514,7 +516,7 @@ private void generateFieldDecodeFrom( } } - private void generatePrimitiveDecodeFrom( + private void generatePrimitiveDecodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -551,11 +553,11 @@ private void generatePrimitiveDecodeFrom( } else if (arrayLength > 1) { - generateArrayDecodeFrom(sb, fieldToken, typeToken, codecClassName, indent); + generateArrayDecodeWith(sb, fieldToken, typeToken, codecClassName, indent); } } - private void generateArrayDecodeFrom( + private void generateArrayDecodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -606,7 +608,7 @@ private void generateArrayDecodeFrom( } } - private void generateBitSetDecodeFrom( + private void generateBitSetDecodeWith( final StringBuilder sb, final Token fieldToken, final String dtoTypeName, @@ -645,7 +647,7 @@ private void generateBitSetDecodeFrom( } } - private void generateEnumDecodeFrom( + private void generateEnumDecodeWith( final StringBuilder sb, final Token fieldToken, final String indent) @@ -662,7 +664,7 @@ private void generateEnumDecodeFrom( .append("codec.").append(formattedPropertyName).append("());\n"); } - private void generateCompositePropertyDecodeFrom( + private void generateCompositePropertyDecodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -677,7 +679,7 @@ private void generateCompositePropertyDecodeFrom( .append("dto.").append(formattedPropertyName).append("());\n"); } - private void generateGroupsDecodeFrom( + private void generateGroupsDecodeWith( final StringBuilder sb, final List tokens, final String indent) @@ -711,7 +713,7 @@ private void generateGroupsDecodeFrom( } } - private void generateVarDataDecodeFrom( + private void generateVarDataDecodeWith( final StringBuilder sb, final List tokens, final String indent) @@ -820,7 +822,7 @@ private void generateRecordPropertyAssignment( } } - private void generateMessageEncodeInto( + private void generateEncodeWith( final ClassBuilder classBuilder, final String dtoClassName, final String codecClassName, @@ -834,14 +836,67 @@ private void generateMessageEncodeInto( .append(dtoClassName).append("& dto)\n") .append(indent).append("{\n"); - generateFieldsEncodeInto(encodeBuilder, codecClassName, fields, indent + INDENT); - generateGroupsEncodeInto(encodeBuilder, groups, indent + INDENT); - generateVarDataEncodeInto(encodeBuilder, varData, indent + INDENT); + generateFieldsEncodeWith(encodeBuilder, codecClassName, fields, indent + INDENT); + generateGroupsEncodeWith(encodeBuilder, groups, indent + INDENT); + generateVarDataEncodeWith(encodeBuilder, varData, indent + INDENT); encodeBuilder.append(indent).append("}\n"); } - private void generateFieldsEncodeInto( + private static void generateEncodeInto( + final ClassBuilder classBuilder, + final String dtoClassName, + final String codecClassName, + final String indent) + { + classBuilder.appendPublic() + .append("\n") + .append(indent).append("static std::size_t encodeInto(const ").append(dtoClassName).append("& dto, ") + .append("char *buffer, std::uint64_t offset, std::uint64_t bufferLength)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(codecClassName).append(" codec;\n") + .append(indent).append(INDENT).append("codec.wrapForEncode(buffer, offset, bufferLength);\n") + .append(indent).append(INDENT).append(dtoClassName).append("::encodeWith(codec, dto);\n") + .append(indent).append(INDENT).append("return codec.encodedLength();\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append("static std::size_t encodeWithHeaderInto(const ") + .append(dtoClassName).append("& dto, ") + .append("char *buffer, std::uint64_t offset, std::uint64_t bufferLength)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(codecClassName).append(" codec;\n") + .append(indent).append(INDENT).append("codec.wrapAndApplyHeader(buffer, offset, bufferLength);\n") + .append(indent).append(INDENT).append(dtoClassName).append("::encodeWith(codec, dto);\n") + .append(indent).append(INDENT).append("return codec.sbePosition() - offset;\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append("[[nodiscard]] static std::vector bytes(const ") + .append(dtoClassName).append("& dto)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("std::vector bytes(dto.computeEncodedLength());\n") + .append(indent).append(INDENT).append(dtoClassName) + .append("::encodeInto(dto, reinterpret_cast(bytes.data()), 0, bytes.size());\n") + .append(indent).append(INDENT).append("return bytes;\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append("[[nodiscard]] static std::vector bytesWithHeader(const ") + .append(dtoClassName).append("& dto)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("std::vector bytes(dto.computeEncodedLength() + ") + .append("MessageHeader::encodedLength());\n") + .append(indent).append(INDENT).append(dtoClassName) + .append("::encodeWithHeaderInto(dto, reinterpret_cast(bytes.data()), 0, bytes.size());\n") + .append(indent).append(INDENT).append("return bytes;\n") + .append(indent).append("}\n"); + } + + private void generateFieldsEncodeWith( final StringBuilder sb, final String codecClassName, final List tokens, @@ -853,12 +908,12 @@ private void generateFieldsEncodeInto( if (signalToken.signal() == Signal.BEGIN_FIELD) { final Token encodingToken = tokens.get(i + 1); - generateFieldEncodeInto(sb, codecClassName, signalToken, encodingToken, indent); + generateFieldEncodeWith(sb, codecClassName, signalToken, encodingToken, indent); } } } - private void generateFieldEncodeInto( + private void generateFieldEncodeWith( final StringBuilder sb, final String codecClassName, final Token fieldToken, @@ -868,16 +923,16 @@ private void generateFieldEncodeInto( switch (typeToken.signal()) { case ENCODING: - generatePrimitiveEncodeInto(sb, codecClassName, fieldToken, typeToken, indent); + generatePrimitiveEncodeWith(sb, codecClassName, fieldToken, typeToken, indent); break; case BEGIN_ENUM: - generateEnumEncodeInto(sb, fieldToken, indent); + generateEnumEncodeWith(sb, fieldToken, indent); break; case BEGIN_SET: case BEGIN_COMPOSITE: - generateComplexPropertyEncodeInto(sb, fieldToken, typeToken, indent); + generateComplexPropertyEncodeWith(sb, fieldToken, typeToken, indent); break; default: @@ -885,7 +940,7 @@ private void generateFieldEncodeInto( } } - private void generatePrimitiveEncodeInto( + private void generatePrimitiveEncodeWith( final StringBuilder sb, final String codecClassName, final Token fieldToken, @@ -901,15 +956,15 @@ private void generatePrimitiveEncodeInto( if (arrayLength == 1) { - generatePrimitiveValueEncodeInto(sb, codecClassName, fieldToken, indent); + generatePrimitiveValueEncodeWith(sb, codecClassName, fieldToken, indent); } else if (arrayLength > 1) { - generateArrayEncodeInto(sb, fieldToken, typeToken, indent); + generateArrayEncodeWith(sb, fieldToken, typeToken, indent); } } - private void generateArrayEncodeInto( + private void generateArrayEncodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -964,7 +1019,7 @@ private void generateArrayEncodeInto( } } - private void generatePrimitiveValueEncodeInto( + private void generatePrimitiveValueEncodeWith( final StringBuilder sb, final String codecClassName, final Token fieldToken, @@ -988,7 +1043,7 @@ private void generatePrimitiveValueEncodeInto( .append(value).append(");\n"); } - private void generateEnumEncodeInto( + private void generateEnumEncodeWith( final StringBuilder sb, final Token fieldToken, final String indent) @@ -1005,7 +1060,7 @@ private void generateEnumEncodeInto( .append(formattedPropertyName).append("());\n"); } - private void generateComplexPropertyEncodeInto( + private void generateComplexPropertyEncodeWith( final StringBuilder sb, final Token fieldToken, final Token typeToken, @@ -1020,7 +1075,7 @@ private void generateComplexPropertyEncodeInto( .append(formattedPropertyName).append("());\n"); } - private void generateGroupsEncodeInto( + private void generateGroupsEncodeWith( final StringBuilder sb, final List tokens, final String indent) @@ -1063,7 +1118,7 @@ private void generateGroupsEncodeInto( } } - private void generateVarDataEncodeInto( + private void generateVarDataEncodeWith( final StringBuilder sb, final List tokens, final String indent) @@ -1657,9 +1712,9 @@ private void generateComposite(final List tokens) throws IOException final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT); generateCompositePropertyElements(classBuilder, codecClassName, compositeTokens, BASE_INDENT + INDENT); - generateCompositeDecodeFrom(classBuilder, className, codecClassName, compositeTokens, + generateCompositeDecodeWith(classBuilder, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); - generateCompositeEncodeInto(classBuilder, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); + generateCompositeEncodeWith(classBuilder, className, codecClassName, compositeTokens, BASE_INDENT + INDENT); generateDisplay(classBuilder, className, codecClassName, codecClassName + "::encodedLength()", "wrap", codecClassName + "::sbeSchemaVersion()", BASE_INDENT + INDENT); @@ -1686,8 +1741,8 @@ private void generateChoiceSet(final List tokens) throws IOException final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT); generateChoices(classBuilder, className, setTokens, BASE_INDENT + INDENT); - generateChoiceSetDecodeFrom(classBuilder, className, codecClassName, setTokens, BASE_INDENT + INDENT); - generateChoiceSetEncodeInto(classBuilder, className, codecClassName, setTokens, BASE_INDENT + INDENT); + generateChoiceSetDecodeWith(classBuilder, className, codecClassName, setTokens, BASE_INDENT + INDENT); + generateChoiceSetEncodeWith(classBuilder, className, codecClassName, setTokens, BASE_INDENT + INDENT); classBuilder.appendTo(out); out.append("} // namespace\n"); @@ -1695,7 +1750,7 @@ private void generateChoiceSet(final List tokens) throws IOException } } - private void generateChoiceSetEncodeInto( + private void generateChoiceSetEncodeWith( final ClassBuilder classBuilder, final String dtoClassName, final String codecClassName, @@ -1724,7 +1779,7 @@ private void generateChoiceSetEncodeInto( encodeBuilder.append(indent).append("}\n"); } - private void generateChoiceSetDecodeFrom( + private void generateChoiceSetDecodeWith( final ClassBuilder classBuilder, final String dtoClassName, final String codecClassName, diff --git a/sbe-tool/src/test/cpp/DtoTest.cpp b/sbe-tool/src/test/cpp/DtoTest.cpp index 2b37c6b910..f5d2d0cd58 100644 --- a/sbe-tool/src/test/cpp/DtoTest.cpp +++ b/sbe-tool/src/test/cpp/DtoTest.cpp @@ -167,7 +167,7 @@ class DtoTest : public testing::Test } }; -TEST_F(DtoTest, shouldRoundTripCar) +TEST_F(DtoTest, shouldRoundTripCar1) { char input[BUFFER_LEN]; std::memset(input, 0, BUFFER_LEN); @@ -205,3 +205,35 @@ TEST_F(DtoTest, shouldRoundTripCar) EXPECT_EQ(0, std::memcmp(input, output, encodedCarLength2)); EXPECT_EQ(originalString, dtoString); } + +TEST_F(DtoTest, shouldRoundTripCar2) +{ + char input[BUFFER_LEN]; + std::memset(input, 0, BUFFER_LEN); + ExtendedCar encoder; + encoder.wrapForEncode(input, 0, BUFFER_LEN); + const std::uint64_t encodedCarLength = encodeCar(encoder); + + ExtendedCarDto dto = ExtendedCarDto::decodeFrom( + input, + 0, + ExtendedCar::sbeBlockLength(), + ExtendedCar::sbeSchemaVersion(), + encodedCarLength); + + EXPECT_EQ(encodedCarLength, dto.computeEncodedLength()); + + std::vector output = ExtendedCarDto::bytes(dto); + + std::ostringstream originalStringStream; + originalStringStream << encoder; + std::string originalString = originalStringStream.str(); + + std::ostringstream dtoStringStream; + dtoStringStream << dto; + std::string dtoString = dtoStringStream.str(); + + EXPECT_EQ(originalString, dtoString); + EXPECT_EQ(encodedCarLength, output.size()); + EXPECT_EQ(0, std::memcmp(input, output.data(), encodedCarLength)); +} From f965d2a7e649d8b2b4646e54e8ccd032accc0057 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 9 Nov 2023 15:07:44 +0000 Subject: [PATCH 367/805] [C++] Address feedback from Todd re var data representation. It is more-idiomatic to represent variable-length data using `std::string` even when there is no character encoding specified, the the `std::string` API provides useful utilities regardless. --- .../sbe/generation/cpp/CppDtoGenerator.java | 39 ++----------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index c13a3211b1..99aae05c3b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -724,8 +724,6 @@ private void generateVarDataDecodeWith( if (token.signal() == Signal.BEGIN_VAR_DATA) { final String propertyName = token.name(); - final Token varDataToken = Generators.findFirst("varData", tokens, i); - final String characterEncoding = varDataToken.encoding().characterEncoding(); final String formattedPropertyName = formatPropertyName(propertyName); final boolean isOptional = token.version() > 0; @@ -739,19 +737,8 @@ private void generateVarDataDecodeWith( .append(blockIndent).append("const char* ").append(dataVar) .append(" = codec.").append(formattedPropertyName).append("();\n"); - final String dtoValue; - final String nullDtoValue; - - if (characterEncoding == null) - { - dtoValue = "std::vector(" + dataVar + ", " + dataVar + " + " + lengthVar + ")"; - nullDtoValue = "std::vector()"; - } - else - { - dtoValue = "std::string(" + dataVar + ", " + lengthVar + ")"; - nullDtoValue = "\"\""; - } + final String dtoValue = "std::string(" + dataVar + ", " + lengthVar + ")"; + final String nullDtoValue = "\"\""; if (isOptional) { @@ -1129,29 +1116,13 @@ private void generateVarDataEncodeWith( if (token.signal() == Signal.BEGIN_VAR_DATA) { final String propertyName = token.name(); - final Token lengthToken = Generators.findFirst("length", tokens, i); - final String lengthTypeName = cppTypeName(lengthToken.encoding().primitiveType()); - final Token varDataToken = Generators.findFirst("varData", tokens, i); - final String characterEncoding = varDataToken.encoding().characterEncoding(); final String formattedPropertyName = formatPropertyName(propertyName); final String varName = toLowerFirstChar(propertyName) + "Vector"; sb.append(indent).append("auto& ").append(varName).append(" = dto.") .append(formattedPropertyName).append("();\n") .append(indent).append("codec.put").append(toUpperFirstChar(propertyName)) - .append("("); - - if (null == characterEncoding) - { - sb.append("reinterpret_cast(").append(varName).append(".data()), ") - .append("static_cast<").append(lengthTypeName).append(">(").append(varName).append(".size())"); - } - else - { - sb.append(varName); - } - - sb.append(");\n"); + .append("(").append(varName).append(");\n"); } } } @@ -1629,9 +1600,7 @@ private void generateVarData( if (token.signal() == Signal.BEGIN_VAR_DATA) { final String propertyName = token.name(); - final Token varDataToken = Generators.findFirst("varData", tokens, i); - final String characterEncoding = varDataToken.encoding().characterEncoding(); - final String dtoType = characterEncoding == null ? "std::vector" : "std::string"; + final String dtoType = "std::string"; final String fieldName = "m_" + toLowerFirstChar(propertyName); final String formattedPropertyName = formatPropertyName(propertyName); From 21cde2a3d9fc82e09b28fa228c3dfda27bf3201a Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Sat, 11 Nov 2023 17:56:52 +0000 Subject: [PATCH 368/805] [C++] Add PBT for C++ DTOs. The main change in this commit is to add property-based testing around the C++ DTOs. We check the same property as the C# tests, i.e., that decoding and re-encoding via a DTO preserves the original bytes. There are some other smaller changes in this commit: 1. We now only generate arbitrary schemas where enums have at least one case, as this is required by the spec. 2. We now log details about how we encoded the `input.dat` file used in property-based tests, which can help diagnose problems in the test. --- .../sbe/generation/cpp/CppDtoGenerator.java | 33 ++- .../properties/CSharpDtosPropertyTest.java | 159 ---------- .../sbe/properties/DtosPropertyTest.java | 273 ++++++++++++++++++ .../arbitraries/SbeArbitraries.java | 267 +++++++++++++---- .../resources/CppDtosPropertyTest/main.cpp | 54 ++++ 5 files changed, 559 insertions(+), 227 deletions(-) delete mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java create mode 100644 sbe-tool/src/propertyTest/resources/CppDtosPropertyTest/main.cpp diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 99aae05c3b..f2371181d0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -121,7 +121,7 @@ public void generate() throws IOException referencedTypes)); out.append(generateDocumentation(BASE_INDENT, msgToken)); classBuilder.appendTo(out); - out.append("} // namespace\n"); + out.append(CppUtil.closingBraces(ir.namespaces().length)); out.append("#endif\n"); } } @@ -1336,15 +1336,21 @@ private void generateArrayProperty( { final String fieldName = "m_" + toLowerFirstChar(propertyName); final String formattedPropertyName = formatPropertyName(propertyName); + final String validateMethod = "validate" + toUpperFirstChar(propertyName); if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { + final CharSequence typeName = typeWithFieldOptionality( + fieldToken, + "std::string" + ); + classBuilder.appendField() - .append(indent).append("std::string ").append(fieldName).append(";\n"); + .append(indent).append(typeName).append(" ").append(fieldName).append(";\n"); classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("[[nodiscard]] const std::string& ") + .append(indent).append("[[nodiscard]] const ").append(typeName).append("& ") .append(formattedPropertyName).append("() const\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") @@ -1353,22 +1359,31 @@ private void generateArrayProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("void ").append(formattedPropertyName) - .append("(const std::string& borrowedValue)\n") + .append("(const ").append(typeName).append("& borrowedValue)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(fieldName).append(" = borrowedValue;\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("void ").append(formattedPropertyName) - .append("(std::string&& ownedValue)\n") + .append(indent).append("void ").append(formattedPropertyName).append("(") + .append(typeName).append("&& ownedValue)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(fieldName).append(" = std::move(ownedValue);\n") .append(indent).append("}\n"); + + generateArrayValidateMethod( + classBuilder, + codecClassName, + fieldToken, + indent, + validateMethod, + typeName, + "std::string", + formattedPropertyName); } else { - final String validateMethod = "validate" + toUpperFirstChar(propertyName); final String elementTypeName = cppTypeName(typeToken.encoding().primitiveType()); final String vectorTypeName = "std::vector<" + elementTypeName + ">"; final CharSequence typeName = typeWithFieldOptionality( @@ -1688,7 +1703,7 @@ private void generateComposite(final List tokens) throws IOException codecClassName + "::sbeSchemaVersion()", BASE_INDENT + INDENT); classBuilder.appendTo(out); - out.append("} // namespace\n"); + out.append(CppUtil.closingBraces(ir.namespaces().length)); out.append("#endif\n"); } } @@ -1714,7 +1729,7 @@ private void generateChoiceSet(final List tokens) throws IOException generateChoiceSetEncodeWith(classBuilder, className, codecClassName, setTokens, BASE_INDENT + INDENT); classBuilder.appendTo(out); - out.append("} // namespace\n"); + out.append(CppUtil.closingBraces(ir.namespaces().length)); out.append("#endif\n"); } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java deleted file mode 100644 index 701ca2fcf4..0000000000 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/CSharpDtosPropertyTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2013-2023 Real Logic Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package uk.co.real_logic.sbe.properties; - -import net.jqwik.api.Arbitrary; -import net.jqwik.api.ForAll; -import net.jqwik.api.Property; -import net.jqwik.api.Provide; -import uk.co.real_logic.sbe.generation.csharp.CSharpDtoGenerator; -import uk.co.real_logic.sbe.generation.csharp.CSharpGenerator; -import uk.co.real_logic.sbe.generation.csharp.CSharpNamespaceOutputManager; -import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; -import org.agrona.IoUtil; -import org.agrona.io.DirectBufferInputStream; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; - -public class CSharpDtosPropertyTest -{ - private static final String DOTNET_EXECUTABLE = System.getProperty("sbe.tests.dotnet.executable", "dotnet"); - - @Property - void dtoEncodeShouldBeTheInverseOfDtoDecode( - @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage - ) throws IOException, InterruptedException - { - final Path tempDir = Files.createTempDirectory("sbe-csharp-dto-test"); - try - { - final CSharpNamespaceOutputManager outputManager = new CSharpNamespaceOutputManager( - tempDir.toString(), - "SbePropertyTest" - ); - - try - { - new CSharpGenerator(encodedMessage.ir(), outputManager) - .generate(); - new CSharpDtoGenerator(encodedMessage.ir(), outputManager) - .generate(); - } - catch (final Exception generationException) - { - throw new AssertionError( - "Code generation failed.\n\nSCHEMA:\n" + encodedMessage.schema(), - generationException); - } - - copyResourceToFile("/CSharpDtosPropertyTest/SbePropertyTest.csproj", tempDir); - copyResourceToFile("/CSharpDtosPropertyTest/Program.cs", tempDir); - try ( - DirectBufferInputStream inputStream = new DirectBufferInputStream( - encodedMessage.buffer(), - 0, - encodedMessage.length() - ); - OutputStream outputStream = Files.newOutputStream(tempDir.resolve("input.dat"))) - { - final byte[] buffer = new byte[2048]; - int read; - while ((read = inputStream.read(buffer, 0, buffer.length)) >= 0) - { - outputStream.write(buffer, 0, read); - } - } - - final Path stdout = tempDir.resolve("stdout.txt"); - final Path stderr = tempDir.resolve("stderr.txt"); - final ProcessBuilder processBuilder = new ProcessBuilder(DOTNET_EXECUTABLE, "run", "--", "input.dat") - .directory(tempDir.toFile()) - .redirectOutput(stdout.toFile()) - .redirectError(stderr.toFile()); - - final Process process = processBuilder.start(); - if (0 != process.waitFor()) - { - throw new AssertionError( - "Process failed with exit code: " + process.exitValue() + "\n\n" + - "STDOUT:\n" + new String(Files.readAllBytes(stdout)) + "\n\n" + - "STDERR:\n" + new String(Files.readAllBytes(stderr)) + "\n\n" + - "SCHEMA:\n" + encodedMessage.schema()); - } - - final byte[] errorBytes = Files.readAllBytes(stderr); - if (errorBytes.length != 0) - { - throw new AssertionError( - "Process wrote to stderr.\n\n" + - "STDOUT:\n" + new String(Files.readAllBytes(stdout)) + "\n\n" + - "STDERR:\n" + new String(errorBytes) + "\n\n" + - "SCHEMA:\n" + encodedMessage.schema() + "\n\n" - ); - } - - final byte[] inputBytes = new byte[encodedMessage.length()]; - encodedMessage.buffer().getBytes(0, inputBytes); - final byte[] outputBytes = Files.readAllBytes(tempDir.resolve("output.dat")); - if (!Arrays.equals(inputBytes, outputBytes)) - { - throw new AssertionError( - "Input and output files differ\n\n" + - "SCHEMA:\n" + encodedMessage.schema()); - } - } - finally - { - IoUtil.delete(tempDir.toFile(), true); - } - } - - @Provide - Arbitrary encodedMessage() - { - final SbeArbitraries.CharGenerationMode mode = - SbeArbitraries.CharGenerationMode.JSON_PRINTER_COMPATIBLE; - return SbeArbitraries.encodedMessage(mode); - } - - private static void copyResourceToFile( - final String resourcePath, - final Path outputDir) - { - try (InputStream inputStream = CSharpDtosPropertyTest.class.getResourceAsStream(resourcePath)) - { - if (inputStream == null) - { - throw new IOException("Resource not found: " + resourcePath); - } - - final int resourceNameIndex = resourcePath.lastIndexOf('/') + 1; - final String resourceName = resourcePath.substring(resourceNameIndex); - final Path outputFilePath = outputDir.resolve(resourceName); - Files.copy(inputStream, outputFilePath); - } - catch (final IOException e) - { - throw new RuntimeException(e); - } - } -} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java new file mode 100644 index 0000000000..d68a1c327c --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -0,0 +1,273 @@ +/* + * Copyright 2013-2023 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties; + +import net.jqwik.api.*; +import uk.co.real_logic.sbe.generation.cpp.CppDtoGenerator; +import uk.co.real_logic.sbe.generation.cpp.CppGenerator; +import uk.co.real_logic.sbe.generation.cpp.NamespaceOutputManager; +import uk.co.real_logic.sbe.generation.csharp.CSharpDtoGenerator; +import uk.co.real_logic.sbe.generation.csharp.CSharpGenerator; +import uk.co.real_logic.sbe.generation.csharp.CSharpNamespaceOutputManager; +import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; +import org.agrona.IoUtil; +import org.agrona.io.DirectBufferInputStream; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; + +@SuppressWarnings("ReadWriteStringCanBeUsed") +public class DtosPropertyTest +{ + private static final String DOTNET_EXECUTABLE = System.getProperty("sbe.tests.dotnet.executable", "dotnet"); + private static final String CPP_EXECUTABLE = System.getProperty("sbe.tests.cpp.executable", "g++"); + private static final boolean KEEP_DIR_ON_FAILURE = Boolean.parseBoolean( + System.getProperty("sbe.tests.keep.dir.on.failure", "true")); + + @Property + void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage + ) throws IOException, InterruptedException + { + final Path tempDir = Files.createTempDirectory("sbe-csharp-dto-test"); + boolean success = false; + + try + { + final CSharpNamespaceOutputManager outputManager = new CSharpNamespaceOutputManager( + tempDir.toString(), + "SbePropertyTest" + ); + + try + { + new CSharpGenerator(encodedMessage.ir(), outputManager) + .generate(); + new CSharpDtoGenerator(encodedMessage.ir(), outputManager) + .generate(); + } + catch (final Exception generationException) + { + throw new AssertionError( + "Code generation failed.\n\n" + + "DIR:" + tempDir + "\n\n" + + "SCHEMA:\n" + encodedMessage.schema(), + generationException); + } + + copyResourceToFile("/CSharpDtosPropertyTest/SbePropertyTest.csproj", tempDir); + copyResourceToFile("/CSharpDtosPropertyTest/Program.cs", tempDir); + + writeInputFile(encodedMessage, tempDir); + + execute(encodedMessage.schema(), tempDir, "test", + DOTNET_EXECUTABLE, "run", "--", "input.dat"); + + final byte[] inputBytes = new byte[encodedMessage.length()]; + encodedMessage.buffer().getBytes(0, inputBytes); + final byte[] outputBytes = Files.readAllBytes(tempDir.resolve("output.dat")); + if (!Arrays.equals(inputBytes, outputBytes)) + { + throw new AssertionError( + "Input and output files differ\n\n" + + "DIR:" + tempDir + "\n\n" + + "SCHEMA:\n" + encodedMessage.schema()); + } + success = true; + } + finally + { + if (!KEEP_DIR_ON_FAILURE || success) + { + IoUtil.delete(tempDir.toFile(), true); + } + else + { + Files.write( + tempDir.resolve("schema.xml"), + encodedMessage.schema().getBytes(StandardCharsets.UTF_8)); + + Files.write( + tempDir.resolve("encoding.log"), + encodedMessage.encodingLog().getBytes(StandardCharsets.UTF_8)); + } + } + } + + @Property(shrinking = ShrinkingMode.OFF) + void cppDtoEncodeShouldBeTheInverseOfDtoDecode( + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage + ) throws IOException, InterruptedException + { + final Path tempDir = Files.createTempDirectory("sbe-cpp-dto-test"); + boolean success = false; + + try + { + final NamespaceOutputManager outputManager = new NamespaceOutputManager( + tempDir.toString(), + "sbe_property_test" + ); + + try + { + new CppGenerator(encodedMessage.ir(), true, outputManager) + .generate(); + new CppDtoGenerator(encodedMessage.ir(), outputManager) + .generate(); + } + catch (final Exception generationException) + { + throw new AssertionError( + "Code generation failed.\n\nSCHEMA:\n" + encodedMessage.schema(), + generationException); + } + + copyResourceToFile("/CppDtosPropertyTest/main.cpp", tempDir); + + writeInputFile(encodedMessage, tempDir); + + execute(encodedMessage.schema(), tempDir, "compile", + CPP_EXECUTABLE, "--std", "c++17", "-o", "round-trip-test", "main.cpp"); + + execute(encodedMessage.schema(), tempDir, "test", + tempDir.resolve("round-trip-test").toString(), "input.dat"); + + final byte[] inputBytes = new byte[encodedMessage.length()]; + encodedMessage.buffer().getBytes(0, inputBytes); + final byte[] outputBytes = Files.readAllBytes(tempDir.resolve("output.dat")); + if (!Arrays.equals(inputBytes, outputBytes)) + { + throw new AssertionError( + "Input and output files differ\n\n" + + "SCHEMA:\n" + encodedMessage.schema()); + } + success = true; + } + finally + { + if (!KEEP_DIR_ON_FAILURE || success) + { + IoUtil.delete(tempDir.toFile(), true); + } + else + { + Files.write( + tempDir.resolve("schema.xml"), + encodedMessage.schema().getBytes(StandardCharsets.UTF_8)); + + Files.write( + tempDir.resolve("encoding.log"), + encodedMessage.encodingLog().getBytes(StandardCharsets.UTF_8)); + } + } + } + + private static void writeInputFile( + final SbeArbitraries.EncodedMessage encodedMessage, + final Path tempDir) throws IOException + { + try ( + DirectBufferInputStream inputStream = new DirectBufferInputStream( + encodedMessage.buffer(), + 0, + encodedMessage.length() + ); + OutputStream outputStream = Files.newOutputStream(tempDir.resolve("input.dat"))) + { + final byte[] buffer = new byte[2048]; + int read; + while ((read = inputStream.read(buffer, 0, buffer.length)) >= 0) + { + outputStream.write(buffer, 0, read); + } + } + } + + private static void execute( + final String schema, + final Path tempDir, + final String name, + final String... args) throws InterruptedException, IOException + { + final Path stdout = tempDir.resolve(name + "_stdout.txt"); + final Path stderr = tempDir.resolve(name + "_stderr.txt"); + final ProcessBuilder compileProcessBuilder = new ProcessBuilder(args) + .directory(tempDir.toFile()) + .redirectOutput(stdout.toFile()) + .redirectError(stderr.toFile()); + + final Process process = compileProcessBuilder.start(); + + if (0 != process.waitFor()) + { + throw new AssertionError( + "Process failed with exit code: " + process.exitValue() + "\n\n" + + "DIR:" + tempDir + "\n\n" + + "STDOUT:\n" + new String(Files.readAllBytes(stdout)) + "\n\n" + + "STDERR:\n" + new String(Files.readAllBytes(stderr)) + "\n\n" + + "SCHEMA:\n" + schema); + } + + final byte[] errorBytes = Files.readAllBytes(stderr); + if (errorBytes.length != 0) + { + throw new AssertionError( + "Process wrote to stderr.\n\n" + + "DIR:" + tempDir + "\n\n" + + "STDOUT:\n" + new String(Files.readAllBytes(stdout)) + "\n\n" + + "STDERR:\n" + new String(errorBytes) + "\n\n" + + "SCHEMA:\n" + schema + "\n\n" + ); + } + } + + @Provide + Arbitrary encodedMessage() + { + final SbeArbitraries.CharGenerationMode mode = + SbeArbitraries.CharGenerationMode.JSON_PRINTER_COMPATIBLE; + return SbeArbitraries.encodedMessage(mode); + } + + private static void copyResourceToFile( + final String resourcePath, + final Path outputDir) + { + try (InputStream inputStream = DtosPropertyTest.class.getResourceAsStream(resourcePath)) + { + if (inputStream == null) + { + throw new IOException("Resource not found: " + resourcePath); + } + + final int resourceNameIndex = resourcePath.lastIndexOf('/') + 1; + final String resourceName = resourcePath.substring(resourceNameIndex); + final Path outputFilePath = outputDir.resolve(resourceName); + Files.copy(inputStream, outputFilePath); + } + catch (final IOException e) + { + throw new RuntimeException(e); + } + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index 25207cdf96..bfc1f9bd88 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -21,7 +21,6 @@ import net.jqwik.api.Combinators; import net.jqwik.api.arbitraries.CharacterArbitrary; import net.jqwik.api.arbitraries.ListArbitrary; -import net.jqwik.api.arbitraries.ShortArbitrary; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.PrimitiveValue; import uk.co.real_logic.sbe.ir.Encoding; @@ -38,9 +37,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; import static uk.co.real_logic.sbe.ir.Signal.*; @@ -130,6 +127,7 @@ private static Arbitrary enumTypeSchema() Arbitraries.chars().alpha() .map(Character::toUpperCase) .list() + .ofMinSize(1) .ofMaxSize(10) .uniqueElements() .map(values -> new EnumTypeSchema( @@ -139,6 +137,7 @@ private static Arbitrary enumTypeSchema() Arbitraries.integers() .between(1, 254) .list() + .ofMinSize(1) .ofMaxSize(254) .uniqueElements() .map(values -> new EnumTypeSchema( @@ -286,18 +285,51 @@ public static Arbitrary messageSchema() ).as(MessageSchema::new); } - public interface Encoder + private interface Encoder { - void encode(MutableDirectBuffer buffer, int offset, MutableInteger limit); + void encode( + EncodingLogger logger, + MutableDirectBuffer buffer, + int offset, + MutableInteger limit); + } + + private static final class EncodingLogger + { + private final StringBuilder builder = new StringBuilder(); + private final Deque scope = new ArrayDeque<>(); + + public void beginScope(final String name) + { + scope.addLast(name); + } + + public StringBuilder appendLine() + { + builder.append("\n"); + scope.forEach(s -> builder.append(".").append(s)); + builder.append(": "); + return builder; + } + + public void endScope() + { + scope.removeLast(); + } + + public String toString() + { + return builder.toString(); + } } private static Encoder combineEncoders(final Collection encoders) { - return (buffer, offset, limit) -> + return (builder, buffer, offset, limit) -> { for (final Encoder encoder : encoders) { - encoder.encode(buffer, offset, limit); + encoder.encode(builder, buffer, offset, limit); } }; } @@ -339,35 +371,57 @@ private static Arbitrary encodedTypeEncoder( case CHAR: assert minValue.longValue() <= maxValue.longValue(); return chars(charGenerationMode).map(c -> - (buffer, offset, limit) -> buffer.putChar(offset, c, encoding.byteOrder())); + (builder, buffer, offset, limit) -> + { + builder.appendLine().append(c).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_BYTE).append("]"); + buffer.putChar(offset, c, encoding.byteOrder()); + }); case UINT8: case INT8: assert (short)minValue.longValue() <= (short)maxValue.longValue(); return Arbitraries.shorts() .between((short)minValue.longValue(), (short)maxValue.longValue()) - .map(b -> (buffer, offset, limit) -> buffer.putByte(offset, (byte)(short)b)); + .map(b -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append((byte)(short)b).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_BYTE).append("]"); + buffer.putByte(offset, (byte)(short)b); + }); case UINT16: case INT16: assert (int)minValue.longValue() <= (int)maxValue.longValue(); return Arbitraries.integers() .between((int)minValue.longValue(), (int)maxValue.longValue()) - .map(s -> (buffer, offset, limit) -> buffer.putShort(offset, (short)(int)s, encoding.byteOrder())); + .map(s -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append((short)(int)s).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_SHORT).append("]"); + buffer.putShort(offset, (short)(int)s, encoding.byteOrder()); + }); case UINT32: case INT32: assert minValue.longValue() <= maxValue.longValue(); return Arbitraries.longs() .between(minValue.longValue(), maxValue.longValue()) - .map(i -> (buffer, offset, limit) -> buffer.putInt(offset, (int)(long)i, encoding.byteOrder())); + .map(i -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append((int)(long)i).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_INT).append("]"); + buffer.putInt(offset, (int)(long)i, encoding.byteOrder()); + }); case UINT64: return Arbitraries.longs() - .map(l -> (buffer, offset, limit) -> + .map(l -> (builder, buffer, offset, limit) -> { final long nullValue = encoding.applicableNullValue().longValue(); final long nonNullValue = l == nullValue ? minValue.longValue() : l; + builder.appendLine().append(nonNullValue).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_LONG).append("]"); buffer.putLong(offset, nonNullValue, encoding.byteOrder()); }); @@ -375,15 +429,30 @@ private static Arbitrary encodedTypeEncoder( assert minValue.longValue() <= maxValue.longValue(); return Arbitraries.longs() .between(minValue.longValue(), maxValue.longValue()) - .map(l -> (buffer, offset, limit) -> buffer.putLong(offset, l, encoding.byteOrder())); + .map(l -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append(l).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_LONG).append("]"); + buffer.putLong(offset, l, encoding.byteOrder()); + }); case FLOAT: return Arbitraries.floats() - .map(f -> (buffer, offset, limit) -> buffer.putFloat(offset, f, encoding.byteOrder())); + .map(f -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append(f).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_FLOAT).append("]"); + buffer.putFloat(offset, f, encoding.byteOrder()); + }); case DOUBLE: return Arbitraries.doubles() - .map(d -> (buffer, offset, limit) -> buffer.putDouble(offset, d, encoding.byteOrder())); + .map(d -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append(d).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_DOUBLE).append("]"); + buffer.putDouble(offset, d, encoding.byteOrder()); + }); default: throw new IllegalArgumentException("Unsupported type: " + encoding.primitiveType()); @@ -400,18 +469,20 @@ private static Arbitrary encodedTypeEncoder( if (typeToken.arrayLength() == 1) { - return arbEncoder.map(encoder -> (buffer, bufferOffset, limit) -> - encoder.encode(buffer, bufferOffset + offset, limit)); + return arbEncoder.map(encoder -> (builder, buffer, bufferOffset, limit) -> + encoder.encode(builder, buffer, bufferOffset + offset, limit)); } else { return arbEncoder.list().ofSize(typeToken.arrayLength()) - .map(encoders -> (buffer, bufferOffset, limit) -> + .map(encoders -> (builder, buffer, bufferOffset, limit) -> { for (int i = 0; i < typeToken.arrayLength(); i++) { + builder.beginScope("[" + i + "]"); final int elementOffset = bufferOffset + offset + i * encoding.primitiveType().size(); - encoders.get(i).encode(buffer, elementOffset, limit); + encoders.get(i).encode(builder, buffer, elementOffset, limit); + builder.endScope(); } }); } @@ -419,7 +490,7 @@ private static Arbitrary encodedTypeEncoder( private static Encoder emptyEncoder() { - return (buffer, offset, limit) -> + return (builder, buffer, offset, limit) -> { }; } @@ -432,19 +503,43 @@ private static Encoder integerValueEncoder(final Encoding encoding, final long v case CHAR: case UINT8: case INT8: - return (buffer, offset, limit) -> buffer.putByte(offset, (byte)value); + return (builder, buffer, offset, limit) -> + { + builder.appendLine().append((byte)value).append("[").append(value).append("]") + .append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_BYTE).append("]"); + buffer.putByte(offset, (byte)value); + }; case UINT16: case INT16: - return (buffer, offset, limit) -> buffer.putShort(offset, (short)value, encoding.byteOrder()); + return (builder, buffer, offset, limit) -> + { + builder.appendLine().append((short)value).append("[").append(value).append("]") + .append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_SHORT).append("]"); + buffer.putShort(offset, (short)value, encoding.byteOrder()); + }; case UINT32: case INT32: - return (buffer, offset, limit) -> buffer.putInt(offset, (int)value, encoding.byteOrder()); + return (builder, buffer, offset, limit) -> + { + builder.appendLine().append((int)value).append("[").append(value).append("]") + .append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_INT).append("]"); + buffer.putInt(offset, (int)value, encoding.byteOrder()); + }; case UINT64: case INT64: - return (buffer, offset, limit) -> buffer.putLong(offset, value, encoding.byteOrder()); + return (builder, buffer, offset, limit) -> + { + builder.appendLine().append(value).append("[").append(value).append("]") + .append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_LONG).append("]"); + buffer.putLong(offset, value, encoding.byteOrder()); + }; default: throw new IllegalArgumentException("Unsupported type: " + type); @@ -484,7 +579,8 @@ private static Arbitrary enumEncoder( } return Arbitraries.of(encoders).map(encoder -> - (buffer, bufferOffset, limit) -> encoder.encode(buffer, bufferOffset + offset, limit)); + (builder, buffer, bufferOffset, limit) -> + encoder.encode(builder, buffer, bufferOffset + offset, limit)); } private static Encoder choiceEncoder(final Encoding encoding) @@ -495,42 +591,54 @@ private static Encoder choiceEncoder(final Encoding encoding) { case UINT8: case INT8: - return (buffer, offset, limit) -> + return (builder, buffer, offset, limit) -> { buffer.checkLimit(offset + BitUtil.SIZE_OF_BYTE); final byte oldValue = buffer.getByte(offset); final byte newValue = (byte)(oldValue | (1 << choiceBitIdx)); buffer.putByte(offset, newValue); + builder.appendLine().append("oldValue: ").append(oldValue); + builder.appendLine().append(newValue).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_BYTE).append("]"); }; case UINT16: case INT16: - return (buffer, offset, limit) -> + return (builder, buffer, offset, limit) -> { buffer.checkLimit(offset + BitUtil.SIZE_OF_SHORT); final short oldValue = buffer.getShort(offset, encoding.byteOrder()); final short newValue = (short)(oldValue | (1 << choiceBitIdx)); buffer.putShort(offset, newValue, encoding.byteOrder()); + builder.appendLine().append("oldValue: ").append(oldValue); + builder.appendLine().append(newValue).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_SHORT).append("]"); }; case UINT32: case INT32: - return (buffer, offset, limit) -> + return (builder, buffer, offset, limit) -> { buffer.checkLimit(offset + BitUtil.SIZE_OF_INT); final int oldValue = buffer.getInt(offset, encoding.byteOrder()); final int newValue = oldValue | (1 << choiceBitIdx); buffer.putInt(offset, newValue, encoding.byteOrder()); + builder.appendLine().append("oldValue: ").append(oldValue); + builder.appendLine().append(newValue).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_INT).append("]"); }; case UINT64: case INT64: - return (buffer, offset, limit) -> + return (builder, buffer, offset, limit) -> { buffer.checkLimit(offset + BitUtil.SIZE_OF_LONG); final long oldValue = buffer.getLong(offset, encoding.byteOrder()); final long newValue = oldValue | (1L << choiceBitIdx); buffer.putLong(offset, newValue, encoding.byteOrder()); + builder.appendLine().append("oldValue: ").append(oldValue); + builder.appendLine().append(newValue).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_LONG).append("]"); }; default: @@ -568,7 +676,8 @@ private static Arbitrary bitSetEncoder( return Arbitraries.subsetOf(encoders) .map(SbeArbitraries::combineEncoders) - .map(encoder -> (buffer, bufferOffset, limit) -> encoder.encode(buffer, bufferOffset + offset, limit)); + .map(encoder -> (builder, buffer, bufferOffset, limit) -> + encoder.encode(builder, buffer, bufferOffset + offset, limit)); } private static Arbitrary fieldsEncoder( @@ -602,6 +711,7 @@ else if (expectFields) if (!memberToken.isConstantEncoding()) { + Arbitrary fieldEncoder = null; switch (typeToken.signal()) { case BEGIN_COMPOSITE: @@ -610,30 +720,40 @@ else if (expectFields) final int lastMemberIdx = nextFieldIdx - endCompositeTokenCount - endFieldTokenCount - 1; final Arbitrary encoder = fieldsEncoder( tokens, cursor, lastMemberIdx, false, charGenerationMode); - final Arbitrary positionedEncoder = encoder.map(e -> - (buffer, bufferOffset, limit) -> e.encode(buffer, bufferOffset + offset, limit)); - encoders.add(positionedEncoder); + fieldEncoder = encoder.map(e -> + (builder, buffer, bufferOffset, limit) -> + e.encode(builder, buffer, bufferOffset + offset, limit)); break; case BEGIN_ENUM: final int endEnumTokenCount = 1; final int lastValidValueIdx = nextFieldIdx - endFieldTokenCount - endEnumTokenCount - 1; - encoders.add(enumEncoder(offset, tokens, typeToken, cursor, lastValidValueIdx)); + fieldEncoder = enumEncoder(offset, tokens, typeToken, cursor, lastValidValueIdx); break; case BEGIN_SET: final int endSetTokenCount = 1; final int lastChoiceIdx = nextFieldIdx - endFieldTokenCount - endSetTokenCount - 1; - encoders.add(bitSetEncoder(offset, tokens, cursor, lastChoiceIdx)); + fieldEncoder = bitSetEncoder(offset, tokens, cursor, lastChoiceIdx); break; case ENCODING: - encoders.add(encodedTypeEncoder(offset, typeToken, charGenerationMode)); + fieldEncoder = encodedTypeEncoder(offset, typeToken, charGenerationMode); break; default: break; } + + if (fieldEncoder != null) + { + encoders.add(fieldEncoder.map(encoder -> (builder, buffer, off, limit) -> + { + builder.beginScope(memberToken.name()); + encoder.encode(builder, buffer, off, limit); + builder.endScope(); + })); + } } cursor.set(nextFieldIdx); @@ -677,29 +797,39 @@ private static Arbitrary groupsEncoder( groupsEncoder(tokens, cursor, nextFieldIdx - 1, charGenerationMode), varDataEncoder(tokens, cursor, nextFieldIdx - 1, charGenerationMode) ).as((fieldsEncoder, groupsEncoder, varDataEncoder) -> - (buffer, ignored, limit) -> + (builder, buffer, ignored, limit) -> { final int offset = limit.get(); - fieldsEncoder.encode(buffer, offset, null); + fieldsEncoder.encode(builder, buffer, offset, null); limit.set(offset + blockLength); - groupsEncoder.encode(buffer, NULL_VALUE, limit); - varDataEncoder.encode(buffer, NULL_VALUE, limit); + builder.appendLine().append("limit: ").append(offset).append(" -> ").append(limit.get()); + groupsEncoder.encode(builder, buffer, NULL_VALUE, limit); + varDataEncoder.encode(builder, buffer, NULL_VALUE, limit); }); final Arbitrary repeatingGroupEncoder = groupElement.list() .ofMaxSize(10) - .map(elements -> (buffer, ignored, limit) -> + .map(elements -> (builder, buffer, ignored, limit) -> { final int offset = limit.get(); limit.set(offset + headerLength); - blockLengthEncoder.encode(buffer, offset, null); + builder.beginScope(token.name()); + builder.appendLine().append("limit: ").append(offset).append(" -> ").append(limit.get()); + builder.beginScope("blockLength"); + blockLengthEncoder.encode(builder, buffer, offset, null); + builder.endScope(); + builder.beginScope("numInGroup"); integerValueEncoder(numInGroupToken.encoding(), elements.size()) - .encode(buffer, offset + blockLengthToken.encodedLength(), null); - - for (final Encoder element : elements) + .encode(builder, buffer, offset + blockLengthToken.encodedLength(), null); + builder.endScope(); + for (int i = 0; i < elements.size(); i++) { - element.encode(buffer, NULL_VALUE, limit); + final Encoder element = elements.get(i); + builder.beginScope("[" + i + "]"); + element.encode(builder, buffer, NULL_VALUE, limit); + builder.endScope(); } + builder.endScope(); }); encoders.add(repeatingGroupEncoder); @@ -738,20 +868,28 @@ private static Arbitrary varDataEncoder( final Arbitrary arbitraryByte = null == characterEncoding ? Arbitraries.bytes() : chars(charGenerationMode).map(c -> (byte)c.charValue()); - encoders.add(arbitraryByte.list().map(bytes -> - (buffer, ignored, limit) -> + encoders.add(arbitraryByte.list() + .ofMaxSize((int)Math.min(lengthToken.encoding().applicableMaxValue().longValue(), 260L)) + .map(bytes -> (builder, buffer, ignored, limit) -> { final int offset = limit.get(); final int elementLength = varDataToken.encoding().primitiveType().size(); limit.set(offset + lengthToken.encodedLength() + bytes.size() * elementLength); + builder.beginScope(token.name()); + builder.appendLine().append("limit: ").append(offset).append(" -> ").append(limit.get()); + builder.beginScope("length"); integerValueEncoder(lengthToken.encoding(), bytes.size()) - .encode(buffer, offset, null); + .encode(builder, buffer, offset, null); + builder.endScope(); for (int i = 0; i < bytes.size(); i++) { final int dataOffset = offset + lengthToken.encodedLength() + i * elementLength; + builder.beginScope("[" + i + "]"); integerValueEncoder(varDataToken.encoding(), bytes.get(i)) - .encode(buffer, dataOffset, null); + .encode(builder, buffer, dataOffset, null); + builder.endScope(); } + builder.endScope(); })); cursor.set(nextFieldIdx); @@ -760,7 +898,7 @@ private static Arbitrary varDataEncoder( return combineArbitraryEncoders(encoders); } - public static Arbitrary messageValueEncoder( + private static Arbitrary messageValueEncoder( final Ir ir, final short messageId, final CharGenerationMode charGenerationMode) @@ -781,7 +919,7 @@ public static Arbitrary messageValueEncoder( final Arbitrary varDataEncoder = varDataEncoder( tokens, cursor, tokens.size() - 1, charGenerationMode); return Combinators.combine(fieldsEncoder, groupsEncoder, varDataEncoder) - .as((fields, groups, varData) -> (buffer, offset, limit) -> + .as((fields, groups, varData) -> (builder, buffer, offset, limit) -> { final int blockLength = token.encodedLength(); buffer.putShort(0, (short)blockLength, ir.byteOrder()); @@ -789,10 +927,12 @@ public static Arbitrary messageValueEncoder( buffer.putShort(4, (short)ir.id(), ir.byteOrder()); buffer.putShort(6, (short)ir.version(), ir.byteOrder()); final int headerLength = 8; - fields.encode(buffer, offset + headerLength, null); + fields.encode(builder, buffer, offset + headerLength, null); + final int oldLimit = limit.get(); limit.set(offset + headerLength + blockLength); - groups.encode(buffer, NULL_VALUE, limit); - varData.encode(buffer, NULL_VALUE, limit); + builder.appendLine().append("limit: ").append(oldLimit).append(" -> ").append(limit.get()); + groups.encode(builder, buffer, NULL_VALUE, limit); + varData.encode(builder, buffer, NULL_VALUE, limit); }); } @@ -802,17 +942,20 @@ public static final class EncodedMessage private final Ir ir; private final ExpandableArrayBuffer buffer; private final int length; + private final String encodingLog; private EncodedMessage( final String schema, final Ir ir, final ExpandableArrayBuffer buffer, - final int length) + final int length, + final String encodingLog) { this.schema = schema; this.ir = ir; this.buffer = buffer; this.length = length; + this.encodingLog = encodingLog; } public String schema() @@ -834,6 +977,11 @@ public int length() { return length; } + + public String encodingLog() + { + return encodingLog; + } } public static Arbitrary encodedMessage(final CharGenerationMode mode) @@ -853,10 +1001,11 @@ public static Arbitrary encodedMessage(final CharGenerationMode return SbeArbitraries.messageValueEncoder(ir, testSchema.templateId(), mode) .map(encoder -> { + final EncodingLogger logger = new EncodingLogger(); final ExpandableArrayBuffer buffer = new ExpandableArrayBuffer(); final MutableInteger limit = new MutableInteger(); - encoder.encode(buffer, 0, limit); - return new EncodedMessage(xml, ir, buffer, limit.get()); + encoder.encode(logger, buffer, 0, limit); + return new EncodedMessage(xml, ir, buffer, limit.get(), logger.toString()); }); } catch (final Exception e) diff --git a/sbe-tool/src/propertyTest/resources/CppDtosPropertyTest/main.cpp b/sbe-tool/src/propertyTest/resources/CppDtosPropertyTest/main.cpp new file mode 100644 index 0000000000..5d366adf6d --- /dev/null +++ b/sbe-tool/src/propertyTest/resources/CppDtosPropertyTest/main.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include "sbe_property_test/MessageHeader.h" +#include "sbe_property_test/TestMessage.h" +#include "sbe_property_test/TestMessageDto.h" + +using namespace uk::co::real_logic::sbe::properties; + +int main(int argc, char* argv[]) { + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " $BINARY_FILE" << std::endl; + return 1; + } + + std::string binaryFile = argv[1]; + + std::cout << "Reading binary file: " << binaryFile << std::endl; + std::ifstream file(binaryFile, std::ios::binary); + std::vector inputBytes((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + + char* buffer = inputBytes.data(); + std::size_t bufferLength = inputBytes.size(); + + MessageHeader messageHeader(buffer, bufferLength); + + TestMessage decoder; + decoder.wrapForDecode( + buffer, + MessageHeader::encodedLength(), + messageHeader.blockLength(), + messageHeader.version(), + bufferLength); + + std::cout << "Decoding binary into DTO" << std::endl; + TestMessageDto dto; + TestMessageDto::decodeWith(decoder, dto); + std::vector outputBytes(inputBytes.size()); + char* outputBuffer = outputBytes.data(); + + TestMessage encoder; + encoder.wrapAndApplyHeader(outputBuffer, 0, bufferLength); + TestMessageDto::encodeWith(encoder, dto); + + std::cout << "Writing binary file: output.dat" << std::endl; + std::ofstream outputFile("output.dat", std::ios::binary); + outputFile.write(outputBuffer, outputBytes.size()); + + std::cout << "Done" << std::endl; + + return 0; +} From a0fc52546fe42059102280e39a15140cfce3acc1 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Mon, 13 Nov 2023 00:40:01 +0000 Subject: [PATCH 369/805] [Java, C++, C#] Ensure buffer is large enough to contain message. Previously, when generating arbitrary encoded values the generator would not necessarily extend the buffer to the size necessary to hold the message, e.g., if optional fields were left unset at the end of the message block. We now call `checkLimit` to "reserve" space for the full block length at the message and group level. This fixes an exception seen in the slow tests: ``` java.lang.IndexOutOfBoundsException: index=0 length=129 capacity=128 at org.agrona.AbstractMutableDirectBuffer.boundsCheck0(AbstractMutableDirectBuffer.java:1719) at org.agrona.AbstractMutableDirectBuffer.getBytes(AbstractMutableDirectBuffer.java:464) at org.agrona.io.DirectBufferInputStream.read(DirectBufferInputStream.java:175) at uk.co.real_logic.sbe.properties.DtosPropertyTest.writeInputFile(DtosPropertyTest.java:199) at uk.co.real_logic.sbe.properties.DtosPropertyTest.cppDtoEncodeShouldBeTheInverseOfDtoDecode(DtosPropertyTest.java:147) at java.lang.reflect.Method.invoke(Method.java:498) at net.jqwik.engine.execution.CheckedPropertyFactory.lambda$createRawFunction$1(CheckedPropertyFactory.java:84) at net.jqwik.engine.execution.CheckedPropertyFactory.lambda$createRawFunction$2(CheckedPropertyFactory.java:91) at net.jqwik.engine.properties.CheckedFunction.execute(CheckedFunction.java:17) at net.jqwik.api.lifecycle.AroundTryHook.lambda$static$0(AroundTryHook.java:57) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$2(HookSupport.java:48) at net.jqwik.engine.hooks.lifecycle.TryLifecycleMethodsHook.aroundTry(TryLifecycleMethodsHook.java:57) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$3(HookSupport.java:53) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$2(HookSupport.java:48) at net.jqwik.engine.hooks.lifecycle.BeforeTryMembersHook.aroundTry(BeforeTryMembersHook.java:69) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$3(HookSupport.java:53) at net.jqwik.engine.execution.CheckedPropertyFactory.lambda$createTryExecutor$0(CheckedPropertyFactory.java:60) at net.jqwik.engine.execution.lifecycle.AroundTryLifecycle.execute(AroundTryLifecycle.java:23) at net.jqwik.engine.properties.GenericProperty.testPredicate(GenericProperty.java:166) at net.jqwik.engine.properties.GenericProperty.check(GenericProperty.java:68) at net.jqwik.engine.execution.CheckedProperty.check(CheckedProperty.java:67) at net.jqwik.engine.execution.PropertyMethodExecutor.executeProperty(PropertyMethodExecutor.java:90) at net.jqwik.engine.execution.PropertyMethodExecutor.executeMethod(PropertyMethodExecutor.java:69) at net.jqwik.engine.execution.PropertyMethodExecutor.lambda$execute$0(PropertyMethodExecutor.java:49) at net.jqwik.api.lifecycle.AroundPropertyHook.lambda$static$0(AroundPropertyHook.java:46) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$0(HookSupport.java:26) at net.jqwik.api.lifecycle.PropertyExecutor.executeAndFinally(PropertyExecutor.java:39) at net.jqwik.engine.hooks.lifecycle.PropertyLifecycleMethodsHook.aroundProperty(PropertyLifecycleMethodsHook.java:56) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$1(HookSupport.java:31) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$0(HookSupport.java:26) at net.jqwik.engine.hooks.statistics.StatisticsHook.aroundProperty(StatisticsHook.java:37) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$1(HookSupport.java:31) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$0(HookSupport.java:26) at net.jqwik.engine.hooks.lifecycle.AutoCloseableHook.aroundProperty(AutoCloseableHook.java:13) at net.jqwik.engine.execution.lifecycle.HookSupport.lambda$wrap$1(HookSupport.java:31) at net.jqwik.engine.execution.PropertyMethodExecutor.execute(PropertyMethodExecutor.java:47) at net.jqwik.engine.execution.PropertyTaskCreator.executeTestMethod(PropertyTaskCreator.java:166) at net.jqwik.engine.execution.PropertyTaskCreator.lambda$createTask$1(PropertyTaskCreator.java:51) at net.jqwik.engine.execution.lifecycle.CurrentDomainContext.runWithContext(CurrentDomainContext.java:28) at net.jqwik.engine.execution.PropertyTaskCreator.lambda$createTask$2(PropertyTaskCreator.java:50) at net.jqwik.engine.execution.pipeline.ExecutionTask$1.lambda$execute$0(ExecutionTask.java:31) at net.jqwik.engine.execution.lifecycle.CurrentTestDescriptor.runWithDescriptor(CurrentTestDescriptor.java:17) at net.jqwik.engine.execution.pipeline.ExecutionTask$1.execute(ExecutionTask.java:31) at net.jqwik.engine.execution.pipeline.ExecutionPipeline.runToTermination(ExecutionPipeline.java:82) at net.jqwik.engine.execution.JqwikExecutor.execute(JqwikExecutor.java:46) at net.jqwik.engine.JqwikTestEngine.executeTests(JqwikTestEngine.java:70) at net.jqwik.engine.JqwikTestEngine.execute(JqwikTestEngine.java:53) ``` --- .../real_logic/sbe/properties/arbitraries/SbeArbitraries.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index bfc1f9bd88..66bfeebcf0 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -801,6 +801,7 @@ private static Arbitrary groupsEncoder( { final int offset = limit.get(); fieldsEncoder.encode(builder, buffer, offset, null); + buffer.checkLimit(offset + blockLength); limit.set(offset + blockLength); builder.appendLine().append("limit: ").append(offset).append(" -> ").append(limit.get()); groupsEncoder.encode(builder, buffer, NULL_VALUE, limit); @@ -929,6 +930,7 @@ private static Arbitrary messageValueEncoder( final int headerLength = 8; fields.encode(builder, buffer, offset + headerLength, null); final int oldLimit = limit.get(); + buffer.checkLimit(offset + headerLength + blockLength); limit.set(offset + headerLength + blockLength); builder.appendLine().append("limit: ").append(oldLimit).append(" -> ").append(limit.get()); groups.encode(builder, buffer, NULL_VALUE, limit); From 2195d6e9754c56780009d8721bd3e69bb95ee3c3 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Sat, 11 Nov 2023 18:41:10 +0000 Subject: [PATCH 370/805] [CI] Fix dependency conflict in JQwik. Recently JUnit was upgraded. Rebasing revealed a dependency conflict. --- .github/workflows/slow.yml | 2 -- build.gradle | 10 ++++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index a5f007f6bf..ba932f8a9e 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -50,8 +50,6 @@ jobs: uses: actions/setup-dotnet@v2 with: dotnet-version: ${{ matrix.dotnet }} - - name: Build SbeTool - run: ./gradlew - name: Build .NET library run: ./csharp/build.sh - name: Run property tests diff --git a/build.gradle b/build.gradle index 2ccfad6010..2bb3c39f22 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.2' -def jqwikVersion = '1.8.0' +def jqwikVersion = '1.8.1' def jsonVersion = '20230618' def jmhVersion = '1.37' def agronaVersion = '1.21.2' @@ -297,11 +297,17 @@ project(':sbe-tool') { } propertyTest(JvmTestSuite) { + // We should be able to use _only_ the JQwik engine, but this issue is outstanding: + // https://github.com/gradle/gradle/issues/21299 useJUnitJupiter junitVersion dependencies { implementation project() - implementation "net.jqwik:jqwik:${jqwikVersion}" + implementation("net.jqwik:jqwik:${jqwikVersion}") { + // Exclude JUnit 5 dependencies that are already provided due to useJUnitJupiter + exclude group: 'org.junit.platform', module: 'junit-platform-commons' + exclude group: 'org.junit.platform', module: 'junit-platform-engine' + } implementation "org.json:json:${jsonVersion}" } From b9ed08b7e29b06e5f85280f43a77bb9c7c9aceee Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Mon, 13 Nov 2023 10:01:22 +0000 Subject: [PATCH 371/805] [CI] Upload slow test artifacts upon failure. --- .github/workflows/slow.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index ba932f8a9e..9b790d276e 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -54,3 +54,9 @@ jobs: run: ./csharp/build.sh - name: Run property tests run: ./gradlew propertyTest + - name: Upload test results + uses: actions/upload-artifact@v3 + if: success() || failure() + with: + name: property-tests + path: sbe-tool/build/reports/tests/propertyTest From b27bb68c83c5aef1da5f8ca4800d04bfde7716c6 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Mon, 13 Nov 2023 12:45:25 +0000 Subject: [PATCH 372/805] [C#] Provide path to SBE.dll for C# property tests in CI. --- build.gradle | 3 +++ .../co/real_logic/sbe/properties/DtosPropertyTest.java | 10 +++++++--- .../CSharpDtosPropertyTest/SbePropertyTest.csproj | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 2bb3c39f22..c21ddf3eba 100644 --- a/build.gradle +++ b/build.gradle @@ -311,6 +311,7 @@ project(':sbe-tool') { implementation "org.json:json:${jsonVersion}" } + targets { all { testTask.configure { @@ -318,6 +319,8 @@ project(':sbe-tool') { maxHeapSize = '2g' javaLauncher.set(toolchainLauncher) + + systemProperty 'sbe.dll', "${rootProject.projectDir}/csharp/sbe-dll/bin/Release/netstandard2.0/SBE.dll" } } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index d68a1c327c..8adc57679d 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -39,6 +39,8 @@ public class DtosPropertyTest { private static final String DOTNET_EXECUTABLE = System.getProperty("sbe.tests.dotnet.executable", "dotnet"); + private static final String SBE_DLL = + System.getProperty("sbe.dll", "csharp/sbe-dll/bin/Release/netstandard2.0/SBE.dll"); private static final String CPP_EXECUTABLE = System.getProperty("sbe.tests.cpp.executable", "g++"); private static final boolean KEEP_DIR_ON_FAILURE = Boolean.parseBoolean( System.getProperty("sbe.tests.keep.dir.on.failure", "true")); @@ -80,7 +82,9 @@ void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( writeInputFile(encodedMessage, tempDir); execute(encodedMessage.schema(), tempDir, "test", - DOTNET_EXECUTABLE, "run", "--", "input.dat"); + DOTNET_EXECUTABLE, "run", + "--property:SBE_DLL=" + SBE_DLL, + "--", "input.dat"); final byte[] inputBytes = new byte[encodedMessage.length()]; encodedMessage.buffer().getBytes(0, inputBytes); @@ -211,12 +215,12 @@ private static void execute( { final Path stdout = tempDir.resolve(name + "_stdout.txt"); final Path stderr = tempDir.resolve(name + "_stderr.txt"); - final ProcessBuilder compileProcessBuilder = new ProcessBuilder(args) + final ProcessBuilder processBuilder = new ProcessBuilder(args) .directory(tempDir.toFile()) .redirectOutput(stdout.toFile()) .redirectError(stderr.toFile()); - final Process process = compileProcessBuilder.start(); + final Process process = processBuilder.start(); if (0 != process.waitFor()) { diff --git a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj index 8b0b167d2b..5da3f76095 100644 --- a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj +++ b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj @@ -7,7 +7,7 @@ - /home/zach/src/real-logic/simple-binary-encoding/csharp/sbe-dll/bin/Release/netstandard2.0/SBE.dll + $(SBE_DLL) From 1e3cf8fea5afc3c8adcc08f9b55bb144b106ec9f Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 1 May 2024 16:19:14 +0100 Subject: [PATCH 373/805] [Java] Adjust copyright banners. --- .../uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java | 2 +- .../co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java | 2 +- .../java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java | 2 +- .../java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java | 2 +- .../uk/co/real_logic/sbe/properties/ParserPropertyTest.java | 2 +- .../real_logic/sbe/properties/arbitraries/SbeArbitraries.java | 2 +- .../real_logic/sbe/properties/schema/CompositeTypeSchema.java | 2 +- .../real_logic/sbe/properties/schema/EncodedDataTypeSchema.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/FieldSchema.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/GroupSchema.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/MessageSchema.java | 2 +- .../java/uk/co/real_logic/sbe/properties/schema/SetSchema.java | 2 +- .../real_logic/sbe/properties/schema/TestXmlSchemaWriter.java | 2 +- .../java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java | 2 +- .../co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/VarDataSchema.java | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index f2371181d0..168f6df665 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java index dfe00b449e..344e48d213 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index a132e751d6..e023b8fd95 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java index 79859d6764..4fc0cc513f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index 8adc57679d..f71e416309 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java index ab5c8d955e..a9b8cd0987 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java index b6ce84ef3a..1b59dca624 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index 66bfeebcf0..a47a93eabf 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java index a6df53d778..06123ffc9f 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java index a1bbeba14e..7abc254e0b 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java index fa669fe04a..fa28ef0a3a 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java index c1fad8abc4..9745b042a1 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java index 47cfe343a7..2aa3dcd3c3 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java index 2095628c39..d992d6559f 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java index 4ed41fc013..5acbc9da40 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index 3c43228099..b7e3d6f8c1 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java index 311521e697..ca236a0673 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java index 830a2e1cf7..2651febfc7 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java index db3d5900a1..1bfd64621d 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2023 Real Logic Limited. + * Copyright 2013-2024 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 328cc427f23629e7bfdaf9caae1f1b540aa9b430 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Mon, 13 May 2024 13:40:51 +0100 Subject: [PATCH 374/805] [Java] Add support for DTO generation. This commit adds support for generating SBE DTOs in Java. Unlike the C# and C++ support, there isn't a natural candidate for the idiomatic representation of optional fields, e.g., `Optional` is only meant for use as a return type. Therefore, the mapping between Java types and the encoding is simpler than in these other languages. In a future commit, I will extend the property-based tests to cover Java DTOs. --- build.gradle | 16 + .../java/uk/co/real_logic/sbe/SbeTool.java | 7 +- .../generation/TargetCodeGeneratorLoader.java | 20 +- .../sbe/generation/cpp/CppDtos.java | 2 +- .../sbe/generation/java/JavaDtoGenerator.java | 1794 +++++++++++++++++ .../sbe/generation/java/JavaDtos.java | 35 + .../sbe/generation/java/JavaGenerator.java | 18 +- .../sbe/generation/java/JavaUtil.java | 11 + .../sbe/generation/java/DtoTest.java | 154 ++ .../resources/example-extension-schema.xml | 103 + 10 files changed, 2141 insertions(+), 19 deletions(-) create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java create mode 100644 sbe-tool/src/test/resources/example-extension-schema.xml diff --git a/build.gradle b/build.gradle index c21ddf3eba..b661f8b406 100644 --- a/build.gradle +++ b/build.gradle @@ -280,6 +280,7 @@ project(':sbe-tool') { compileGeneratedJava { dependsOn 'generateTestCodecs' + dependsOn 'generateTestDtos' classpath += sourceSets.main.runtimeClasspath } @@ -344,6 +345,21 @@ project(':sbe-tool') { 'src/test/resources/field-order-check-schema.xml'] } + tasks.register('generateTestDtos', JavaExec) { + dependsOn 'compileJava' + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': generatedDir, + 'sbe.target.language': 'java', + 'sbe.validation.stop.on.error': 'true', + 'sbe.validation.xsd': validationXsdPath, + 'sbe.generate.precedence.checks': 'true', + 'sbe.java.precedence.checks.property.name': 'sbe.enable.test.precedence.checks', + 'sbe.java.generate.dtos': 'true') + args = ['src/test/resources/example-extension-schema.xml'] + } + jar { manifest.attributes( 'Specification-Title': 'Simple Binary Encoding', diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index a6958a12bf..d65a6a4601 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -195,7 +195,12 @@ public class SbeTool /** * Should generate C++ DTOs. Defaults to false. */ - public static final String GENERATE_CPP_DTOS = "sbe.cpp.generate.dtos"; + public static final String CPP_GENERATE_DTOS = "sbe.cpp.generate.dtos"; + + /** + * Should generate Java DTOs. Defaults to false. + */ + public static final String JAVA_GENERATE_DTOS = "sbe.java.generate.dtos"; /** * Configuration option used to manage sinceVersion based transformations. When set, parsed schemas will be diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 6f872cd55e..2b2383dfd2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -23,6 +23,7 @@ import uk.co.real_logic.sbe.generation.cpp.NamespaceOutputManager; import uk.co.real_logic.sbe.generation.golang.GolangGenerator; import uk.co.real_logic.sbe.generation.golang.GolangOutputManager; +import uk.co.real_logic.sbe.generation.java.JavaDtoGenerator; import uk.co.real_logic.sbe.generation.java.JavaGenerator; import uk.co.real_logic.sbe.generation.java.JavaOutputManager; import uk.co.real_logic.sbe.generation.rust.RustGenerator; @@ -47,7 +48,9 @@ public enum TargetCodeGeneratorLoader implements TargetCodeGenerator */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new JavaGenerator( + final JavaOutputManager outputManager = new JavaOutputManager(outputDir, ir.applicableNamespace()); + + final JavaGenerator codecGenerator = new JavaGenerator( ir, System.getProperty(JAVA_ENCODING_BUFFER_TYPE, JAVA_DEFAULT_ENCODING_BUFFER_TYPE), System.getProperty(JAVA_DECODING_BUFFER_TYPE, JAVA_DEFAULT_DECODING_BUFFER_TYPE), @@ -56,7 +59,18 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)), "true".equals(System.getProperty(TYPES_PACKAGE_OVERRIDE)), precedenceChecks(), - new JavaOutputManager(outputDir, ir.applicableNamespace())); + outputManager); + + final JavaDtoGenerator dtoGenerator = new JavaDtoGenerator(ir, outputManager); + + final CodeGenerator combinedGenerator = () -> + { + codecGenerator.generate(); + dtoGenerator.generate(); + }; + + final boolean generateDtos = "true".equals(System.getProperty(JAVA_GENERATE_DTOS)); + return generateDtos ? combinedGenerator : codecGenerator; } }, @@ -97,7 +111,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) dtoGenerator.generate(); }; - final boolean generateDtos = "true".equals(System.getProperty(GENERATE_CPP_DTOS)); + final boolean generateDtos = "true".equals(System.getProperty(CPP_GENERATE_DTOS)); return generateDtos ? combinedGenerator : codecGenerator; } }, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java index 344e48d213..09dbfb052f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java @@ -22,7 +22,7 @@ import uk.co.real_logic.sbe.ir.Ir; /** - * {@link CodeGenerator} factory for CSharp DTOs. + * {@link CodeGenerator} factory for C++ DTOs. */ public class CppDtos implements TargetCodeGenerator { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java new file mode 100644 index 0000000000..b5fd05e665 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -0,0 +1,1794 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * Copyright (C) 2017 MarketFactory, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.Signal; +import uk.co.real_logic.sbe.ir.Token; +import org.agrona.LangUtil; +import org.agrona.Verify; +import org.agrona.generation.OutputManager; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; +import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; +import static uk.co.real_logic.sbe.generation.java.JavaUtil.*; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; +import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; + +/** + * DTO generator for the Java programming language. + */ +public class JavaDtoGenerator implements CodeGenerator +{ + private static final String INDENT = " "; + private static final String BASE_INDENT = ""; + + private final Ir ir; + private final OutputManager outputManager; + + /** + * Create a new C# DTO {@link CodeGenerator}. + * + * @param ir for the messages and types. + * @param outputManager for generating the DTOs to. + */ + public JavaDtoGenerator(final Ir ir, final OutputManager outputManager) + { + Verify.notNull(ir, "ir"); + Verify.notNull(outputManager, "outputManager"); + + this.ir = ir; + this.outputManager = outputManager; + } + + /** + * {@inheritDoc} + */ + public void generate() throws IOException + { + generateDtosForTypes(); + + for (final List tokens : ir.messages()) + { + final Token msgToken = tokens.get(0); + final String encoderClassName = encoderName(msgToken.name()); + final String decoderClassName = decoderName(msgToken.name()); + final String dtoClassName = formatDtoClassName(msgToken.name()); + + final List messageBody = tokens.subList(1, tokens.size() - 1); + int offset = 0; + + final ClassBuilder classBuilder = new ClassBuilder(dtoClassName, BASE_INDENT, "public final"); + + final List fields = new ArrayList<>(); + offset = collectFields(messageBody, offset, fields); + generateFields(classBuilder, decoderClassName, fields, BASE_INDENT + INDENT); + + final List groups = new ArrayList<>(); + offset = collectGroups(messageBody, offset, groups); + generateGroups(classBuilder, dtoClassName, encoderClassName, decoderClassName, groups, + BASE_INDENT + INDENT); + + final List varData = new ArrayList<>(); + collectVarData(messageBody, offset, varData); + generateVarData(classBuilder, varData, BASE_INDENT + INDENT); + + generateDecodeWith(classBuilder, dtoClassName, decoderClassName, fields, + groups, varData, BASE_INDENT + INDENT); + generateDecodeFrom(classBuilder, dtoClassName, decoderClassName, BASE_INDENT + INDENT); + generateEncodeWith(classBuilder, dtoClassName, encoderClassName, fields, groups, varData, + BASE_INDENT + INDENT); + generateEncodeWithOverloads(classBuilder, dtoClassName, encoderClassName, BASE_INDENT + INDENT); + generateComputeEncodedLength(classBuilder, decoderClassName, + decoderClassName + ".BLOCK_LENGTH", + groups, varData, BASE_INDENT + INDENT); + generateDisplay(classBuilder, encoderClassName, "computeEncodedLength()", + BASE_INDENT + INDENT); + + try (Writer out = outputManager.createOutput(dtoClassName)) + { + out.append(generateDtoFileHeader(ir.applicableNamespace())); + out.append("import org.agrona.DirectBuffer;\n"); + out.append("import org.agrona.MutableDirectBuffer;\n"); + out.append("import org.agrona.concurrent.UnsafeBuffer;\n\n"); + out.append("import java.util.ArrayList;\n"); + out.append("import java.util.List;\n\n"); + out.append(generateDocumentation(BASE_INDENT, msgToken)); + classBuilder.appendTo(out); + } + } + } + + private static final class ClassBuilder + { + private final StringBuilder fieldSb = new StringBuilder(); + private final StringBuilder privateSb = new StringBuilder(); + private final StringBuilder publicSb = new StringBuilder(); + private final String className; + private final String indent; + private final String modifiers; + + private ClassBuilder( + final String className, + final String indent, + final String modifiers) + { + this.className = className; + this.indent = indent; + this.modifiers = modifiers.length() == 0 ? modifiers : modifiers + " "; + } + + public StringBuilder appendField() + { + return fieldSb; + } + + public StringBuilder appendPrivate() + { + return privateSb; + } + + public StringBuilder appendPublic() + { + return publicSb; + } + + public void appendTo(final Appendable out) + { + try + { + out.append(indent).append(modifiers).append("class ").append(className).append("\n") + .append(indent).append("{\n") + .append(fieldSb) + .append("\n") + .append(privateSb) + .append("\n") + .append(publicSb) + .append("\n") + .append(indent).append("}\n"); + } + catch (final IOException exception) + { + LangUtil.rethrowUnchecked(exception); + } + } + } + + private void generateGroups( + final ClassBuilder classBuilder, + final String qualifiedParentDtoClassName, + final String qualifiedParentEncoderClassName, + final String qualifiedParentDecoderClassName, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String groupClassName = formatDtoClassName(groupName); + final String qualifiedDtoClassName = qualifiedParentDtoClassName + "." + groupClassName; + + final String fieldName = formatFieldName(groupName); + final String formattedPropertyName = formatPropertyName(groupName); + + classBuilder.appendField().append(indent).append("private List<") + .append(qualifiedDtoClassName).append("> ") + .append(fieldName).append(" = new ArrayList<>();\n"); + + final ClassBuilder groupClassBuilder = new ClassBuilder(groupClassName, indent, "public static final"); + + i++; + i += tokens.get(i).componentTokenCount(); + + final String qualifiedEncoderClassName = + qualifiedParentEncoderClassName + "." + encoderName(groupName); + final String qualifiedDecoderClassName = + qualifiedParentDecoderClassName + "." + decoderName(groupName); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + generateFields(groupClassBuilder, qualifiedDecoderClassName, fields, indent + INDENT); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + generateGroups(groupClassBuilder, qualifiedDtoClassName, + qualifiedEncoderClassName, qualifiedDecoderClassName, groups, indent + INDENT); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + generateVarData(groupClassBuilder, varData, indent + INDENT); + + generateDecodeListWith( + groupClassBuilder, groupClassName, qualifiedDecoderClassName, indent + INDENT); + generateDecodeWith(groupClassBuilder, groupClassName, qualifiedDecoderClassName, + fields, groups, varData, indent + INDENT); + generateEncodeWith( + groupClassBuilder, groupClassName, qualifiedEncoderClassName, fields, groups, varData, indent + INDENT); + generateComputeEncodedLength(groupClassBuilder, qualifiedDecoderClassName, + qualifiedDecoderClassName + ".sbeBlockLength()", + groups, varData, indent + INDENT); + + groupClassBuilder.appendTo( + classBuilder.appendPublic().append("\n").append(generateDocumentation(indent, groupToken)) + ); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("public List<").append(qualifiedDtoClassName).append("> ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, groupToken)) + .append(indent).append("public void ").append(formattedPropertyName).append("(") + .append("List<").append(qualifiedDtoClassName).append("> value)") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + } + } + + private void generateComputeEncodedLength( + final ClassBuilder classBuilder, + final String qualifiedDecoderClassName, + final String blockLengthExpression, + final List groupTokens, + final List varDataTokens, + final String indent) + { + final StringBuilder lengthBuilder = classBuilder.appendPublic() + .append("\n") + .append(indent).append("public int computeEncodedLength()\n") + .append(indent).append("{\n"); + + lengthBuilder + .append(indent).append(INDENT).append("int encodedLength = 0;\n"); + + lengthBuilder.append(indent).append(INDENT).append("encodedLength += ").append(blockLengthExpression) + .append(";\n\n"); + + for (int i = 0, size = groupTokens.size(); i < size; i++) + { + final Token groupToken = groupTokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + i++; + i += groupTokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(groupTokens, i, fields); + final List subGroups = new ArrayList<>(); + i = collectGroups(groupTokens, i, subGroups); + final List subVarData = new ArrayList<>(); + i = collectVarData(groupTokens, i, subVarData); + + final String groupName = groupToken.name(); + final String fieldName = formatFieldName(groupName); + final String groupDecoderClassName = qualifiedDecoderClassName + "." + decoderName(groupName); + final String groupDtoClassName = formatDtoClassName(groupName); + + lengthBuilder + .append(indent).append(INDENT).append("encodedLength += ") + .append(groupDecoderClassName).append(".sbeHeaderSize();\n\n") + .append(indent).append(INDENT).append("for (").append(groupDtoClassName).append(" group : ") + .append(fieldName).append(")\n") + .append(indent).append(INDENT).append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("encodedLength += group.computeEncodedLength();\n") + .append(indent).append(INDENT).append("}\n\n"); + } + + for (int i = 0, size = varDataTokens.size(); i < size; i++) + { + final Token token = varDataTokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final Token varDataToken = Generators.findFirst("varData", varDataTokens, i); + final String fieldName = formatFieldName(propertyName); + + lengthBuilder.append(indent).append(INDENT).append("encodedLength += ") + .append(qualifiedDecoderClassName).append(".") + .append(formatPropertyName(propertyName)).append("HeaderLength();\n"); + + lengthBuilder.append(indent).append(INDENT).append("encodedLength += ") + .append(fieldName).append(".length()"); + + final int elementByteLength = varDataToken.encoding().primitiveType().size(); + if (elementByteLength != 1) + { + lengthBuilder.append(" * ").append(elementByteLength); + } + + lengthBuilder.append(";\n\n"); + } + } + + lengthBuilder.append(indent).append(INDENT).append("return encodedLength;\n") + .append(indent).append("}\n"); + } + + private void generateCompositeDecodeWith( + final ClassBuilder classBuilder, + final String dtoClassName, + final String decoderClassName, + final List tokens, + final String indent) + { + final StringBuilder decodeBuilder = classBuilder.appendPublic().append("\n") + .append(indent).append("public static void decodeWith(").append(decoderClassName).append(" decoder, ") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n"); + + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + + generateFieldDecodeWith( + decodeBuilder, token, token, decoderClassName, indent + INDENT); + + i += tokens.get(i).componentTokenCount(); + } + + decodeBuilder.append(indent).append("}\n"); + } + + private void generateCompositeEncodeWith( + final ClassBuilder classBuilder, + final String dtoClassName, + final String encoderClassName, + final List tokens, + final String indent) + { + final StringBuilder encodeBuilder = classBuilder.appendPublic().append("\n") + .append(indent).append("public static void encodeWith(").append(encoderClassName).append(" encoder, ") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n"); + + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + + generateFieldEncodeWith(encodeBuilder, token, token, indent + INDENT); + + i += tokens.get(i).componentTokenCount(); + } + + encodeBuilder.append(indent).append("}\n"); + } + + private void generateDecodeListWith( + final ClassBuilder classBuilder, + final String dtoClassName, + final String decoderClassName, + final String indent) + { + classBuilder.appendPublic().append("\n") + .append(indent).append("static List<").append(dtoClassName).append("> decodeManyWith(") + .append(decoderClassName).append(" decoder)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("List<").append(dtoClassName) + .append("> dtos = new ArrayList<>(decoder.count());\n") + .append(indent).append(INDENT) + .append("while (decoder.hasNext())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append(dtoClassName).append(" dto = new ").append(dtoClassName).append("();\n") + .append(indent).append(INDENT).append(INDENT) + .append(dtoClassName).append(".decodeWith(decoder.next(), dto);\n") + .append(indent).append(INDENT).append(INDENT) + .append("dtos.add(dto);\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append(INDENT) + .append("return dtos;\n") + .append(indent).append("}\n"); + } + + private void generateDecodeWith( + final ClassBuilder classBuilder, + final String dtoClassName, + final String decoderClassName, + final List fields, + final List groups, + final List varData, + final String indent) + { + final StringBuilder decodeBuilder = classBuilder.appendPublic().append("\n") + .append(indent).append("public static void decodeWith(").append(decoderClassName).append(" decoder, ") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n"); + + generateMessageFieldsDecodeWith(decodeBuilder, fields, decoderClassName, indent + INDENT); + generateGroupsDecodeWith(decodeBuilder, groups, indent + INDENT); + generateVarDataDecodeWith(decodeBuilder, varData, indent + INDENT); + decodeBuilder.append(indent).append("}\n"); + } + + private static void generateDecodeFrom( + final ClassBuilder classBuilder, + final String dtoClassName, + final String decoderClassName, + final String indent) + { + classBuilder.appendPublic() + .append("\n") + .append(indent).append("public static ").append(dtoClassName).append(" decodeFrom(") + .append("DirectBuffer buffer, int offset, ") + .append("short actingBlockLength, short actingVersion)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(decoderClassName).append(" decoder = new ") + .append(decoderClassName).append("();\n") + .append(indent).append(INDENT) + .append("decoder.wrap(buffer, offset, actingBlockLength, actingVersion);\n") + .append(indent).append(INDENT).append(dtoClassName).append(" dto = new ") + .append(dtoClassName).append("();\n") + .append(indent).append(INDENT).append("decodeWith(decoder, dto);\n") + .append(indent).append(INDENT).append("return dto;\n") + .append(indent).append("}\n"); + } + + private void generateMessageFieldsDecodeWith( + final StringBuilder sb, + final List tokens, + final String decoderClassName, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + + generateFieldDecodeWith(sb, signalToken, encodingToken, decoderClassName, indent); + } + } + } + + private void generateFieldDecodeWith( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String decoderClassName, + final String indent) + { + switch (typeToken.signal()) + { + case ENCODING: + generatePrimitiveDecodeWith(sb, fieldToken, typeToken, decoderClassName, indent); + break; + + case BEGIN_SET: + final String bitSetName = formatDtoClassName(typeToken.applicableTypeName()); + generateBitSetDecodeWith(sb, fieldToken, bitSetName, indent); + break; + + case BEGIN_ENUM: + generateEnumDecodeWith(sb, fieldToken, indent); + break; + + case BEGIN_COMPOSITE: + generateCompositePropertyDecodeWith(sb, fieldToken, typeToken, indent); + break; + + default: + break; + } + } + + private void generatePrimitiveDecodeWith( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String decoderClassName, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + return; + } + + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + final String decoderNullValue = + decoderClassName + "." + formatPropertyName(fieldToken.name()) + "NullValue()"; + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + generateRecordPropertyAssignment( + sb, + fieldToken, + indent, + "decoder.actingVersion() >= " + decoderClassName + "." + formattedPropertyName + "SinceVersion()", + "decoder." + formattedPropertyName + "()", + decoderNullValue + ); + } + else if (arrayLength > 1) + { + generateArrayDecodeWith(sb, decoderClassName, fieldToken, typeToken, indent); + } + } + + private void generateArrayDecodeWith( + final StringBuilder sb, + final String decoderClassName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + generateRecordPropertyAssignment( + sb, + fieldToken, + indent, + "decoder.actingVersion() >= " + decoderClassName + "." + formattedPropertyName + "SinceVersion()", + "decoder." + formattedPropertyName + "()", + "\"\"" + ); + } + else + { + final StringBuilder initializerList = new StringBuilder(); + final String elementType = javaTypeName(typeToken.encoding().primitiveType()); + initializerList.append("new ").append(elementType).append("[] { "); + final int arrayLength = typeToken.arrayLength(); + for (int i = 0; i < arrayLength; i++) + { + initializerList.append("decoder.").append(formattedPropertyName).append("(").append(i).append("),"); + } + assert arrayLength > 0; + initializerList.setLength(initializerList.length() - 1); + initializerList.append(" }"); + + generateRecordPropertyAssignment( + sb, + fieldToken, + indent, + "decoder.actingVersion() >= " + decoderClassName + "." + formattedPropertyName + "SinceVersion()", + initializerList, + null + ); + } + } + + private void generateBitSetDecodeWith( + final StringBuilder sb, + final Token fieldToken, + final String dtoTypeName, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (fieldToken.isOptionalEncoding()) + { + sb.append(indent).append("if (decoder.").append(formattedPropertyName).append("InActingVersion()"); + + sb.append(")\n") + .append(indent).append("{\n"); + + sb.append(indent).append(INDENT).append(dtoTypeName).append(".decodeWith(decoder.") + .append(formattedPropertyName).append("(), ") + .append("dto.").append(formattedPropertyName).append("());\n"); + + sb.append(indent).append("}\n") + .append(indent).append("else\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("().clear();\n") + .append(indent).append("}\n"); + } + else + { + sb.append(indent).append(dtoTypeName).append(".decodeWith(decoder.") + .append(formattedPropertyName).append("(), ") + .append("dto.").append(formattedPropertyName).append("());\n"); + } + } + + private void generateEnumDecodeWith( + final StringBuilder sb, + final Token fieldToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + sb.append(indent).append("dto.").append(formattedPropertyName).append("(") + .append("decoder.").append(formattedPropertyName).append("());\n"); + } + + private void generateCompositePropertyDecodeWith( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + final String dtoClassName = formatDtoClassName(typeToken.applicableTypeName()); + + sb.append(indent).append(dtoClassName).append(".decodeWith(decoder.") + .append(formattedPropertyName).append("(), ") + .append("dto.").append(formattedPropertyName).append("());\n"); + } + + private void generateGroupsDecodeWith( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String formattedPropertyName = formatPropertyName(groupName); + final String groupDtoClassName = formatDtoClassName(groupName); + + sb.append(indent).append("dto.").append(formattedPropertyName).append("(") + .append(groupDtoClassName).append(".decodeManyWith(decoder.") + .append(formattedPropertyName).append("()));\n"); + + i++; + i += tokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + } + } + + private void generateVarDataDecodeWith( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0; i < tokens.size(); i++) + { + final Token token = tokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + + final boolean isOptional = token.version() > 0; + final String blockIndent = isOptional ? indent + INDENT : indent; + + final String dataVar = toLowerFirstChar(propertyName) + "Data"; + + final StringBuilder decoderValueExtraction = new StringBuilder(); + + if (characterEncoding == null) + { + decoderValueExtraction.append(blockIndent).append("byte[] ").append(dataVar) + .append(" = new byte[decoder.").append(formattedPropertyName).append("Length()];\n") + .append(blockIndent).append("decoder.get").append(formattedPropertyName) + .append("(").append(dataVar).append(", 0, decoder.").append(formattedPropertyName) + .append("Length());\n"); + } + else + { + decoderValueExtraction.append(blockIndent).append("String ").append(dataVar) + .append(" = decoder.").append(formattedPropertyName).append("();\n"); + } + + if (isOptional) + { + sb.append(indent).append("if (decoder.").append(formattedPropertyName).append("InActingVersion()"); + + sb.append(")\n") + .append(indent).append("{\n"); + + sb.append(decoderValueExtraction); + + sb.append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(") + .append(dataVar).append(");\n"); + + final String nullDtoValue = "\"\""; + + sb.append(indent).append("}\n") + .append(indent).append("else\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("dto.") + .append(formattedPropertyName).append("(").append(nullDtoValue).append(");\n") + .append(indent).append("}\n"); + } + else + { + sb.append(decoderValueExtraction); + + sb.append(indent).append("dto.").append(formattedPropertyName).append("(") + .append(dataVar).append(");\n"); + } + } + } + } + + private void generateRecordPropertyAssignment( + final StringBuilder sb, + final Token token, + final String indent, + final String presenceExpression, + final CharSequence getExpression, + final String nullDecoderValueOrNull) + { + final String propertyName = token.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (token.isOptionalEncoding()) + { + + sb.append(indent).append("if (").append(presenceExpression).append(")\n") + .append(indent).append("{\n"); + + sb.append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(") + .append(getExpression).append(");\n"); + + final String nullValue = nullDecoderValueOrNull == null ? "null" : nullDecoderValueOrNull; + + sb.append(indent).append("}\n") + .append(indent).append("else\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(") + .append(nullValue).append(");\n") + .append(indent).append("}\n"); + } + else + { + sb.append(indent).append("dto.").append(formattedPropertyName).append("(") + .append(getExpression).append(");\n"); + } + } + + private void generateEncodeWith( + final ClassBuilder classBuilder, + final String dtoClassName, + final String encoderClassName, + final List fields, + final List groups, + final List varData, + final String indent) + { + final StringBuilder encodeBuilder = classBuilder.appendPublic().append("\n") + .append(indent).append("public static void encodeWith(").append(encoderClassName).append(" encoder, ") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n"); + + generateFieldsEncodeWith(encodeBuilder, fields, indent + INDENT); + generateGroupsEncodeWith(encodeBuilder, encoderClassName, groups, indent + INDENT); + generateVarDataEncodeWith(encodeBuilder, varData, indent + INDENT); + + encodeBuilder.append(indent).append("}\n"); + } + + private static void generateEncodeWithOverloads( + final ClassBuilder classBuilder, + final String dtoClassName, + final String encoderClassName, + final String indent) + { + classBuilder.appendPublic() + .append("\n") + .append(indent).append("public static int encodeWith(").append(dtoClassName).append(" dto, ") + .append("MutableDirectBuffer buffer, int offset)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(encoderClassName).append(" encoder = new ") + .append(encoderClassName).append("();\n") + .append(indent).append(INDENT).append("encoder.wrap(buffer, offset);\n") + .append(indent).append(INDENT).append("encodeWith(encoder, dto);\n") + .append(indent).append(INDENT).append("return encoder.encodedLength();\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append("public static int encodeWithHeaderWith(") + .append(dtoClassName).append(" dto, ") + .append("MutableDirectBuffer buffer, int offset)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(encoderClassName).append(" encoder = new ") + .append(encoderClassName).append("();\n") + .append(indent).append(INDENT) + .append("encoder.wrapAndApplyHeader(buffer, offset, new MessageHeaderEncoder());\n") + .append(indent).append(INDENT).append("encodeWith(encoder, dto);\n") + .append(indent).append(INDENT).append("return encoder.limit() - offset;\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append("public static byte[] bytes(") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("byte[] bytes = new byte[dto.computeEncodedLength()];\n") + .append(indent).append(INDENT).append("encodeWith(dto, new UnsafeBuffer(bytes), 0);\n") + .append(indent).append(INDENT).append("return bytes;\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append("public static byte[] bytesWithHeader(") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("byte[] bytes = new byte[dto.computeEncodedLength() + ") + .append("MessageHeaderEncoder.ENCODED_LENGTH];\n") + .append(indent).append(INDENT).append("encodeWithHeaderWith(dto, new UnsafeBuffer(bytes), 0);\n") + .append(indent).append(INDENT).append("return bytes;\n") + .append(indent).append("}\n"); + } + + private void generateFieldsEncodeWith( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + generateFieldEncodeWith(sb, signalToken, encodingToken, indent); + } + } + } + + private void generateFieldEncodeWith( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + switch (typeToken.signal()) + { + case ENCODING: + generatePrimitiveEncodeWith(sb, fieldToken, typeToken, indent); + break; + + case BEGIN_ENUM: + generateEnumEncodeWith(sb, fieldToken, indent); + break; + + case BEGIN_SET: + case BEGIN_COMPOSITE: + generateComplexPropertyEncodeWith(sb, fieldToken, typeToken, indent); + break; + + default: + break; + } + } + + private void generatePrimitiveEncodeWith( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + return; + } + + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + generatePrimitiveValueEncodeWith(sb, fieldToken, indent); + } + else if (arrayLength > 1) + { + generateArrayEncodeWith(sb, fieldToken, typeToken, indent); + } + } + + private void generateArrayEncodeWith( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + sb.append(indent).append("encoder.").append(toLowerFirstChar(propertyName)).append("(") + .append("dto.").append(formattedPropertyName).append("());\n"); + } + else if (typeToken.encoding().primitiveType() == PrimitiveType.UINT8) + { + sb.append(indent).append("encoder.put").append(toUpperFirstChar(propertyName)).append("(") + .append("dto.").append(formattedPropertyName).append("());\n"); + } + else + { + final String javaTypeName = javaTypeName(typeToken.encoding().primitiveType()); + sb.append(indent).append(javaTypeName).append("[] ").append(formattedPropertyName).append(" = ") + .append("dto.").append(formattedPropertyName).append("();\n") + .append(indent).append("for (int i = 0; i < ").append(formattedPropertyName).append(".length; i++)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("encoder.").append(formattedPropertyName).append("(") + .append("i, ").append(formattedPropertyName).append("[i]);\n") + .append(indent).append("}\n"); + } + } + + private void generatePrimitiveValueEncodeWith( + final StringBuilder sb, + final Token fieldToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + final String accessor = "dto." + formattedPropertyName + "()"; + + sb.append(indent).append("encoder.").append(formattedPropertyName).append("(") + .append(accessor).append(");\n"); + } + + private void generateEnumEncodeWith( + final StringBuilder sb, + final Token fieldToken, + final String indent) + { + if (fieldToken.isConstantEncoding()) + { + return; + } + + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + + sb.append(indent).append("encoder.").append(formattedPropertyName).append("(dto.") + .append(formattedPropertyName).append("());\n"); + } + + private void generateComplexPropertyEncodeWith( + final StringBuilder sb, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String propertyName = fieldToken.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + final String typeName = formatDtoClassName(typeToken.applicableTypeName()); + + sb.append(indent).append(typeName).append(".encodeWith(encoder.") + .append(formattedPropertyName).append("(), dto.") + .append(formattedPropertyName).append("());\n"); + } + + private void generateGroupsEncodeWith( + final StringBuilder sb, + final String parentEncoderClassName, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + final String groupName = groupToken.name(); + final String formattedPropertyName = formatPropertyName(groupName); + final String groupEncoderVarName = groupName + "Encoder"; + final String groupDtoTypeName = formatDtoClassName(groupName); + final String groupEncoderTypeName = parentEncoderClassName + "." + encoderName(groupName); + + sb.append("\n") + .append(indent).append("List<").append(groupDtoTypeName).append("> ") + .append(formattedPropertyName).append(" = dto.").append(formattedPropertyName).append("();\n\n") + .append(indent).append(groupEncoderTypeName).append(" ").append(groupEncoderVarName) + .append(" = encoder.").append(formattedPropertyName) + .append("Count(").append(formattedPropertyName).append(".size());\n\n") + .append(indent).append("for (").append(groupDtoTypeName).append(" group : ") + .append(formattedPropertyName).append(")\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(groupDtoTypeName) + .append(".encodeWith(").append(groupEncoderVarName).append(".next(), group);\n") + .append(indent).append("}\n\n"); + + i++; + i += tokens.get(i).componentTokenCount(); + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + } + } + + private void generateVarDataEncodeWith( + final StringBuilder sb, + final List tokens, + final String indent) + { + for (int i = 0; i < tokens.size(); i++) + { + final Token token = tokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final String formattedPropertyName = formatPropertyName(propertyName); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + + if (characterEncoding == null) + { + sb.append(indent).append("encoder.put").append(toUpperFirstChar(propertyName)).append("(") + .append("dto.").append(formattedPropertyName).append("());\n"); + } + else + { + sb.append(indent).append("encoder.").append(formattedPropertyName).append("(") + .append("dto.").append(formattedPropertyName).append("());\n"); + } + } + } + } + + private void generateDisplay( + final ClassBuilder classBuilder, + final String encoderClassName, + final String lengthExpression, + final String indent) + { + final StringBuilder sb = classBuilder.appendPublic(); + + sb.append("\n") + .append(indent).append("public String toString()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT) + .append("MutableDirectBuffer buffer = new UnsafeBuffer(new byte[").append(lengthExpression).append("]);\n") + .append(indent).append(INDENT).append(encoderClassName).append(" encoder = new ") + .append(encoderClassName).append("();\n") + .append(indent).append(INDENT).append("encoder."); + + sb.append("wrap").append("(buffer, 0);\n"); + + sb.append(indent).append(INDENT).append("encodeWith(encoder, this);\n") + .append(indent).append(INDENT).append("StringBuilder sb = new StringBuilder();\n") + .append(indent).append(INDENT).append("encoder.appendTo(sb);\n") + .append(indent).append(INDENT).append("return sb.toString();\n") + .append(indent).append("}\n"); + } + + private void generateFields( + final ClassBuilder classBuilder, + final String decoderClassName, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + final String propertyName = signalToken.name(); + + switch (encodingToken.signal()) + { + case ENCODING: + generatePrimitiveProperty( + classBuilder, decoderClassName, propertyName, signalToken, encodingToken, indent); + break; + + case BEGIN_ENUM: + generateEnumProperty(classBuilder, propertyName, signalToken, encodingToken, indent); + break; + + case BEGIN_SET: + case BEGIN_COMPOSITE: + generateComplexProperty(classBuilder, propertyName, signalToken, encodingToken, indent); + break; + + default: + break; + } + } + } + } + + private void generateComplexProperty( + final ClassBuilder classBuilder, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String typeName = formatDtoClassName(typeToken.applicableTypeName()); + final String formattedPropertyName = formatPropertyName(propertyName); + final String fieldName = formatFieldName(propertyName); + + classBuilder.appendField() + .append(indent).append("private ").append(typeName).append(" ").append(fieldName) + .append(" = new ").append(typeName).append("();\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(typeName).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public void ") + .append(formattedPropertyName).append("(").append(typeName).append(" value)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + } + + private void generateEnumProperty( + final ClassBuilder classBuilder, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String enumName = formatClassName(typeToken.applicableTypeName()); + + final String formattedPropertyName = formatPropertyName(propertyName); + + if (fieldToken.isConstantEncoding()) + { + final String constValue = fieldToken.encoding().constValue().toString(); + final String caseName = constValue.substring(constValue.indexOf(".") + 1); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public static ").append(enumName).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(enumName).append(".") + .append(caseName).append(";\n") + .append(indent).append("}\n"); + } + else + { + final String fieldName = formatFieldName(propertyName); + + classBuilder.appendField() + .append(indent).append("private ").append(enumName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(enumName).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public void ").append(formattedPropertyName) + .append("(").append(enumName).append(" value)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + } + } + + private void generatePrimitiveProperty( + final ClassBuilder classBuilder, + final String decoderClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.isConstantEncoding()) + { + generateConstPropertyMethods(classBuilder, propertyName, fieldToken, typeToken, indent); + } + else + { + generatePrimitivePropertyMethods( + classBuilder, decoderClassName, propertyName, fieldToken, typeToken, indent); + } + } + + private void generatePrimitivePropertyMethods( + final ClassBuilder classBuilder, + final String decoderClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final int arrayLength = typeToken.arrayLength(); + + if (arrayLength == 1) + { + generateSingleValueProperty(classBuilder, decoderClassName, propertyName, fieldToken, typeToken, indent); + } + else if (arrayLength > 1) + { + generateArrayProperty(classBuilder, decoderClassName, propertyName, fieldToken, typeToken, indent); + } + } + + private void generateArrayProperty( + final ClassBuilder classBuilder, + final String decoderClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String formattedPropertyName = formatPropertyName(propertyName); + final String fieldName = formatFieldName(propertyName); + final String validateMethod = "validate" + toUpperFirstChar(propertyName); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + final CharSequence typeName = "String"; + + classBuilder.appendField() + .append(indent).append("private ").append(typeName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(typeName).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("void ").append(formattedPropertyName) + .append("(").append(typeName).append(" value)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(validateMethod).append("(value);\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + + generateArrayValidateMethod( + classBuilder, + decoderClassName, + indent, + validateMethod, + typeName, + ".length()", + formattedPropertyName); + } + else + { + final String elementTypeName = javaTypeName(typeToken.encoding().primitiveType()); + final String typeName = elementTypeName + "[]"; + + classBuilder.appendField() + .append(indent).append("private ").append(typeName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(typeName).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public void ").append(formattedPropertyName).append("(") + .append(typeName).append(" value").append(")\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(validateMethod).append("(value);\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + + generateArrayValidateMethod( + classBuilder, + decoderClassName, + indent, + validateMethod, + typeName, + ".length", + formattedPropertyName); + } + } + + private static void generateArrayValidateMethod( + final ClassBuilder classBuilder, + final String decoderClassName, + final String indent, + final String validateMethod, + final CharSequence typeName, + final String lengthAccessor, + final String formattedPropertyName) + { + final StringBuilder validateBuilder = classBuilder.appendPrivate().append("\n") + .append(indent).append("private static void ").append(validateMethod).append("(") + .append(typeName).append(" value)\n") + .append(indent).append("{\n"); + + validateBuilder.append(indent).append(INDENT) + .append("if (value").append(lengthAccessor).append(" > ").append(decoderClassName).append(".") + .append(formattedPropertyName).append("Length())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw new IllegalArgumentException(\"") + .append(formattedPropertyName) + .append(": too many elements: \" + ") + .append("value").append(lengthAccessor).append(");\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append("}\n"); + } + + private void generateSingleValueProperty( + final ClassBuilder classBuilder, + final String decoderClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + final String typeName = javaTypeName(typeToken.encoding().primitiveType()); + final String formattedPropertyName = formatPropertyName(propertyName); + final String fieldName = formatFieldName(propertyName); + final String validateMethod = "validate" + toUpperFirstChar(propertyName); + + final boolean representedWithinJavaType = typeToken.encoding().primitiveType() != PrimitiveType.UINT64; + + final StringBuilder validationCall = new StringBuilder(); + + if (representedWithinJavaType) + { + final StringBuilder validateBuilder = classBuilder.appendPrivate().append("\n") + .append(indent).append("private static void ").append(validateMethod).append("(") + .append(typeName).append(" value)\n") + .append(indent).append("{\n"); + + validateBuilder.append(indent).append(INDENT) + .append("if (value < ") + .append(decoderClassName).append(".").append(formattedPropertyName).append("MinValue() || ") + .append("value").append(" > ") + .append(decoderClassName).append(".").append(formattedPropertyName).append("MaxValue())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw new IllegalArgumentException(\"") + .append(propertyName) + .append(": value is out of allowed range: \" + ") + .append("value").append(");\n") + .append(indent).append(INDENT) + .append("}\n") + .append(indent).append("}\n"); + + validationCall.append(indent).append(INDENT).append(validateMethod).append("(value);\n"); + } + + classBuilder.appendField() + .append(indent).append("private ").append(typeName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(typeName).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public void ").append(formattedPropertyName).append("(") + .append(typeName).append(" value)\n") + .append(indent).append("{\n") + .append(validationCall) + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + } + + private void generateConstPropertyMethods( + final ClassBuilder classBuilder, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent) + { + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public static String ").append(toLowerFirstChar(propertyName)).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT) + .append("return \"").append(typeToken.encoding().constValue().toString()).append("\";\n") + .append(indent).append("}\n"); + } + else + { + final CharSequence literalValue = + generateLiteral(typeToken.encoding().primitiveType(), typeToken.encoding().constValue().toString()); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public static ") + .append(javaTypeName(typeToken.encoding().primitiveType())) + .append(" ").append(formatPropertyName(propertyName)).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(literalValue).append(";\n") + .append(indent).append("}\n"); + } + } + + private void generateVarData( + final ClassBuilder classBuilder, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token token = tokens.get(i); + if (token.signal() == Signal.BEGIN_VAR_DATA) + { + final String propertyName = token.name(); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + final String dtoType = characterEncoding == null ? "byte[]" : "String"; + + final String fieldName = formatFieldName(propertyName); + final String formattedPropertyName = formatPropertyName(propertyName); + + classBuilder.appendField() + .append(indent).append("private ").append(dtoType).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(indent).append("public ").append(dtoType).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic().append("\n") + .append(indent).append("public void ").append(formattedPropertyName) + .append("(").append(dtoType).append(" value)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + } + } + } + + private static String formatDtoClassName(final String name) + { + return formatClassName(name + "Dto"); + } + + private void generateDtosForTypes() throws IOException + { + for (final List tokens : ir.types()) + { + switch (tokens.get(0).signal()) + { + case BEGIN_COMPOSITE: + generateComposite(tokens); + break; + + case BEGIN_SET: + generateChoiceSet(tokens); + break; + + default: + break; + } + } + } + + private void generateComposite(final List tokens) throws IOException + { + final String name = tokens.get(0).applicableTypeName(); + final String className = formatDtoClassName(name); + final String encoderClassName = encoderName(name); + final String decoderClassName = decoderName(name); + + try (Writer out = outputManager.createOutput(className)) + { + final List compositeTokens = tokens.subList(1, tokens.size() - 1); + out.append(generateDtoFileHeader(ir.applicableNamespace())); + out.append("import org.agrona.DirectBuffer;\n"); + out.append("import org.agrona.MutableDirectBuffer;\n"); + out.append("import org.agrona.concurrent.UnsafeBuffer;\n\n"); + out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); + + final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT, "public final"); + + generateCompositePropertyElements(classBuilder, decoderClassName, compositeTokens, + BASE_INDENT + INDENT); + generateCompositeDecodeWith(classBuilder, className, decoderClassName, compositeTokens, + BASE_INDENT + INDENT); + generateCompositeEncodeWith(classBuilder, className, encoderClassName, compositeTokens, + BASE_INDENT + INDENT); + generateDisplay(classBuilder, encoderClassName, encoderClassName + ".ENCODED_LENGTH", + BASE_INDENT + INDENT); + + classBuilder.appendTo(out); + } + } + + private void generateChoiceSet(final List tokens) throws IOException + { + final String name = tokens.get(0).applicableTypeName(); + final String className = formatDtoClassName(name); + final String encoderClassName = encoderName(name); + final String decoderClassName = decoderName(name); + + try (Writer out = outputManager.createOutput(className)) + { + final List setTokens = tokens.subList(1, tokens.size() - 1); + out.append(generateDtoFileHeader(ir.applicableNamespace())); + out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); + + final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT, "public final"); + + generateChoices(classBuilder, className, setTokens, BASE_INDENT + INDENT); + generateChoiceSetDecodeWith(classBuilder, className, decoderClassName, setTokens, BASE_INDENT + INDENT); + generateChoiceSetEncodeWith(classBuilder, className, encoderClassName, setTokens, BASE_INDENT + INDENT); + + classBuilder.appendTo(out); + } + } + + private void generateChoiceSetEncodeWith( + final ClassBuilder classBuilder, + final String dtoClassName, + final String encoderClassName, + final List setTokens, + final String indent) + { + final StringBuilder encodeBuilder = classBuilder.appendPublic() + .append("\n") + .append(indent).append("public static void encodeWith(\n") + .append(indent).append(INDENT).append(encoderClassName).append(" encoder, ") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n"); + + encodeBuilder.append(indent).append(INDENT).append("encoder.clear();\n"); + + for (final Token token : setTokens) + { + if (token.signal() == Signal.CHOICE) + { + final String formattedPropertyName = formatPropertyName(token.name()); + encodeBuilder.append(indent).append(INDENT).append("encoder.").append(formattedPropertyName) + .append("(dto.").append(formattedPropertyName).append("());\n"); + } + } + + encodeBuilder.append(indent).append("}\n"); + } + + private void generateChoiceSetDecodeWith( + final ClassBuilder classBuilder, + final String dtoClassName, + final String decoderClassName, + final List setTokens, + final String indent) + { + final StringBuilder decodeBuilder = classBuilder.appendPublic() + .append("\n") + .append(indent).append("public static void decodeWith(\n") + .append(indent).append(INDENT).append(decoderClassName).append(" decoder, ") + .append(dtoClassName).append(" dto)\n") + .append(indent).append("{\n"); + + for (final Token token : setTokens) + { + if (token.signal() == Signal.CHOICE) + { + final String formattedPropertyName = formatPropertyName(token.name()); + decodeBuilder.append(indent).append(INDENT).append("dto.").append(formattedPropertyName) + .append("(decoder.").append(formattedPropertyName).append("());\n"); + } + } + + decodeBuilder.append(indent).append("}\n"); + } + + private void generateChoices( + final ClassBuilder classBuilder, + final String dtoClassName, + final List setTokens, + final String indent) + { + final List fields = new ArrayList<>(); + + for (final Token token : setTokens) + { + if (token.signal() == Signal.CHOICE) + { + final String fieldName = formatFieldName(token.name()); + final String formattedPropertyName = formatPropertyName(token.name()); + + fields.add(fieldName); + + classBuilder.appendField() + .append(indent).append("boolean ").append(fieldName).append(";\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append("public boolean ").append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + classBuilder.appendPublic() + .append("\n") + .append(indent).append(dtoClassName).append(" ") + .append(formattedPropertyName).append("(boolean value)\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("return this;\n") + .append(indent).append("}\n"); + } + } + + final StringBuilder clearBuilder = classBuilder.appendPublic() + .append(indent).append(dtoClassName).append(" clear()\n") + .append(indent).append("{\n"); + + for (final String field : fields) + { + clearBuilder.append(indent).append(INDENT).append(field).append(" = false;\n"); + } + + clearBuilder.append(indent).append(INDENT).append("return this;\n") + .append(indent).append("}\n"); + } + + private void generateCompositePropertyElements( + final ClassBuilder classBuilder, + final String decoderClassName, + final List tokens, + final String indent) + { + for (int i = 0; i < tokens.size(); ) + { + final Token token = tokens.get(i); + final String propertyName = formatPropertyName(token.name()); + + switch (token.signal()) + { + case ENCODING: + generatePrimitiveProperty(classBuilder, decoderClassName, propertyName, token, token, indent); + break; + + case BEGIN_ENUM: + generateEnumProperty(classBuilder, propertyName, token, token, indent); + break; + + case BEGIN_SET: + case BEGIN_COMPOSITE: + generateComplexProperty(classBuilder, propertyName, token, token, indent); + break; + + default: + break; + } + + i += tokens.get(i).componentTokenCount(); + } + } + + private static CharSequence generateDtoFileHeader(final String packageName) + { + final StringBuilder sb = new StringBuilder(); + + sb.append("/* Generated SBE (Simple Binary Encoding) message DTO */\n"); + sb.append("package ").append(packageName).append(";\n\n"); + + return sb; + } + + private static String generateDocumentation(final String indent, final Token token) + { + final String description = token.description(); + if (null == description || description.isEmpty()) + { + return ""; + } + + return + indent + "/**\n" + + indent + " * " + description + "\n" + + indent + " */\n"; + } + + private static String formatFieldName(final String propertyName) + { + return formatPropertyName(propertyName); + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java new file mode 100644 index 0000000000..45eeccff93 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java @@ -0,0 +1,35 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * Copyright (C) 2017 MarketFactory, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.TargetCodeGenerator; +import uk.co.real_logic.sbe.ir.Ir; + +/** + * {@link CodeGenerator} factory for Java DTOs. + */ +public class JavaDtos implements TargetCodeGenerator +{ + /** + * {@inheritDoc} + */ + public CodeGenerator newInstance(final Ir ir, final String outputDir) + { + return new JavaDtoGenerator(ir, new JavaOutputManager(outputDir, ir.applicableNamespace())); + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 1a5e17bb20..01cd0cf121 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -303,7 +303,7 @@ private void generateEncoder( if (shouldGenerateGroupOrderAnnotation) { - generateAnnotations(BASE_INDENT, className, groups, out, this::encoderName); + generateAnnotations(BASE_INDENT, className, groups, out, JavaUtil::encoderName); } out.append(generateDeclaration(className, implementsString, msgToken)); @@ -816,7 +816,7 @@ private void generateDecoder( if (shouldGenerateGroupOrderAnnotation) { - generateAnnotations(BASE_INDENT, className, groups, out, this::decoderName); + generateAnnotations(BASE_INDENT, className, groups, out, JavaUtil::decoderName); } out.append(generateDeclaration(className, implementsString, msgToken)); @@ -872,7 +872,7 @@ private void generateDecoderGroups( if (shouldGenerateGroupOrderAnnotation) { - generateAnnotations(indent + INDENT, groupName, groups, sb, this::decoderName); + generateAnnotations(indent + INDENT, groupName, groups, sb, JavaUtil::decoderName); } generateGroupDecoderClassHeader(sb, groupName, outerClassName, fieldPrecedenceModel, groupToken, tokens, groups, index, indent + INDENT); @@ -926,7 +926,7 @@ private void generateEncoderGroups( if (shouldGenerateGroupOrderAnnotation) { - generateAnnotations(indent + INDENT, groupClassName, groups, sb, this::encoderName); + generateAnnotations(indent + INDENT, groupClassName, groups, sb, JavaUtil::encoderName); } generateGroupEncoderClassHeader( sb, groupName, outerClassName, fieldPrecedenceModel, groupToken, @@ -4701,16 +4701,6 @@ private static String validateBufferImplementation( } } - private String encoderName(final String className) - { - return formatClassName(className) + "Encoder"; - } - - private String decoderName(final String className) - { - return formatClassName(className) + "Decoder"; - } - private String implementsInterface(final String interfaceName) { return shouldGenerateInterfaces ? " implements " + interfaceName : ""; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index 5bdc6e38b0..2431542d30 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -464,6 +464,16 @@ public static void generateGroupEncodePropertyJavadoc( .append(indent).append(" */"); } + static String encoderName(final String className) + { + return formatClassName(className) + "Encoder"; + } + + static String decoderName(final String className) + { + return formatClassName(className) + "Decoder"; + } + private static void escapeJavadoc(final Appendable out, final String doc) throws IOException { for (int i = 0, length = doc.length(); i < length; i++) @@ -511,4 +521,5 @@ private static void escapeJavadoc(final StringBuilder sb, final String doc) } } } + } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java new file mode 100644 index 0000000000..a28b0ac374 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java @@ -0,0 +1,154 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.generation.java; + +import extension.*; +import org.agrona.ExpandableArrayBuffer; +import org.agrona.MutableDirectBuffer; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class DtoTest +{ + @Test + void shouldRoundTripCar1() + { + final ExpandableArrayBuffer inputBuffer = new ExpandableArrayBuffer(); + encodeCar(inputBuffer, 0); + + final CarDecoder decoder = new CarDecoder(); + decoder.wrap(inputBuffer, 0, CarDecoder.BLOCK_LENGTH, CarDecoder.SCHEMA_VERSION); + final String decoderString = decoder.toString(); + + final CarDto dto = new CarDto(); + CarDto.decodeWith(decoder, dto); + + final ExpandableArrayBuffer outputBuffer = new ExpandableArrayBuffer(); + final CarEncoder encoder = new CarEncoder(); + encoder.wrap(outputBuffer, 0); + CarDto.encodeWith(encoder, dto); + + final String dtoString = dto.toString(); + + assertThat(outputBuffer.byteArray(), equalTo(inputBuffer.byteArray())); + assertThat(dtoString, equalTo(decoderString)); + } + + @Test + void shouldRoundTripCar2() + { + final ExpandableArrayBuffer inputBuffer = new ExpandableArrayBuffer(); + final int inputLength = encodeCar(inputBuffer, 0); + + final CarDto dto = + CarDto.decodeFrom(inputBuffer, 0, (short)CarDecoder.BLOCK_LENGTH, (short)CarDecoder.SCHEMA_VERSION); + + final ExpandableArrayBuffer outputBuffer = new ExpandableArrayBuffer(); + final int outputLength = CarDto.encodeWith(dto, outputBuffer, 0); + + assertThat(outputLength, equalTo(inputLength)); + assertThat(outputBuffer.byteArray(), equalTo(inputBuffer.byteArray())); + } + + private static int encodeCar(final MutableDirectBuffer buffer, final int offset) + { + final CarEncoder car = new CarEncoder(); + car.wrap(buffer, offset); + car.serialNumber(1234); + car.modelYear(2013); + car.available(BooleanType.T); + car.code(Model.A); + car.vehicleCode("ABCDEF"); + + for (int i = 0, size = CarEncoder.someNumbersLength(); i < size; i++) + { + car.someNumbers(i, i); + } + + car.extras().cruiseControl(true).sportsPack(true); + + car.cupHolderCount((short)119); + + car.engine().capacity(2000) + .numCylinders((short)4) + .manufacturerCode("ABC") + .efficiency((byte)35) + .boosterEnabled(BooleanType.T) + .booster().boostType(BoostType.NITROUS) + .horsePower((short)200); + + final CarEncoder.FuelFiguresEncoder fuelFigures = car.fuelFiguresCount(3); + fuelFigures.next() + .speed(30) + .mpg(35.9f) + .usageDescription("this is a description"); + + fuelFigures.next() + .speed(55) + .mpg(49.0f) + .usageDescription("this is a description"); + + fuelFigures.next() + .speed(75) + .mpg(40.0f) + .usageDescription("this is a description"); + + final CarEncoder.PerformanceFiguresEncoder perfFigures = car.performanceFiguresCount(2); + + perfFigures.next() + .octaneRating((short)95); + + CarEncoder.PerformanceFiguresEncoder.AccelerationEncoder acceleration = perfFigures.accelerationCount(3); + + acceleration.next() + .mph(30) + .seconds(4.0f); + + acceleration.next() + .mph(60) + .seconds(7.5f); + + acceleration.next() + .mph(100) + .seconds(12.2f); + + perfFigures.next() + .octaneRating((short)99); + + acceleration = perfFigures.accelerationCount(3); + + acceleration.next() + .mph(30) + .seconds(3.8f); + + acceleration.next() + .mph(60) + .seconds(7.1f); + + acceleration.next() + .mph(100) + .seconds(11.8f); + + car.manufacturer("Ford"); + car.model("Fiesta"); + car.activationCode("1234"); + + return car.limit(); + } +} diff --git a/sbe-tool/src/test/resources/example-extension-schema.xml b/sbe-tool/src/test/resources/example-extension-schema.xml new file mode 100644 index 0000000000..3770489b9f --- /dev/null +++ b/sbe-tool/src/test/resources/example-extension-schema.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T + S + N + K + + + + + + + 9000 + + Petrol + + + + + + 0 + 1 + + + A + B + C + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 41f4b0e27932ef5dfca502b52fe24ff5e86f4f08 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Tue, 14 May 2024 11:57:24 +0100 Subject: [PATCH 375/805] [Java] Extend property-based tests to exercise Java DTOs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The added test (non-exhaustively) checks the property: ``` ∀ msg ∈ MessageSchemas, ∀ encoding ∈ EncodingsOf(msg), encoding = dtoEncode(dtoDecode(encoding)) ``` The added test shows some compilation failures, which need to be resolved before enabling it. --- .../sbe/generation/java/JavaGenerator.java | 1 + .../sbe/properties/DtosPropertyTest.java | 112 +++++++++- .../utils/InMemoryOutputManager.java | 207 ++++++++++++++++++ 3 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 01cd0cf121..2d939309b9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -160,6 +160,7 @@ public JavaGenerator( { Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); + Verify.notNull(precedenceChecks, "precedenceChecks"); this.ir = ir; this.shouldSupportTypesPackageNames = shouldSupportTypesPackageNames; diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index f71e416309..fed7d4c94d 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -13,28 +13,42 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties; import net.jqwik.api.*; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; import uk.co.real_logic.sbe.generation.cpp.CppDtoGenerator; import uk.co.real_logic.sbe.generation.cpp.CppGenerator; import uk.co.real_logic.sbe.generation.cpp.NamespaceOutputManager; import uk.co.real_logic.sbe.generation.csharp.CSharpDtoGenerator; import uk.co.real_logic.sbe.generation.csharp.CSharpGenerator; import uk.co.real_logic.sbe.generation.csharp.CSharpNamespaceOutputManager; +import uk.co.real_logic.sbe.generation.java.JavaDtoGenerator; +import uk.co.real_logic.sbe.generation.java.JavaGenerator; +import uk.co.real_logic.sbe.ir.generated.MessageHeaderDecoder; import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; +import uk.co.real_logic.sbe.properties.utils.InMemoryOutputManager; +import org.agrona.DirectBuffer; +import org.agrona.ExpandableArrayBuffer; import org.agrona.IoUtil; +import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.UnsafeBuffer; import org.agrona.io.DirectBufferInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URLClassLoader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import static uk.co.real_logic.sbe.SbeTool.JAVA_DEFAULT_DECODING_BUFFER_TYPE; +import static uk.co.real_logic.sbe.SbeTool.JAVA_DEFAULT_ENCODING_BUFFER_TYPE; + @SuppressWarnings("ReadWriteStringCanBeUsed") public class DtosPropertyTest { @@ -44,6 +58,101 @@ public class DtosPropertyTest private static final String CPP_EXECUTABLE = System.getProperty("sbe.tests.cpp.executable", "g++"); private static final boolean KEEP_DIR_ON_FAILURE = Boolean.parseBoolean( System.getProperty("sbe.tests.keep.dir.on.failure", "true")); + private final ExpandableArrayBuffer outputBuffer = new ExpandableArrayBuffer(); + +// @Test +// void oneRun() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, +// IllegalAccessException +// { +// javaDtoEncodeShouldBeTheInverseOfDtoDecode(encodedMessage().sample()); +// } + + @Property + @Disabled + void javaDtoEncodeShouldBeTheInverseOfDtoDecode( + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage + ) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + IllegalAccessException + { + final String packageName = encodedMessage.ir().applicableNamespace(); + final InMemoryOutputManager outputManager = new InMemoryOutputManager(packageName); + + boolean success = false; + + try + { + try + { + new JavaGenerator( + encodedMessage.ir(), + JAVA_DEFAULT_ENCODING_BUFFER_TYPE, + JAVA_DEFAULT_DECODING_BUFFER_TYPE, + false, + false, + false, + false, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + outputManager) + .generate(); + + new JavaDtoGenerator(encodedMessage.ir(), outputManager) + .generate(); + } + catch (final Exception generationException) + { + throw new AssertionError( + "Code generation failed.\n\n" + + "SCHEMA:\n" + encodedMessage.schema(), + generationException); + } + + try (URLClassLoader generatedClassLoader = outputManager.compileGeneratedSources()) + { + final Class dtoClass = + generatedClassLoader.loadClass(packageName + ".TestMessageDto"); + + final Method decodeFrom = + dtoClass.getMethod("decodeFrom", DirectBuffer.class, int.class, short.class, short.class); + + final Method encodeWith = + dtoClass.getMethod("encodeWithHeaderWith", dtoClass, MutableDirectBuffer.class, int.class); + + final int inputLength = encodedMessage.length(); + final ExpandableArrayBuffer inputBuffer = encodedMessage.buffer(); + final MessageHeaderDecoder header = new MessageHeaderDecoder().wrap(inputBuffer, 0); + final short blockLength = (short)header.blockLength(); + final short actingVersion = (short)header.version(); + final Object dto = decodeFrom.invoke(null, + encodedMessage.buffer(), MessageHeaderDecoder.ENCODED_LENGTH, blockLength, actingVersion); + outputBuffer.setMemory(0, outputBuffer.capacity(), (byte)0); + final int outputLength = (int)encodeWith.invoke(null, dto, outputBuffer, 0); + if (!areEqual(inputBuffer, inputLength, outputBuffer, outputLength)) + { + throw new AssertionError( + "Input and output differ\n\n" + + "SCHEMA:\n" + encodedMessage.schema()); + } + + success = true; + } + } + finally + { + if (!success) + { + outputManager.dumpSources(); + } + } + } + + private boolean areEqual( + final ExpandableArrayBuffer inputBuffer, + final int inputLength, + final ExpandableArrayBuffer outputBuffer, + final int outputLength) + { + return new UnsafeBuffer(inputBuffer, 0, inputLength).equals(new UnsafeBuffer(outputBuffer, 0, outputLength)); + } @Property void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( @@ -274,4 +383,5 @@ private static void copyResourceToFile( throw new RuntimeException(e); } } + } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java new file mode 100644 index 0000000000..a34669593e --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java @@ -0,0 +1,207 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties.utils; + +import org.agrona.generation.DynamicPackageOutputManager; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; +import javax.tools.*; + +/** + * An implementation of {@link DynamicPackageOutputManager} that stores generated source code in memory and compiles it + * on demand. + */ +public class InMemoryOutputManager implements DynamicPackageOutputManager +{ + private final String packageName; + private final Map sourceFiles = new HashMap<>(); + private String packageNameOverride; + + public InMemoryOutputManager(final String packageName) + { + this.packageName = packageName; + } + + @Override + public Writer createOutput(final String name) + { + return new InMemoryWriter(name); + } + + @Override + public void setPackageName(final String packageName) + { + packageNameOverride = packageName; + } + + /** + * Compile the generated sources and return a {@link URLClassLoader} that can be used to load the generated classes. + * + * @return a {@link URLClassLoader} that can be used to load the generated classes + */ + public URLClassLoader compileGeneratedSources() + { + final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + final StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null); + final InMemoryFileManager fileManager = new InMemoryFileManager(standardFileManager); + final JavaCompiler.CompilationTask task = compiler.getTask( + null, + fileManager, + null, + null, + null, + sourceFiles.values() + ); + + if (!task.call()) + { + throw new IllegalStateException("Compilation failed"); + } + + final GeneratedCodeLoader classLoader = new GeneratedCodeLoader(getClass().getClassLoader()); + classLoader.defineClasses(fileManager); + return classLoader; + } + + public void dumpSources() + { + sourceFiles.forEach((qualifiedName, file) -> + { + System.out.println( + System.lineSeparator() + "Source file: " + qualifiedName + + System.lineSeparator() + file.sourceCode + + System.lineSeparator()); + }); + } + + class InMemoryWriter extends StringWriter + { + private final String name; + + InMemoryWriter(final String name) + { + this.name = name; + } + + @Override + public void close() throws IOException + { + super.close(); + final String actingPackageName = packageNameOverride == null ? packageName : packageNameOverride; + packageNameOverride = null; + + final String qualifiedName = actingPackageName + "." + name; + final InMemoryJavaFileObject sourceFile = + new InMemoryJavaFileObject(qualifiedName, getBuffer().toString()); + + final InMemoryJavaFileObject existingFile = sourceFiles.putIfAbsent(qualifiedName, sourceFile); + + if (existingFile != null && !Objects.equals(existingFile.sourceCode, sourceFile.sourceCode)) + { + throw new IllegalStateException("Duplicate (but different) class: " + qualifiedName); + } + } + } + + static class InMemoryFileManager extends ForwardingJavaFileManager + { + private final List outputFiles = new ArrayList<>(); + + InMemoryFileManager(final StandardJavaFileManager fileManager) + { + super(fileManager); + } + + @Override + public JavaFileObject getJavaFileForOutput( + final Location location, + final String className, + final JavaFileObject.Kind kind, + final FileObject sibling) + { + final InMemoryJavaFileObject outputFile = new InMemoryJavaFileObject(className, kind); + outputFiles.add(outputFile); + return outputFile; + } + + public Collection outputFiles() + { + return outputFiles; + } + } + + static class InMemoryJavaFileObject extends SimpleJavaFileObject + { + private final String sourceCode; + private final ByteArrayOutputStream outputStream; + + InMemoryJavaFileObject(final String className, final String sourceCode) + { + super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.sourceCode = sourceCode; + this.outputStream = new ByteArrayOutputStream(); + } + + InMemoryJavaFileObject(final String className, final Kind kind) + { + super(URI.create("mem:///" + className.replace('.', '/') + kind.extension), kind); + this.sourceCode = null; + this.outputStream = new ByteArrayOutputStream(); + } + + @Override + public CharSequence getCharContent(final boolean ignoreEncodingErrors) + { + return sourceCode; + } + + @Override + public ByteArrayOutputStream openOutputStream() + { + return outputStream; + } + + public byte[] getClassBytes() + { + return outputStream.toByteArray(); + } + } + + static class GeneratedCodeLoader extends URLClassLoader + { + GeneratedCodeLoader(final ClassLoader parent) + { + super(new URL[0], parent); + } + + void defineClasses(final InMemoryFileManager fileManager) + { + fileManager.outputFiles().forEach(file -> + { + final byte[] classBytes = file.getClassBytes(); + super.defineClass(file.getName(), classBytes, 0, classBytes.length); + }); + } + } +} From 75df4629c72ea06c1fd73d420709fa3868183f44 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 15 May 2024 11:45:10 +0100 Subject: [PATCH 376/805] [Java] Avoid checking parentMessage.actingVersion inside composite. Most not present conditions were already elided via `generateFieldNotPresentCondition(inComposite=true, ...)` but the condition within the wrap method was not. Here's an example of a failing schema found with the DTO property-based tests: ``` ``` And generated code (within a composite without a `parentMessage`): ``` public void wrapMember0OfType0(final DirectBuffer wrapBuffer) { if (parentMessage.actingVersion < 1) { wrapBuffer.wrap(buffer, offset, 0); return; } wrapBuffer.wrap(buffer, offset + 0, 2); } ``` --- .../real_logic/sbe/generation/java/JavaGenerator.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 2d939309b9..0a47fbfe56 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1665,7 +1665,7 @@ private void generateVarDataWrapDecoder( indent + " }\n", propertyName, readOnlyBuffer, - generateWrapFieldNotPresentCondition(token.version(), indent), + generateWrapFieldNotPresentCondition(false, token.version(), indent), accessOrderListenerCall, sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", @@ -2671,9 +2671,12 @@ private CharSequence generatePrimitivePropertyEncode( generatePut(encoding.primitiveType(), "offset + " + offset, "value", byteOrderStr)); } - private CharSequence generateWrapFieldNotPresentCondition(final int sinceVersion, final String indent) + private CharSequence generateWrapFieldNotPresentCondition( + final boolean inComposite, + final int sinceVersion, + final String indent) { - if (0 == sinceVersion) + if (inComposite || 0 == sinceVersion) { return ""; } @@ -2925,7 +2928,7 @@ else if (encoding.primitiveType() == PrimitiveType.UINT8) indent + " }\n", Generators.toUpperFirstChar(propertyName), readOnlyBuffer, - generateWrapFieldNotPresentCondition(propertyToken.version(), indent), + generateWrapFieldNotPresentCondition(inComposite, propertyToken.version(), indent), accessOrderListenerCall, offset, fieldLength); From 60bd11986c5b6186c5a9e6c5bb122ec2676b424c Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 15 May 2024 11:54:55 +0100 Subject: [PATCH 377/805] [Java] Fix remaining DTO issues uncovered with PBT. The main issue was around determining when a field might not be present. We were checking `token.version() > 0`, which isn't accurate in composites or groups. In this commit, I've also started to use the `Footnotes` API in JQWIK, which allows useful debug information to be captured _only_ for failing attempts. It then prints out the shrunken footnotes upon a failure. --- .../sbe/generation/java/JavaDtoGenerator.java | 131 ++++++++------ .../sbe/generation/java/JavaGenerator.java | 4 + .../sbe/properties/DtosPropertyTest.java | 161 ++++++++++-------- .../utils/InMemoryOutputManager.java | 14 +- .../resources/example-extension-schema.xml | 4 +- 5 files changed, 184 insertions(+), 130 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index b5fd05e665..0056ba4703 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -30,6 +30,7 @@ import java.io.Writer; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; @@ -43,6 +44,7 @@ */ public class JavaDtoGenerator implements CodeGenerator { + private static final Predicate ALWAYS_FALSE_PREDICATE = ignored -> false; private static final String INDENT = " "; private static final String BASE_INDENT = ""; @@ -97,7 +99,7 @@ public void generate() throws IOException generateVarData(classBuilder, varData, BASE_INDENT + INDENT); generateDecodeWith(classBuilder, dtoClassName, decoderClassName, fields, - groups, varData, BASE_INDENT + INDENT); + groups, varData, BASE_INDENT + INDENT, fieldToken -> fieldToken.version() > msgToken.version()); generateDecodeFrom(classBuilder, dtoClassName, decoderClassName, BASE_INDENT + INDENT); generateEncodeWith(classBuilder, dtoClassName, encoderClassName, fields, groups, varData, BASE_INDENT + INDENT); @@ -196,6 +198,13 @@ private void generateGroups( final String groupClassName = formatDtoClassName(groupName); final String qualifiedDtoClassName = qualifiedParentDtoClassName + "." + groupClassName; + final Token dimToken = tokens.get(i + 1); + if (dimToken.signal() != Signal.BEGIN_COMPOSITE) + { + throw new IllegalStateException("groups must start with BEGIN_COMPOSITE: token=" + dimToken); + } + final int sinceVersion = dimToken.version(); + final String fieldName = formatFieldName(groupName); final String formattedPropertyName = formatPropertyName(groupName); @@ -226,10 +235,22 @@ private void generateGroups( i = collectVarData(tokens, i, varData); generateVarData(groupClassBuilder, varData, indent + INDENT); + final Predicate wasAddedAfterGroup = token -> + { + final boolean addedAfterParent = token.version() > sinceVersion; + + if (addedAfterParent && token.signal() == Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("Cannot extend var data inside a group."); + } + + return addedAfterParent; + }; + generateDecodeListWith( groupClassBuilder, groupClassName, qualifiedDecoderClassName, indent + INDENT); generateDecodeWith(groupClassBuilder, groupClassName, qualifiedDecoderClassName, - fields, groups, varData, indent + INDENT); + fields, groups, varData, indent + INDENT, wasAddedAfterGroup); generateEncodeWith( groupClassBuilder, groupClassName, qualifiedEncoderClassName, fields, groups, varData, indent + INDENT); generateComputeEncodedLength(groupClassBuilder, qualifiedDecoderClassName, @@ -324,8 +345,10 @@ private void generateComputeEncodedLength( .append(qualifiedDecoderClassName).append(".") .append(formatPropertyName(propertyName)).append("HeaderLength();\n"); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + final String lengthAccessor = characterEncoding == null ? ".length" : ".length()"; lengthBuilder.append(indent).append(INDENT).append("encodedLength += ") - .append(fieldName).append(".length()"); + .append(fieldName).append(lengthAccessor); final int elementByteLength = varDataToken.encoding().primitiveType().size(); if (elementByteLength != 1) @@ -358,7 +381,7 @@ private void generateCompositeDecodeWith( final Token token = tokens.get(i); generateFieldDecodeWith( - decodeBuilder, token, token, decoderClassName, indent + INDENT); + decodeBuilder, token, token, decoderClassName, indent + INDENT, ALWAYS_FALSE_PREDICATE); i += tokens.get(i).componentTokenCount(); } @@ -426,16 +449,17 @@ private void generateDecodeWith( final List fields, final List groups, final List varData, - final String indent) + final String indent, + final Predicate wasAddedAfterParent) { final StringBuilder decodeBuilder = classBuilder.appendPublic().append("\n") .append(indent).append("public static void decodeWith(").append(decoderClassName).append(" decoder, ") .append(dtoClassName).append(" dto)\n") .append(indent).append("{\n"); - generateMessageFieldsDecodeWith(decodeBuilder, fields, decoderClassName, indent + INDENT); + generateMessageFieldsDecodeWith(decodeBuilder, fields, decoderClassName, indent + INDENT, wasAddedAfterParent); generateGroupsDecodeWith(decodeBuilder, groups, indent + INDENT); - generateVarDataDecodeWith(decodeBuilder, varData, indent + INDENT); + generateVarDataDecodeWith(decodeBuilder, decoderClassName, varData, indent + INDENT, wasAddedAfterParent); decodeBuilder.append(indent).append("}\n"); } @@ -466,7 +490,8 @@ private void generateMessageFieldsDecodeWith( final StringBuilder sb, final List tokens, final String decoderClassName, - final String indent) + final String indent, + final Predicate wasAddedAfterParent) { for (int i = 0, size = tokens.size(); i < size; i++) { @@ -475,7 +500,7 @@ private void generateMessageFieldsDecodeWith( { final Token encodingToken = tokens.get(i + 1); - generateFieldDecodeWith(sb, signalToken, encodingToken, decoderClassName, indent); + generateFieldDecodeWith(sb, signalToken, encodingToken, decoderClassName, indent, wasAddedAfterParent); } } } @@ -485,17 +510,18 @@ private void generateFieldDecodeWith( final Token fieldToken, final Token typeToken, final String decoderClassName, - final String indent) + final String indent, + final Predicate wasAddedAfterParent) { switch (typeToken.signal()) { case ENCODING: - generatePrimitiveDecodeWith(sb, fieldToken, typeToken, decoderClassName, indent); + generatePrimitiveDecodeWith(sb, fieldToken, typeToken, decoderClassName, indent, wasAddedAfterParent); break; case BEGIN_SET: final String bitSetName = formatDtoClassName(typeToken.applicableTypeName()); - generateBitSetDecodeWith(sb, fieldToken, bitSetName, indent); + generateBitSetDecodeWith(sb, decoderClassName, fieldToken, bitSetName, indent, wasAddedAfterParent); break; case BEGIN_ENUM: @@ -516,7 +542,8 @@ private void generatePrimitiveDecodeWith( final Token fieldToken, final Token typeToken, final String decoderClassName, - final String indent) + final String indent, + final Predicate wasAddedAfterParent) { if (typeToken.isConstantEncoding()) { @@ -543,12 +570,13 @@ private void generatePrimitiveDecodeWith( indent, "decoder.actingVersion() >= " + decoderClassName + "." + formattedPropertyName + "SinceVersion()", "decoder." + formattedPropertyName + "()", - decoderNullValue + decoderNullValue, + wasAddedAfterParent ); } else if (arrayLength > 1) { - generateArrayDecodeWith(sb, decoderClassName, fieldToken, typeToken, indent); + generateArrayDecodeWith(sb, decoderClassName, fieldToken, typeToken, indent, wasAddedAfterParent); } } @@ -557,7 +585,8 @@ private void generateArrayDecodeWith( final String decoderClassName, final Token fieldToken, final Token typeToken, - final String indent) + final String indent, + final Predicate wasAddedAfterParent) { if (fieldToken.isConstantEncoding()) { @@ -566,8 +595,9 @@ private void generateArrayDecodeWith( final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); + final PrimitiveType primitiveType = typeToken.encoding().primitiveType(); - if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + if (primitiveType == PrimitiveType.CHAR) { generateRecordPropertyAssignment( sb, @@ -575,13 +605,14 @@ private void generateArrayDecodeWith( indent, "decoder.actingVersion() >= " + decoderClassName + "." + formattedPropertyName + "SinceVersion()", "decoder." + formattedPropertyName + "()", - "\"\"" + "\"\"", + wasAddedAfterParent ); } else { final StringBuilder initializerList = new StringBuilder(); - final String elementType = javaTypeName(typeToken.encoding().primitiveType()); + final String elementType = javaTypeName(primitiveType); initializerList.append("new ").append(elementType).append("[] { "); final int arrayLength = typeToken.arrayLength(); for (int i = 0; i < arrayLength; i++) @@ -598,16 +629,19 @@ private void generateArrayDecodeWith( indent, "decoder.actingVersion() >= " + decoderClassName + "." + formattedPropertyName + "SinceVersion()", initializerList, - null + "new " + elementType + "[0]", + wasAddedAfterParent ); } } private void generateBitSetDecodeWith( final StringBuilder sb, + final String decoderClassName, final Token fieldToken, final String dtoTypeName, - final String indent) + final String indent, + final Predicate wasAddedAfterParent) { if (fieldToken.isConstantEncoding()) { @@ -617,11 +651,11 @@ private void generateBitSetDecodeWith( final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); - if (fieldToken.isOptionalEncoding()) + if (wasAddedAfterParent.test(fieldToken)) { - sb.append(indent).append("if (decoder.").append(formattedPropertyName).append("InActingVersion()"); - - sb.append(")\n") + sb.append(indent).append("if (decoder.actingVersion() >= ") + .append(decoderClassName).append(".") + .append(formattedPropertyName).append("SinceVersion())\n") .append(indent).append("{\n"); sb.append(indent).append(INDENT).append(dtoTypeName).append(".decodeWith(decoder.") @@ -710,8 +744,10 @@ private void generateGroupsDecodeWith( private void generateVarDataDecodeWith( final StringBuilder sb, + final String decoderClassName, final List tokens, - final String indent) + final String indent, + final Predicate wasAddedAfterParent) { for (int i = 0; i < tokens.size(); i++) { @@ -723,7 +759,7 @@ private void generateVarDataDecodeWith( final Token varDataToken = Generators.findFirst("varData", tokens, i); final String characterEncoding = varDataToken.encoding().characterEncoding(); - final boolean isOptional = token.version() > 0; + final boolean isOptional = wasAddedAfterParent.test(token); final String blockIndent = isOptional ? indent + INDENT : indent; final String dataVar = toLowerFirstChar(propertyName) + "Data"; @@ -734,7 +770,7 @@ private void generateVarDataDecodeWith( { decoderValueExtraction.append(blockIndent).append("byte[] ").append(dataVar) .append(" = new byte[decoder.").append(formattedPropertyName).append("Length()];\n") - .append(blockIndent).append("decoder.get").append(formattedPropertyName) + .append(blockIndent).append("decoder.get").append(toUpperFirstChar(formattedPropertyName)) .append("(").append(dataVar).append(", 0, decoder.").append(formattedPropertyName) .append("Length());\n"); } @@ -746,9 +782,9 @@ private void generateVarDataDecodeWith( if (isOptional) { - sb.append(indent).append("if (decoder.").append(formattedPropertyName).append("InActingVersion()"); - - sb.append(")\n") + sb.append(indent).append("if (decoder.actingVersion() >= ") + .append(decoderClassName).append(".") + .append(formattedPropertyName).append("SinceVersion())\n") .append(indent).append("{\n"); sb.append(decoderValueExtraction); @@ -756,7 +792,7 @@ private void generateVarDataDecodeWith( sb.append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(") .append(dataVar).append(");\n"); - final String nullDtoValue = "\"\""; + final String nullDtoValue = characterEncoding == null ? "new byte[0]" : "\"\""; sb.append(indent).append("}\n") .append(indent).append("else\n") @@ -782,27 +818,25 @@ private void generateRecordPropertyAssignment( final String indent, final String presenceExpression, final CharSequence getExpression, - final String nullDecoderValueOrNull) + final String nullDecoderValue, + final Predicate wasAddedAfterParent) { final String propertyName = token.name(); final String formattedPropertyName = formatPropertyName(propertyName); - if (token.isOptionalEncoding()) + if (wasAddedAfterParent.test(token)) { - sb.append(indent).append("if (").append(presenceExpression).append(")\n") .append(indent).append("{\n"); sb.append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(") .append(getExpression).append(");\n"); - final String nullValue = nullDecoderValueOrNull == null ? "null" : nullDecoderValueOrNull; - sb.append(indent).append("}\n") .append(indent).append("else\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("dto.").append(formattedPropertyName).append("(") - .append(nullValue).append(");\n") + .append(nullDecoderValue).append(");\n") .append(indent).append("}\n"); } else @@ -966,19 +1000,16 @@ private void generateArrayEncodeWith( final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); - if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + final PrimitiveType primitiveType = typeToken.encoding().primitiveType(); + + if (primitiveType == PrimitiveType.CHAR) { sb.append(indent).append("encoder.").append(toLowerFirstChar(propertyName)).append("(") .append("dto.").append(formattedPropertyName).append("());\n"); } - else if (typeToken.encoding().primitiveType() == PrimitiveType.UINT8) - { - sb.append(indent).append("encoder.put").append(toUpperFirstChar(propertyName)).append("(") - .append("dto.").append(formattedPropertyName).append("());\n"); - } else { - final String javaTypeName = javaTypeName(typeToken.encoding().primitiveType()); + final String javaTypeName = javaTypeName(primitiveType); sb.append(indent).append(javaTypeName).append("[] ").append(formattedPropertyName).append(" = ") .append("dto.").append(formattedPropertyName).append("();\n") .append(indent).append("for (int i = 0; i < ").append(formattedPropertyName).append(".length; i++)\n") @@ -1103,7 +1134,9 @@ private void generateVarDataEncodeWith( if (characterEncoding == null) { sb.append(indent).append("encoder.put").append(toUpperFirstChar(propertyName)).append("(") - .append("dto.").append(formattedPropertyName).append("());\n"); + .append("dto.").append(formattedPropertyName).append("(),") + .append("0,") + .append("dto.").append(formattedPropertyName).append("().length);\n"); } else { @@ -1310,7 +1343,9 @@ private void generateArrayProperty( final String fieldName = formatFieldName(propertyName); final String validateMethod = "validate" + toUpperFirstChar(propertyName); - if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + final PrimitiveType primitiveType = typeToken.encoding().primitiveType(); + + if (primitiveType == PrimitiveType.CHAR) { final CharSequence typeName = "String"; @@ -1345,7 +1380,7 @@ private void generateArrayProperty( } else { - final String elementTypeName = javaTypeName(typeToken.encoding().primitiveType()); + final String elementTypeName = javaTypeName(primitiveType); final String typeName = elementTypeName + "[]"; classBuilder.appendField() diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 0a47fbfe56..7d0d4ba97b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1034,6 +1034,10 @@ private void generateGroupDecoderClassHeader( .append(indent).append(" {\n") .append(indent).append(" return blockLength;\n") .append(indent).append(" }\n\n") + .append(indent).append(" public int actingVersion()\n") + .append(indent).append(" {\n") + .append(indent).append(" return parentMessage.actingVersion;\n") + .append(indent).append(" }\n\n") .append(indent).append(" public int count()\n") .append(indent).append(" {\n") .append(indent).append(" return count;\n") diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index fed7d4c94d..b21ba27674 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -16,6 +16,8 @@ package uk.co.real_logic.sbe.properties; import net.jqwik.api.*; +import net.jqwik.api.footnotes.EnableFootnotes; +import net.jqwik.api.footnotes.Footnotes; import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; import uk.co.real_logic.sbe.generation.cpp.CppDtoGenerator; import uk.co.real_logic.sbe.generation.cpp.CppGenerator; @@ -28,10 +30,7 @@ import uk.co.real_logic.sbe.ir.generated.MessageHeaderDecoder; import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; import uk.co.real_logic.sbe.properties.utils.InMemoryOutputManager; -import org.agrona.DirectBuffer; -import org.agrona.ExpandableArrayBuffer; -import org.agrona.IoUtil; -import org.agrona.MutableDirectBuffer; +import org.agrona.*; import org.agrona.concurrent.UnsafeBuffer; import org.agrona.io.DirectBufferInputStream; @@ -45,40 +44,33 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.Base64; +import java.util.stream.Stream; +import static org.junit.jupiter.api.Assertions.fail; import static uk.co.real_logic.sbe.SbeTool.JAVA_DEFAULT_DECODING_BUFFER_TYPE; import static uk.co.real_logic.sbe.SbeTool.JAVA_DEFAULT_ENCODING_BUFFER_TYPE; @SuppressWarnings("ReadWriteStringCanBeUsed") +@EnableFootnotes public class DtosPropertyTest { private static final String DOTNET_EXECUTABLE = System.getProperty("sbe.tests.dotnet.executable", "dotnet"); private static final String SBE_DLL = System.getProperty("sbe.dll", "csharp/sbe-dll/bin/Release/netstandard2.0/SBE.dll"); private static final String CPP_EXECUTABLE = System.getProperty("sbe.tests.cpp.executable", "g++"); - private static final boolean KEEP_DIR_ON_FAILURE = Boolean.parseBoolean( - System.getProperty("sbe.tests.keep.dir.on.failure", "true")); private final ExpandableArrayBuffer outputBuffer = new ExpandableArrayBuffer(); -// @Test -// void oneRun() throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, -// IllegalAccessException -// { -// javaDtoEncodeShouldBeTheInverseOfDtoDecode(encodedMessage().sample()); -// } - @Property - @Disabled void javaDtoEncodeShouldBeTheInverseOfDtoDecode( - @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage, + final Footnotes footnotes ) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { final String packageName = encodedMessage.ir().applicableNamespace(); final InMemoryOutputManager outputManager = new InMemoryOutputManager(packageName); - boolean success = false; - try { try @@ -100,10 +92,7 @@ void javaDtoEncodeShouldBeTheInverseOfDtoDecode( } catch (final Exception generationException) { - throw new AssertionError( - "Code generation failed.\n\n" + - "SCHEMA:\n" + encodedMessage.schema(), - generationException); + fail("Code generation failed.", generationException); } try (URLClassLoader generatedClassLoader = outputManager.compileGeneratedSources()) @@ -128,39 +117,29 @@ void javaDtoEncodeShouldBeTheInverseOfDtoDecode( final int outputLength = (int)encodeWith.invoke(null, dto, outputBuffer, 0); if (!areEqual(inputBuffer, inputLength, outputBuffer, outputLength)) { - throw new AssertionError( - "Input and output differ\n\n" + - "SCHEMA:\n" + encodedMessage.schema()); + fail("Input and output differ"); } - - success = true; } } - finally + catch (final Throwable throwable) { - if (!success) - { - outputManager.dumpSources(); - } - } - } + addInputFootnotes(footnotes, encodedMessage); - private boolean areEqual( - final ExpandableArrayBuffer inputBuffer, - final int inputLength, - final ExpandableArrayBuffer outputBuffer, - final int outputLength) - { - return new UnsafeBuffer(inputBuffer, 0, inputLength).equals(new UnsafeBuffer(outputBuffer, 0, outputLength)); + final StringBuilder generatedSources = new StringBuilder(); + outputManager.dumpSources(generatedSources); + footnotes.addFootnote(generatedSources.toString()); + + throw throwable; + } } @Property void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( - @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage, + final Footnotes footnotes ) throws IOException, InterruptedException { final Path tempDir = Files.createTempDirectory("sbe-csharp-dto-test"); - boolean success = false; try { @@ -205,34 +184,27 @@ void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( "DIR:" + tempDir + "\n\n" + "SCHEMA:\n" + encodedMessage.schema()); } - success = true; } - finally + catch (final Throwable throwable) { - if (!KEEP_DIR_ON_FAILURE || success) - { - IoUtil.delete(tempDir.toFile(), true); - } - else - { - Files.write( - tempDir.resolve("schema.xml"), - encodedMessage.schema().getBytes(StandardCharsets.UTF_8)); + addInputFootnotes(footnotes, encodedMessage); + addGeneratedSourcesFootnotes(footnotes, tempDir, ".cs"); - Files.write( - tempDir.resolve("encoding.log"), - encodedMessage.encodingLog().getBytes(StandardCharsets.UTF_8)); - } + throw throwable; + } + finally + { + IoUtil.delete(tempDir.toFile(), true); } } @Property(shrinking = ShrinkingMode.OFF) void cppDtoEncodeShouldBeTheInverseOfDtoDecode( - @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage, + final Footnotes footnotes ) throws IOException, InterruptedException { final Path tempDir = Files.createTempDirectory("sbe-cpp-dto-test"); - boolean success = false; try { @@ -274,24 +246,17 @@ void cppDtoEncodeShouldBeTheInverseOfDtoDecode( "Input and output files differ\n\n" + "SCHEMA:\n" + encodedMessage.schema()); } - success = true; } - finally + catch (final Throwable throwable) { - if (!KEEP_DIR_ON_FAILURE || success) - { - IoUtil.delete(tempDir.toFile(), true); - } - else - { - Files.write( - tempDir.resolve("schema.xml"), - encodedMessage.schema().getBytes(StandardCharsets.UTF_8)); + addInputFootnotes(footnotes, encodedMessage); + addGeneratedSourcesFootnotes(footnotes, tempDir, ".cpp"); - Files.write( - tempDir.resolve("encoding.log"), - encodedMessage.encodingLog().getBytes(StandardCharsets.UTF_8)); - } + throw throwable; + } + finally + { + IoUtil.delete(tempDir.toFile(), true); } } @@ -384,4 +349,52 @@ private static void copyResourceToFile( } } + private boolean areEqual( + final ExpandableArrayBuffer inputBuffer, + final int inputLength, + final ExpandableArrayBuffer outputBuffer, + final int outputLength) + { + return new UnsafeBuffer(inputBuffer, 0, inputLength).equals(new UnsafeBuffer(outputBuffer, 0, outputLength)); + } + + private void addGeneratedSourcesFootnotes( + final Footnotes footnotes, + final Path directory, + final String suffix) + { + try (Stream contents = Files.walk(directory)) + { + contents + .filter(path -> path.toString().endsWith(suffix)) + .forEach(path -> + { + try + { + footnotes.addFootnote(System.lineSeparator() + "File: " + path + + System.lineSeparator() + + new String(Files.readAllBytes(path), StandardCharsets.UTF_8)); + } + catch (final IOException exn) + { + LangUtil.rethrowUnchecked(exn); + } + }); + } + catch (final IOException exn) + { + LangUtil.rethrowUnchecked(exn); + } + } + + public void addInputFootnotes(final Footnotes footnotes, final SbeArbitraries.EncodedMessage encodedMessage) + { + final byte[] messageBytes = new byte[encodedMessage.length()]; + encodedMessage.buffer().getBytes(0, messageBytes); + final byte[] base64EncodedMessageBytes = Base64.getEncoder().encode(messageBytes); + + footnotes.addFootnote("Schema:" + System.lineSeparator() + encodedMessage.schema()); + footnotes.addFootnote("Input Message:" + System.lineSeparator() + + new String(base64EncodedMessageBytes, StandardCharsets.UTF_8)); + } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java index a34669593e..a17f74914e 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java @@ -84,14 +84,16 @@ public URLClassLoader compileGeneratedSources() return classLoader; } - public void dumpSources() + public void dumpSources(final StringBuilder builder) { + builder.append(System.lineSeparator()).append("Generated sources file count: ").append(sourceFiles.size()) + .append(System.lineSeparator()); + sourceFiles.forEach((qualifiedName, file) -> { - System.out.println( - System.lineSeparator() + "Source file: " + qualifiedName + - System.lineSeparator() + file.sourceCode + - System.lineSeparator()); + builder.append(System.lineSeparator()).append("Source file: ").append(qualifiedName) + .append(System.lineSeparator()).append(file.sourceCode) + .append(System.lineSeparator()); }); } @@ -200,7 +202,7 @@ void defineClasses(final InMemoryFileManager fileManager) fileManager.outputFiles().forEach(file -> { final byte[] classBytes = file.getClassBytes(); - super.defineClass(file.getName(), classBytes, 0, classBytes.length); + super.defineClass(null, classBytes, 0, classBytes.length); }); } } diff --git a/sbe-tool/src/test/resources/example-extension-schema.xml b/sbe-tool/src/test/resources/example-extension-schema.xml index 3770489b9f..ab89ba12cc 100644 --- a/sbe-tool/src/test/resources/example-extension-schema.xml +++ b/sbe-tool/src/test/resources/example-extension-schema.xml @@ -2,7 +2,7 @@ @@ -86,7 +86,7 @@ - + From 6e0234b0c9dbd1d585407530c6b453a89fd72ea8 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 15 May 2024 12:02:41 +0100 Subject: [PATCH 378/805] [Java] Tidy up spacing. --- .../co/real_logic/sbe/generation/java/JavaDtoGenerator.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index 0056ba4703..4b8ceb876d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -165,11 +165,8 @@ public void appendTo(final Appendable out) out.append(indent).append(modifiers).append("class ").append(className).append("\n") .append(indent).append("{\n") .append(fieldSb) - .append("\n") .append(privateSb) - .append("\n") .append(publicSb) - .append("\n") .append(indent).append("}\n"); } catch (final IOException exception) @@ -420,7 +417,7 @@ private void generateDecodeListWith( final String indent) { classBuilder.appendPublic().append("\n") - .append(indent).append("static List<").append(dtoClassName).append("> decodeManyWith(") + .append(indent).append("public static List<").append(dtoClassName).append("> decodeManyWith(") .append(decoderClassName).append(" decoder)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("List<").append(dtoClassName) From d93b3370221644866600f0364dcd555695c693a4 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Tue, 25 Jun 2024 17:47:48 +0100 Subject: [PATCH 379/805] [C++, C#] Avoid unnecessary validation code. Previously, regardless of whether the min and max values were the min and max values for the host language representation of an SBE type, we would generate a range check. Now, we do not generate the check unless it is meaningful. Also, adjust the property-based test dotnet version to bring inline with other tests. --- .../sbe/generation/cpp/CppDtoGenerator.java | 87 +++++++++++++++---- .../generation/csharp/CSharpDtoGenerator.java | 42 ++++++--- .../SbePropertyTest.csproj | 2 +- 3 files changed, 101 insertions(+), 30 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 168f6df665..39b59412e5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -20,6 +20,7 @@ import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.generation.CodeGenerator; import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Encoding; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.ir.Signal; import uk.co.real_logic.sbe.ir.Token; @@ -1489,7 +1490,8 @@ private void generateSingleValueProperty( final Token typeToken, final String indent) { - final String elementTypeName = cppTypeName(typeToken.encoding().primitiveType()); + final Encoding encoding = typeToken.encoding(); + final String elementTypeName = cppTypeName(encoding.primitiveType()); final CharSequence typeName = typeWithFieldOptionality( fieldToken, elementTypeName @@ -1518,6 +1520,31 @@ private void generateSingleValueProperty( .append(indent).append(INDENT).append(fieldName).append(" = value;\n") .append(indent).append("}\n"); + generateSingleValuePropertyValidateMethod( + classBuilder, + codecClassName, + propertyName, + fieldToken, + indent, + validateMethod, + typeName, + formattedPropertyName, + elementTypeName, + encoding); + } + + private static void generateSingleValuePropertyValidateMethod( + final ClassBuilder classBuilder, + final String codecClassName, + final String propertyName, + final Token fieldToken, + final String indent, + final String validateMethod, + final CharSequence typeName, + final String formattedPropertyName, + final String elementTypeName, + final Encoding encoding) + { final StringBuilder validateBuilder = classBuilder.appendPrivate().append("\n") .append(indent).append("static void ").append(validateMethod).append("(") .append(typeName).append(" value)\n") @@ -1525,6 +1552,9 @@ private void generateSingleValueProperty( String value = "value"; + final boolean mustPreventLesser = !encoding.applicableMinValue().equals(encoding.primitiveType().minValue()); + final boolean mustPreventGreater = !encoding.applicableMaxValue().equals(encoding.primitiveType().maxValue()); + if (fieldToken.isOptionalEncoding()) { validateBuilder.append(indent).append(INDENT) @@ -1548,27 +1578,48 @@ private void generateSingleValueProperty( .append(indent).append(INDENT) .append("}\n"); + if (mustPreventLesser || mustPreventGreater) + { + validateBuilder.append(indent).append(INDENT) + .append(elementTypeName).append(" actualValue = value.value();\n"); + + value = "actualValue"; + } + } + + if (mustPreventLesser) + { validateBuilder.append(indent).append(INDENT) - .append(elementTypeName).append(" actualValue = value.value();\n"); + .append("if (").append(value).append(" < ") + .append(codecClassName).append("::").append(formattedPropertyName).append("MinValue())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw std::invalid_argument(\"") + .append(propertyName) + .append(": value is less than allowed minimum: \" + std::to_string(") + .append(value).append("));\n") + .append(indent).append(INDENT) + .append("}\n"); + } - value = "actualValue"; + if (mustPreventGreater) + { + validateBuilder.append(indent).append(INDENT) + .append("if (").append(value).append(" > ") + .append(codecClassName).append("::").append(formattedPropertyName).append("MaxValue())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw std::invalid_argument(\"") + .append(propertyName) + .append(": value is greater than allowed maximum: \" + std::to_string(") + .append(value).append("));\n") + .append(indent).append(INDENT) + .append("}\n"); } - validateBuilder.append(indent).append(INDENT) - .append("if (").append(value).append(" < ") - .append(codecClassName).append("::").append(formattedPropertyName).append("MinValue() || ") - .append(value).append(" > ") - .append(codecClassName).append("::").append(formattedPropertyName).append("MaxValue())\n") - .append(indent).append(INDENT) - .append("{\n") - .append(indent).append(INDENT).append(INDENT) - .append("throw std::invalid_argument(\"") - .append(propertyName) - .append(": value is out of allowed range: \" + std::to_string(") - .append(value).append("));\n") - .append(indent).append(INDENT) - .append("}\n") - .append(indent).append("}\n"); + validateBuilder.append(indent).append("}\n"); } private void generateConstPropertyMethods( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index e023b8fd95..ad2e3068c7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -20,6 +20,7 @@ import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.generation.CodeGenerator; import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Encoding; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.ir.Signal; import uk.co.real_logic.sbe.ir.Token; @@ -1194,7 +1195,8 @@ private void generateSingleValueProperty( final String indent) { final String nullableSuffix = fieldToken.isOptionalEncoding() ? "?" : ""; - final String typeName = cSharpTypeName(typeToken.encoding().primitiveType()) + nullableSuffix; + final Encoding encoding = typeToken.encoding(); + final String typeName = cSharpTypeName(encoding.primitiveType()) + nullableSuffix; final String formattedPropertyName = formatPropertyName(propertyName); final String fieldName = "_" + toLowerFirstChar(propertyName); @@ -1242,17 +1244,35 @@ private void generateSingleValueProperty( .append("}\n"); } + final boolean mustPreventLesser = !encoding.applicableMinValue().equals(encoding.primitiveType().minValue()); + if (mustPreventLesser) + { + sb.append(indent).append(INDENT) + .append("if (value < ") + .append(codecClassName).append(".").append(formattedPropertyName).append("MinValue)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw new ArgumentException(\"value is less than minimum allowed: \" + value);\n") + .append(indent).append(INDENT) + .append("}\n"); + } + + final boolean mustPreventGreater = !encoding.applicableMaxValue().equals(encoding.primitiveType().maxValue()); + if (mustPreventGreater) + { + sb.append(indent).append(INDENT) + .append("if (value > ") + .append(codecClassName).append(".").append(formattedPropertyName).append("MaxValue)\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw new ArgumentException(\"value is greater than maximum allowed: \" + value);\n") + .append(indent).append(INDENT) + .append("}\n"); + } + sb.append(indent).append(INDENT) - .append("if (value < ") - .append(codecClassName).append(".").append(formattedPropertyName).append("MinValue || value > ") - .append(codecClassName).append(".").append(formattedPropertyName).append("MaxValue)\n") - .append(indent).append(INDENT) - .append("{\n") - .append(indent).append(INDENT).append(INDENT) - .append("throw new ArgumentException(\"value is out of allowed range: \" + value);\n") - .append(indent).append(INDENT) - .append("}\n") - .append(indent).append(INDENT) .append("return value;\n") .append(indent).append("}\n"); } diff --git a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj index 5da3f76095..ab700af657 100644 --- a/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj +++ b/sbe-tool/src/propertyTest/resources/CSharpDtosPropertyTest/SbePropertyTest.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 From ebd2fd296ee5c829c6825f69e61291705f07a455 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:56:24 +0200 Subject: [PATCH 380/805] [Java] Upgrade to JUnit 5.10.3. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b661f8b406..8b09e720c3 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' -def junitVersion = '5.10.2' +def junitVersion = '5.10.3' def jqwikVersion = '1.8.1' def jsonVersion = '20230618' def jmhVersion = '1.37' From dbebeb0ca24bdb6aee0517638eee9ac83d3163a6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:57:07 +0200 Subject: [PATCH 381/805] [Java] Upgrade to json 20240303. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8b09e720c3..8f31bfba9c 100644 --- a/build.gradle +++ b/build.gradle @@ -59,7 +59,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.3' def jqwikVersion = '1.8.1' -def jsonVersion = '20230618' +def jsonVersion = '20240303' def jmhVersion = '1.37' def agronaVersion = '1.21.2' def agronaVersionRange = '[1.21.2,2.0[' // allow any release >= 1.21.2 and < 2.0.0 From b0bfa08b5339c128c9699278c93f10c1fef19172 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:57:49 +0200 Subject: [PATCH 382/805] [Java] Upgrade to jqwik 1.9.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8f31bfba9c..24898d4bce 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' def mockitoVersion = '4.11.0' def junitVersion = '5.10.3' -def jqwikVersion = '1.8.1' +def jqwikVersion = '1.9.0' def jsonVersion = '20240303' def jmhVersion = '1.37' def agronaVersion = '1.21.2' From 02b0c7a01ec16fdcaf02d7d63578cb65f925cd4c Mon Sep 17 00:00:00 2001 From: James Watson Date: Mon, 8 Jul 2024 18:19:39 +0100 Subject: [PATCH 383/805] [Java] Switch JsonPrinter.print to use DirectBuffer instead of UnsafeBuffer. --- .../src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java index 5e58d4f0e7..3071afb6c9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java @@ -15,6 +15,7 @@ */ package uk.co.real_logic.sbe.json; +import org.agrona.DirectBuffer; import org.agrona.concurrent.UnsafeBuffer; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.ir.Token; @@ -62,7 +63,7 @@ public void print(final ByteBuffer encodedMessage, final StringBuilder output) * @param buffer with encoded message and header. * @param offset at which the header begins. */ - public void print(final StringBuilder output, final UnsafeBuffer buffer, final int offset) + public void print(final StringBuilder output, final DirectBuffer buffer, final int offset) { final int blockLength = headerDecoder.getBlockLength(buffer, offset); final int templateId = headerDecoder.getTemplateId(buffer, offset); From cf61f3a5cf4ee93cfc79bcc1fe2aaf877c803745 Mon Sep 17 00:00:00 2001 From: marc-adaptive Date: Wed, 17 Jul 2024 11:10:04 -0400 Subject: [PATCH 384/805] [Build] publish OSS artifacts through GitHub workflow --- .github/workflows/ci.yml | 3 +- .github/workflows/codeql.yml | 3 +- .github/workflows/release.yml | 62 +++++++++++++++++++++++++++++++++++ .github/workflows/slow.yml | 3 +- build.gradle | 17 ++++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6bb6a9736..20b3fd4413 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,7 @@ name: Continuous Integration on: + workflow_call: workflow_dispatch: push: branches: @@ -11,7 +12,7 @@ on: - master concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 44a604749a..63bb4b11c8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,6 +1,7 @@ name: "CodeQL" on: + workflow_call: push: branches: - master @@ -10,7 +11,7 @@ on: - master concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: codeql-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..5c5099f479 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,62 @@ +name: Release + +on: + workflow_dispatch: + push: + tags: + - '*.*.*' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +env: + GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' + +jobs: + ci: + uses: ./.github/workflows/ci.yml + + codeql: + uses: ./.github/workflows/codeql.yml + + slow: + uses: ./.github/workflows/slow.yml + + release: + name: Release java artifacts + permissions: + contents: write + packages: write + needs: [ ci , codeql, slow ] + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.ref }} + - name: Create Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: true + - name: Setup java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 8 + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=8" >> $GITHUB_ENV + - name: Publish with Gradle + run: ./gradlew publish + env: + ORG_GRADLE_PROJECT_ossrhUsername: ${{ secrets.ossrhUsername }} + ORG_GRADLE_PROJECT_ossrhPassword: ${{ secrets.ossrhPassword }} + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.signingKey }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.signingPassword }} diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 9b790d276e..9b4b0c22b0 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -1,6 +1,7 @@ name: Slow checks on: + workflow_call: workflow_dispatch: branches: - '**' @@ -8,7 +9,7 @@ on: - cron: '0 12 * * *' concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: slow-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: diff --git a/build.gradle b/build.gradle index 24898d4bce..c0ce5ee4e9 100644 --- a/build.gradle +++ b/build.gradle @@ -79,6 +79,14 @@ ext { if (!project.hasProperty('ossrhPassword')) { ossrhPassword = '' } + + if (!project.hasProperty('signingKey')) { + signingKey = null + } + + if (!project.hasProperty('signingPassword')) { + signingPassword = null + } } def projectPom = { @@ -404,6 +412,9 @@ project(':sbe-tool') { } signing { + if (signingKey != null) { + useInMemoryPgpKeys(signingKey, signingPassword) + } sign publishing.publications.sbe } } @@ -471,6 +482,9 @@ project(':sbe-all') { } signing { + if (signingKey != null) { + useInMemoryPgpKeys(signingKey, signingPassword) + } sign publishing.publications.sbeAll } } @@ -584,6 +598,9 @@ project(':sbe-samples') { } signing { + if (signingKey != null) { + useInMemoryPgpKeys(signingKey, signingPassword) + } sign publishing.publications.sbeSamples } } From fd81387306fe52d704a65434b0490f334a1ca22c Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Wed, 17 Jul 2024 20:48:57 -0500 Subject: [PATCH 385/805] [Java] add #define for template id in C --- .../sbe/generation/c/CGenerator.java | 20 ++++- .../sbe/generation/c/CGeneratorTest.java | 75 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/c/CGeneratorTest.java diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 301532e771..7e597141fd 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1960,6 +1960,8 @@ private CharSequence generateMessageFlyweightFunctions( " return %2$s;\n" + "}\n\n" + + "#define %13$s_SBE_TEMPLATE_ID %4$s\n\n" + + "SBE_ONE_DEF %3$s %10$s_sbe_template_id(void)\n" + "{\n" + " return %4$s;\n" + @@ -2100,7 +2102,23 @@ private CharSequence generateMessageFlyweightFunctions( semanticType, structName, messageHeaderStruct, - semanticVersion); + semanticVersion, + toUppercaseWithUnderscores(structName)); + } + + private String toUppercaseWithUnderscores(final String camelCaseString) + { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < camelCaseString.length(); i++) + { + final char theChar = camelCaseString.charAt(i); + if (Character.isUpperCase(theChar)) + { + sb.append("_"); + } + sb.append(Character.toUpperCase(theChar)); + } + return sb.toString(); } private CharSequence generateFieldFunctions( diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/c/CGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/c/CGeneratorTest.java new file mode 100644 index 0000000000..8b3575e0ab --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/c/CGeneratorTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.cpp; + +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +class CppGeneratorTest +{ + @Test + void shouldUseGeneratedLiteralForConstantOneWhenGeneratingBitsetCode() throws Exception + { + try (InputStream in = Tests.getLocalResource("issue827.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CppGenerator generator = new CppGenerator(ir, false, outputManager); + generator.generate(); + + final String source = outputManager.getSource("issue827.FlagsSet").toString(); + assertThat(source, not(containsString("1u << "))); + assertThat(source, containsString("UINT64_C(0x1) << ")); + } + } + + @Test + void shouldUseConstexprWhenInitializingSemanticVersion() throws Exception + { + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CppGenerator generator = new CppGenerator(ir, false, outputManager); + generator.generate(); + + final String source = outputManager.getSource("code.generation.test.Car").toString(); + assertThat(source, containsString("static constexpr const char* SBE_SEMANTIC_VERSION = \"5.2\"")); + } + } +} From d99bf7e27edd57305ca6b169871f2b64f1b92484 Mon Sep 17 00:00:00 2001 From: Nate Bradac <38217740+nbradac@users.noreply.github.com> Date: Wed, 17 Jul 2024 21:56:40 -0400 Subject: [PATCH 386/805] remove extra file --- .../sbe/generation/c/CGeneratorTest.java | 75 ------------------- 1 file changed, 75 deletions(-) delete mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/c/CGeneratorTest.java diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/c/CGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/c/CGeneratorTest.java deleted file mode 100644 index 8b3575e0ab..0000000000 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/c/CGeneratorTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2013-2024 Real Logic Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package uk.co.real_logic.sbe.generation.cpp; - -import org.agrona.generation.StringWriterOutputManager; -import org.junit.jupiter.api.Test; -import uk.co.real_logic.sbe.Tests; -import uk.co.real_logic.sbe.ir.Ir; -import uk.co.real_logic.sbe.xml.IrGenerator; -import uk.co.real_logic.sbe.xml.MessageSchema; -import uk.co.real_logic.sbe.xml.ParserOptions; - -import java.io.InputStream; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; -import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; - -class CppGeneratorTest -{ - @Test - void shouldUseGeneratedLiteralForConstantOneWhenGeneratingBitsetCode() throws Exception - { - try (InputStream in = Tests.getLocalResource("issue827.xml")) - { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(in, options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final StringWriterOutputManager outputManager = new StringWriterOutputManager(); - outputManager.setPackageName(ir.applicableNamespace()); - - final CppGenerator generator = new CppGenerator(ir, false, outputManager); - generator.generate(); - - final String source = outputManager.getSource("issue827.FlagsSet").toString(); - assertThat(source, not(containsString("1u << "))); - assertThat(source, containsString("UINT64_C(0x1) << ")); - } - } - - @Test - void shouldUseConstexprWhenInitializingSemanticVersion() throws Exception - { - try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) - { - final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); - final MessageSchema schema = parse(in, options); - final IrGenerator irg = new IrGenerator(); - final Ir ir = irg.generate(schema); - final StringWriterOutputManager outputManager = new StringWriterOutputManager(); - outputManager.setPackageName(ir.applicableNamespace()); - - final CppGenerator generator = new CppGenerator(ir, false, outputManager); - generator.generate(); - - final String source = outputManager.getSource("code.generation.test.Car").toString(); - assertThat(source, containsString("static constexpr const char* SBE_SEMANTIC_VERSION = \"5.2\"")); - } - } -} From 76bf4d009ec15cf9b1c496c878be069ebb670086 Mon Sep 17 00:00:00 2001 From: marc-adaptive Date: Mon, 22 Jul 2024 06:28:20 -0400 Subject: [PATCH 387/805] [Build] Update github release secrets --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5c5099f479..10fbcff404 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,7 +56,7 @@ jobs: - name: Publish with Gradle run: ./gradlew publish env: - ORG_GRADLE_PROJECT_ossrhUsername: ${{ secrets.ossrhUsername }} - ORG_GRADLE_PROJECT_ossrhPassword: ${{ secrets.ossrhPassword }} - ORG_GRADLE_PROJECT_signingKey: ${{ secrets.signingKey }} - ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.signingPassword }} + ORG_GRADLE_PROJECT_ossrhUsername: ${{ secrets.SONATYPE_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_ossrhPassword: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }} + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_RSA_SIGN_KEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_RSA_SIGN_KEYPASS }} From 0cb82dc2a026877ffcd85d1be60acd13673086d2 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Sat, 27 Jul 2024 20:06:35 +0100 Subject: [PATCH 388/805] [Java] Formatting. --- .../sbe/generation/java/JavaGenerator.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 7d0d4ba97b..1d6aa830a4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -274,14 +274,14 @@ public void generate() throws IOException final String decoderClassName = formatClassName(decoderName(msgToken.name())); final String decoderStateClassName = decoderClassName + "#CodecStates"; - final FieldPrecedenceModel decoderPrecedenceModel = - precedenceChecks.createDecoderModel(decoderStateClassName, tokens); + final FieldPrecedenceModel decoderPrecedenceModel = precedenceChecks.createDecoderModel( + decoderStateClassName, tokens); generateDecoder(decoderClassName, msgToken, fields, groups, varData, hasVarData, decoderPrecedenceModel); final String encoderClassName = formatClassName(encoderName(msgToken.name())); final String encoderStateClassName = encoderClassName + "#CodecStates"; - final FieldPrecedenceModel encoderPrecedenceModel = - precedenceChecks.createEncoderModel(encoderStateClassName, tokens); + final FieldPrecedenceModel encoderPrecedenceModel = precedenceChecks.createEncoderModel( + encoderStateClassName, tokens); generateEncoder(encoderClassName, msgToken, fields, groups, varData, hasVarData, encoderPrecedenceModel); } } @@ -839,7 +839,8 @@ private void generateDecoder( private void generateDecoderGroups( final StringBuilder sb, - final FieldPrecedenceModel fieldPrecedenceModel, final String outerClassName, + final FieldPrecedenceModel fieldPrecedenceModel, + final String outerClassName, final List tokens, final String indent, final boolean isSubGroup) throws IOException @@ -993,7 +994,6 @@ private void generateGroupDecoderClassHeader( .append(indent).append(" count = ").append(numInGroupCast).append(numInGroupGet).append(";\n") .append(indent).append(" }\n\n"); - generateAccessOrderListenerMethodForNextGroupElement(sb, fieldPrecedenceModel, indent + " ", groupToken); sb.append(indent).append(" public ").append(className).append(" next()\n") @@ -2345,16 +2345,16 @@ private String interfaceImportLine() } - private CharSequence generateFileHeader(final String packageName, final Set importedTypesPackages, + private CharSequence generateFileHeader( + final String packageName, + final Set importedTypesPackages, final String fqBuffer) { - final StringBuilder importStatements = generateImportStatements(importedTypesPackages, packageName); - return "/* Generated SBE (Simple Binary Encoding) message codec. */\n" + "package " + packageName + ";\n\n" + "import " + fqBuffer + ";\n" + interfaceImportLine() + - importStatements; + generateImportStatements(importedTypesPackages, packageName); } private CharSequence generateMainHeader( @@ -4470,7 +4470,6 @@ private void appendDecoderDisplay( append(sb, indent, groupName + ".index = " + groupName + "OriginalIndex;"); Separator.END_GROUP.appendToGeneratedBuilder(sb, indent); - lengthBeforeLastGeneratedSeparator = sb.length(); Separator.FIELD.appendToGeneratedBuilder(sb, indent); From cc3ea3a8f0b6cff325cf05f6fc912bad58d141a0 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 31 Jul 2024 14:03:50 +0100 Subject: [PATCH 389/805] [Java] Style consistency. --- .../common/FieldPrecedenceModel.java | 187 ++++++++---------- 1 file changed, 78 insertions(+), 109 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java index 58a68c17ff..40e5ac7441 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java @@ -136,7 +136,7 @@ public void forEachTerminalEncoderState(final Consumer consumer) public void forEachStateOrderedByStateNumber(final Consumer consumer) { transitionsByState.keySet().stream() - .sorted(Comparator.comparingInt(s -> s.number)) + .sorted(Comparator.comparingInt((s) -> s.number)) .forEach(consumer); } @@ -208,27 +208,31 @@ public void forEachTransitionFrom(final State state, final Consumer - { - transitionsForContext.forEach(transition -> + transitionsByInteraction.values().forEach( + (transitionsForContext) -> { - transition.forEachStartState(startState -> - { - sb.append(indent).append(" ") - .append(startState.name) - .append(" -> ") - .append(transition.endState().name) - .append(" [label=\" ").append(transition.interaction.exampleCode()); - - if (!transition.interaction.exampleConditions().isEmpty()) + transitionsForContext.forEach( + (transition) -> { - sb.append("\\n").append(" where ").append(transition.interaction.exampleConditions()); - } - - sb.append(" \"];\n"); - }); + transition.forEachStartState( + (startState) -> + { + sb.append(indent).append(" ") + .append(startState.name) + .append(" -> ") + .append(transition.endState().name) + .append(" [label=\" ").append(transition.interaction.exampleCode()); + + if (!transition.interaction.exampleConditions().isEmpty()) + { + sb.append("\\n").append(" where ") + .append(transition.interaction.exampleConditions()); + } + + sb.append(" \"];\n"); + }); + }); }); - }); sb.append(indent).append("}\n"); } @@ -244,34 +248,33 @@ private void findTransitions( walkSchemaLevel(new VersionCollector(versions), fields, groups, varData); walkSchemaLevel(new PathCollector(topLevelBlockFields, groupPathsByField), fields, groups, varData); - final IntStream selectedVersions = versionsSelector.apply(versions.stream().mapToInt(i -> i)); - selectedVersions.sorted().forEach(version -> - { - final State versionWrappedState = allocateState("V" + version + "_BLOCK"); + final IntStream selectedVersions = versionsSelector.apply(versions.stream().mapToInt((i) -> i)); + selectedVersions.sorted().forEach( + (version) -> + { + final State versionWrappedState = allocateState("V" + version + "_BLOCK"); - versionWrappedStates.put(version, versionWrappedState); + versionWrappedStates.put(version, versionWrappedState); - final CodecInteraction wrapInteraction = interactionFactory.wrap(version); + final CodecInteraction wrapInteraction = interactionFactory.wrap(version); - allocateTransitions( - wrapInteraction, - Collections.singletonList(notWrappedState), - versionWrappedState - ); + allocateTransitions( + wrapInteraction, + Collections.singletonList(notWrappedState), + versionWrappedState); - final TransitionCollector transitionCollector = new TransitionCollector( - "V" + version + "_", - Collections.singleton(versionWrappedState), - versionWrappedState, - token -> token.version() <= version - ); + final TransitionCollector transitionCollector = new TransitionCollector( + "V" + version + "_", + Collections.singleton(versionWrappedState), + versionWrappedState, + (token) -> token.version() <= version); - walkSchemaLevel(transitionCollector, fields, groups, varData); + walkSchemaLevel(transitionCollector, fields, groups, varData); - // Last writer (highest version) wins when there are multiple versions - encoderWrappedState = versionWrappedState; - terminalEncoderStates = transitionCollector.exitStates(); - }); + // Last writer (highest version) wins when there are multiple versions + encoderWrappedState = versionWrappedState; + terminalEncoderStates = transitionCollector.exitStates(); + }); } private State allocateState(final String name) @@ -287,11 +290,11 @@ private void allocateTransitions( final State to) { final TransitionGroup transitionGroup = new TransitionGroup(interaction, from, to); - final List transitionsForInteraction = - transitionsByInteraction.computeIfAbsent(interaction, ignored -> new ArrayList<>()); + final List transitionsForInteraction = transitionsByInteraction.computeIfAbsent( + interaction, (ignored) -> new ArrayList<>()); final boolean duplicateEndState = - transitionsForInteraction.stream().anyMatch(t -> t.to.number == transitionGroup.to.number); + transitionsForInteraction.stream().anyMatch((t) -> t.to.number == transitionGroup.to.number); if (duplicateEndState) { @@ -299,7 +302,7 @@ private void allocateTransitions( } final Optional conflictingTransition = transitionsForInteraction.stream() - .filter(t -> t.from.stream().anyMatch(transitionGroup.from::contains)) + .filter((t) -> t.from.stream().anyMatch(transitionGroup.from::contains)) .findAny(); if (conflictingTransition.isPresent()) @@ -310,7 +313,7 @@ private void allocateTransitions( transitionsForInteraction.add(transitionGroup); - from.forEach(fromState -> transitionsByState.get(fromState).add(transitionGroup)); + from.forEach((fromState) -> transitionsByState.get(fromState).add(transitionGroup)); } private static void walkSchemaLevel( @@ -394,7 +397,6 @@ public void onBlockField(final Token token) groupPathsByField.put(token, currentGroupPath()); } - @Override public void onEnterRepeatingGroup( final Token token, final List groupFields, @@ -407,7 +409,6 @@ public void onEnterRepeatingGroup( groupPath.removeLast(); } - @Override public void onVarData(final Token token) { groupPathsByField.put(token, currentGroupPath()); @@ -416,15 +417,15 @@ public void onVarData(final Token token) private String currentGroupPath() { final StringBuilder sb = new StringBuilder(); - groupPath.forEach(token -> - { - sb.append(token.name()).append('.'); - }); + groupPath.forEach( + (token) -> + { + sb.append(token.name()).append('.'); + }); return sb.toString(); } } - @SuppressWarnings("ClassCanBeRecord") private static final class VersionCollector implements SchemaConsumer { private final IntHashSet versions; @@ -434,13 +435,11 @@ private static final class VersionCollector implements SchemaConsumer this.versions = versions; } - @Override public void onBlockField(final Token token) { versions.add(token.version()); } - @Override public void onEnterRepeatingGroup( final Token token, final List groupFields, @@ -451,7 +450,6 @@ public void onEnterRepeatingGroup( walkSchemaLevel(this, groupFields, groupGroups, groupVarData); } - @Override public void onVarData(final Token token) { versions.add(token.version()); @@ -479,7 +477,6 @@ private TransitionCollector( currentStates.add(blockState); } - @Override public void onBlockField(final Token token) { if (filter.test(token)) @@ -489,7 +486,6 @@ public void onBlockField(final Token token) } } - @Override public void onEnterRepeatingGroup( final Token token, final List groupFields, @@ -521,8 +517,7 @@ public void onEnterRepeatingGroup( groupPrefix + "N_", currentStates, nRemainingGroupElement, - filter - ); + filter); walkSchemaLevel(nRemainingCollector, groupFields, groupGroups, groupVarData); currentStates.clear(); @@ -548,8 +543,7 @@ public void onEnterRepeatingGroup( groupPrefix + "1_", currentStates, oneRemainingGroupElement, - filter - ); + filter); walkSchemaLevel(oneRemainingCollector, groupFields, groupGroups, groupVarData); final CodecInteraction resetCountToIndexInteraction = interactionFactory.resetCountToIndex(token); @@ -566,16 +560,13 @@ public void onEnterRepeatingGroup( } } - @Override public void onVarData(final Token token) { if (filter.test(token)) { final CodecInteraction lengthAccessInteraction = interactionFactory.accessVarDataLength(token); - currentStates.forEach(state -> - { - allocateTransitions(lengthAccessInteraction, Collections.singleton(state), state); - }); + currentStates.forEach( + (state) -> allocateTransitions(lengthAccessInteraction, Collections.singleton(state), state)); final CodecInteraction codecInteraction = interactionFactory.accessField(token); final State accessedState = allocateState(statePrefix + token.name().toUpperCase() + "_DONE"); @@ -624,7 +615,9 @@ public String name() return name; } - @Override + /** + * {@inheritDoc} + */ public String toString() { return "State{" + @@ -690,7 +683,9 @@ public String exampleCode() return interaction.exampleCode(); } - @Override + /** + * {@inheritDoc} + */ public String toString() { return "Transition{" + @@ -724,7 +719,6 @@ public final boolean isTopLevelBlockFieldAccess() { if (this instanceof AccessField) { - //noinspection PatternVariableCanBeUsed final AccessField accessField = (AccessField)this; return accessField.isTopLevelBlockField(); } @@ -744,19 +738,16 @@ private static final class Wrap extends CodecInteraction this.version = version; } - @Override public String groupQualifiedName() { return "wrap"; } - @Override public String exampleCode() { return "wrap(version=" + version + ")"; } - @Override public String exampleConditions() { return ""; @@ -786,19 +777,16 @@ boolean isTopLevelBlockField() return isTopLevelBlockField; } - @Override public String groupQualifiedName() { return groupPath + token.name(); } - @Override public String exampleCode() { return groupPath + token.name() + "(?)"; } - @Override public String exampleConditions() { return ""; @@ -821,19 +809,16 @@ private DetermineGroupIsEmpty(final String groupPath, final Token token) this.token = token; } - @Override public String groupQualifiedName() { return groupPath + token.name(); } - @Override String exampleCode() { return groupPath + token.name() + "Count(0)"; } - @Override String exampleConditions() { return ""; @@ -856,19 +841,16 @@ private DetermineGroupHasElements(final String groupPath, final Token token) this.token = token; } - @Override public String groupQualifiedName() { return groupPath + token.name(); } - @Override String exampleCode() { return groupPath + token.name() + "Count(>0)"; } - @Override String exampleConditions() { return ""; @@ -892,19 +874,16 @@ private MoveToNextElement(final String groupPath, final Token token) this.token = token; } - @Override public String groupQualifiedName() { return groupPath + token.name(); } - @Override String exampleCode() { return groupPath + token.name() + ".next()"; } - @Override String exampleConditions() { return "count - newIndex > 1"; @@ -928,19 +907,16 @@ private MoveToLastElement(final String groupPath, final Token token) this.token = token; } - @Override public String groupQualifiedName() { return groupPath + token.name(); } - @Override String exampleCode() { return groupPath + token.name() + ".next()"; } - @Override String exampleConditions() { return "count - newIndex == 1"; @@ -963,19 +939,16 @@ private ResetCountToIndex(final String groupPath, final Token token) this.token = token; } - @Override public String groupQualifiedName() { return groupPath + token.name(); } - @Override String exampleCode() { return groupPath + token.name() + ".resetCountToIndex()"; } - @Override String exampleConditions() { return ""; @@ -998,26 +971,22 @@ private AccessVarDataLength(final String groupPath, final Token token) this.token = token; } - @Override public String groupQualifiedName() { return groupPath + token.name(); } - @Override String exampleCode() { return groupPath + token.name() + "Length()"; } - @Override String exampleConditions() { return ""; } } - /** * Factory for creating {@link CodecInteraction} instances. This factory * is used to hash-cons the instances, so that they can be compared by @@ -1068,8 +1037,8 @@ public CodecInteraction wrap(final int version) */ public CodecInteraction accessField(final Token token) { - return accessFieldInteractions.computeIfAbsent(token, - t -> new AccessField(groupPathsByField.get(t), t, topLevelBlockFields.contains(t))); + return accessFieldInteractions.computeIfAbsent( + token, (t) -> new AccessField(groupPathsByField.get(t), t, topLevelBlockFields.contains(t))); } /** @@ -1089,8 +1058,8 @@ public CodecInteraction accessField(final Token token) */ public CodecInteraction determineGroupIsEmpty(final Token token) { - return determineGroupIsEmptyInteractions.computeIfAbsent(token, - t -> new DetermineGroupIsEmpty(groupPathsByField.get(t), t)); + return determineGroupIsEmptyInteractions.computeIfAbsent( + token, (t) -> new DetermineGroupIsEmpty(groupPathsByField.get(t), t)); } /** @@ -1110,8 +1079,8 @@ public CodecInteraction determineGroupIsEmpty(final Token token) */ public CodecInteraction determineGroupHasElements(final Token token) { - return determineGroupHasElementsInteractions.computeIfAbsent(token, - t -> new DetermineGroupHasElements(groupPathsByField.get(t), t)); + return determineGroupHasElementsInteractions.computeIfAbsent( + token, (t) -> new DetermineGroupHasElements(groupPathsByField.get(t), t)); } /** @@ -1128,8 +1097,8 @@ public CodecInteraction determineGroupHasElements(final Token token) */ public CodecInteraction moveToNextElement(final Token token) { - return moveToNextElementInteractions.computeIfAbsent(token, - t -> new MoveToNextElement(groupPathsByField.get(t), t)); + return moveToNextElementInteractions.computeIfAbsent( + token, (t) -> new MoveToNextElement(groupPathsByField.get(t), t)); } /** @@ -1144,8 +1113,8 @@ public CodecInteraction moveToNextElement(final Token token) */ public CodecInteraction moveToLastElement(final Token token) { - return moveToLastElementInteractions.computeIfAbsent(token, - t -> new MoveToLastElement(groupPathsByField.get(t), t)); + return moveToLastElementInteractions.computeIfAbsent( + token, (t) -> new MoveToLastElement(groupPathsByField.get(t), t)); } /** @@ -1162,8 +1131,8 @@ public CodecInteraction moveToLastElement(final Token token) */ public CodecInteraction resetCountToIndex(final Token token) { - return resetCountToIndexInteractions.computeIfAbsent(token, - t -> new ResetCountToIndex(groupPathsByField.get(t), t)); + return resetCountToIndexInteractions.computeIfAbsent( + token, (t) -> new ResetCountToIndex(groupPathsByField.get(t), t)); } /** @@ -1180,8 +1149,8 @@ public CodecInteraction resetCountToIndex(final Token token) */ public CodecInteraction accessVarDataLength(final Token token) { - return accessVarDataLengthInteractions.computeIfAbsent(token, - t -> new AccessVarDataLength(groupPathsByField.get(t), t)); + return accessVarDataLengthInteractions.computeIfAbsent( + token, (t) -> new AccessVarDataLength(groupPathsByField.get(t), t)); } } } From 64ce522f63bdd295fde805a4e49aa88faa53986a Mon Sep 17 00:00:00 2001 From: marc-adaptive Date: Wed, 31 Jul 2024 11:39:42 -0400 Subject: [PATCH 390/805] [Build] Add explicit job permissions for on-workflow calls --- .github/workflows/release.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 10fbcff404..9ce363e17c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,12 +16,20 @@ env: jobs: ci: uses: ./.github/workflows/ci.yml - - codeql: - uses: ./.github/workflows/codeql.yml + permissions: + contents: read slow: uses: ./.github/workflows/slow.yml + permissions: + contents: read + + codeql: + uses: ./.github/workflows/codeql.yml + permissions: + actions: read + contents: read + security-events: write release: name: Release java artifacts From 4ddf522c184e4474e7ffe7d929e4eef4f2be1894 Mon Sep 17 00:00:00 2001 From: Ami Bar Date: Wed, 24 Apr 2024 10:59:48 +0300 Subject: [PATCH 391/805] [C#] Avoid ToString() affect the message internal state --- csharp/sbe-tests/Issue992Tests.cs | 65 +++++++++++++++++++ .../generation/csharp/CSharpGenerator.java | 20 ++++-- 2 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 csharp/sbe-tests/Issue992Tests.cs diff --git a/csharp/sbe-tests/Issue992Tests.cs b/csharp/sbe-tests/Issue992Tests.cs new file mode 100644 index 0000000000..8a5e47ca3a --- /dev/null +++ b/csharp/sbe-tests/Issue992Tests.cs @@ -0,0 +1,65 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Org.SbeTool.Sbe.Dll; +using Mktdata; + +namespace Org.SbeTool.Sbe.Tests +{ + [TestClass] + public class Issue992Tests + { + private const int Offset = 0; + private DirectBuffer _buffer; + private MessageHeader _messageHeader; + + [TestInitialize] + public void SetUp() + { + var byteArray = new byte[4096]; + _buffer = new DirectBuffer(byteArray); + + _messageHeader = new MessageHeader(); + + _messageHeader.Wrap(_buffer, 0, MessageHeader.SbeSchemaVersion); + _messageHeader.BlockLength = MDIncrementalRefreshBook46.BlockLength; + _messageHeader.SchemaId = MDIncrementalRefreshBook46.SchemaId; + _messageHeader.TemplateId = MDIncrementalRefreshBook46.TemplateId; + _messageHeader.Version = MDIncrementalRefreshBook46.SchemaVersion; + } + + [TestMethod] + public void CheckToStringDontMessWithGroupIteration() + { + var encoder = new MDIncrementalRefreshBook46() + .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); + encoder.TransactTime = (ulong)new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; + var noMDEntries = encoder.NoMDEntriesCount(2); + noMDEntries.Next(); + noMDEntries.MDEntryPx.Mantissa = 12; + noMDEntries.MDEntrySize = 3; + noMDEntries.Next(); + noMDEntries.MDEntryPx.Mantissa = 15; + noMDEntries.MDEntrySize = 7; + encoder.NoOrderIDEntriesCount(0); + encoder.CheckEncodingIsComplete(); + + var expectedString = "[MDIncrementalRefreshBook46](sbeTemplateId=46|sbeSchemaId=1|sbeSchemaVersion=9|sbeBlockLength=11):TransactTime=630822816000000000|MatchEventIndicator={0}|NoMDEntries=[(MDEntryPx=(Mantissa=12|)|MDEntrySize=3|SecurityID=0|RptSeq=0|NumberOfOrders=0|MDPriceLevel=0|MDUpdateAction=New|MDEntryType=NULL_VALUE),(MDEntryPx=(Mantissa=15|)|MDEntrySize=7|SecurityID=0|RptSeq=0|NumberOfOrders=0|MDPriceLevel=0|MDUpdateAction=New|MDEntryType=NULL_VALUE)]|NoOrderIDEntries=[]"; + + var decoder = new MDIncrementalRefreshBook46() + .WrapForDecodeAndApplyHeader(_buffer, Offset, _messageHeader); + noMDEntries = decoder.NoMDEntries; + Assert.AreEqual(expectedString, decoder.ToString()); + int counter = 0; + while (noMDEntries.HasNext) + { + Assert.AreEqual(expectedString, decoder.ToString()); + ++counter; + noMDEntries.Next(); + Assert.AreEqual(expectedString, decoder.ToString()); + } + + Assert.AreEqual(2, counter); + Assert.AreEqual(expectedString, decoder.ToString()); + } + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 530717c9c4..bfd53ff311 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -181,7 +181,7 @@ public void generate() throws IOException out.append(generateVarData(fieldPrecedenceModel, varData, BASE_INDENT + INDENT)); out.append(generateDisplay(toUpperFirstChar(msgToken.name()), - fields, groups, varData, fieldPrecedenceModel)); + className, fields, groups, varData, fieldPrecedenceModel)); out.append(INDENT + "}\n"); out.append("}\n"); @@ -2406,13 +2406,22 @@ private int writeTokenDisplay( return lengthBeforeFieldSeparator; } - private void appendToString(final StringBuilder sb, final String indent) + private void appendToString(final StringBuilder sb, final String indent, final String className) { sb.append('\n'); append(sb, indent, "public override string ToString()"); append(sb, indent, "{"); append(sb, indent, " var sb = new StringBuilder(100);"); - append(sb, indent, " this.BuildString(sb);"); + if(null != className) + { + append(sb, indent, " var m = new " + className + "();"); + append(sb, indent, " m.WrapForDecode(_buffer, _offset, _actingBlockLength, _actingVersion);"); + append(sb, indent, " m.BuildString(sb);"); + } + else + { + append(sb, indent, " this.BuildString(sb);"); + } append(sb, indent, " return sb.ToString();"); append(sb, indent, "}"); } @@ -2437,6 +2446,7 @@ private CharSequence generateChoiceDisplay(final String enumName) private CharSequence generateDisplay( final String name, + final String className, final List tokens, final List groups, final List varData, @@ -2444,7 +2454,7 @@ private CharSequence generateDisplay( { final StringBuilder sb = new StringBuilder(100); - appendToString(sb, TWO_INDENT); + appendToString(sb, TWO_INDENT, className); sb.append('\n'); append(sb, TWO_INDENT, "internal void BuildString(StringBuilder builder)"); append(sb, TWO_INDENT, "{"); @@ -2502,7 +2512,7 @@ private CharSequence generateCompositeDisplay(final List tokens) { final StringBuilder sb = new StringBuilder(); - appendToString(sb, TWO_INDENT); + appendToString(sb, TWO_INDENT, null); sb.append('\n'); append(sb, TWO_INDENT, "internal void BuildString(StringBuilder builder)"); append(sb, TWO_INDENT, "{"); From 4c8f35bf3efe6f60c395c0bf4262633477ac43ef Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 1 Aug 2024 12:23:41 +0100 Subject: [PATCH 392/805] Use conventions from JavaGenerator in CSharpGenerator where possible. Note that the `BuildString` methods are still unsafe to use during group iteration. --- csharp/sbe-tests/Issue992Tests.cs | 2 +- .../generation/csharp/CSharpGenerator.java | 30 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/csharp/sbe-tests/Issue992Tests.cs b/csharp/sbe-tests/Issue992Tests.cs index 8a5e47ca3a..b4bf704565 100644 --- a/csharp/sbe-tests/Issue992Tests.cs +++ b/csharp/sbe-tests/Issue992Tests.cs @@ -28,7 +28,7 @@ public void SetUp() } [TestMethod] - public void CheckToStringDontMessWithGroupIteration() + public void CheckToStringDoesNotBreakGroupIteration() { var encoder = new MDIncrementalRefreshBook46() .WrapForEncodeAndApplyHeader(_buffer, Offset, _messageHeader); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index bfd53ff311..85d2a49855 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -2406,22 +2406,26 @@ private int writeTokenDisplay( return lengthBeforeFieldSeparator; } - private void appendToString(final StringBuilder sb, final String indent, final String className) + private void appendToString(final StringBuilder sb, final String indent) { sb.append('\n'); append(sb, indent, "public override string ToString()"); append(sb, indent, "{"); append(sb, indent, " var sb = new StringBuilder(100);"); - if(null != className) - { - append(sb, indent, " var m = new " + className + "();"); - append(sb, indent, " m.WrapForDecode(_buffer, _offset, _actingBlockLength, _actingVersion);"); - append(sb, indent, " m.BuildString(sb);"); - } - else - { - append(sb, indent, " this.BuildString(sb);"); - } + append(sb, indent, " this.BuildString(sb);"); + append(sb, indent, " return sb.ToString();"); + append(sb, indent, "}"); + } + + private void appendMessageToString(final StringBuilder sb, final String indent, final String className) + { + sb.append('\n'); + append(sb, indent, "public override string ToString()"); + append(sb, indent, "{"); + append(sb, indent, " var sb = new StringBuilder(100);"); + append(sb, indent, " var m = new " + className + "();"); + append(sb, indent, " m.WrapForDecode(_buffer, _offset, _actingBlockLength, _actingVersion);"); + append(sb, indent, " m.BuildString(sb);"); append(sb, indent, " return sb.ToString();"); append(sb, indent, "}"); } @@ -2454,7 +2458,7 @@ private CharSequence generateDisplay( { final StringBuilder sb = new StringBuilder(100); - appendToString(sb, TWO_INDENT, className); + appendMessageToString(sb, TWO_INDENT, className); sb.append('\n'); append(sb, TWO_INDENT, "internal void BuildString(StringBuilder builder)"); append(sb, TWO_INDENT, "{"); @@ -2512,7 +2516,7 @@ private CharSequence generateCompositeDisplay(final List tokens) { final StringBuilder sb = new StringBuilder(); - appendToString(sb, TWO_INDENT, null); + appendToString(sb, TWO_INDENT); sb.append('\n'); append(sb, TWO_INDENT, "internal void BuildString(StringBuilder builder)"); append(sb, TWO_INDENT, "{"); From 156b528289e0ee2d68319f03a2debb7a4978a418 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Thu, 1 Aug 2024 10:14:50 -0500 Subject: [PATCH 393/805] [Java] add keyword suffix check for java enums --- .../sbe/generation/java/JavaGenerator.java | 4 +- .../sbe/generation/java/JavaUtil.java | 22 +++- .../sbe/generation/java/EnumTest.java | 102 ++++++++++++++++++ sbe-tool/src/test/resources/issue1007.xml | 24 +++++ 4 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java create mode 100644 sbe-tool/src/test/resources/issue1007.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 1d6aa830a4..b47b8839cc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -2238,7 +2238,7 @@ private CharSequence generateEnumValues(final List tokens, final String n final Encoding encoding = token.encoding(); final CharSequence constVal = generateLiteral(encoding.primitiveType(), encoding.constValue().toString()); generateTypeJavadoc(sb, INDENT, token); - sb.append(INDENT).append(token.name()).append('(').append(constVal).append("),\n\n"); + sb.append(INDENT).append(formatForJavaKeyword(token.name())).append('(').append(constVal).append("),\n\n"); } if (shouldDecodeUnknownEnumValues) @@ -2297,7 +2297,7 @@ private CharSequence generateEnumLookupMethod(final List tokens, final St for (final Token token : tokens) { final String constStr = token.encoding().constValue().toString(); - final String name = token.name(); + final String name = formatForJavaKeyword(token.name()); sb.append(" case ").append(constStr).append(": return ").append(name).append(";\n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index 2431542d30..d5d3ac6693 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -155,22 +155,34 @@ public static String javaTypeName(final PrimitiveType primitiveType) */ public static String formatPropertyName(final String value) { - String formattedValue = Generators.toLowerFirstChar(value); + return formatForJavaKeyword(Generators.toLowerFirstChar(value)); + } - if (ValidationUtil.isJavaKeyword(formattedValue)) + /** + * Format a name for generated code. + *

    + * If the formatted name is a keyword then {@link SbeTool#KEYWORD_APPEND_TOKEN} is appended if set. + * + * @param value to be formatted. + * @return the string formatted as a valid name. + * @throws IllegalStateException if a keyword and {@link SbeTool#KEYWORD_APPEND_TOKEN} is not set. + */ + public static String formatForJavaKeyword(final String value) + { + if (ValidationUtil.isJavaKeyword(value)) { final String keywordAppendToken = System.getProperty(SbeTool.KEYWORD_APPEND_TOKEN); if (null == keywordAppendToken) { throw new IllegalStateException( - "Invalid property name='" + formattedValue + + "Invalid property name='" + value + "' please correct the schema or consider setting system property: " + SbeTool.KEYWORD_APPEND_TOKEN); } - formattedValue += keywordAppendToken; + return value + keywordAppendToken; } - return formattedValue; + return value; } /** diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java new file mode 100644 index 0000000000..6ec55dc56a --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import org.agrona.DirectBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.SbeTool; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; +import uk.co.real_logic.sbe.xml.XmlSchemaParser; + +import java.io.InputStream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +class EnumTest +{ + private static final Class BUFFER_CLASS = MutableDirectBuffer.class; + private static final String BUFFER_NAME = BUFFER_CLASS.getName(); + private static final Class READ_ONLY_BUFFER_CLASS = DirectBuffer.class; + private static final String READ_ONLY_BUFFER_NAME = READ_ONLY_BUFFER_CLASS.getName(); + + private StringWriterOutputManager outputManager; + private JavaGenerator generator; + + private void setupGenerator(final InputStream in) throws Exception + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = XmlSchemaParser.parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, outputManager); + } + + @SuppressWarnings("checkstyle:LineLength") + @Test + void shouldFailOnKeywordEnumValues() throws Exception + { + try (InputStream in = Tests.getLocalResource("issue1007.xml")) + { + setupGenerator(in); + + try + { + generator.generate(); + } + catch (final IllegalStateException exception) + { + assertEquals( + "Invalid property name='false' please correct the schema or consider setting system property: sbe.keyword.append.token", + exception.getMessage()); + return; + } + + fail("expected IllegalStateException"); + } + } + + @Test + void shouldAddSuffixToEnumValues() throws Exception + { + System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); + + try (InputStream in = Tests.getLocalResource("issue1007.xml")) + { + setupGenerator(in); + + generator.generate(); + final String sources = outputManager.getSources().toString(); + + assertThat(sources, containsString("false_(")); + assertThat(sources, containsString("true_(")); + assertThat(sources, containsString("return false_;")); + assertThat(sources, containsString("return true_;")); + } + } +} diff --git a/sbe-tool/src/test/resources/issue1007.xml b/sbe-tool/src/test/resources/issue1007.xml new file mode 100644 index 0000000000..1ba4ad548c --- /dev/null +++ b/sbe-tool/src/test/resources/issue1007.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + 0 + 1 + + + + + + From 5e0dcfb12d01f2f17bf416dbb9482f6f97af2d24 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Thu, 1 Aug 2024 14:58:05 -0500 Subject: [PATCH 394/805] [Java] add enum keyword check to C++ and C# --- .../sbe/generation/cpp/CppGenerator.java | 14 ++- .../sbe/generation/cpp/CppUtil.java | 19 +++- .../generation/csharp/CSharpGenerator.java | 2 +- .../sbe/generation/csharp/CSharpUtil.java | 26 +++++ .../sbe/generation/cpp/CppEnumTest.java | 102 ++++++++++++++++++ .../sbe/generation/csharp/CSharpEnumTest.java | 97 +++++++++++++++++ .../sbe/generation/java/EnumTest.java | 2 + 7 files changed, 253 insertions(+), 9 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpEnumTest.java diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 99f5498e38..cc6921a0bb 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1471,7 +1471,11 @@ private CharSequence generateEnumValues(final List tokens, final Token en { final CharSequence constVal = generateLiteral( token.encoding().primitiveType(), token.encoding().constValue().toString()); - sb.append(" ").append(token.name()).append(" = ").append(constVal).append(",\n"); + sb.append(" ") + .append(formatForCppKeyword(token.name())) + .append(" = ") + .append(constVal) + .append(",\n"); } final CharSequence nullLiteral = generateLiteral( @@ -1505,7 +1509,11 @@ private CharSequence generateEnumLookupMethod(final List tokens, final To final CharSequence constVal = generateLiteral( token.encoding().primitiveType(), token.encoding().constValue().toString()); - sb.append(" case ").append(constVal).append(": return ").append(token.name()).append(";\n"); + sb.append(" case ") + .append(constVal) + .append(": return ") + .append(formatForCppKeyword(token.name())) + .append(";\n"); } final CharSequence nullVal = generateLiteral( @@ -3839,7 +3847,7 @@ private CharSequence generateEnumDisplay(final List tokens, final Token e { new Formatter(sb).format( " case %1$s: return \"%1$s\";\n", - token.name()); + formatForCppKeyword(token.name())); } sb.append(" case NULL_VALUE: return \"NULL_VALUE\";\n").append(" }\n\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java index 6ac6d8afa8..534547a7fb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java @@ -67,22 +67,31 @@ public static String cppTypeName(final PrimitiveType primitiveType) */ public static String formatPropertyName(final String value) { - String formattedValue = toLowerFirstChar(value); + return formatForCppKeyword(toLowerFirstChar(value)); + } - if (ValidationUtil.isCppKeyword(formattedValue)) + /** + * Format a String with a suffix in case it's a keyword. + * + * @param value to be formatted. + * @return the formatted string. + */ + public static String formatForCppKeyword(final String value) + { + if (ValidationUtil.isCppKeyword(value)) { final String keywordAppendToken = System.getProperty(SbeTool.KEYWORD_APPEND_TOKEN); if (null == keywordAppendToken) { throw new IllegalStateException( - "Invalid property name='" + formattedValue + + "Invalid property name='" + value + "' please correct the schema or consider setting system property: " + SbeTool.KEYWORD_APPEND_TOKEN); } - formattedValue += keywordAppendToken; + return value + keywordAppendToken; } - return formattedValue; + return value; } /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 85d2a49855..8c06689da8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -775,7 +775,7 @@ private CharSequence generateEnumValues(final List tokens, final Token en for (final Token token : tokens) { sb.append(generateDocumentation(INDENT + INDENT, token)) - .append(INDENT).append(INDENT).append(token.name()).append(" = ") + .append(INDENT).append(INDENT).append(formatForCSharpKeyword(token.name())).append(" = ") .append(token.encoding().constValue()).append(",\n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index 1fc1cb64b2..31c4444feb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -17,6 +17,8 @@ package uk.co.real_logic.sbe.generation.csharp; import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.SbeTool; +import uk.co.real_logic.sbe.ValidationUtil; import uk.co.real_logic.sbe.generation.Generators; import uk.co.real_logic.sbe.ir.Token; @@ -241,6 +243,30 @@ public static String formatPropertyName(final String str) return toUpperFirstChar(str); } + /** + * Format a String with a suffix in case it's a keyword. + * + * @param value to be formatted. + * @return the formatted string. + */ + public static String formatForCSharpKeyword(final String value) + { + if (ValidationUtil.isCSharpKeyword(value)) + { + final String keywordAppendToken = System.getProperty(SbeTool.KEYWORD_APPEND_TOKEN); + if (null == keywordAppendToken) + { + throw new IllegalStateException( + "Invalid property name='" + value + + "' please correct the schema or consider setting system property: " + SbeTool.KEYWORD_APPEND_TOKEN); + } + + return value + keywordAppendToken; + } + + return value; + } + /** * Format a String as a variable name. * diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java new file mode 100644 index 0000000000..db69b1cf83 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.cpp; + +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.SbeTool; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +import static org.junit.jupiter.api.Assertions.fail; + +class CppEnumTest +{ + private StringWriterOutputManager outputManager; + private CppGenerator generator; + + private void setupGenerator(final InputStream in) throws Exception + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + generator = new CppGenerator(ir, false, outputManager); + } + + @SuppressWarnings("checkstyle:LineLength") + @Test + void shouldFailOnKeywordEnumValues() throws Exception + { + System.clearProperty(SbeTool.KEYWORD_APPEND_TOKEN); + + try (InputStream in = Tests.getLocalResource("issue1007.xml")) + { + setupGenerator(in); + + try + { + generator.generate(); + } + catch (final IllegalStateException exception) + { + assertEquals( + "Invalid property name='false' please correct the schema or consider setting system property: sbe.keyword.append.token", + exception.getMessage()); + return; + } + + fail("expected IllegalStateException"); + final String source = outputManager.getSources().toString(); + + System.err.println(source); + } + } + + @Test + void shouldAddSuffixToEnumValues() throws Exception + { + System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); + + try (InputStream in = Tests.getLocalResource("issue1007.xml")) + { + setupGenerator(in); + + generator.generate(); + final String sources = outputManager.getSources().toString(); + + assertThat(sources, containsString("false_ = static")); + assertThat(sources, containsString("true_ = static")); + assertThat(sources, containsString("return false_;")); + assertThat(sources, containsString("return true_;")); + assertThat(sources, containsString("case false_:")); + assertThat(sources, containsString("case true_:")); + } + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpEnumTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpEnumTest.java new file mode 100644 index 0000000000..fec4a1bcfd --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpEnumTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.csharp; + +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.SbeTool; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +class CSharpEnumTest +{ + private StringWriterOutputManager outputManager; + private CSharpGenerator generator; + + private void setupGenerator(final InputStream in) throws Exception + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + generator = new CSharpGenerator(ir, outputManager); + } + + @SuppressWarnings("checkstyle:LineLength") + @Test + void shouldFailOnKeywordEnumValues() throws Exception + { + System.clearProperty(SbeTool.KEYWORD_APPEND_TOKEN); + + try (InputStream in = Tests.getLocalResource("issue1007.xml")) + { + setupGenerator(in); + + try + { + generator.generate(); + } + catch (final IllegalStateException exception) + { + assertEquals( + "Invalid property name='false' please correct the schema or consider setting system property: sbe.keyword.append.token", + exception.getMessage()); + return; + } + + fail("expected IllegalStateException"); + final String source = outputManager.getSources().toString(); + + System.err.println(source); + } + } + + @Test + void shouldAddSuffixToEnumValues() throws Exception + { + System.setProperty(SbeTool.KEYWORD_APPEND_TOKEN, "_"); + + try (InputStream in = Tests.getLocalResource("issue1007.xml")) + { + setupGenerator(in); + + generator.generate(); + final String sources = outputManager.getSources().toString(); + + assertThat(sources, containsString("false_ = ")); + assertThat(sources, containsString("true_ = ")); + } + } +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java index 6ec55dc56a..11c3424e6c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java @@ -61,6 +61,8 @@ private void setupGenerator(final InputStream in) throws Exception @Test void shouldFailOnKeywordEnumValues() throws Exception { + System.clearProperty(SbeTool.KEYWORD_APPEND_TOKEN); + try (InputStream in = Tests.getLocalResource("issue1007.xml")) { setupGenerator(in); From 67a4e410606acff9646002287e4e59f4671500d6 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Fri, 2 Aug 2024 11:20:50 -0500 Subject: [PATCH 395/805] 1.32.0 release --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 365468802a..359c41089a 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.32.0-SNAPSHOT \ No newline at end of file +1.32.0 From d419f7fc00ae32fbab40525daafe3ae46260062f Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Fri, 2 Aug 2024 11:21:58 -0500 Subject: [PATCH 396/805] 1.33.0 snapshot --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 359c41089a..f1b6e31361 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.32.0 +1.33.0-SNAPSHOT From 49c2b99e04a7c77b504e594ed84415b87040d9a6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:53:06 +0200 Subject: [PATCH 397/805] [Java] Upgrade to Agrona 1.22.0. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c0ce5ee4e9..438597ba6c 100644 --- a/build.gradle +++ b/build.gradle @@ -61,8 +61,8 @@ def junitVersion = '5.10.3' def jqwikVersion = '1.9.0' def jsonVersion = '20240303' def jmhVersion = '1.37' -def agronaVersion = '1.21.2' -def agronaVersionRange = '[1.21.2,2.0[' // allow any release >= 1.21.2 and < 2.0.0 +def agronaVersion = '1.22.0' +def agronaVersionRange = '[1.22.0,2.0[' // allow any release >= 1.22.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 0f9e4100241fb36a48f1bc0814be2ae2170eb6f3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:54:48 +0200 Subject: [PATCH 398/805] [Java] Upgrade to Hamcrest 3.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 438597ba6c..613c3dd563 100644 --- a/build.gradle +++ b/build.gradle @@ -55,7 +55,7 @@ def toolchainLauncher = javaToolchains.launcherFor { } def checkstyleVersion = '9.3' -def hamcrestVersion = '2.2' +def hamcrestVersion = '3.0' def mockitoVersion = '4.11.0' def junitVersion = '5.10.3' def jqwikVersion = '1.9.0' From 2a48a285683110020c1198246a7660b72c4c7110 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Mon, 5 Aug 2024 07:17:10 -0500 Subject: [PATCH 399/805] 1.32.1 release --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f1b6e31361..96cd6ee1e7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.33.0-SNAPSHOT +1.32.1 From 0f49ae57a4fb2fc5b99c8a0e8f08b7f43023b4f9 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Mon, 5 Aug 2024 07:18:13 -0500 Subject: [PATCH 400/805] 1.33.0 snapshot --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 96cd6ee1e7..f1b6e31361 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.32.1 +1.33.0-SNAPSHOT From a5e12d1c0d22e477ca302ee58c352984540e882f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:08:58 +0200 Subject: [PATCH 401/805] [Java] Upgrade to JUnit 5.11.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 613c3dd563..c0741e6ab7 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '3.0' def mockitoVersion = '4.11.0' -def junitVersion = '5.10.3' +def junitVersion = '5.11.0' def jqwikVersion = '1.9.0' def jsonVersion = '20240303' def jmhVersion = '1.37' From 7ce24c3f7344fcb2f6e8fb3ca04c162b3f4f5f35 Mon Sep 17 00:00:00 2001 From: Grzegorz Gierlach Date: Fri, 31 May 2024 13:31:10 +0200 Subject: [PATCH 402/805] [Rust] Generate imports in alphabetical order. --- .../java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 1 + .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 109d3ba4c5..ad8a62c23e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -73,6 +73,7 @@ void generate() throws IOException .filter((fileName) -> fileName.endsWith(".rs")) .filter((fileName) -> !fileName.equals("lib.rs")) .map((fileName) -> fileName.substring(0, fileName.length() - 3)) + .sorted() .forEach(modules::add); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 1b53987098..734b57d2bc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -152,8 +152,8 @@ public void generate() throws IOException try (Writer out = outputManager.createOutput(codecModName)) { indent(out, 0, "use crate::*;\n\n"); - indent(out, 0, "pub use encoder::%sEncoder;\n", formatStructName(msgToken.name())); - indent(out, 0, "pub use decoder::%sDecoder;\n\n", formatStructName(msgToken.name())); + indent(out, 0, "pub use decoder::%sDecoder;\n", formatStructName(msgToken.name())); + indent(out, 0, "pub use encoder::%sEncoder;\n\n", formatStructName(msgToken.name())); final String blockLengthType = blockLengthType(); final String templateIdType = rustTypeName(ir.headerStructure().templateIdType()); final String schemaIdType = rustTypeName(ir.headerStructure().schemaIdType()); From 80308ae87c198e9fd884a5cad85d35030afd8bd6 Mon Sep 17 00:00:00 2001 From: Grzegorz Gierlach Date: Wed, 22 May 2024 12:33:05 +0200 Subject: [PATCH 403/805] [Rust] Make Rust crate version configurable. --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 734b57d2bc..c7a33c9cd6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -48,6 +48,7 @@ */ public class RustGenerator implements CodeGenerator { + private static final String CRATE_VERSION = System.getProperty("sbe.rust.crate.version"); static final String WRITE_BUF_TYPE = "WriteBuf"; static final String READ_BUF_TYPE = "ReadBuf"; static final String BUF_LIFETIME = "'a"; @@ -114,10 +115,11 @@ public void generate() throws IOException { namespace = (ir.namespaceName() + "_" + packageName).toLowerCase(); } + final String version = CRATE_VERSION == null ? "0.1.0" : CRATE_VERSION; indent(writer, 0, "[package]\n"); indent(writer, 0, "name = \"%s\"\n", namespace); - indent(writer, 0, "version = \"0.1.0\"\n"); + indent(writer, 0, "version = \"%s\"\n", version); indent(writer, 0, "authors = [\"sbetool\"]\n"); indent(writer, 0, "description = \"%s\"\n", ir.description()); indent(writer, 0, "edition = \"2021\"\n\n"); From 86d0adbc9d2560f703e8106aaadb8a172f14f54d Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 22 Aug 2024 13:40:56 +0100 Subject: [PATCH 404/805] Make new Rust sysprop usage consistent with others. --- .../src/main/java/uk/co/real_logic/sbe/SbeTool.java | 10 ++++++++++ .../sbe/generation/TargetCodeGeneratorLoader.java | 1 + .../real_logic/sbe/generation/rust/RustGenerator.java | 9 ++++++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index d65a6a4601..3d95be6172 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -150,6 +150,16 @@ public class SbeTool */ public static final String CPP_NAMESPACES_COLLAPSE = "sbe.cpp.namespaces.collapse"; + /** + * Version of the Rust crate to generate. + */ + public static final String RUST_CRATE_VERSION = "sbe.rust.crate.version"; + + /** + * The default version of the Rust crate to generate, when not specified via the system property. + */ + public static final String RUST_DEFAULT_CRATE_VERSION = "0.1.0"; + /** * Boolean system property to turn on or off generation of the interface hierarchy. Defaults to false. */ diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 2b2383dfd2..c031ad60a8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -142,6 +142,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) { return new RustGenerator( ir, + System.getProperty(RUST_CRATE_VERSION, RUST_DEFAULT_CRATE_VERSION), new RustOutputManager(outputDir, ir.packageName())); } }; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index c7a33c9cd6..9df137c80a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -48,7 +48,6 @@ */ public class RustGenerator implements CodeGenerator { - private static final String CRATE_VERSION = System.getProperty("sbe.rust.crate.version"); static final String WRITE_BUF_TYPE = "WriteBuf"; static final String READ_BUF_TYPE = "ReadBuf"; static final String BUF_LIFETIME = "'a"; @@ -81,21 +80,26 @@ interface ParentDef private final Ir ir; private final RustOutputManager outputManager; + private final String crateVersion; /** * Create a new Rust language {@link CodeGenerator}. * * @param ir for the messages and types. + * @param crateVersion for the generated crate. * @param outputManager for generating the codecs to. */ public RustGenerator( final Ir ir, + final String crateVersion, final OutputManager outputManager) { Verify.notNull(ir, "ir"); + Verify.notNull(crateVersion, "crateVersion"); Verify.notNull(outputManager, "outputManager"); this.ir = ir; + this.crateVersion = crateVersion; this.outputManager = (RustOutputManager)outputManager; } @@ -115,11 +119,10 @@ public void generate() throws IOException { namespace = (ir.namespaceName() + "_" + packageName).toLowerCase(); } - final String version = CRATE_VERSION == null ? "0.1.0" : CRATE_VERSION; indent(writer, 0, "[package]\n"); indent(writer, 0, "name = \"%s\"\n", namespace); - indent(writer, 0, "version = \"%s\"\n", version); + indent(writer, 0, "version = \"%s\"\n", crateVersion); indent(writer, 0, "authors = [\"sbetool\"]\n"); indent(writer, 0, "description = \"%s\"\n", ir.description()); indent(writer, 0, "edition = \"2021\"\n\n"); From 23e01477d56ef32d4de32b8084fcd2bab19d0fbd Mon Sep 17 00:00:00 2001 From: Nate Bradac <38217740+nbradac@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:20:36 -0400 Subject: [PATCH 405/805] [C] fix compliation error in C string view functions (#1010) --- .../co/real_logic/sbe/generation/c/CGenerator.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 7e597141fd..68afbb8283 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -613,7 +613,7 @@ private CharSequence generateVarData( " return ret;\n" + "}\n", propertyName, - generateStringViewNotPresentCondition(token.version()), + generateStringViewNotPresentCondition(token.version(), outermostStruct), lengthOfLengthField, lengthCType, structName, @@ -1032,7 +1032,9 @@ private static CharSequence generateArrayFieldNotPresentCondition(final int sinc sinceVersion); } - private static CharSequence generateStringViewNotPresentCondition(final int sinceVersion) + private static CharSequence generateStringViewNotPresentCondition( + final int sinceVersion, + final String outermostStruct) { if (0 == sinceVersion) { @@ -1042,9 +1044,11 @@ private static CharSequence generateStringViewNotPresentCondition(final int sinc return String.format( " if (codec->acting_version < %1$d)\n" + " {\n" + - " return { NULL, 0 };\n" + + " struct %2$s_string_view ret = { NULL, 0 };\n" + + " return ret;\n" + " }\n\n", - sinceVersion); + sinceVersion, + outermostStruct); } private static CharSequence generateTypeFieldNotPresentCondition(final int sinceVersion) From e7c1c2c20ccba5f56362023f8297a2c2e3785e09 Mon Sep 17 00:00:00 2001 From: Nate Bradac <38217740+nbradac@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:43:05 -0400 Subject: [PATCH 406/805] [C] add test to ensure generated C code properly compiles when versions are set (#1011) --- sbe-tool/src/test/c/CComplianceTest.c | 2 +- .../src/test/c/CComplianceWithVersionTest.c | 21 +++++ sbe-tool/src/test/c/CMakeLists.txt | 12 ++- .../code-generation-schema-with-version.xml | 93 +++++++++++++++++++ 4 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 sbe-tool/src/test/c/CComplianceWithVersionTest.c create mode 100644 sbe-tool/src/test/resources/code-generation-schema-with-version.xml diff --git a/sbe-tool/src/test/c/CComplianceTest.c b/sbe-tool/src/test/c/CComplianceTest.c index 9acbb22334..150edec6e5 100644 --- a/sbe-tool/src/test/c/CComplianceTest.c +++ b/sbe-tool/src/test/c/CComplianceTest.c @@ -21,6 +21,6 @@ #include "group_with_data/testMessage3.h" #include "group_with_data/testMessage4.h" -int main() +int main(void) { } diff --git a/sbe-tool/src/test/c/CComplianceWithVersionTest.c b/sbe-tool/src/test/c/CComplianceWithVersionTest.c new file mode 100644 index 0000000000..9156d58ce5 --- /dev/null +++ b/sbe-tool/src/test/c/CComplianceWithVersionTest.c @@ -0,0 +1,21 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "code_generation_test_version/car.h" +#include "code_generation_test_version/messageHeader.h" + +int main(void) +{ +} diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index 52bf553afd..e8ea222cf7 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -34,6 +34,7 @@ endfunction() find_package(Java REQUIRED) set(CODE_GENERATION_SCHEMA ${CODEC_SCHEMA_DIR}/code-generation-schema.xml) +set(CODE_GENERATION_SCHEMA_WITH_VERSION ${CODEC_SCHEMA_DIR}/code-generation-schema-with-version.xml) set(GROUP_WITH_DATA_SCHEMA ${CODEC_SCHEMA_DIR}/group-with-data-schema.xml) set(ISSUE889_SCHEMA ${CODEC_SCHEMA_DIR}/issue889.xml) @@ -43,13 +44,14 @@ set(GENERATED_CODECS add_custom_command( OUTPUT ${GENERATED_CODECS} - DEPENDS sbe-jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${GROUP_WITH_DATA_SCHEMA} ${ISSUE889_SCHEMA} + DEPENDS sbe-jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${CODE_GENERATION_SCHEMA_WITH_VERSION} ${GROUP_WITH_DATA_SCHEMA} ${ISSUE889_SCHEMA} COMMAND ${Java_JAVA_EXECUTABLE} -Dsbe.output.dir=${C_CODEC_TARGET_DIR} -Dsbe.target.language="C" -jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} + ${CODE_GENERATION_SCHEMA_WITH_VERSION} ${GROUP_WITH_DATA_SCHEMA} ${ISSUE889_SCHEMA} ) @@ -70,3 +72,11 @@ target_include_directories(CComplianceTest ) add_dependencies(CComplianceTest c_codecs) + +add_executable(CComplianceWithVersionTest CComplianceWithVersionTest.c) + +target_include_directories(CComplianceWithVersionTest + PRIVATE ${C_CODEC_TARGET_DIR} +) + +add_dependencies(CComplianceWithVersionTest c_codecs) diff --git a/sbe-tool/src/test/resources/code-generation-schema-with-version.xml b/sbe-tool/src/test/resources/code-generation-schema-with-version.xml new file mode 100644 index 0000000000..1ebd46c77a --- /dev/null +++ b/sbe-tool/src/test/resources/code-generation-schema-with-version.xml @@ -0,0 +1,93 @@ + + + + + + T + S + N + K + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 9000 + + Petrol + + + + 0 + 1 + + + A + B + C + + + 0 + 1 + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8d085e4f179bfeddd24758a6a248eb3276113c33 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 10:27:59 +0200 Subject: [PATCH 407/805] 1.32.2 release --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f1b6e31361..c78d39b8ed 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.33.0-SNAPSHOT +1.32.2 From 7c2305838f6c3f2737963b348384d404c2e6ada4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 10:28:11 +0200 Subject: [PATCH 408/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index c78d39b8ed..7341032ba0 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.32.2 +1.32.0-SNAPSHOT From 996014f9250456a60b25296f1e2633c4851bf7a8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:40:24 +0200 Subject: [PATCH 409/805] correct snapshot version --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 7341032ba0..f1b6e31361 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.32.0-SNAPSHOT +1.33.0-SNAPSHOT From ccddba964bd8dacaa01af62b8391f722b748ef5b Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:54:45 +0200 Subject: [PATCH 410/805] [Java] Upgrade to Gradle 8.10. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 62076 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 3 ++- gradlew | 27 ++++++++++++++--------- gradlew.bat | 22 +++++++++--------- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index c0741e6ab7..51b968361c 100644 --- a/build.gradle +++ b/build.gradle @@ -959,7 +959,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '8.1.1' + gradleVersion = '8.10' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c1962a79e29d3e0ab67b14947c167a862655af9b..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 62076 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8707e8b506..66cd5a0e49 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index aeb74cbb43..f5feea6d6b 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,7 +85,9 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -130,10 +134,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -141,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -149,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -198,11 +205,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 93e3f59f13..9d21a21834 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail From 286f583492071fedc93fe4bf7ab3745311f39561 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:56:32 +0200 Subject: [PATCH 411/805] [Java] Upgrade to Shadow 8.3.0. --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 51b968361c..353ada9da2 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { plugins { id 'java-library' id 'jvm-test-suite' - id 'com.github.johnrengelman.shadow' version '8.1.1' apply false + id 'com.gradleup.shadow' version '8.3.0' apply false id 'com.github.ben-manes.versions' version '0.51.0' } @@ -422,7 +422,7 @@ project(':sbe-tool') { project(':sbe-all') { apply plugin: 'maven-publish' apply plugin: 'signing' - apply plugin: 'com.github.johnrengelman.shadow' + apply plugin: 'com.gradleup.shadow' dependencies { implementation project(':sbe-tool') @@ -606,7 +606,7 @@ project(':sbe-samples') { } project(':sbe-benchmarks') { - apply plugin: 'com.github.johnrengelman.shadow' + apply plugin: 'com.gradleup.shadow' dependencies { implementation "org.openjdk.jmh:jmh-core:${jmhVersion}" From 81e92929e70adcfbc9ca76a89771d34262e4f2b4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:57:09 +0200 Subject: [PATCH 412/805] [Java] Upgrade to Mockito 5.12.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 353ada9da2..3510266529 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '3.0' -def mockitoVersion = '4.11.0' +def mockitoVersion = '5.12.0' def junitVersion = '5.11.0' def jqwikVersion = '1.9.0' def jsonVersion = '20240303' From 822c8929ba070ed495d030f1227ddce96d9b846f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:59:55 +0200 Subject: [PATCH 413/805] [Java] Set `sourceCompatibility = 17` and cleanup warnings. --- build.gradle | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index 3510266529..cb9cf10fe7 100644 --- a/build.gradle +++ b/build.gradle @@ -185,6 +185,7 @@ subprojects { toolchain { languageVersion = JavaLanguageVersion.of(buildJavaVersion) } + sourceCompatibility = 17 } checkstyle.toolVersion = "${checkstyleVersion}" @@ -214,18 +215,13 @@ subprojects { options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' options.links("https://www.javadoc.io/doc/org.agrona/agrona/${agronaVersion}/") - if (buildJavaVersion > 21) { // early access JavaDoc location is different + if (buildJavaVersion >= 23) { // early access JavaDoc location is different options.links("https://download.java.net/java/early_access/jdk${buildJavaVersion}/docs/api/") } - else if (buildJavaVersion >= 11) { - options.links("https://docs.oracle.com/en/java/javase/${buildJavaVersion}/docs/api/") - } else { - options.links("https://docs.oracle.com/javase/${buildJavaVersion}/docs/api/") - } - if (buildJavaVersion >= 10) { - options.addBooleanOption 'html5', true + options.links("https://docs.oracle.com/en/java/javase/${buildJavaVersion}/docs/api/") } + options.addBooleanOption('html5', true) } testing { @@ -274,7 +270,7 @@ project(':sbe-tool') { } } - def generatedDir = 'build/generated-src' + def generatedDir = "${layout.buildDirectory.get()}/generated-src" sourceSets { generated { java.srcDir generatedDir @@ -909,7 +905,7 @@ tasks.register('runJavaBenchmarks', Exec) { } tasks.register('testReport', TestReport) { - destinationDirectory = file("$buildDir/reports/allTests") + destinationDirectory = file("${layout.buildDirectory.get()}/reports/allTests") // Include the results from the `test` task in all sub-projects testResults.setFrom(subprojects*.test) } From c5d5cdfd5f01a289bf9c82eddeb80e30814638ab Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:06:16 +0200 Subject: [PATCH 414/805] [CI] Remove JDK 8 + switch to Ubuntu 24.04 and latest compilers. --- .github/workflows/ci.yml | 48 +++++++++++++++++------------------ .github/workflows/codeql.yml | 6 ++--- .github/workflows/release.yml | 4 +-- .github/workflows/slow.yml | 4 +-- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20b3fd4413..588b7bc568 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,8 +29,8 @@ jobs: strategy: fail-fast: false matrix: - java: [ '8', '17', '21' ] - os: [ 'ubuntu-22.04', 'windows-latest' ] + java: [ '17', '21' ] + os: [ 'ubuntu-24.04', 'windows-latest' ] steps: - name: Checkout code uses: actions/checkout@v4 @@ -62,13 +62,13 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Build with Gradle run: ./gradlew csharp-build: name: C# ${{ matrix.dotnet }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -97,7 +97,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Cache NuGet dependencies uses: actions/cache@v4 with: @@ -154,17 +154,17 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Build run: ./cppbuild/cppbuild - cpp-gcc-2204-build: - name: C++ GCC ${{ matrix.version }} (Ubuntu 22.04) - runs-on: ubuntu-22.04 + cpp-gcc-2404-build: + name: C++ GCC ${{ matrix.version }} (Ubuntu 24.04) + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: - version: [ '11', '12', '13' ] + version: [ '11', '12', '13', '14' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} @@ -197,7 +197,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Build run: ./cppbuild/cppbuild @@ -242,17 +242,17 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Build run: ./cppbuild/cppbuild - cpp-clang-2204-build: - name: C++ Clang ${{ matrix.version }} (Ubuntu 22.04) - runs-on: ubuntu-22.04 + cpp-clang-2404-build: + name: C++ Clang ${{ matrix.version }} (Ubuntu 24.04) + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: - version: [ '13', '14', '15', '16', '17' ] + version: [ '13', '14', '15', '16', '17', '18' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} @@ -287,7 +287,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Build run: ./cppbuild/cppbuild @@ -297,7 +297,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'macos-14' ] + os: [ 'macos-latest' ] env: CC: clang CXX: clang++ @@ -327,7 +327,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -368,13 +368,13 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Build run: cppbuild/cppbuild.cmd rust-build: name: Rust ${{ matrix.rust }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -406,12 +406,12 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - run: ./gradlew runRustTests golang-build: name: Golang ${{ matrix.version }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: @@ -441,7 +441,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Generate codecs run: ./gradlew generateGolangCodecs - name: Go diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 63bb4b11c8..c91468d27f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -25,7 +25,7 @@ jobs: java-analyze: name: Java Analyze ${{ matrix.java }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 permissions: actions: read contents: read @@ -80,7 +80,7 @@ jobs: csharp-analyze: name: C# Analyze ${{ matrix.dotnet }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 permissions: actions: read contents: read @@ -138,7 +138,7 @@ jobs: cpp-gcc-2204-analyze: name: C++ GCC Analyze ${{ matrix.version }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 permissions: actions: read contents: read diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ce363e17c..c34e4a7408 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,7 +37,7 @@ jobs: contents: write packages: write needs: [ ci , codeql, slow ] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@v4 @@ -55,7 +55,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION run: | java -Xinternalversion diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 9b4b0c22b0..9fc75825c0 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -21,7 +21,7 @@ permissions: jobs: property-tests: name: Property tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: java: [ '21' ] @@ -46,7 +46,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'zulu' - java-version: 8 + java-version: 17 - name: Setup dotnet uses: actions/setup-dotnet@v2 with: From 97e7b4831ecb710dfb3181bb9eef26464a7c7ee2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:19:12 +0200 Subject: [PATCH 415/805] [CI] Debug. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 588b7bc568..5333c4d700 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: distribution: 'zulu' java-version: 17 - name: Build with Gradle - run: ./gradlew + run: ./gradlew --stacktrace csharp-build: name: C# ${{ matrix.dotnet }} From 12a3ad0cb586e692fb1c38004d3feb4313f1ecd1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:27:04 +0200 Subject: [PATCH 416/805] [Java] Fix Gradle warning. --- settings.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/settings.gradle b/settings.gradle index 72d590e400..19ec0d7679 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ include 'sbe-tool', 'sbe-samples', 'sbe-benchmarks', 'sbe-all' rootProject.name = 'sbe' +project(':sbe-all').projectDir.mkdirs() From af090dad060da9157101fd3bc8b3851a85a451da Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:31:00 +0200 Subject: [PATCH 417/805] [CI] Add `macos-latest` to the build matrix. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5333c4d700..cf3ce2d344 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: fail-fast: false matrix: java: [ '17', '21' ] - os: [ 'ubuntu-24.04', 'windows-latest' ] + os: [ 'ubuntu-24.04', 'windows-latest', 'macos-latest' ] steps: - name: Checkout code uses: actions/checkout@v4 From 287adb5ece9ed0a51039498214d557605fb532a6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:31:58 +0200 Subject: [PATCH 418/805] [CI] Fix CodeQL build. --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c91468d27f..757fb40381 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -34,7 +34,7 @@ jobs: fail-fast: false matrix: language: [ 'java' ] - java: [ '8' ] + java: [ '17' ] steps: - name: Checkout code @@ -136,7 +136,7 @@ jobs: with: category: "/language:${{matrix.language}}" - cpp-gcc-2204-analyze: + cpp-gcc-analyze: name: C++ GCC Analyze ${{ matrix.version }} runs-on: ubuntu-24.04 permissions: @@ -147,7 +147,7 @@ jobs: fail-fast: false matrix: language: ['cpp'] - version: [ '12' ] + version: [ '14' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} From 57d73bfd32a9ff859ff64d58f41eab01ee516994 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:39:34 +0200 Subject: [PATCH 419/805] [CI] Try CodeQL without version. --- .github/workflows/codeql.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 757fb40381..459f3a29bd 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -34,7 +34,6 @@ jobs: fail-fast: false matrix: language: [ 'java' ] - java: [ '17' ] steps: - name: Checkout code From c7dd79dd22c31a0344e37d9fee8433743bdebcf6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:43:14 +0200 Subject: [PATCH 420/805] [CI] CodeQL java. --- .github/workflows/codeql.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 459f3a29bd..3e6fa7be22 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -56,21 +56,21 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: ${{ matrix.java }} + java-version: 17 - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION run: | java -Xinternalversion echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - + + - name: Build with Gradle + run: ./gradlew + - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml - - - name: Build with Gradle - run: ./gradlew - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 From b5df1f881ddf54504d77b07ded762f82dda9fdda Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:47:19 +0200 Subject: [PATCH 421/805] [CI] Move the compilation to the right phase. --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3e6fa7be22..5c2089713a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -63,15 +63,15 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - - name: Build with Gradle - run: ./gradlew - - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml + - name: Build with Gradle + run: ./gradlew + - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: From b713baf7b2e618ebb9516610b367de1e084475a3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:56:03 +0200 Subject: [PATCH 422/805] [CI] Simplify. --- .github/workflows/codeql.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5c2089713a..8684a7bd54 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -34,6 +34,7 @@ jobs: fail-fast: false matrix: language: [ 'java' ] + java: [ '17' ] steps: - name: Checkout code @@ -56,12 +57,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 - - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION - run: | - java -Xinternalversion - echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV - echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV + java-version: ${{ matrix.java }} - name: Initialize CodeQL uses: github/codeql-action/init@v3 From 4e9689671f3367b3cac627cce3850ea450c25936 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:02:37 +0200 Subject: [PATCH 423/805] [CI] Try CodeQL workaround. --- .github/workflows/codeql.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8684a7bd54..b4ddb31dba 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -17,6 +17,7 @@ concurrency: env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' CMAKE_VERSION: '3.14.7' + JAVA_TOOL_OPTIONS: "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED" permissions: contents: read From ff0b993b8573afbcedfd9ff0bf0de6081c3ffa8c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:02:49 +0200 Subject: [PATCH 424/805] [Java] Use layout. --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index cb9cf10fe7..0f31db6c71 100644 --- a/build.gradle +++ b/build.gradle @@ -294,7 +294,7 @@ project(':sbe-tool') { suites { test { dependencies { - implementation files('build/classes/java/generated') + implementation files("${layout.buildDirectory.get()}/classes/java/generated") implementation "org.hamcrest:hamcrest:${hamcrestVersion}" implementation "org.mockito:mockito-core:${mockitoVersion}" implementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" @@ -491,7 +491,7 @@ project(':sbe-samples') { dependencies { api project(':sbe-tool') - implementation files('build/classes/java/generated') + implementation files("${layout.buildDirectory.get()}/classes/java/generated") } def generatedDir = 'build/generated-src' @@ -608,7 +608,7 @@ project(':sbe-benchmarks') { implementation "org.openjdk.jmh:jmh-core:${jmhVersion}" annotationProcessor "org.openjdk.jmh:jmh-generator-annprocess:${jmhVersion}" implementation project(':sbe-tool') - implementation files('build/classes/java/generated') + implementation files("${layout.buildDirectory.get()}/classes/java/generated") } sourceSets { From 9bee1597871533c2206172ca32f47974d4d63be2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:09:25 +0200 Subject: [PATCH 425/805] [CI] Remove CMake installation step. --- .github/workflows/ci.yml | 44 ++++++++---------------------------- .github/workflows/codeql.yml | 6 +---- .github/workflows/slow.yml | 2 +- 3 files changed, 12 insertions(+), 40 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf3ce2d344..5bc6da223f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,6 @@ concurrency: env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' - CMAKE_VERSION: '3.14.7' permissions: contents: read @@ -58,7 +57,7 @@ jobs: java -Xinternalversion echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -93,7 +92,7 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -147,10 +146,7 @@ jobs: run: | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ bionic main universe" sudo apt-get install -y g++-${{ matrix.version }} libsparsehash-dev libidn11 - curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -190,10 +186,7 @@ jobs: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install -y g++-${{ matrix.version }} - curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -235,10 +228,7 @@ jobs: echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 - curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -280,10 +270,7 @@ jobs: echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} - curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -318,12 +305,7 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - - name: Install CMake - run: | - curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz - tar xf cmake-${CMAKE_VERSION}-Darwin-x86_64.tar.gz - echo "cmake-${CMAKE_VERSION}-Darwin-x86_64/CMake.app/Contents/bin" >> $GITHUB_PATH - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -358,13 +340,7 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - - name: Install CMake - run: | - $client = new-object System.Net.WebClient - $client.DownloadFile("https://github.com/Kitware/CMake/releases/download/v$Env:CMAKE_VERSION/cmake-$Env:CMAKE_VERSION-win64-x64.zip","cmake-$Env:CMAKE_VERSION-win64-x64.zip") - 7z x cmake-$Env:CMAKE_VERSION-win64-x64.zip - echo "cmake-$Env:CMAKE_VERSION-win64-x64/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -402,7 +378,7 @@ jobs: profile: minimal toolchain: ${{ matrix.rust }} override: true - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' @@ -437,7 +413,7 @@ jobs: uses: actions/setup-go@v4 with: go-version: ${{ matrix.version }} - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b4ddb31dba..5942820cc6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -16,7 +16,6 @@ concurrency: env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' - CMAKE_VERSION: '3.14.7' JAVA_TOOL_OPTIONS: "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED" permissions: @@ -167,10 +166,7 @@ jobs: - name: Install compiler run: | sudo apt-get install -y g++-${{ matrix.version }} - curl -O -L https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - tar xf cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz - echo "cmake-${CMAKE_VERSION}-Linux-x86_64/bin" >> $GITHUB_PATH - + - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 9fc75825c0..e67cd05af7 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -42,7 +42,7 @@ jobs: java -Xinternalversion echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - - name: Setup java 8 to run the Gradle script + - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v3 with: distribution: 'zulu' From 0e99110b6467ae59c87a2ba540fabe0f88bb07ca Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 21:35:06 +0200 Subject: [PATCH 426/805] [Java] Use `Set.of` instead of `HashSet<>(Arrays.asList(...))`. --- .../uk/co/real_logic/sbe/ValidationUtil.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index 3ba64ef105..74e58e3f5a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -15,8 +15,6 @@ */ package uk.co.real_logic.sbe; -import java.util.Arrays; -import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; @@ -27,7 +25,7 @@ public class ValidationUtil { private static final Pattern PATTERN = Pattern.compile("\\."); - private static final Set C_KEYWORDS = new HashSet<>(Arrays.asList( + private static final Set C_KEYWORDS = Set.of( "auto", "_Alignas", "_Alignof", "_Atomic", "bool", "_Bool", "break", "case", "_Complex", "char", "const", "continue", "default", @@ -36,7 +34,7 @@ public class ValidationUtil "int", "long", "_Noreturn", "register", "restrict", "return", "short", "signed", "sizeof", "static", "_Static_assert", "struct", "switch", "_Thread_local", "true", "typedef", "union", - "unsigned", "void", "volatile", "wchar_t", "while")); + "unsigned", "void", "volatile", "wchar_t", "while"); /** * Check value for validity of usage as a C identifier. A programmatic variable @@ -114,7 +112,7 @@ private static boolean isSbeCIdentifierPart(final char c) return Character.isLetterOrDigit(c) || c == '_'; } - private static final Set CPP_KEYWORDS = new HashSet<>(Arrays.asList( + private static final Set CPP_KEYWORDS = Set.of( "alignas", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "class", "compl", "const", @@ -134,7 +132,7 @@ private static boolean isSbeCIdentifierPart(final char c) // since C++11 "alignof", "constexpr", "decltype", "nullptr", "static_assert", "thread_local", // since C++11 have special meaning, so avoid - "final")); + "final"); /** * Check value for validity of usage as a C++ identifier. A programmatic variable @@ -212,7 +210,7 @@ private static boolean isSbeCppIdentifierPart(final char c) return Character.isLetterOrDigit(c) || c == '_'; } - private static final Set JAVA_KEYWORDS = new HashSet<>(Arrays.asList( + private static final Set JAVA_KEYWORDS = Set.of( "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", @@ -223,7 +221,7 @@ private static boolean isSbeCppIdentifierPart(final char c) "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", - "null", "true", "false", "_")); + "null", "true", "false", "_"); /** * Check string for validity of usage as a Java identifier. Avoiding keywords. @@ -292,7 +290,7 @@ private static boolean isJavaIdentifier(final String token) } /* https://golang.org/ref/spec#Keywords */ - private static final Set GOLANG_KEYWORDS = new HashSet<>(Arrays.asList( + private static final Set GOLANG_KEYWORDS = Set.of( "break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", @@ -310,7 +308,7 @@ private static boolean isJavaIdentifier(final String token) "nil", /* functions */ "append", "cap", "close", "complex", "copy", "delete", "imag", "len", - "make", "new", "panic", "print", "println", "real", "recover")); + "make", "new", "panic", "print", "println", "real", "recover"); /** * "Check" value for validity of usage as a golang identifier. From: @@ -398,7 +396,7 @@ private static boolean isSbeGolangIdentifierPart(final char c) * Note this does not include the contextual keywords * Note "virtual" is no longer but was in early versions of C# */ - private static final Set CSHARP_KEYWORDS = new HashSet<>(Arrays.asList( + private static final Set CSHARP_KEYWORDS = Set.of( "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", @@ -414,7 +412,7 @@ private static boolean isSbeGolangIdentifierPart(final char c) "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "using static", "virtual", - "void", "volatile", "while")); + "void", "volatile", "while"); /** * "Check" value for validity of usage as a csharp identifier. From 9892b15bb99dbf05ca032e8507aa0e3d1680ee88 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:27:07 +0200 Subject: [PATCH 427/805] [Java] Upgrade to Agrona 1.23.0. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 0f31db6c71..16ddc10efe 100644 --- a/build.gradle +++ b/build.gradle @@ -61,8 +61,8 @@ def junitVersion = '5.11.0' def jqwikVersion = '1.9.0' def jsonVersion = '20240303' def jmhVersion = '1.37' -def agronaVersion = '1.22.0' -def agronaVersionRange = '[1.22.0,2.0[' // allow any release >= 1.22.0 and < 2.0.0 +def agronaVersion = '1.23.0' +def agronaVersionRange = '[1.23.0,2.0[' // allow any release >= 1.23.0 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From d0c2fbec8e58da0c91c8685eb890f9d190fdabe8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:27:29 +0200 Subject: [PATCH 428/805] 1.33.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f1b6e31361..7aa332e416 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.33.0-SNAPSHOT +1.33.0 From 7bf33de90a20ad41862eba538961db25310bf026 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:27:40 +0200 Subject: [PATCH 429/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 7aa332e416..6214e03b71 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.33.0 +1.34.0-SNAPSHOT From ded4e486b8dd6312eaa20991491cc5872669fae6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:28:24 +0200 Subject: [PATCH 430/805] [Java] Use type-safe version. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 16ddc10efe..48da2f29e0 100644 --- a/build.gradle +++ b/build.gradle @@ -185,7 +185,7 @@ subprojects { toolchain { languageVersion = JavaLanguageVersion.of(buildJavaVersion) } - sourceCompatibility = 17 + sourceCompatibility = JavaVersion.VERSION_17 } checkstyle.toolVersion = "${checkstyleVersion}" From ce67429d152a0ecd7c32f5865771c2945e7e7156 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:48:23 +0200 Subject: [PATCH 431/805] [CI] Fix publish workflow. --- .github/workflows/release.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c34e4a7408..837f2eaf09 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,11 +56,6 @@ jobs: with: distribution: 'zulu' java-version: 17 - - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION - run: | - java -Xinternalversion - echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV - echo "BUILD_JAVA_VERSION=8" >> $GITHUB_ENV - name: Publish with Gradle run: ./gradlew publish env: From 844bca43ebc87f06e8b8dfa9404c07a3d981ea04 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:48:42 +0200 Subject: [PATCH 432/805] 1.33.0 released v2. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6214e03b71..7aa332e416 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.34.0-SNAPSHOT +1.33.0 From f9baab6caff7d424ce3761d993b06e0f96ed4f2d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 23 Aug 2024 23:48:54 +0200 Subject: [PATCH 433/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 7aa332e416..6214e03b71 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.33.0 +1.34.0-SNAPSHOT From 95f353bc1887089099c6b6b79ac02e339ccf6892 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 24 Aug 2024 11:56:52 +0200 Subject: [PATCH 434/805] [Java] Simplify versioning. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 48da2f29e0..2bc3c8d4e2 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ def jqwikVersion = '1.9.0' def jsonVersion = '20240303' def jmhVersion = '1.37' def agronaVersion = '1.23.0' -def agronaVersionRange = '[1.23.0,2.0[' // allow any release >= 1.23.0 and < 2.0.0 +def agronaVersionRange = "[${agronaVersion},2.0[" def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From 0d13aea3ec9d8cb810bef5bc62dbd402ff845a9a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 24 Aug 2024 12:02:19 +0200 Subject: [PATCH 435/805] [Java] Use JUnit BOM. --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2bc3c8d4e2..85d7a38edf 100644 --- a/build.gradle +++ b/build.gradle @@ -297,7 +297,8 @@ project(':sbe-tool') { implementation files("${layout.buildDirectory.get()}/classes/java/generated") implementation "org.hamcrest:hamcrest:${hamcrestVersion}" implementation "org.mockito:mockito-core:${mockitoVersion}" - implementation "org.junit.jupiter:junit-jupiter-params:${junitVersion}" + implementation platform("org.junit:junit-bom:${junitVersion}") + implementation "org.junit.jupiter:junit-jupiter-params" } } From 2f5e8ab3d1d5fb024e5d5296fee3a97a7889adf8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 26 Aug 2024 17:21:24 +0200 Subject: [PATCH 436/805] [Java] Upgrade to Checkstyle 10.18.0. --- build.gradle | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 85d7a38edf..6328a54f99 100644 --- a/build.gradle +++ b/build.gradle @@ -54,7 +54,7 @@ def toolchainLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(buildJavaVersion) } -def checkstyleVersion = '9.3' +def checkstyleVersion = '10.18.0' def hamcrestVersion = '3.0' def mockitoVersion = '5.12.0' def junitVersion = '5.11.0' @@ -163,6 +163,11 @@ allprojects { configurations.configureEach { resolutionStrategy { failOnVersionConflict() + // patching conflicting Checkstyle dependencies + force "org.codehaus.plexus:plexus-utils:3.3.0", + "org.apache.commons:commons-lang3:3.8.1", + "org.apache.httpcomponents:httpcore:4.4.14", + "commons-codec:commons-codec:1.15" } } From bb984d44205c77998fd3a8505beadd9e9f02fc3c Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 30 Aug 2024 11:37:41 +0100 Subject: [PATCH 437/805] [Java] Fix #1012 DTO char array setter visibility. Previously, the setter was generated as package-private rather than public. --- .../uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index 4b8ceb876d..9b22f240f6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -1359,7 +1359,7 @@ private void generateArrayProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("void ").append(formattedPropertyName) + .append(indent).append("public void ").append(formattedPropertyName) .append("(").append(typeName).append(" value)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(validateMethod).append("(value);\n") From e0846a80d24f26b5d1ab0b1394285ba45aad14a0 Mon Sep 17 00:00:00 2001 From: Grzegorz Gierlach Date: Sun, 1 Sep 2024 11:56:16 +0200 Subject: [PATCH 438/805] [Rust] Indicate the anonymous lifetime in set's Display impl. (#1014) --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 9df137c80a..5ed04fc9fb 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1112,7 +1112,7 @@ private static void generateSingleBitSet( indent(writer, 0, "impl core::fmt::Debug for %s {\n", bitSetType); indent(writer, 1, "#[inline]\n"); - indent(writer, 1, "fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {\n"); + indent(writer, 1, "fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n"); indent(writer, 2, "write!(fmt, \"%s[", bitSetType); final StringBuilder builder = new StringBuilder(); From eca18dd4ab61b275927fc9bc68fbe050851ea6a1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 1 Sep 2024 12:01:41 +0200 Subject: [PATCH 439/805] [Java] Upgrade to JUnit 5.13.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6328a54f99..242fbb845b 100644 --- a/build.gradle +++ b/build.gradle @@ -56,7 +56,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '10.18.0' def hamcrestVersion = '3.0' -def mockitoVersion = '5.12.0' +def mockitoVersion = '5.13.0' def junitVersion = '5.11.0' def jqwikVersion = '1.9.0' def jsonVersion = '20240303' From 99db7a8434fbba6dac9d5f7fbb510833cccd1d93 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Mon, 2 Sep 2024 12:03:47 +0100 Subject: [PATCH 440/805] [Java] Style consistency and add JavadocVariable Checkstyle test. --- config/checkstyle/checkstyle.xml | 3 ++ config/checkstyle/suppressions.xml | 1 + .../sbe/properties/DtosPropertyTest.java | 17 +++---- .../sbe/properties/JsonPropertyTest.java | 5 +-- .../sbe/properties/ParserPropertyTest.java | 1 - .../arbitraries/SbeArbitraries.java | 7 ++- .../schema/CompositeTypeSchema.java | 2 - .../schema/EncodedDataTypeSchema.java | 7 +-- .../sbe/properties/schema/EnumTypeSchema.java | 2 - .../sbe/properties/schema/FieldSchema.java | 4 +- .../sbe/properties/schema/GroupSchema.java | 2 - .../sbe/properties/schema/MessageSchema.java | 1 - .../sbe/properties/schema/SetSchema.java | 2 - .../schema/TestXmlSchemaWriter.java | 45 +++++++------------ .../sbe/properties/schema/TypeSchema.java | 1 - .../properties/schema/TypeSchemaVisitor.java | 1 - .../sbe/properties/schema/VarDataSchema.java | 1 - .../utils/InMemoryOutputManager.java | 12 +---- 18 files changed, 36 insertions(+), 78 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 4f40d0b3fa..f34d3bd2e5 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -33,6 +33,9 @@ + + + diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 2823a9547e..b7a043008b 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -7,5 +7,6 @@ + diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index b21ba27674..93508ad709 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -64,8 +64,8 @@ public class DtosPropertyTest @Property void javaDtoEncodeShouldBeTheInverseOfDtoDecode( @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage, - final Footnotes footnotes - ) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + final Footnotes footnotes) + throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { final String packageName = encodedMessage.ir().applicableNamespace(); @@ -136,8 +136,8 @@ void javaDtoEncodeShouldBeTheInverseOfDtoDecode( @Property void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage, - final Footnotes footnotes - ) throws IOException, InterruptedException + final Footnotes footnotes) + throws IOException, InterruptedException { final Path tempDir = Files.createTempDirectory("sbe-csharp-dto-test"); @@ -201,17 +201,14 @@ void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( @Property(shrinking = ShrinkingMode.OFF) void cppDtoEncodeShouldBeTheInverseOfDtoDecode( @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage, - final Footnotes footnotes - ) throws IOException, InterruptedException + final Footnotes footnotes) throws IOException, InterruptedException { final Path tempDir = Files.createTempDirectory("sbe-cpp-dto-test"); try { final NamespaceOutputManager outputManager = new NamespaceOutputManager( - tempDir.toString(), - "sbe_property_test" - ); + tempDir.toString(), "sbe_property_test"); try { @@ -244,7 +241,7 @@ void cppDtoEncodeShouldBeTheInverseOfDtoDecode( { throw new AssertionError( "Input and output files differ\n\n" + - "SCHEMA:\n" + encodedMessage.schema()); + "SCHEMA:\n" + encodedMessage.schema()); } } catch (final Throwable throwable) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java index a9b8cd0987..f3d49fbbe7 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties; import net.jqwik.api.Arbitrary; @@ -29,9 +28,7 @@ public class JsonPropertyTest { @Property - void shouldGenerateValidJson( - @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage - ) + void shouldGenerateValidJson(@ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage) { final StringBuilder output = new StringBuilder(); final JsonPrinter printer = new JsonPrinter(encodedMessage.ir()); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java index 1b59dca624..3be05c85ae 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties; import net.jqwik.api.Arbitrary; diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index a47a93eabf..b8543b0abd 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.arbitraries; import net.jqwik.api.Arbitraries; @@ -268,9 +267,7 @@ private static Arbitrary varDataSchema() (short)0, (short)0, (short)1, - (short)2 - ) - ); + (short)2)); } public static Arbitrary messageSchema() @@ -352,8 +349,10 @@ public static CharacterArbitrary chars(final CharGenerationMode mode) { case UNRESTRICTED: return Arbitraries.chars(); + case JSON_PRINTER_COMPATIBLE: return Arbitraries.chars().alpha(); + default: throw new IllegalArgumentException("Unsupported mode: " + mode); } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java index 06123ffc9f..264a49219d 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; import java.util.List; @@ -32,7 +31,6 @@ public List fields() return fields; } - @Override public void accept(final TypeSchemaVisitor visitor) { visitor.onComposite(this); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java index 7abc254e0b..ea9d3228bb 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; import uk.co.real_logic.sbe.PrimitiveType; @@ -30,8 +29,7 @@ public EncodedDataTypeSchema( final PrimitiveType primitiveType, final int length, final Encoding.Presence presence, - final boolean isEmbedded - ) + final boolean isEmbedded) { this.primitiveType = primitiveType; this.length = length; @@ -54,16 +52,13 @@ public Encoding.Presence presence() return presence; } - @Override public boolean isEmbedded() { return isEmbedded; } - @Override public void accept(final TypeSchemaVisitor visitor) { visitor.onEncoded(this); } - } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java index fa28ef0a3a..b129e54c71 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; import java.util.List; @@ -41,7 +40,6 @@ public List validValues() return validValues; } - @Override public void accept(final TypeSchemaVisitor visitor) { visitor.onEnum(this); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java index 9745b042a1..1cf9cc2ccf 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; import uk.co.real_logic.sbe.ir.Encoding; @@ -27,8 +26,7 @@ public final class FieldSchema public FieldSchema( final TypeSchema type, final Encoding.Presence presence, - final short sinceVersion - ) + final short sinceVersion) { assert sinceVersion == 0 || presence.equals(Encoding.Presence.OPTIONAL); this.type = type; diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java index 2aa3dcd3c3..c0fafb0dbf 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; import java.util.Comparator; @@ -54,5 +53,4 @@ public List varData() { return varData; } - } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java index d992d6559f..edde5e89b6 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; import java.util.Comparator; diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java index 5acbc9da40..071f8e7419 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; import java.util.Set; @@ -41,7 +40,6 @@ public Set choices() return choices; } - @Override public void accept(final TypeSchemaVisitor visitor) { visitor.onSet(this); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index b7e3d6f8c1..faeaab331b 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -13,20 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; -import uk.co.real_logic.sbe.ir.Encoding; import org.agrona.collections.MutableInteger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; +import uk.co.real_logic.sbe.ir.Encoding; -import java.io.File; -import java.io.StringWriter; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; @@ -34,6 +28,11 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import java.io.File; +import java.io.StringWriter; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; import static java.util.Objects.requireNonNull; @@ -81,8 +80,7 @@ private static void writeTo( final TypeSchemaConverter typeSchemaConverter = new TypeSchemaConverter( document, topLevelTypes, - typeToName - ); + typeToName); final Set visitedTypes = new HashSet<>(); appendTypes( @@ -197,15 +195,13 @@ private static Element createTypesElement(final Document document) createTypeElement(document, "blockLength", "uint16"), createTypeElement(document, "templateId", "uint16"), createTypeElement(document, "schemaId", "uint16"), - createTypeElement(document, "version", "uint16") - )); + createTypeElement(document, "version", "uint16"))); types.appendChild(createCompositeElement( document, "groupSizeEncoding", createTypeElement(document, "blockLength", "uint16"), - createTypeElement(document, "numInGroup", "uint16") - )); + createTypeElement(document, "numInGroup", "uint16"))); return types; } @@ -256,8 +252,7 @@ private static Element createEnumElement( private static Element createCompositeElement( final Document document, final String name, - final Element... types - ) + final Element... types) { final Element composite = document.createElement("composite"); composite.setAttribute("name", name); @@ -377,10 +372,9 @@ private TypeSchemaConverter( this.document = document; this.topLevelTypes = topLevelTypes; this.typeToName = typeToName; - nextName = ignored -> "Type" + typeToName.size(); + nextName = (ignored) -> "Type" + typeToName.size(); } - @Override public void onEncoded(final EncodedDataTypeSchema type) { result = createTypeElement( @@ -392,7 +386,6 @@ public void onEncoded(final EncodedDataTypeSchema type) ); } - @Override public void onComposite(final CompositeTypeSchema type) { final Element[] members = type.fields().stream() @@ -403,14 +396,13 @@ public void onComposite(final CompositeTypeSchema type) final Element member = members[i]; member.setAttribute("name", "member" + i + "Of" + member.getAttribute("name")); } + result = createCompositeElement( document, typeToName.computeIfAbsent(type, nextName), - members - ); + members); } - @Override public void onEnum(final EnumTypeSchema type) { result = createEnumElement( @@ -421,15 +413,13 @@ public void onEnum(final EnumTypeSchema type) ); } - @Override public void onSet(final SetSchema type) { result = createSetElement( document, typeToName.computeIfAbsent(type, nextName), type.encodingType(), - type.choices() - ); + type.choices()); } private Element embedOrReference(final TypeSchema type) @@ -464,8 +454,8 @@ public Element convert(final TypeSchema type) public Node convert(final VarDataSchema varData) { - final Element lengthElement = createTypeElement(document, "length", - varData.lengthEncoding().primitiveName()); + final Element lengthElement = createTypeElement( + document, "length", varData.lengthEncoding().primitiveName()); if (varData.lengthEncoding().size() >= 4) { @@ -484,8 +474,7 @@ public Node convert(final VarDataSchema varData) document, typeToName.computeIfAbsent(varData, nextName), lengthElement, - varDataElement - ); + varDataElement); } } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java index ca236a0673..4a359fa6be 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; public interface TypeSchema diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java index 2651febfc7..7dbc69188f 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; public interface TypeSchemaVisitor diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java index 1bfd64621d..a4298e89e7 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.schema; import uk.co.real_logic.sbe.PrimitiveType; diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java index a17f74914e..dc8482c525 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package uk.co.real_logic.sbe.properties.utils; import org.agrona.generation.DynamicPackageOutputManager; +import javax.tools.*; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringWriter; @@ -26,7 +26,6 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.*; -import javax.tools.*; /** * An implementation of {@link DynamicPackageOutputManager} that stores generated source code in memory and compiles it @@ -43,13 +42,11 @@ public InMemoryOutputManager(final String packageName) this.packageName = packageName; } - @Override public Writer createOutput(final String name) { return new InMemoryWriter(name); } - @Override public void setPackageName(final String packageName) { packageNameOverride = packageName; @@ -71,8 +68,7 @@ public URLClassLoader compileGeneratedSources() null, null, null, - sourceFiles.values() - ); + sourceFiles.values()); if (!task.call()) { @@ -106,7 +102,6 @@ class InMemoryWriter extends StringWriter this.name = name; } - @Override public void close() throws IOException { super.close(); @@ -135,7 +130,6 @@ static class InMemoryFileManager extends ForwardingJavaFileManager Date: Tue, 10 Sep 2024 00:29:04 +0200 Subject: [PATCH 441/805] [Java] Upgrade to Gradle 8.10.1. --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 242fbb845b..40ea2a3d45 100644 --- a/build.gradle +++ b/build.gradle @@ -961,7 +961,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '8.10' + gradleVersion = '8.10.1' distributionType = 'ALL' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 66cd5a0e49..1ed247ec13 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 159a03f2a2c7e3621d87927ad06869fb569de6f2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:40:39 +0200 Subject: [PATCH 442/805] [Java] Upgrade to Shadow 8.3.1. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 40ea2a3d45..d86c838098 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ buildscript { plugins { id 'java-library' id 'jvm-test-suite' - id 'com.gradleup.shadow' version '8.3.0' apply false + id 'com.gradleup.shadow' version '8.3.1' apply false id 'com.github.ben-manes.versions' version '0.51.0' } From 4d4d6e4a6687a5327066e1cfd318e359365202a5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:53:36 +0200 Subject: [PATCH 443/805] [Java] Use version catalogs. --- build.gradle | 54 ++++++++++----------------------------- gradle/libs.versions.toml | 18 +++++++++++++ 2 files changed, 32 insertions(+), 40 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/build.gradle b/build.gradle index d86c838098..454e2f1e0f 100644 --- a/build.gradle +++ b/build.gradle @@ -18,22 +18,11 @@ import java.nio.file.Files import java.nio.file.StandardOpenOption import java.security.MessageDigest -buildscript { - repositories { - gradlePluginPortal() - mavenCentral() - } - dependencies { - classpath 'org.ow2.asm:asm:9.7' - classpath 'org.ow2.asm:asm-commons:9.7' - } -} - plugins { id 'java-library' id 'jvm-test-suite' - id 'com.gradleup.shadow' version '8.3.1' apply false - id 'com.github.ben-manes.versions' version '0.51.0' + alias(libs.plugins.shadow).apply(false) + alias(libs.plugins.versions) } defaultTasks 'clean', 'build' @@ -54,16 +43,6 @@ def toolchainLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(buildJavaVersion) } -def checkstyleVersion = '10.18.0' -def hamcrestVersion = '3.0' -def mockitoVersion = '5.13.0' -def junitVersion = '5.11.0' -def jqwikVersion = '1.9.0' -def jsonVersion = '20240303' -def jmhVersion = '1.37' -def agronaVersion = '1.23.0' -def agronaVersionRange = "[${agronaVersion},2.0[" - def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() @@ -193,7 +172,7 @@ subprojects { sourceCompatibility = JavaVersion.VERSION_17 } - checkstyle.toolVersion = "${checkstyleVersion}" + checkstyle.toolVersion = libs.versions.checkstyle.get() tasks.withType(Sign).configureEach { onlyIf { @@ -219,7 +198,7 @@ subprojects { options.encoding = 'UTF-8' options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' - options.links("https://www.javadoc.io/doc/org.agrona/agrona/${agronaVersion}/") + options.links("https://www.javadoc.io/doc/org.agrona/agrona/${libs.versions.agrona.get()}/") if (buildJavaVersion >= 23) { // early access JavaDoc location is different options.links("https://download.java.net/java/early_access/jdk${buildJavaVersion}/docs/api/") } @@ -232,7 +211,7 @@ subprojects { testing { suites { test { - useJUnitJupiter junitVersion + useJUnitJupiter libs.versions.junit.get() targets { all { @@ -267,12 +246,7 @@ project(':sbe-tool') { apply plugin: 'signing' dependencies { - api("org.agrona:agrona") { - version { - strictly(agronaVersionRange) - prefer(agronaVersion) - } - } + api libs.agrona } def generatedDir = "${layout.buildDirectory.get()}/generated-src" @@ -300,9 +274,9 @@ project(':sbe-tool') { test { dependencies { implementation files("${layout.buildDirectory.get()}/classes/java/generated") - implementation "org.hamcrest:hamcrest:${hamcrestVersion}" - implementation "org.mockito:mockito-core:${mockitoVersion}" - implementation platform("org.junit:junit-bom:${junitVersion}") + implementation libs.hamcrest + implementation libs.mockito + implementation platform("org.junit:junit-bom:${libs.versions.junit.get()}") implementation "org.junit.jupiter:junit-jupiter-params" } } @@ -310,16 +284,16 @@ project(':sbe-tool') { propertyTest(JvmTestSuite) { // We should be able to use _only_ the JQwik engine, but this issue is outstanding: // https://github.com/gradle/gradle/issues/21299 - useJUnitJupiter junitVersion + useJUnitJupiter libs.versions.junit.get() dependencies { implementation project() - implementation("net.jqwik:jqwik:${jqwikVersion}") { + implementation(libs.jqwik) { // Exclude JUnit 5 dependencies that are already provided due to useJUnitJupiter exclude group: 'org.junit.platform', module: 'junit-platform-commons' exclude group: 'org.junit.platform', module: 'junit-platform-engine' } - implementation "org.json:json:${jsonVersion}" + implementation libs.json } @@ -611,8 +585,8 @@ project(':sbe-benchmarks') { apply plugin: 'com.gradleup.shadow' dependencies { - implementation "org.openjdk.jmh:jmh-core:${jmhVersion}" - annotationProcessor "org.openjdk.jmh:jmh-generator-annprocess:${jmhVersion}" + implementation libs.jmh.core + annotationProcessor libs.jmh.generator.annprocess implementation project(':sbe-tool') implementation files("${layout.buildDirectory.get()}/classes/java/generated") } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000000..7ef3fad716 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,18 @@ +[versions] +agrona = "1.23.0" +checkstyle = "10.18.1" +junit = "5.11.0" +jmh = "1.37" + +[libraries] +agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23, 2.0[", require = "1.23.0" } } +mockito = { group = "org.mockito", name = "mockito-core", version = "5.13.0" } +hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } +jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.0" } +json = { group = "org.json", name = "json", version = "20240303" } +jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "jmh" } +jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "jmh" } + +[plugins] +versions = { id = "com.github.ben-manes.versions", version = "0.51.0" } +shadow = { id = "com.gradleup.shadow", version = "8.3.1" } From 4ba4fcb4ba2c4413e0a153a3667f31a1f98fa923 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:20:08 +0100 Subject: [PATCH 444/805] [Java] Upgrade to Shadow 8.3.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7ef3fad716..117d4bbf02 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,4 +15,4 @@ jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-an [plugins] versions = { id = "com.github.ben-manes.versions", version = "0.51.0" } -shadow = { id = "com.gradleup.shadow", version = "8.3.1" } +shadow = { id = "com.gradleup.shadow", version = "8.3.2" } From 60cfa7a6c6f8aef6f7630d00bfacb11adf72a776 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Sep 2024 13:41:03 +0200 Subject: [PATCH 445/805] 1.33.1 released --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6214e03b71..02261bead1 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.34.0-SNAPSHOT +1.33.1 From c8ff5804190b01ea031c451d8e315911341729f9 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Sep 2024 13:41:17 +0200 Subject: [PATCH 446/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 02261bead1..6214e03b71 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.33.1 +1.34.0-SNAPSHOT From afc1066821a3cd2b3017561c573b21197d9cf920 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:52:39 +0200 Subject: [PATCH 447/805] [Java] Upgrade to Gradle 8.10.2. --- build.gradle | 2 +- gradle/libs.versions.toml | 1 + gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 454e2f1e0f..ebfc61a04d 100644 --- a/build.gradle +++ b/build.gradle @@ -935,7 +935,7 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = '8.10.1' + gradleVersion = libs.versions.gradle.get() distributionType = 'ALL' } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 117d4bbf02..3b524b84bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,7 @@ agrona = "1.23.0" checkstyle = "10.18.1" junit = "5.11.0" jmh = "1.37" +gradle = "8.10.2" [libraries] agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23, 2.0[", require = "1.23.0" } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1ed247ec13..79eb9d003f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 0a3fb51a9bd86492adfe5ca1b2dfc1622b4d1de6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:42:57 +0200 Subject: [PATCH 448/805] [Gradle] Disable auto detection of JVMs to force a specific JVM for test execution in CI. --- gradle.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle.properties b/gradle.properties index 13abd18beb..5d926397cb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,4 @@ +org.gradle.java.installations.auto-detect=false org.gradle.java.installations.auto-download=false org.gradle.java.installations.fromEnv=BUILD_JAVA_HOME From ae8a211065a865cc003516112937a1daeb72fb14 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:04:55 +0200 Subject: [PATCH 449/805] [Java] Upgrade to JUnit 5.11.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3b524b84bd..d91feb3580 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agrona = "1.23.0" checkstyle = "10.18.1" -junit = "5.11.0" +junit = "5.11.1" jmh = "1.37" gradle = "8.10.2" From f83f986794cbdba8e0c33d36a9c3bd3fd66abb17 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Thu, 26 Sep 2024 23:33:24 +0100 Subject: [PATCH 450/805] [Java] Fix bug in DTO `decodeFrom` signature. It was using `short` for `actingVersion` and `blockLength`, but the inner call to `Decoder#wrap` expects an `int` (in the `uint16` range) for both arguments. There were a bunch of down/narrowing casts in tests, which I should have spotted when doing the port and have now been removed. --- .../co/real_logic/sbe/generation/java/JavaDtoGenerator.java | 2 +- .../uk/co/real_logic/sbe/properties/DtosPropertyTest.java | 6 +++--- .../java/uk/co/real_logic/sbe/generation/java/DtoTest.java | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index 9b22f240f6..b922bd14ed 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -470,7 +470,7 @@ private static void generateDecodeFrom( .append("\n") .append(indent).append("public static ").append(dtoClassName).append(" decodeFrom(") .append("DirectBuffer buffer, int offset, ") - .append("short actingBlockLength, short actingVersion)\n") + .append("int actingBlockLength, int actingVersion)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(decoderClassName).append(" decoder = new ") .append(decoderClassName).append("();\n") diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index 93508ad709..8df61fe2b3 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -101,7 +101,7 @@ void javaDtoEncodeShouldBeTheInverseOfDtoDecode( generatedClassLoader.loadClass(packageName + ".TestMessageDto"); final Method decodeFrom = - dtoClass.getMethod("decodeFrom", DirectBuffer.class, int.class, short.class, short.class); + dtoClass.getMethod("decodeFrom", DirectBuffer.class, int.class, int.class, int.class); final Method encodeWith = dtoClass.getMethod("encodeWithHeaderWith", dtoClass, MutableDirectBuffer.class, int.class); @@ -109,8 +109,8 @@ void javaDtoEncodeShouldBeTheInverseOfDtoDecode( final int inputLength = encodedMessage.length(); final ExpandableArrayBuffer inputBuffer = encodedMessage.buffer(); final MessageHeaderDecoder header = new MessageHeaderDecoder().wrap(inputBuffer, 0); - final short blockLength = (short)header.blockLength(); - final short actingVersion = (short)header.version(); + final int blockLength = header.blockLength(); + final int actingVersion = header.version(); final Object dto = decodeFrom.invoke(null, encodedMessage.buffer(), MessageHeaderDecoder.ENCODED_LENGTH, blockLength, actingVersion); outputBuffer.setMemory(0, outputBuffer.capacity(), (byte)0); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java index a28b0ac374..68b2fdce83 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java @@ -56,8 +56,7 @@ void shouldRoundTripCar2() final ExpandableArrayBuffer inputBuffer = new ExpandableArrayBuffer(); final int inputLength = encodeCar(inputBuffer, 0); - final CarDto dto = - CarDto.decodeFrom(inputBuffer, 0, (short)CarDecoder.BLOCK_LENGTH, (short)CarDecoder.SCHEMA_VERSION); + final CarDto dto = CarDto.decodeFrom(inputBuffer, 0, CarDecoder.BLOCK_LENGTH, CarDecoder.SCHEMA_VERSION); final ExpandableArrayBuffer outputBuffer = new ExpandableArrayBuffer(); final int outputLength = CarDto.encodeWith(dto, outputBuffer, 0); From edd15cc070be244f9d88af948024df2ab9a57f2f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 28 Sep 2024 13:14:36 +0200 Subject: [PATCH 451/805] [Java] Upgrade to Mockito 5.14.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d91feb3580..f2e62a353c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ gradle = "8.10.2" [libraries] agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23, 2.0[", require = "1.23.0" } } -mockito = { group = "org.mockito", name = "mockito-core", version = "5.13.0" } +mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.0" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.0" } json = { group = "org.json", name = "json", version = "20240303" } From fa49cc4103ff5d48c0d553e575d20652d243313f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:29:37 +0200 Subject: [PATCH 452/805] [Java] Upgrade to Mockito 5.14.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f2e62a353c..ca7ada31f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ gradle = "8.10.2" [libraries] agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23, 2.0[", require = "1.23.0" } } -mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.0" } +mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.1" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.0" } json = { group = "org.json", name = "json", version = "20240303" } From a677d84af6d5c30c77917ea30dc7da124d6c5e57 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 1 Oct 2024 16:57:39 +0200 Subject: [PATCH 453/805] [Java] Upgrade to Agrona 1.23.1. --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ca7ada31f3..bc10b558c4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,12 @@ [versions] -agrona = "1.23.0" +agrona = "1.23.1" checkstyle = "10.18.1" junit = "5.11.1" jmh = "1.37" gradle = "8.10.2" [libraries] -agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23, 2.0[", require = "1.23.0" } } +agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23.1, 2.0[", require = "1.23.1" } } mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.1" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.0" } From 9237d173a115124355739b3c2dcd2c9aa18effc4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:01:05 +0200 Subject: [PATCH 454/805] [Java] Upgrade to Shadow 8.3.3. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bc10b558c4..1d8307bd35 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,4 +16,4 @@ jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-an [plugins] versions = { id = "com.github.ben-manes.versions", version = "0.51.0" } -shadow = { id = "com.gradleup.shadow", version = "8.3.2" } +shadow = { id = "com.gradleup.shadow", version = "8.3.3" } From 153c985f5dfee59fc362e7d57c079e169873d475 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 6 Oct 2024 11:39:32 +0200 Subject: [PATCH 455/805] [Java] Upgrade to JUnit 5.11.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1d8307bd35..91ec4ad9f7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agrona = "1.23.1" checkstyle = "10.18.1" -junit = "5.11.1" +junit = "5.11.2" jmh = "1.37" gradle = "8.10.2" From 338b2746e60d562924cef33fdb594a38a1f9d96f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 17 Oct 2024 22:44:54 +0200 Subject: [PATCH 456/805] [Java] Create DTO generator only if enabled. --- .../generation/TargetCodeGeneratorLoader.java | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index c031ad60a8..fbf7a9d0f0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -54,23 +54,23 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) ir, System.getProperty(JAVA_ENCODING_BUFFER_TYPE, JAVA_DEFAULT_ENCODING_BUFFER_TYPE), System.getProperty(JAVA_DECODING_BUFFER_TYPE, JAVA_DEFAULT_DECODING_BUFFER_TYPE), - "true".equals(System.getProperty(JAVA_GROUP_ORDER_ANNOTATION)), - "true".equals(System.getProperty(JAVA_GENERATE_INTERFACES)), - "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)), - "true".equals(System.getProperty(TYPES_PACKAGE_OVERRIDE)), + Boolean.getBoolean(JAVA_GROUP_ORDER_ANNOTATION), + Boolean.getBoolean(JAVA_GENERATE_INTERFACES), + Boolean.getBoolean(DECODE_UNKNOWN_ENUM_VALUES), + Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE), precedenceChecks(), outputManager); - final JavaDtoGenerator dtoGenerator = new JavaDtoGenerator(ir, outputManager); - - final CodeGenerator combinedGenerator = () -> + if (Boolean.getBoolean(JAVA_GENERATE_DTOS)) { - codecGenerator.generate(); - dtoGenerator.generate(); - }; - - final boolean generateDtos = "true".equals(System.getProperty(JAVA_GENERATE_DTOS)); - return generateDtos ? combinedGenerator : codecGenerator; + final JavaDtoGenerator dtoGenerator = new JavaDtoGenerator(ir, outputManager); + return () -> + { + codecGenerator.generate(); + dtoGenerator.generate(); + }; + } + return codecGenerator; } }, @@ -100,19 +100,21 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) { final NamespaceOutputManager outputManager = new NamespaceOutputManager( outputDir, ir.applicableNamespace()); - final boolean decodeUnknownEnumValues = "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)); + final boolean decodeUnknownEnumValues = Boolean.getBoolean(DECODE_UNKNOWN_ENUM_VALUES); final CodeGenerator codecGenerator = new CppGenerator(ir, decodeUnknownEnumValues, precedenceChecks(), outputManager); - final CodeGenerator dtoGenerator = new CppDtoGenerator(ir, outputManager); - final CodeGenerator combinedGenerator = () -> - { - codecGenerator.generate(); - dtoGenerator.generate(); - }; - final boolean generateDtos = "true".equals(System.getProperty(CPP_GENERATE_DTOS)); - return generateDtos ? combinedGenerator : codecGenerator; + if (Boolean.getBoolean(CPP_GENERATE_DTOS)) + { + final CodeGenerator dtoGenerator = new CppDtoGenerator(ir, outputManager); + return () -> + { + codecGenerator.generate(); + dtoGenerator.generate(); + }; + } + return codecGenerator; } }, From 385bffe05f3b7cecf3227c667ac3561a62a0b173 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:20:07 +0200 Subject: [PATCH 457/805] [Java] Upgrade to JUnit 5.11.3. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 91ec4ad9f7..57cb9ede9d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agrona = "1.23.1" checkstyle = "10.18.1" -junit = "5.11.2" +junit = "5.11.3" jmh = "1.37" gradle = "8.10.2" From b5df61657818e2d83bcca863fed589464b2b9750 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:20:21 +0200 Subject: [PATCH 458/805] [Java] Upgrade to Mockito 5.14.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 57cb9ede9d..b9ad02c53a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ gradle = "8.10.2" [libraries] agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23.1, 2.0[", require = "1.23.1" } } -mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.1" } +mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.2" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.0" } json = { group = "org.json", name = "json", version = "20240303" } From 956a46b18ac892e7f5efc8bcab55f4cb7ea96c7c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 21 Oct 2024 21:23:25 +0200 Subject: [PATCH 459/805] [Java] Upgrade to CheckStyle 10.18.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b9ad02c53a..e8889233da 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "1.23.1" -checkstyle = "10.18.1" +checkstyle = "10.18.2" junit = "5.11.3" jmh = "1.37" gradle = "8.10.2" From e34fc03617d2d42acf90f44db574aeceb11cb71c Mon Sep 17 00:00:00 2001 From: Elvis Wang Date: Fri, 25 Oct 2024 15:45:59 +0800 Subject: [PATCH 460/805] Help decoding multiple messages using rust by resolving #987 (#991) * Add new arguments for generated MessageDecoder#header method When decoding multiple messages from a single byte buffer, the second and following message decoder should offset to the new header offset plus header length. * Update code to reflect method signature change in decoder's header method * Add test for introduced changes --------- Co-authored-by: Elvis Wang --- build.gradle | 1 + rust/Cargo.toml | 3 +- rust/benches/car_benchmark.rs | 2 +- rust/benches/md_benchmark.rs | 2 +- rust/car_example_baseline_data.sbe | Bin 0 -> 207 bytes rust/car_example_extension_data.sbe | Bin 0 -> 207 bytes rust/tests/baseline_test.rs | 2 +- rust/tests/big_endian_test.rs | 2 +- rust/tests/extension_test.rs | 2 +- rust/tests/issue_435_test.rs | 2 +- rust/tests/issue_895_test.rs | 6 +- rust/tests/issue_972_test.rs | 2 +- rust/tests/issue_984_test.rs | 2 +- rust/tests/issue_987_test.rs | 71 ++++++++++++++++++ .../sbe/generation/rust/MessageCoderDef.java | 4 +- sbe-tool/src/test/resources/issue987.xml | 25 ++++++ 16 files changed, 112 insertions(+), 14 deletions(-) create mode 100644 rust/car_example_baseline_data.sbe create mode 100644 rust/car_example_extension_data.sbe create mode 100644 rust/tests/issue_987_test.rs create mode 100644 sbe-tool/src/test/resources/issue987.xml diff --git a/build.gradle b/build.gradle index ebfc61a04d..ebc9013168 100644 --- a/build.gradle +++ b/build.gradle @@ -652,6 +652,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe-tool/src/test/resources/issue895.xml', 'sbe-tool/src/test/resources/issue972.xml', 'sbe-tool/src/test/resources/issue984.xml', + 'sbe-tool/src/test/resources/issue987.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', 'sbe-tool/src/test/resources/nested-composite-name.xml', ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 4be04c957b..6b265a3020 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -15,6 +15,7 @@ issue_435 = { path = "../generated/rust/issue435" } issue_895 = { path = "../generated/rust/issue895" } issue_972 = { path = "../generated/rust/issue972" } issue_984 = { path = "../generated/rust/issue984" } +issue_987 = { path = "../generated/rust/issue987" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } nested_composite_name = { path = "../generated/rust/nested-composite-name" } @@ -27,4 +28,4 @@ harness = false [[bench]] name = "md_benchmark" -harness = false \ No newline at end of file +harness = false diff --git a/rust/benches/car_benchmark.rs b/rust/benches/car_benchmark.rs index 5f78fff1e4..44ed774c0e 100644 --- a/rust/benches/car_benchmark.rs +++ b/rust/benches/car_benchmark.rs @@ -131,7 +131,7 @@ fn decode(state: &State) -> SbeResult { let buf = ReadBuf::new(state.buffer.as_slice()); let header = MessageHeaderDecoder::default().wrap(buf, 0); - car = car.header(header); + car = car.header(header, 0); // Car... car.serial_number(); diff --git a/rust/benches/md_benchmark.rs b/rust/benches/md_benchmark.rs index 025df09f4f..27c3fa4939 100644 --- a/rust/benches/md_benchmark.rs +++ b/rust/benches/md_benchmark.rs @@ -90,7 +90,7 @@ fn decode_md(state: &State) -> SbeResult { let buf = ReadBuf::new(state.buffer.as_slice()); let header = MessageHeaderDecoder::default().wrap(buf, 0); - market_data = market_data.header(header); + market_data = market_data.header(header, 0); market_data.transact_time(); market_data.event_time_delta(); diff --git a/rust/car_example_baseline_data.sbe b/rust/car_example_baseline_data.sbe new file mode 100644 index 0000000000000000000000000000000000000000..0fd6c7e013786ac15e784a2e80cafadcb6121d21 GIT binary patch literal 207 zcmdO8U<5)2hD$6!0toK1GdhC!OhC*G#313sq~w&;G`0)uEQUtL%8Y&|*nm=U46|nP zJ8=W0LyM9U^AwyblXFtdfm|0SJ|O9wpPQ7Kmzn|*_Xdh6IPn5WkIeLp^2ADrFeA{K zc!*&P3=Ix8K=}_2DGbKO&W_0tVPoTBps=y=W1#TaGd7N_AS3egQW80V4Cl4p!^4i6b55sXUAlSu(5G5P}tb`F;MvI85>7dkP-QLDT$mwhI3|FX0k$9 LNG2PQ192n(19vIr literal 0 HcmV?d00001 diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index 58a8503d20..ab9eecb1fd 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -44,7 +44,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); assert_eq!(SBE_TEMPLATE_ID, header.template_id()); - car = car.header(header); + car = car.header(header, 0); // Car... assert_eq!(1234, car.serial_number()); diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index aabea63ce2..1bef7278dd 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -43,7 +43,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); assert_eq!(SBE_TEMPLATE_ID, header.template_id()); - car = car.header(header); + car = car.header(header, 0); // Car... assert_eq!(1234, car.serial_number()); diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index 072b9b8baa..d7258bc39b 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -43,7 +43,7 @@ fn decode_car_and_assert_expected_content(buffer: &[u8]) -> SbeResult<()> { let buf = ReadBuf::new(buffer); let header = MessageHeaderDecoder::default().wrap(buf, 0); assert_eq!(SBE_TEMPLATE_ID, header.template_id()); - car = car.header(header); + car = car.header(header, 0); // Car... assert_eq!(1234, car.serial_number()); diff --git a/rust/tests/issue_435_test.rs b/rust/tests/issue_435_test.rs index 8664be42cd..7b1a9f8ffe 100644 --- a/rust/tests/issue_435_test.rs +++ b/rust/tests/issue_435_test.rs @@ -33,7 +33,7 @@ fn issue_435_ref_test() -> SbeResult<()> { assert_eq!(SBE_SCHEMA_ID, header.schema_id()); assert_eq!(*SetRef::default().set_one(true), header.s()); - let decoder = Issue435Decoder::default().header(header); + let decoder = Issue435Decoder::default().header(header, 0); assert_eq!(EnumRef::Two, decoder.example_decoder().e()); Ok(()) diff --git a/rust/tests/issue_895_test.rs b/rust/tests/issue_895_test.rs index 96968d2459..cb58e82d85 100644 --- a/rust/tests/issue_895_test.rs +++ b/rust/tests/issue_895_test.rs @@ -27,7 +27,7 @@ fn issue_895_both_some() -> SbeResult<()> { assert_eq!(SBE_TEMPLATE_ID, header.template_id()); assert_eq!(SBE_SCHEMA_ID, header.schema_id()); - let decoder = Issue895Decoder::default().header(header); + let decoder = Issue895Decoder::default().header(header, 0); assert_eq!(Some(2.07), decoder.optional_float()); assert_eq!(Some(4.12), decoder.optional_double()); @@ -46,7 +46,7 @@ fn issue_895_float_none() -> SbeResult<()> { let buf = ReadBuf::new(buf.as_slice()); let header = MessageHeaderDecoder::default().wrap(buf, 0); - let decoder = Issue895Decoder::default().header(header); + let decoder = Issue895Decoder::default().header(header, 0); assert_eq!(None, decoder.optional_float()); assert_eq!(Some(4.12), decoder.optional_double()); @@ -65,7 +65,7 @@ fn issue_895_double_none() -> SbeResult<()> { let buf = ReadBuf::new(buffer.as_slice()); let header = MessageHeaderDecoder::default().wrap(buf, 0); - let decoder = Issue895Decoder::default().header(header); + let decoder = Issue895Decoder::default().header(header, 0); assert_eq!(Some(2.07), decoder.optional_float()); assert_eq!(None, decoder.optional_double()); diff --git a/rust/tests/issue_972_test.rs b/rust/tests/issue_972_test.rs index 2cbab324d0..bcf4cd77e8 100644 --- a/rust/tests/issue_972_test.rs +++ b/rust/tests/issue_972_test.rs @@ -26,7 +26,7 @@ fn round_trip() -> SbeResult<()> { assert_eq!(SBE_TEMPLATE_ID, header.template_id()); assert_eq!(SBE_SCHEMA_ID, header.schema_id()); - let decoder = Issue972Decoder::default().header(header); + let decoder = Issue972Decoder::default().header(header, 0); if let Either::Right(composite) = decoder.new_field_decoder() { assert_eq!(2007, composite.f1().unwrap()); assert_eq!(2012, composite.f2().unwrap()); diff --git a/rust/tests/issue_984_test.rs b/rust/tests/issue_984_test.rs index 7ca0dcfc76..74cae2eb07 100644 --- a/rust/tests/issue_984_test.rs +++ b/rust/tests/issue_984_test.rs @@ -34,7 +34,7 @@ fn round_trip() -> SbeResult<()> { assert_eq!(SBE_TEMPLATE_ID, header.template_id()); assert_eq!(SBE_SCHEMA_ID, header.schema_id()); - let simple_msg_decoder = SimpleMessageDecoder::default().header(header); + let simple_msg_decoder = SimpleMessageDecoder::default().header(header, 0); assert_eq!(1985, simple_msg_decoder.id()); let mut grp_decoder = simple_msg_decoder.my_group_decoder(); assert_eq!(1, grp_decoder.count()); diff --git a/rust/tests/issue_987_test.rs b/rust/tests/issue_987_test.rs new file mode 100644 index 0000000000..4462f58b52 --- /dev/null +++ b/rust/tests/issue_987_test.rs @@ -0,0 +1,71 @@ +use issue_987::{ + issue_987_codec::{Issue987Decoder, Issue987Encoder, SBE_BLOCK_LENGTH, SBE_SCHEMA_ID, SBE_SCHEMA_VERSION, SBE_TEMPLATE_ID}, message_header_codec::MessageHeaderDecoder, * +}; + +fn create_encoder(buffer: &mut Vec, off: usize) -> Issue987Encoder { + let encoder = Issue987Encoder::default().wrap( + WriteBuf::new(buffer.as_mut_slice()), + off + message_header_codec::ENCODED_LENGTH, + ); + let mut header = encoder.header(off); + header.parent().unwrap() +} + +#[test] +fn encode_2_messages_and_then_decode() -> SbeResult<()> { + let mut buffer = vec![0u8; 256]; + + let mut off = 0; + + // encode message 1 + let mut encoder = create_encoder(&mut buffer, off); + encoder.old_field(10); + let mut other_encoder = encoder.new_field_encoder(); + other_encoder.f1(11); + other_encoder.f2(12); + let encoder = other_encoder.parent().unwrap(); + + // Update offset + off += message_header_codec::ENCODED_LENGTH + encoder.encoded_length(); + + // encode message 2 + let mut encoder = create_encoder(&mut buffer, off); + encoder.old_field(20); + let mut other_encoder = encoder.new_field_encoder(); + other_encoder.f1(21); + other_encoder.f2(22); + + // decoding ... + off = 0; + + // decode message 1 + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, off); + assert_eq!(SBE_BLOCK_LENGTH, header.block_length()); + assert_eq!(SBE_SCHEMA_VERSION, header.version()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_SCHEMA_ID, header.schema_id()); + let decoder = Issue987Decoder::default().header(header, off); + assert_eq!(10, decoder.old_field()); + let other_decoder = decoder.new_field_decoder(); + assert_eq!(11, other_decoder.f1()); + assert_eq!(12, other_decoder.f2()); + + // Update offset + off += message_header_codec::ENCODED_LENGTH + decoder.encoded_length(); + + // decode message 2 + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, off); + assert_eq!(SBE_BLOCK_LENGTH, header.block_length()); + assert_eq!(SBE_SCHEMA_VERSION, header.version()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_SCHEMA_ID, header.schema_id()); + let decoder = Issue987Decoder::default().header(header, off); + assert_eq!(20, decoder.old_field()); + let other_decoder = decoder.new_field_decoder(); + assert_eq!(21, other_decoder.f1()); + assert_eq!(22, other_decoder.f2()); + + Ok(()) +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 67c37f22fd..8faaa9c451 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -141,13 +141,13 @@ void appendMessageHeaderEncoderFn(final Appendable out) throws IOException void appendMessageHeaderDecoderFn(final Appendable out) throws IOException { - indent(out, 2, "pub fn header(self, mut header: MessageHeaderDecoder>) -> Self {\n"); + indent(out, 2, "pub fn header(self, mut header: MessageHeaderDecoder>, offset: usize) -> Self {\n"); indent(out, 3, "debug_assert_eq!(SBE_TEMPLATE_ID, header.template_id());\n"); indent(out, 3, "let acting_block_length = header.block_length();\n"); indent(out, 3, "let acting_version = header.version();\n\n"); indent(out, 3, "self.wrap(\n"); indent(out, 4, "header.parent().unwrap(),\n"); - indent(out, 4, "message_header_codec::ENCODED_LENGTH,\n"); + indent(out, 4, "offset + message_header_codec::ENCODED_LENGTH,\n"); indent(out, 4, "acting_block_length,\n"); indent(out, 4, "acting_version,\n"); indent(out, 3, ")\n"); diff --git a/sbe-tool/src/test/resources/issue987.xml b/sbe-tool/src/test/resources/issue987.xml new file mode 100644 index 0000000000..4daebc019d --- /dev/null +++ b/sbe-tool/src/test/resources/issue987.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + From da547ccd5a6710f3596771a2cf536cbca0f07380 Mon Sep 17 00:00:00 2001 From: Ethan Date: Tue, 29 Oct 2024 05:40:55 -0400 Subject: [PATCH 461/805] [Go] SBE implementation in Go using flyweights (#951) * [Go] SBE implementation in Go using flyweights #765 To generate flyweights instead of structs, set the following flag: ``` sbe.go.generate.generate.flyweights=true ``` * [Go] Checkstyle fix * [Go] Fix null string return value * [Go] Remove spurious type definition for choices * [Go] Fix formatting in WrapForDecode * [Go] Add returning an array by []byte * [Go] Fix array not present in version * [Go] Add ComputeLength methods * [Go] Fix some compiler warnings and remove unused code * [Go] Draft of OTF decoder * [Go] Add OTF Json Printer * [Go] Fix SbeBlockAndHeaderLength and add constants for composite sizes * [Go] Add IrDecoder for runtime types * [Go] Add enum get method * [Go] Fixes for updating component counts in irdecoder * [Go] Run goimports * [Go] Update with latest changes * [Go] Change the file structure for GOPATH * [Go] Fix copywrite year * [Go] Fix tests for otf This generates flyweights in the sbe-tool build for use in the otf library. * [Go] Add helpers for otf PrimitiveValue --- .gitignore | 37 +- README.md | 2 + build.gradle | 100 +- gocode/Makefile | 74 +- gocode/README.md | 10 +- .../src/baseline-bigendian/Car_test.go | 146 + gocode/flyweight/src/baseline/Car_test.go | 138 + .../src/basic/SBE tests/ENUM_test.go | 12 + .../src/basic/SBE tests/Message1_test.go | 29 + .../flyweight/src/basic/SBE tests/SET_test.go | 28 + .../flyweight/src/composite/Composite_test.go | 52 + .../src/composite_elements/Message_test.go | 91 + .../src/example-schema/CarExample_test.go | 572 +++ .../src/group/SBE tests/TestMessage1_test.go | 55 + .../src/group_with_data/TestMessages_test.go | 200 + .../Extension_test.go | 210 + .../flyweight/src/issue435/Issue435_test.go | 48 + .../flyweight/src/issue472/Issue472_test.go | 27 + .../flyweight/src/issue483/Issue483_test.go | 35 + .../flyweight/src/issue488/Issue488_test.go | 9 + .../flyweight/src/issue560/Issue560_test.go | 28 + .../src/issue847/issue847_test.go | 0 .../src/issue848/issue848_test.go | 0 .../src/issue849/issue849_test.go | 0 .../{ => flyweight}/src/mktdata/fixme_test.go | 0 gocode/flyweight/src/otf/go.mod | 10 + gocode/flyweight/src/otf/go.sum | 18 + gocode/flyweight/src/otf/json_test.go | 114 + gocode/flyweight/src/otf/otf_test.go | 159 + gocode/flyweight/src/otf/testlistener.go | 311 ++ gocode/flyweight/src/simple/simple_test.go | 46 + .../since-deprecated/SinceDeprecated_test.go | 23 + .../vardata/SBE tests/TestMessage1_test.go | 27 + gocode/go.mod | 7 + gocode/go.sum | 7 + .../src/baseline-bigendian/Car_test.go | 0 gocode/{ => struct}/src/baseline/Car_test.go | 0 .../src/basic/SBE tests/ENUM_test.go | 0 .../src/basic/SBE tests/Message1_test.go | 0 .../src/basic/SBE tests/SET_test.go | 0 .../src/composite/Composite_test.go | 0 .../src/composite_elements/Message_test.go | 0 .../src/example-schema/CarExample.go | 0 .../src/example-schema/CarExample_test.go | 0 .../clientserver.go | 0 .../src/group/SBE tests/TestMessage1_test.go | 0 .../src/group_with_data/TestMessages_test.go | 0 .../Extension_test.go | 0 .../src/issue435/Issue435_test.go | 0 .../src/issue472/Issue472_test.go | 0 .../src/issue483/Issue483_test.go | 0 .../src/issue488/Issue488_test.go | 0 .../src/issue505/Issue505_test.go | 0 .../src/issue560/Issue560_test.go | 0 gocode/struct/src/issue847/issue847_test.go | 9 + gocode/struct/src/issue848/issue848_test.go | 9 + gocode/struct/src/issue849/issue849_test.go | 9 + gocode/struct/src/mktdata/fixme_test.go | 10 + .../src/mktdata/preallocated_test.go | 0 gocode/{ => struct}/src/simple/simple_test.go | 0 .../since-deprecated/SinceDeprecated_test.go | 0 gocode/{ => struct}/src/test973/EventType.go | 0 .../{ => struct}/src/test973/MessageHeader.go | 0 .../src/test973/SbeMarshalling.go | 0 .../{ => struct}/src/test973/SomeMessage.go | 0 .../{ => struct}/src/test973/test973_test.go | 0 .../vardata/SBE tests/TestMessage1_test.go | 0 sbe-tool/src/main/golang/.gitignore | 1 + sbe-tool/src/main/golang/go.mod | 3 + sbe-tool/src/main/golang/go.sum | 17 + sbe-tool/src/main/golang/json/json_printer.go | 76 + .../main/golang/json/json_token_listener.go | 410 ++ sbe-tool/src/main/golang/main.go | 3 + sbe-tool/src/main/golang/otf/encoding.go | 673 ++++ sbe-tool/src/main/golang/otf/irdecoder.go | 355 ++ .../src/main/golang/otf/otfheaderdecoder.go | 105 + .../src/main/golang/otf/otfmessagedecoder.go | 311 ++ sbe-tool/src/main/golang/otf/token.go | 162 + .../java/uk/co/real_logic/sbe/SbeTool.java | 6 + .../generation/TargetCodeGeneratorLoader.java | 20 +- .../flyweight/GolangFlyweightGenerator.java | 3382 +++++++++++++++++ .../GolangFlyweightOutputManager.java | 72 + .../golang/flyweight/GolangFlyweightUtil.java | 224 ++ .../golang/{ => struct}/GolangGenerator.java | 4 +- .../{ => struct}/GolangOutputManager.java | 2 +- .../golang/{ => struct}/GolangUtil.java | 2 +- ...st.java => GolangStructGeneratorTest.java} | 3 +- 87 files changed, 8428 insertions(+), 65 deletions(-) create mode 100644 gocode/flyweight/src/baseline-bigendian/Car_test.go create mode 100644 gocode/flyweight/src/baseline/Car_test.go create mode 100644 gocode/flyweight/src/basic/SBE tests/ENUM_test.go create mode 100644 gocode/flyweight/src/basic/SBE tests/Message1_test.go create mode 100644 gocode/flyweight/src/basic/SBE tests/SET_test.go create mode 100644 gocode/flyweight/src/composite/Composite_test.go create mode 100644 gocode/flyweight/src/composite_elements/Message_test.go create mode 100644 gocode/flyweight/src/example-schema/CarExample_test.go create mode 100644 gocode/flyweight/src/group/SBE tests/TestMessage1_test.go create mode 100644 gocode/flyweight/src/group_with_data/TestMessages_test.go create mode 100644 gocode/flyweight/src/group_with_data_extension/Extension_test.go create mode 100644 gocode/flyweight/src/issue435/Issue435_test.go create mode 100644 gocode/flyweight/src/issue472/Issue472_test.go create mode 100644 gocode/flyweight/src/issue483/Issue483_test.go create mode 100644 gocode/flyweight/src/issue488/Issue488_test.go create mode 100644 gocode/flyweight/src/issue560/Issue560_test.go rename gocode/{ => flyweight}/src/issue847/issue847_test.go (100%) rename gocode/{ => flyweight}/src/issue848/issue848_test.go (100%) rename gocode/{ => flyweight}/src/issue849/issue849_test.go (100%) rename gocode/{ => flyweight}/src/mktdata/fixme_test.go (100%) create mode 100644 gocode/flyweight/src/otf/go.mod create mode 100644 gocode/flyweight/src/otf/go.sum create mode 100644 gocode/flyweight/src/otf/json_test.go create mode 100644 gocode/flyweight/src/otf/otf_test.go create mode 100644 gocode/flyweight/src/otf/testlistener.go create mode 100644 gocode/flyweight/src/simple/simple_test.go create mode 100644 gocode/flyweight/src/since-deprecated/SinceDeprecated_test.go create mode 100644 gocode/flyweight/src/vardata/SBE tests/TestMessage1_test.go create mode 100644 gocode/go.mod create mode 100644 gocode/go.sum rename gocode/{ => struct}/src/baseline-bigendian/Car_test.go (100%) rename gocode/{ => struct}/src/baseline/Car_test.go (100%) rename gocode/{ => struct}/src/basic/SBE tests/ENUM_test.go (100%) rename gocode/{ => struct}/src/basic/SBE tests/Message1_test.go (100%) rename gocode/{ => struct}/src/basic/SBE tests/SET_test.go (100%) rename gocode/{ => struct}/src/composite/Composite_test.go (100%) rename gocode/{ => struct}/src/composite_elements/Message_test.go (100%) rename gocode/{ => struct}/src/example-schema/CarExample.go (100%) rename gocode/{ => struct}/src/example-schema/CarExample_test.go (100%) rename gocode/{ => struct}/src/example-socket-clientserver/clientserver.go (100%) rename gocode/{ => struct}/src/group/SBE tests/TestMessage1_test.go (100%) rename gocode/{ => struct}/src/group_with_data/TestMessages_test.go (100%) rename gocode/{ => struct}/src/group_with_data_extension/Extension_test.go (100%) rename gocode/{ => struct}/src/issue435/Issue435_test.go (100%) rename gocode/{ => struct}/src/issue472/Issue472_test.go (100%) rename gocode/{ => struct}/src/issue483/Issue483_test.go (100%) rename gocode/{ => struct}/src/issue488/Issue488_test.go (100%) rename gocode/{ => struct}/src/issue505/Issue505_test.go (100%) rename gocode/{ => struct}/src/issue560/Issue560_test.go (100%) create mode 100644 gocode/struct/src/issue847/issue847_test.go create mode 100644 gocode/struct/src/issue848/issue848_test.go create mode 100644 gocode/struct/src/issue849/issue849_test.go create mode 100644 gocode/struct/src/mktdata/fixme_test.go rename gocode/{ => struct}/src/mktdata/preallocated_test.go (100%) rename gocode/{ => struct}/src/simple/simple_test.go (100%) rename gocode/{ => struct}/src/since-deprecated/SinceDeprecated_test.go (100%) rename gocode/{ => struct}/src/test973/EventType.go (100%) rename gocode/{ => struct}/src/test973/MessageHeader.go (100%) rename gocode/{ => struct}/src/test973/SbeMarshalling.go (100%) rename gocode/{ => struct}/src/test973/SomeMessage.go (100%) rename gocode/{ => struct}/src/test973/test973_test.go (100%) rename gocode/{ => struct}/src/vardata/SBE tests/TestMessage1_test.go (100%) create mode 100644 sbe-tool/src/main/golang/.gitignore create mode 100644 sbe-tool/src/main/golang/go.mod create mode 100644 sbe-tool/src/main/golang/go.sum create mode 100644 sbe-tool/src/main/golang/json/json_printer.go create mode 100644 sbe-tool/src/main/golang/json/json_token_listener.go create mode 100644 sbe-tool/src/main/golang/main.go create mode 100644 sbe-tool/src/main/golang/otf/encoding.go create mode 100644 sbe-tool/src/main/golang/otf/irdecoder.go create mode 100644 sbe-tool/src/main/golang/otf/otfheaderdecoder.go create mode 100644 sbe-tool/src/main/golang/otf/otfmessagedecoder.go create mode 100644 sbe-tool/src/main/golang/otf/token.go create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightOutputManager.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java rename sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/{ => struct}/GolangGenerator.java (99%) rename sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/{ => struct}/GolangOutputManager.java (98%) rename sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/{ => struct}/GolangUtil.java (98%) rename sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/{GolangGeneratorTest.java => GolangStructGeneratorTest.java} (99%) diff --git a/.gitignore b/.gitignore index 4ffe2537bc..4e46271843 100644 --- a/.gitignore +++ b/.gitignore @@ -65,31 +65,18 @@ cppbuild/Win32 # golang gocode/pkg -gocode/src/baseline/*.go -!gocode/src/baseline/*_test.go -gocode/src/baseline-bigendian/*.go -!gocode/src/baseline-bigendian/*_test.go -gocode/src/composite/*.go -!gocode/src/composite/*_test.go -gocode/src/composite_elements/*.go -!gocode/src/composite_elements/*_test.go -gocode/src/since-deprecated/*.go -!gocode/src/since-deprecated/*_test.go -gocode/src/group_with_data*/*.go -!gocode/src/group_with_data*/*_test.go -gocode/src/mktdata/*.go -!gocode/src/mktdata/*_test.go -gocode/src/simple/*.go -!gocode/src/simple/*_test.go -gocode/src/issue*/*.go -!gocode/src/issue*/*_test.go -gocode/src/*/*/*.go -!gocode/src/*/*/*_test.go -gocode/src/example-schema/example-schema* -gocode/src/example-schema/cpu.out -gocode/src/example-socket-clientserver/example-socket-clientserver -gocode/src/extension -gocode/src/extension2 +gocode/*/pkg +gocode/struct/src/*/*.go +!gocode/struct/src/*/*_test.go +gocode/struct/src/*/*/*.go +!gocode/struct/src/*/*/*_test.go +gocode/struct/src/example-schema/example-schema* +gocode/struct/src/example-socket-clientserver/example-socket-clientserver +gocode/flyweight/src/*/*.go +!gocode/flyweight/src/*/*_test.go +gocode/flyweight/src/*/*/*.go +!gocode/flyweight/src/*/*/*_test.go +gocode/flyweight/src/otf/code-generation-schema.sbeir # csharp csharp/*/bin diff --git a/README.md b/README.md index c393d2dd26..26efe26f10 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ For convenience on Linux, a gnu Makefile is provided that runs some tests and co $ cd gocode # make # test, examples, bench +Go supports both generating Go structs with encode / decode methods, and flyweights like the other languages. Structs are generated by default for compatibility. Set `sbe.go.generate.generate.flyweights=true` to generate flyweights. + Users of golang generated code should see the [user documentation](https://github.com/real-logic/simple-binary-encoding/wiki/Golang-User-Guide). diff --git a/build.gradle b/build.gradle index ebc9013168..40bbbbef9c 100644 --- a/build.gradle +++ b/build.gradle @@ -700,7 +700,7 @@ tasks.register('generateGolangCodecTestComposite', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src', + 'sbe.output.dir': 'gocode/struct/src', 'sbe.target.language': 'golang') args = ['sbe-tool/src/test/resources/composite-elements-schema-rc4.xml'] } @@ -709,7 +709,7 @@ tasks.register('generateGolangCodecTestBasic', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src/basic', + 'sbe.output.dir': 'gocode/struct/src/basic', 'sbe.target.language': 'golang') args = ['sbe-tool/src/test/resources/basic-types-schema.xml'] } @@ -718,7 +718,7 @@ tasks.register('generateGolangCodecTestGroup', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src/group', + 'sbe.output.dir': 'gocode/struct/src/group', 'sbe.target.language': 'golang') args = ['sbe-tool/src/test/resources/basic-group-schema.xml'] } @@ -727,7 +727,7 @@ tasks.register('generateGolangCodecTestVarData', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src/vardata', + 'sbe.output.dir': 'gocode/struct/src/vardata', 'sbe.target.language': 'golang') args = ['sbe-tool/src/test/resources/basic-variable-length-schema.xml'] } @@ -736,7 +736,7 @@ tasks.register('generateGolangCodecsWithXIncludes', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src', + 'sbe.output.dir': 'gocode/struct/src', 'sbe.target.language': 'golang', 'sbe.xinclude.aware': 'true', 'sbe.validation.xsd': validationXsdPath) @@ -748,7 +748,87 @@ tasks.register('generateGolangCodecsWithXSD', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( - 'sbe.output.dir': 'gocode/src', + 'sbe.output.dir': 'gocode/struct/src', + 'sbe.target.language': 'golang', + 'sbe.xinclude.aware': 'true', + 'sbe.validation.xsd': validationXsdPath) + args = ['sbe-tool/src/test/resources/group-with-data-schema.xml', + 'sbe-tool/src/test/resources/FixBinary.xml', + 'sbe-tool/src/test/resources/issue435.xml', + 'sbe-tool/src/test/resources/issue472.xml', + 'sbe-tool/src/test/resources/issue483.xml', + 'sbe-tool/src/test/resources/issue488.xml', + 'sbe-tool/src/test/resources/issue560.xml', + 'sbe-tool/src/test/resources/issue661.xml', + 'sbe-tool/src/test/resources/issue847.xml', + 'sbe-tool/src/test/resources/issue848.xml', + 'sbe-tool/src/test/resources/issue849.xml', + 'sbe-tool/src/test/resources/since-deprecated-test-schema.xml', + 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', + 'gocode/resources/example-composite.xml', + 'gocode/resources/group-with-data-extension-schema.xml', + 'gocode/resources/simple.xml'] +} + +tasks.register('generateGolangFlyweightCodecTestComposite', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'gocode/flyweight/src', + 'sbe.go.generate.generate.flyweights': 'true', + 'sbe.target.language': 'golang') + args = ['sbe-tool/src/test/resources/composite-elements-schema-rc4.xml'] +} + +tasks.register('generateGolangFlyweightCodecTestBasic', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'gocode/flyweight/src/basic', + 'sbe.go.generate.generate.flyweights': 'true', + 'sbe.target.language': 'golang') + args = ['sbe-tool/src/test/resources/basic-types-schema.xml'] +} + +tasks.register('generateGolangFlyweightCodecTestGroup', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'gocode/flyweight/src/group', + 'sbe.go.generate.generate.flyweights': 'true', + 'sbe.target.language': 'golang') + args = ['sbe-tool/src/test/resources/basic-group-schema.xml'] +} + +tasks.register('generateGolangFlyweightCodecTestVarData', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'gocode/flyweight/src/vardata', + 'sbe.go.generate.generate.flyweights': 'true', + 'sbe.target.language': 'golang') + args = ['sbe-tool/src/test/resources/basic-variable-length-schema.xml'] +} + +tasks.register('generateGolangFlyweightCodecsWithXIncludes', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'gocode/flyweight/src', + 'sbe.go.generate.generate.flyweights': 'true', + 'sbe.target.language': 'golang', + 'sbe.xinclude.aware': 'true', + 'sbe.validation.xsd': validationXsdPath) + args = ['sbe-samples/src/main/resources/example-schema.xml', + 'sbe-samples/src/main/resources/example-extension-schema.xml'] +} + +tasks.register('generateGolangFlyweightCodecsWithXSD', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'gocode/flyweight/src', + 'sbe.go.generate.generate.flyweights': 'true', 'sbe.target.language': 'golang', 'sbe.xinclude.aware': 'true', 'sbe.validation.xsd': validationXsdPath) @@ -780,6 +860,13 @@ tasks.register('generateGolangCodecs') { 'generateGolangCodecTestComposite', 'generateGolangCodecsWithXIncludes', 'generateGolangCodecsWithXSD', + 'generateGolangFlyweightCodecTestVarData', + 'generateGolangFlyweightCodecTestGroup', + 'generateGolangFlyweightCodecTestBasic', + 'generateGolangFlyweightCodecTestComposite', + 'generateGolangFlyweightCodecsWithXIncludes', + 'generateGolangFlyweightCodecsWithXSD', + 'generateIrCodecs', ':sbe-all:jar' } @@ -868,6 +955,7 @@ tasks.register('generateGolangIrCodecs', JavaExec) { systemProperties( 'sbe.output.dir': 'sbe-tool/src/main/golang', 'sbe.target.language': 'golang', + 'sbe.go.generate.generate.flyweights': true, 'sbe.validation.xsd': validationXsdPath) args = ['sbe-tool/src/main/resources/sbe-ir.xml'] } diff --git a/gocode/Makefile b/gocode/Makefile index eebb2b4f38..a635c61f1d 100644 --- a/gocode/Makefile +++ b/gocode/Makefile @@ -19,11 +19,11 @@ all: example test # bench # This target is used to build golang files using parent gradle # script's invocation of sbe-tool in case it needs to be run again. We # use this one output file to check that dependency as it's simple -DEP=src/simple/SbeMarshalling.go +DEP=struct/src/simple/SbeMarshalling.go $(DEP): $(SBE_JAR) (cd ..; ./gradlew generateGolangCodecs) - (export GOPATH=$(GOPATH) && \ - cd src/simple && \ + (export GOPATH=$(GOPATH)/struct && \ + cd struct/src/simple && \ go build && \ $(SAVE_FORMAT) \ go fmt && \ @@ -31,27 +31,27 @@ $(DEP): $(SBE_JAR) # Will regenerate codecs by removing dependencies clean: - rm -f src/*/SbeMarshalling.go src/*/*/SbeMarshalling.go + rm -f struct/src/*/SbeMarshalling.go struct/src/*/*/SbeMarshalling.go -# Example code and benchmarking -example: src/example-schema/example-schema -src/example-schema/example-schema: $(DEP) - (export GOPATH=$(GOPATH) && \ - cd src/example-schema && \ +# Example code and benchmarking +example: struct/src/example-schema/example-schema +struct/src/example-schema/example-schema: $(DEP) + (export GOPATH=$(GOPATH)/struct && \ + cd struct/src/example-schema && \ go build && \ go fmt && \ ./example-schema) bench: $(DEP) - (export GOPATH=$(GOPATH) && \ - cd src/example-schema && \ + (export GOPATH=$(GOPATH)/struct && \ + cd struct/src/example-schema && \ go test --bench . -cpuprofile=cpu.out && \ go tool pprof -text example-schema.test cpu.out) -src/baseline/SbeMarshalling.go: $(DEP) +struct/src/baseline/SbeMarshalling.go: $(DEP) $(GOPATH)/sbe-tool -d src -s $(EXAMPLES_SCHEMA) - (export GOPATH=$(GOPATH) && \ - cd src/baseline && \ + (export GOPATH=$(GOPATH)/struct && \ + cd struct/src/baseline && \ go build && \ go fmt && \ go test && \ @@ -59,29 +59,59 @@ src/baseline/SbeMarshalling.go: $(DEP) # The first set does a make install as there is a test that uses # multiple packages and needs them in GOPATH The second set work in -# src/foo, and the third need a GOPATH addition as for Java and C++ +# struct/src/foo, and the third need a GOPATH addition as for Java and C++ # they generate into the same directory but golang doesn't allow that test: $(DEP) - (export GOPATH=$(GOPATH) && \ + (export GOPATH=$(GOPATH)/struct && \ (for t in baseline extension; do \ - export GOPATH=$(GOPATH) && \ - cd $(GOPATH)/src/$$t && \ + export GOPATH=$(GOPATH)/struct && \ + cd $(GOPATH)/struct/src/$$t && \ go build && \ go fmt && \ go test && \ go install \ ;done)) - (export GOPATH=$(GOPATH) && \ + (export GOPATH=$(GOPATH)/struct && \ (for t in baseline-bigendian mktdata group_with_data group_with_data_extension composite_elements composite since-deprecated simple issue435 issue472 issue483 issue488 issue560 issue847 issue848 issue849 issue505 test973; do \ - cd $(GOPATH)/src/$$t && \ + cd $(GOPATH)/struct/src/$$t && \ go build && \ go fmt && \ go test \ ;done)) (for t in vardata group basic; do \ - export GOPATH=$(GOPATH)/$$t && \ - cd $(GOPATH)/src/$$t/'SBE tests' && \ + export GOPATH=$(GOPATH)/struct/$$t && \ + cd $(GOPATH)/struct/src/$$t/'SBE tests' && \ go build && \ go fmt && \ go test \ ;done) + (export GOPATH=$(GOPATH)/flyweight && \ + (for t in baseline extension; do \ + export GOPATH=$(GOPATH)/flyweight && \ + cd $(GOPATH)/flyweight/src/$$t && \ + go build && \ + go fmt && \ + go test && \ + go install \ + ;done)) + (export GOPATH=$(GOPATH)/flyweight && \ + (for t in baseline-bigendian mktdata group_with_data group_with_data_extension composite_elements composite since-deprecated simple issue435 issue472 issue483 issue488 issue560 issue847 issue848 issue849; do \ + cd $(GOPATH)/flyweight/src/$$t && \ + go build && \ + go fmt && \ + go test \ + ;done)) + (for t in vardata group basic; do \ + export GOPATH=$(GOPATH)/flyweight/$$t && \ + cd $(GOPATH)/flyweight/src/$$t/'SBE tests' && \ + go build && \ + go fmt && \ + go test \ + ;done) + (export SBE_JAR=$(SBE_JAR) && \ + export GO111MODULE=on && \ + (cd $(GOPATH)/flyweight/src/otf && \ + go generate && \ + go build && \ + go fmt && \ + go test)) diff --git a/gocode/README.md b/gocode/README.md index fb8b994539..5740d9dbca 100755 --- a/gocode/README.md +++ b/gocode/README.md @@ -5,10 +5,13 @@ There is now a [user guide](https://github.com/real-logic/simple-binary-encoding/wiki/Golang-User-Guide) and this document is for development of the SBE golang generator. +Go supports both generating Go structs with encode / decode methods, and flyweights like the other languages. +Structs are generated by default for compatibility. Set `sbe.go.generate.generate.flyweights=true` to generate flyweights. + Code Layout ----------- The Java code that performs the generation of golang code is -[here](https://github.com/real-logic/simple-binary-encoding/tree/master/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang). +[here](https://github.com/real-logic/simple-binary-encoding/tree/master/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang). There is both a struct and a flyweight generator. Golang code used for testing resides in the top-level [gocode directory](https://github.com/real-logic/simple-binary-encoding/tree/master/gocode). @@ -24,11 +27,12 @@ the build environment, example and test code are structured into a top level gocode directory hierarchy. Code is generated into this structure with pre-existing test code in place. +There are tests for both the struct and flyweight styles of generated code. For the example, the code is generated into a library and the matching example code lives in it's own directory at the same level. For example, the example-schema generates the baseline library code into -`gocode/src/baseline` and example code lives in `gocode/src/example-schema`. +`gocode/src/struct/baseline` and example code lives in `gocode/src/example-schema`. To use this layout you should `set GOPATH=/path/to/gocode` or use the supplied Makefile which does this for you. For the tests you will need @@ -60,5 +64,3 @@ generator processes. Roadmap ======= * Windows developer support (currently tested on Linux/MacOS) - * Further Unicode support - * Testing/Bug fixes diff --git a/gocode/flyweight/src/baseline-bigendian/Car_test.go b/gocode/flyweight/src/baseline-bigendian/Car_test.go new file mode 100644 index 0000000000..d06ed4102a --- /dev/null +++ b/gocode/flyweight/src/baseline-bigendian/Car_test.go @@ -0,0 +1,146 @@ +package baseline_bigendian + +import ( + _ "fmt" + "testing" +) + +func TestEncodeDecodeCar(t *testing.T) { + var data [256]byte + var in Car + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.SetSerialNumber(1234). + SetModelYear(2000). + SetAvailable(BooleanType_T). + SetCode(Model_A). + SetVehicleCode("abcdef") + + in.SetSomeNumbersIndex(0, 0) + in.SetSomeNumbersIndex(1, 1) + in.SetSomeNumbersIndex(2, 2) + in.SetSomeNumbersIndex(3, 3) + in.SetSomeNumbersIndex(4, 4) + + in.Extras(). + SetCruiseControl(true). + SetSportsPack(true) + + in.Engine(). + SetCapacity(2000). + SetNumCylinders(4). + SetManufacturerCode("123"). + SetEfficiency(42). + SetBoosterEnabled(BooleanType_T). + Booster(). + SetBoostType(BoostType_NITROUS). + SetHorsePower(200) + + in.FuelFiguresCount(3).Next(). + SetSpeed(30). + SetMpg(35.9). + PutUsageDescription("Urban Cycle").Next(). + SetSpeed(55). + SetMpg(49.0). + PutUsageDescription("Combined Cycle").Next(). + SetSpeed(75). + SetMpg(40.0). + PutUsageDescription("Highway Cycle") + + performanceFigures := in.PerformanceFiguresCount(2) + performanceFigures.SetOctaneRating(95).Next(). + AccelerationCount(3). + SetMph(30). + SetSeconds(3.8).Next(). + SetMph(60). + SetSeconds(7.5).Next(). + SetMph(100). + SetSeconds(12.2) + performanceFigures.Next(). + SetOctaneRating(99). + AccelerationCount(3). + SetMph(30). + SetSeconds(3.8).Next(). + SetMph(60). + SetSeconds(7.5).Next(). + SetMph(100). + SetSeconds(12.2) + + in.PutManufacturer("123"). + PutModel("Civic VTi"). + PutActivationCode("deadbeef") + + var out Car + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeSchemaVersion()), + uint64(in.SbeBlockLength()), + uint64(len(data)), + ) + + if in.SerialNumber() != out.SerialNumber() { + t.Log("in.SerialNumber != out.SerialNumber:\n", in.SerialNumber(), out.SerialNumber()) + t.Fail() + } + if in.ModelYear() != out.ModelYear() { + t.Log("in.ModelYear != out.ModelYear:\n", in.ModelYear(), out.ModelYear()) + t.Fail() + } + if in.Available() != out.Available() { + t.Log("in.Available != out.Available:\n", in.Available(), out.Available()) + t.Fail() + } + if in.Code() != out.Code() { + t.Log("in.Code != out.Code:\n", in.Code(), out.Code()) + t.Fail() + } + for i, l := uint64(0), uint64(in.SomeNumbersLength()); i < l; i++ { + if in.SomeNumbersIndex(i) != out.SomeNumbersIndex(i) { + t.Log("in.SomeNumbers != out.SomeNumbers:\n", in.SomeNumbersIndex(i), out.SomeNumbersIndex(i)) + t.Fail() + } + } + for i, l := uint64(0), uint64(in.VehicleCodeLength()); i < l; i++ { + if in.VehicleCodeIndex(i) != out.VehicleCodeIndex(i) { + t.Log("in.VehicleCode != out.VehicleCode:\n", in.VehicleCodeIndex(i), out.VehicleCodeIndex(i)) + t.Fail() + } + } + if in.Extras().String() != out.Extras().String() { + t.Log("in.Extras != out.Extras:\n", in.Extras(), out.Extras()) + t.Fail() + } + + // DiscountedModel is constant + if Model_C != out.DiscountedModel() { + t.Log("in.DiscountedModel != out.DiscountedModel:\n", in.DiscountedModel(), out.DiscountedModel()) + t.Fail() + } + + if in.Engine().String() != out.Engine().String() { + t.Log("in.Engine != out.Engine:\n", in.Engine().String(), out.Engine().String()) + t.Fail() + } + + return + +} + +func TestDecodeJavaBuffer(t *testing.T) { + // The byte array is from the java example for interop test + // made by editing example-schgema to be bigendian and running + // with the example with -Dsbe.encoding.filename + // and then decoded using od -tu1 + data := []byte{0, 49, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 210, 7, 221, 1, 65, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 97, 98, 99, 100, 101, 102, 6, 7, 208, 4, 49, 50, 51, 35, 1, 78, 200, 0, 6, 0, 3, 0, 30, 66, 15, 153, 154, 0, 0, 0, 11, 85, 114, 98, 97, 110, 32, 67, 121, 99, 108, 101, 0, 55, 66, 68, 0, 0, 0, 0, 0, 14, 67, 111, 109, 98, 105, 110, 101, 100, 32, 67, 121, 99, 108, 101, 0, 75, 66, 32, 0, 0, 0, 0, 0, 13, 72, 105, 103, 104, 119, 97, 121, 32, 67, 121, 99, 108, 101, 0, 1, 0, 2, 95, 0, 6, 0, 3, 0, 30, 64, 128, 0, 0, 0, 60, 64, 240, 0, 0, 0, 100, 65, 67, 51, 51, 99, 0, 6, 0, 3, 0, 30, 64, 115, 51, 51, 0, 60, 64, 227, 51, 51, 0, 100, 65, 60, 204, 205, 0, 0, 0, 5, 72, 111, 110, 100, 97, 0, 0, 0, 9, 67, 105, 118, 105, 99, 32, 86, 84, 105, 0, 0, 0, 6, 97, 98, 99, 100, 101, 102} + + var c Car + c.WrapAndApplyHeader(data, 0, uint64(len(data))) + + expected := `{"Name": "Car", "sbeTemplateId": 1, "serialNumber": "1234", "modelYear": "2013", "available": "T", "code": "A", "someNumbers": [0,1,2,3,4], "vehicleCode": "abcdef", "extras": ["SportsPack","CruiseControl"], "discountedModel": "C", "engine": {"capacity": "2000", "numCylinders": "4", "manufacturerCode": "123", "efficiency": "35", "boosterEnabled": "T", "booster": {"BoostType": "NITROUS", "horsePower": "200"}}, "fuelFigures": [{"speed": "30", "mpg": "35.9", "usageDescription": "Urban Cycle"}, {"speed": "55", "mpg": "49", "usageDescription": "Combined Cycle"}, {"speed": "75", "mpg": "40", "usageDescription": "Highway Cycle"}], "performanceFigures": [{"octaneRating": "95", "acceleration": [{"mph": "30", "seconds": "4"}, {"mph": "60", "seconds": "7.5"}, {"mph": "100", "seconds": "12.2"}]}, {"octaneRating": "99", "acceleration": [{"mph": "30", "seconds": "3.8"}, {"mph": "60", "seconds": "7.1"}, {"mph": "100", "seconds": "11.8"}]}], "manufacturer": "Honda", "model": "Civic VTi", "activationCode": "abcdef"}` + if actual := c.String(); actual != expected { + t.Logf("Failed to decode car, expected %s, got %s", expected, actual) + t.Fail() + } + return +} diff --git a/gocode/flyweight/src/baseline/Car_test.go b/gocode/flyweight/src/baseline/Car_test.go new file mode 100644 index 0000000000..9aa2127b7a --- /dev/null +++ b/gocode/flyweight/src/baseline/Car_test.go @@ -0,0 +1,138 @@ +package baseline + +import ( + _ "fmt" + "testing" +) + +func TestEncodeDecodeCar(t *testing.T) { + var data [256]byte + var in Car + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.SetSerialNumber(1234). + SetModelYear(2000). + SetAvailable(BooleanType_T). + SetCode(Model_A). + PutSomeNumbersValues(0, 1, 2, 3). + SetVehicleCode("abcdef") + + in.Extras(). + SetCruiseControl(true). + SetSportsPack(true) + + in.Engine(). + SetCapacity(2000). + SetNumCylinders(4). + SetManufacturerCode("123"). + SetEfficiency(42). + SetBoosterEnabled(BooleanType_T). + Booster(). + SetBoostType(BoostType_NITROUS). + SetHorsePower(200) + + in.FuelFiguresCount(3).Next(). + SetSpeed(30). + SetMpg(35.9). + PutUsageDescription("Urban Cycle").Next(). + SetSpeed(55). + SetMpg(49.0). + PutUsageDescription("Combined Cycle").Next(). + SetSpeed(75). + SetMpg(40.0). + PutUsageDescription("Highway Cycle") + + performanceFigures := in.PerformanceFiguresCount(2) + performanceFigures.SetOctaneRating(95).Next(). + AccelerationCount(3). + SetMph(30). + SetSeconds(3.8).Next(). + SetMph(60). + SetSeconds(7.5).Next(). + SetMph(100). + SetSeconds(12.2) + performanceFigures.Next(). + SetOctaneRating(99). + AccelerationCount(3). + SetMph(30). + SetSeconds(3.8).Next(). + SetMph(60). + SetSeconds(7.5).Next(). + SetMph(100). + SetSeconds(12.2) + + in.PutManufacturer("123"). + PutModel("Civic VTi"). + PutActivationCode("deadbeef") + + var out Car + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeSchemaVersion()), + uint64(in.SbeBlockLength()), + uint64(len(data)), + ) + + if in.SerialNumber() != out.SerialNumber() { + t.Log("in.SerialNumber != out.SerialNumber:\n", in.SerialNumber(), out.SerialNumber()) + t.Fail() + } + if in.ModelYear() != out.ModelYear() { + t.Log("in.ModelYear != out.ModelYear:\n", in.ModelYear(), out.ModelYear()) + t.Fail() + } + if in.Available() != out.Available() { + t.Log("in.Available != out.Available:\n", in.Available(), out.Available()) + t.Fail() + } + if in.Code() != out.Code() { + t.Log("in.Code != out.Code:\n", in.Code(), out.Code()) + t.Fail() + } + for i, l := uint64(0), uint64(in.SomeNumbersLength()); i < l; i++ { + if in.SomeNumbersIndex(i) != out.SomeNumbersIndex(i) { + t.Log("in.SomeNumbers != out.SomeNumbers:\n", in.SomeNumbersIndex(i), out.SomeNumbersIndex(i)) + t.Fail() + } + } + for i, l := uint64(0), uint64(in.VehicleCodeLength()); i < l; i++ { + if in.VehicleCodeIndex(i) != out.VehicleCodeIndex(i) { + t.Log("in.VehicleCode != out.VehicleCode:\n", in.VehicleCodeIndex(i), out.VehicleCodeIndex(i)) + t.Fail() + } + } + if in.Extras().String() != out.Extras().String() { + t.Log("in.Extras != out.Extras:\n", in.Extras(), out.Extras()) + t.Fail() + } + + // DiscountedModel is constant + if Model_C != out.DiscountedModel() { + t.Log("in.DiscountedModel != out.DiscountedModel:\n", in.DiscountedModel(), out.DiscountedModel()) + t.Fail() + } + + if in.Engine().String() != out.Engine().String() { + t.Log("in.Engine != out.Engine:\n", in.Engine().String(), out.Engine().String()) + t.Fail() + } + + return + +} + +func TestDecodeJavaBuffer(t *testing.T) { + // See ~gocode/src/example-schema/CarExample.go for how this is generated + data := []byte{45, 0, 1, 0, 1, 0, 0, 0, 210, 4, 0, 0, 0, 0, 0, 0, 221, 7, 1, 65, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 97, 98, 99, 100, 101, 102, 6, 208, 7, 4, 49, 50, 51, 35, 1, 78, 200, 6, 0, 3, 0, 30, 0, 154, 153, 15, 66, 11, 0, 0, 0, 85, 114, 98, 97, 110, 32, 67, 121, 99, 108, 101, 55, 0, 0, 0, 68, 66, 14, 0, 0, 0, 67, 111, 109, 98, 105, 110, 101, 100, 32, 67, 121, 99, 108, 101, 75, 0, 0, 0, 32, 66, 13, 0, 0, 0, 72, 105, 103, 104, 119, 97, 121, 32, 67, 121, 99, 108, 101, 1, 0, 2, 0, 95, 6, 0, 3, 0, 30, 0, 0, 0, 128, 64, 60, 0, 0, 0, 240, 64, 100, 0, 51, 51, 67, 65, 99, 6, 0, 3, 0, 30, 0, 51, 51, 115, 64, 60, 0, 51, 51, 227, 64, 100, 0, 205, 204, 60, 65, 5, 0, 0, 0, 72, 111, 110, 100, 97, 9, 0, 0, 0, 67, 105, 118, 105, 99, 32, 86, 84, 105, 6, 0, 0, 0, 97, 98, 99, 100, 101, 102} + + var c Car + c.WrapAndApplyHeader(data, 0, uint64(len(data))) + + expected := `{"Name": "Car", "sbeTemplateId": 1, "serialNumber": "1234", "modelYear": "2013", "available": "T", "code": "A", "someNumbers": [1,2,3,4], "vehicleCode": "abcdef", "extras": ["SportsPack","CruiseControl"], "discountedModel": "C", "engine": {"capacity": "2000", "numCylinders": "4", "manufacturerCode": "123", "efficiency": "35", "boosterEnabled": "T", "booster": {"BoostType": "NITROUS", "horsePower": "200"}}, "fuelFigures": [{"speed": "30", "mpg": "35.9", "usageDescription": "Urban Cycle"}, {"speed": "55", "mpg": "49", "usageDescription": "Combined Cycle"}, {"speed": "75", "mpg": "40", "usageDescription": "Highway Cycle"}], "performanceFigures": [{"octaneRating": "95", "acceleration": [{"mph": "30", "seconds": "4"}, {"mph": "60", "seconds": "7.5"}, {"mph": "100", "seconds": "12.2"}]}, {"octaneRating": "99", "acceleration": [{"mph": "30", "seconds": "3.8"}, {"mph": "60", "seconds": "7.1"}, {"mph": "100", "seconds": "11.8"}]}], "manufacturer": "Honda", "model": "Civic VTi", "activationCode": "abcdef"}` + if actual := c.String(); actual != expected { + t.Logf("Failed to decode car, expected %s, got %s", expected, actual) + t.Fail() + } + return +} diff --git a/gocode/flyweight/src/basic/SBE tests/ENUM_test.go b/gocode/flyweight/src/basic/SBE tests/ENUM_test.go new file mode 100644 index 0000000000..0a3418592d --- /dev/null +++ b/gocode/flyweight/src/basic/SBE tests/ENUM_test.go @@ -0,0 +1,12 @@ +package sbe_tests + +import ( + "testing" +) + +func TestEnum(t *testing.T) { + e := ENUM_Value1 + if e.String() != "Value1" { + t.Fail() + } +} diff --git a/gocode/flyweight/src/basic/SBE tests/Message1_test.go b/gocode/flyweight/src/basic/SBE tests/Message1_test.go new file mode 100644 index 0000000000..c6963115a2 --- /dev/null +++ b/gocode/flyweight/src/basic/SBE tests/Message1_test.go @@ -0,0 +1,29 @@ +package sbe_tests + +import ( + "testing" +) + +func TestEncodeDecodeMessage1(t *testing.T) { + var data [256]byte + var in Message1 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.SetEDTField("abcdefghijklmnopqrst") + in.SetENUMField(ENUM_Value10) + + var out Message1 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + expected := `{"Name": "Message1", "sbeTemplateId": 1, "header": {"blockLength": "0", "templateId": "0", "schemaId": "0", "version": "0"}, "EDTField": "abcdefghijklmnopqrst", "ENUMField": "Value10", "SETField": [], "int64Field": "0"}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} diff --git a/gocode/flyweight/src/basic/SBE tests/SET_test.go b/gocode/flyweight/src/basic/SBE tests/SET_test.go new file mode 100644 index 0000000000..936730c617 --- /dev/null +++ b/gocode/flyweight/src/basic/SBE tests/SET_test.go @@ -0,0 +1,28 @@ +package sbe_tests + +import ( + "testing" +) + +func TestEncodeDecodeSet(t *testing.T) { + var data [256]byte + var in SET + in.Wrap(data[:], 0, 0, uint64(len(data))) + in.SetBit16(true) + + var out SET + out.Wrap( + data[:], + 0, + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + if out.Bit0() { + t.Fail() + } + + if !out.Bit16() { + t.Fail() + } +} diff --git a/gocode/flyweight/src/composite/Composite_test.go b/gocode/flyweight/src/composite/Composite_test.go new file mode 100644 index 0000000000..20e5c9e757 --- /dev/null +++ b/gocode/flyweight/src/composite/Composite_test.go @@ -0,0 +1,52 @@ +package composite + +import ( + "testing" +) + +func TestEncodeDecode(t *testing.T) { + var data [256]byte + var in Composite + in.WrapForEncode(data[:], 0, uint64(len(data))) + + if in.SbeBlockAndHeaderLength() != 50 { + t.Logf("Failed to encode, expected %d, got %d", + 50, + in.SbeBlockAndHeaderLength(), + ) + t.Fail() + } + + in.Start(). + SetName("start"). + SetD(3.14). + SetI(1). + SetUIndex(0, 66). + SetUIndex(1, 77). + SetTruthval1(BooleanEnum_NULL_VALUE). + SetTruthval2(BooleanEnum_T) + + in.End(). + SetName("end"). + SetD(0.31). + SetI(2). + SetUIndex(0, 77). + SetUIndex(1, 88). + SetTruthval1(BooleanEnum_T). + SetTruthval2(BooleanEnum_F) + + var out Composite + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeSchemaVersion()), + uint64(in.SbeBlockLength()), + uint64(len(data)), + ) + + expected := `{"Name": "Composite", "sbeTemplateId": 1, "start": {"name": "start", "d": "3.14", "i": "1", "u": [66,77], "truthval1": "NULL_VALUE", "truthval2": "T"}, "end": {"name": "end", "d": "0.31", "i": "2", "u": [77,88], "truthval1": "T", "truthval2": "F"}}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} diff --git a/gocode/flyweight/src/composite_elements/Message_test.go b/gocode/flyweight/src/composite_elements/Message_test.go new file mode 100644 index 0000000000..90dfe20f98 --- /dev/null +++ b/gocode/flyweight/src/composite_elements/Message_test.go @@ -0,0 +1,91 @@ +package composite_elements + +import ( + "testing" +) + +func TestEncodeDecodeMsg(t *testing.T) { + var data [256]byte + var in Msg + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.Structure(). + SetEnumOne(EnumOne_Value10). + SetZeroth(0) + in.Structure(). + SetOne().SetBit0(true) + in.Structure().Inner(). + SetFirst(1). + SetSecond(2) + + var out Msg + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeSchemaVersion()), + uint64(in.SbeBlockLength()), + uint64(len(data)), + ) + + expected := `{"Name": "Msg", "sbeTemplateId": 1, "structure": {"enumOne": "Value10", "zeroth": "0", "setOne": ["Bit0"], "inner": {"first": "1", "second": "2"}}}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} + +func TestEncodeDecodeMsg2(t *testing.T) { + var data [256]byte + var in Msg2 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.Structure(). + SetEnumOne(EnumOne_Value10). + SetZeroth(0) + in.Structure(). + SetOne().SetBit16(true) + in.Structure().Inner(). + SetFirst(1). + SetSecond(2) + + var out Msg2 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeSchemaVersion()), + uint64(in.SbeBlockLength()), + uint64(len(data)), + ) + + expected := `{"Name": "Msg2", "sbeTemplateId": 2, "structure": {"enumOne": "Value10", "zeroth": "0", "setOne": ["Bit16"], "inner": {"first": "1", "second": "2"}}}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} + +func TestEncodeDecodeMsg3(t *testing.T) { + var data [256]byte + var in Msg3 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.Structure(). + SetMantissa(65). + SetExponent(3). + SetIsSettlement(BooleanEnum_T) + + var out Msg3 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeSchemaVersion()), + uint64(in.SbeBlockLength()), + uint64(len(data)), + ) + + expected := `{"Name": "Msg3", "sbeTemplateId": 3, "structure": {"mantissa": "65", "exponent": "3", "isSettlement": "T"}}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} diff --git a/gocode/flyweight/src/example-schema/CarExample_test.go b/gocode/flyweight/src/example-schema/CarExample_test.go new file mode 100644 index 0000000000..12b8d3edc8 --- /dev/null +++ b/gocode/flyweight/src/example-schema/CarExample_test.go @@ -0,0 +1,572 @@ +package main + +import ( + "fmt" + "github.com/real-logic/simple-binary-encoding/src/baseline" + "github.com/real-logic/simple-binary-encoding/src/extension" + "io" + "testing" +) + +func TestNoop(t *testing.T) { +} + +func BenchmarkInstantiateCar(b *testing.B) { + var data [256]byte + for i := 0; i < b.N; i++ { + var hdr baseline.MessageHeader + var car baseline.Car + makeCar(&hdr, &car, data[:], 0) + } +} + +func BenchmarkDecodeStrict(b *testing.B) { + var data [256]byte + var hdr baseline.MessageHeader + var car baseline.Car + makeCar(&hdr, &car, data[:], 0) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + var out baseline.Car + out.WrapForDecode( + data[:], + 0, + uint64(car.SbeBlockLength()), + uint64(car.SbeSchemaVersion()), + uint64(len(data)), + ) + } +} + +func BenchmarkPipe(b *testing.B) { + var r, w = io.Pipe() + data := []byte{49, 0, 1, 0, 1, 0, 0, 0, 210, 4, 0, 0, 0, 0, 0, 0, 221, 7, 1, 65, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 97, 98, 99, 100, 101, 102, 6, 208, 7, 4, 49, 50, 51, 35, 1, 78, 200, 6, 0, 3, 0, 30, 0, 154, 153, 15, 66, 11, 0, 0, 0, 85, 114, 98, 97, 110, 32, 67, 121, 99, 108, 101, 55, 0, 0, 0, 68, 66, 14, 0, 0, 0, 67, 111, 109, 98, 105, 110, 101, 100, 32, 67, 121, 99, 108, 101, 75, 0, 0, 0, 32, 66, 13, 0, 0, 0, 72, 105, 103, 104, 119, 97, 121, 32, 67, 121, 99, 108, 101, 1, 0, 2, 0, 95, 6, 0, 3, 0, 30, 0, 0, 0, 128, 64, 60, 0, 0, 0, 240, 64, 100, 0, 51, 51, 67, 65, 99, 6, 0, 3, 0, 30, 0, 51, 51, 115, 64, 60, 0, 51, 51, 227, 64, 100, 0, 205, 204, 60, 65, 5, 0, 0, 0, 72, 111, 110, 100, 97, 9, 0, 0, 0, 67, 105, 118, 105, 99, 32, 86, 84, 105, 6, 0, 0, 0, 97, 98, 99, 100, 101, 102} + writerReady := make(chan bool) + + go func() { + defer w.Close() + writerReady <- true + // By way of test, stream the bytes into the pipe a + // chunk at a time + for looping := true; looping; { + if _, err := w.Write(data); err != nil { + looping = false + } + } + }() + + <-writerReady + b.ResetTimer() + + var buf [1024]byte + for i := 0; i < b.N; i++ { + var hdr baseline.MessageHeader + hdrSize := int(hdr.EncodedLength()) + _, err := io.ReadAtLeast(r, buf[:], hdrSize) + if err != nil { + b.Log("Failed to read", err) + b.Fail() + } + hdr.Wrap(buf[:], 0, 0, uint64(hdrSize)) + + n, err := io.ReadAtLeast(r, buf[:], hdrSize) + if err != nil { + b.Log("Failed to read", err) + b.Fail() + } + + var out baseline.Car + out.WrapForDecode( + buf[hdrSize:], + 0, + uint64(hdr.BlockLength()), + hdr.ActingVersion(), + uint64(n-hdrSize), + ) + } + r.Close() +} + +func BenchmarkPipeBufio(b *testing.B) { + var r, w = io.Pipe() + data := []byte{49, 0, 1, 0, 1, 0, 0, 0, 210, 4, 0, 0, 0, 0, 0, 0, 221, 7, 1, 65, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 97, 98, 99, 100, 101, 102, 6, 208, 7, 4, 49, 50, 51, 35, 1, 78, 200, 6, 0, 3, 0, 30, 0, 154, 153, 15, 66, 11, 0, 0, 0, 85, 114, 98, 97, 110, 32, 67, 121, 99, 108, 101, 55, 0, 0, 0, 68, 66, 14, 0, 0, 0, 67, 111, 109, 98, 105, 110, 101, 100, 32, 67, 121, 99, 108, 101, 75, 0, 0, 0, 32, 66, 13, 0, 0, 0, 72, 105, 103, 104, 119, 97, 121, 32, 67, 121, 99, 108, 101, 1, 0, 2, 0, 95, 6, 0, 3, 0, 30, 0, 0, 0, 128, 64, 60, 0, 0, 0, 240, 64, 100, 0, 51, 51, 67, 65, 99, 6, 0, 3, 0, 30, 0, 51, 51, 115, 64, 60, 0, 51, 51, 227, 64, 100, 0, 205, 204, 60, 65, 5, 0, 0, 0, 72, 111, 110, 100, 97, 9, 0, 0, 0, 67, 105, 118, 105, 99, 32, 86, 84, 105, 6, 0, 0, 0, 97, 98, 99, 100, 101, 102} + + writerReady := make(chan bool) + + go func() { + defer w.Close() + writerReady <- true + // By way of test, stream the bytes into the pipe a + // chunk at a time + for looping := true; looping; { + if _, err := w.Write(data); err != nil { + looping = false + } + } + }() + + <-writerReady + b.ResetTimer() + + var buf [1024]byte + for i := 0; i < b.N; i++ { + var hdr baseline.MessageHeader + hdrSize := int(hdr.EncodedLength()) + _, err := io.ReadAtLeast(r, buf[:], hdrSize) + if err != nil { + b.Log("Failed to read", err) + b.Fail() + } + hdr.Wrap(buf[:], 0, 0, uint64(hdrSize)) + + n, err := io.ReadAtLeast(r, buf[:], hdrSize) + if err != nil { + b.Log("Failed to read", err) + b.Fail() + } + + var out baseline.Car + out.WrapForDecode( + buf[:], + uint64(hdrSize), + uint64(hdr.BlockLength()), + hdr.ActingVersion(), + uint64(n-hdrSize), + ) + } + r.Close() +} + +// String Preallocations which matches what the Java and C++ benchmarks do +var vehicleCode = [6]byte{'a', 'b', 'c', 'd', 'e', 'f'} +var manufacturerCode = [3]byte{'1', '2', '3'} +var manufacturer = []uint8("Honda") +var model = []uint8("Civic VTi") +var activationCode = []uint8("abcdef") + +// Both Java and C++ benchmarks ignore CarFuelFigures.UsageDescription +var urban = []uint8("Urban Cycle") +var combined = []uint8("Combined Cycle") +var highway = []uint8("Highway Cycle") + +func ExampleEncodeDecode() { + var data [256]byte + var hdr baseline.MessageHeader + var in baseline.Car + + makeCar(&hdr, &in, data[:], 0) + in.WrapForDecode( + data[:], + hdr.EncodedLength(), + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data))-hdr.EncodedLength(), + ) + + var out baseline.Car + out.WrapForDecode( + data[:], + hdr.EncodedLength(), + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data))-hdr.EncodedLength(), + ) + + if in.SerialNumber() != out.SerialNumber() { + fmt.Println("in.SerialNumber() != out.SerialNumber():\n", in.SerialNumber(), out.SerialNumber()) + return + } + if in.ModelYear() != out.ModelYear() { + fmt.Println("in.ModelYear() != out.ModelYear():\n", in.ModelYear(), out.ModelYear()) + return + } + if in.Available() != out.Available() { + fmt.Println("in.Available() != out.Available():\n", in.Available(), out.Available()) + return + } + if in.Code() != out.Code() { + fmt.Println("in.Code() != out.Code():\n", in.Code(), out.Code()) + return + } + + if in.SomeNumbersLength() != out.SomeNumbersLength() { + fmt.Println("in.SomeNumbers != out.SomeNumbers:\n", in.SomeNumbersLength(), out.SomeNumbersLength()) + return + } + for i := uint64(0); i < uint64(in.SomeNumbersLength()); i++ { + if in.SomeNumbersIndex(i) != out.SomeNumbersIndex(i) { + fmt.Println("in.SomeNumbers != out.SomeNumbers:\n", in.SomeNumbersIndex(i), out.SomeNumbersIndex(i)) + return + } + } + + if in.GetVehicleCodeAsString() != out.GetVehicleCodeAsString() { + fmt.Println("in.VehicleCode != out.VehicleCode:\n", in.GetVehicleCodeAsString(), out.GetVehicleCodeAsString()) + return + } + if in.Extras().String() != out.Extras().String() { + fmt.Println("in.Extras != out.Extras:\n", in.Extras().String(), out.Extras().String()) + return + } + if baseline.Model_C != out.DiscountedModel() { + fmt.Println("in.DiscountedModel != out.DiscountedModel:\n", in.DiscountedModel(), out.DiscountedModel()) + return + } + if in.Engine().String() != out.Engine().String() { + fmt.Println("in.Engine != out.Engine:\n", in.Engine().String(), "\n", out.Engine().String()) + return + } + // Output: +} + +func ExampleCarToExtension() { + var data [256]byte + var hdr baseline.MessageHeader + var in baseline.Car + + makeCar(&hdr, &in, data[:], 0) + + in.WrapForDecode( + data[:], + hdr.EncodedLength(), + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data))-hdr.EncodedLength(), + ) + + var out extension.Car + out.WrapForDecode( + data[:], + hdr.EncodedLength(), + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data))-hdr.EncodedLength(), + ) + + if in.SerialNumber() != out.SerialNumber() { + fmt.Println("in.SerialNumber() != out.SerialNumber():\n", in.SerialNumber(), out.SerialNumber()) + return + } + if in.ModelYear() != out.ModelYear() { + fmt.Println("in.ModelYear() != out.ModelYear():\n", in.ModelYear(), out.ModelYear()) + return + } + + // Note casts so we can compare + if in.Available() != baseline.BooleanType(out.Available()) { + fmt.Println("in.Available != out.Available:\n", in.Available(), out.Available()) + return + } + if in.Code() != baseline.Model(out.Code()) { + fmt.Println("in.Code != out.Code:\n", in.Code(), out.Code()) + return + } + + if in.SomeNumbersLength() != out.SomeNumbersLength() { + fmt.Println("in.SomeNumbers != out.SomeNumbers:\n", in.SomeNumbersLength(), out.SomeNumbersLength()) + return + } + for i := uint64(0); i < uint64(in.SomeNumbersLength()); i++ { + if in.SomeNumbersIndex(i) != out.SomeNumbersIndex(i) { + fmt.Println("in.SomeNumbers != out.SomeNumbers:\n", in.SomeNumbersIndex(i), out.SomeNumbersIndex(i)) + return + } + } + + if in.GetVehicleCodeAsString() != out.GetVehicleCodeAsString() { + fmt.Println("in.VehicleCode != out.VehicleCode:\n", in.GetVehicleCodeAsString(), out.GetVehicleCodeAsString()) + return + } + if in.Extras().String() != out.Extras().String() { + fmt.Println("in.Extras != out.Extras:\n", in.Extras().String(), out.Extras().String()) + return + } + if extension.Model_C != out.DiscountedModel() { + fmt.Println("in.DiscountedModel != out.DiscountedModel:\n", in.DiscountedModel(), out.DiscountedModel()) + return + } + if in.Engine().String() != out.Engine().String() { + fmt.Println("in.Engine != out.Engine:\n", in.Engine().String(), "\n", out.Engine().String()) + return + } + + // Engine has two constant values which should come back filled in + if in.Engine().MaxRpm() != out.Engine().MaxRpm() { + fmt.Println("in.Engine.MaxRpm != out.Engine/MaxRpm:\n", + in.Engine().MaxRpm(), out.Engine().MaxRpm()) + return + } + + inFuelFigures, outFuelFigures := in.FuelFigures(), out.FuelFigures() + if inFuelFigures.Count() != outFuelFigures.Count() { + fmt.Println("in.FuelFiguresCount() != out.FuelFiguresCount():\n", + inFuelFigures.Count(), outFuelFigures.Count()) + return + } + for i := uint64(0); i < inFuelFigures.Count(); i++ { + inFuelFigures, outFuelFigures = inFuelFigures.Next(), outFuelFigures.Next() + if e, a := inFuelFigures.String(), outFuelFigures.String(); e != a { + fmt.Println("in.FuelFigures != out.FuelFigures:\n", e, a) + return + } + } + + inPerformanceFigures, outPerformanceFigures := in.PerformanceFigures(), out.PerformanceFigures() + if inPerformanceFigures.Count() != outPerformanceFigures.Count() { + fmt.Println("in.PerformanceFiguresCount() != out.PerformanceFiguresCount():\n", + inPerformanceFigures.Count(), outPerformanceFigures.Count()) + return + } + for i := uint64(0); i < inPerformanceFigures.Count(); i++ { + inPerformanceFigures, outPerformanceFigures = inPerformanceFigures.Next(), outPerformanceFigures.Next() + if e, a := inPerformanceFigures.String(), outPerformanceFigures.String(); e != a { + fmt.Println("in.PerformanceFigures != out.PerformanceFigures:\n", e, a) + return + } + } + + if e, a := in.Manufacturer(), out.Manufacturer(); e != a { + fmt.Println("in.Manufacturer != out.Manufacturer:\n", e, a) + return + } + + if e, a := in.Model(), out.Model(); e != a { + fmt.Println("in.Model != out.Model:\n", e, a) + return + } + + if e, a := in.ActivationCode(), out.ActivationCode(); e != a { + fmt.Println("in.ActivationCode != out.ActivationCode:\n", e, a) + return + } + + // Cupholder is not in example-schema and was introduced in + // extension-schema, so it should be NullValue + if out.CupHolderCount() != out.CupHolderCountNullValue() { + fmt.Println("out.cupholderCount not successfully nulled:\n", out.CupHolderCount()) + return + } + // Output: +} + +func ExampleExtensionToCar() { + var data [256]byte + var hdr extension.MessageHeader + var in extension.Car + + makeExtension(&hdr, &in, data[:], 0) + + in.WrapForDecode( + data[:], + hdr.EncodedLength(), + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data))-hdr.EncodedLength(), + ) + + var out baseline.Car + out.WrapForDecode( + data[:], + hdr.EncodedLength(), + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data))-hdr.EncodedLength(), + ) + + if in.SerialNumber() != out.SerialNumber() { + fmt.Println("in.SerialNumber() != out.SerialNumber():\n", in.SerialNumber(), out.SerialNumber()) + return + } + if in.ModelYear() != out.ModelYear() { + fmt.Println("in.ModelYear() != out.ModelYear():\n", in.ModelYear(), out.ModelYear()) + return + } + + // Note casts so we can compare + if in.Available() != extension.BooleanType(out.Available()) { + fmt.Println("in.Available != out.Available:\n", in.Available(), out.Available()) + return + } + if in.Code() != extension.Model(out.Code()) { + fmt.Println("in.Code != out.Code:\n", in.Code(), out.Code()) + return + } + + if in.SomeNumbersLength() != out.SomeNumbersLength() { + fmt.Println("in.SomeNumbers != out.SomeNumbers:\n", in.SomeNumbersLength(), out.SomeNumbersLength()) + return + } + for i := uint64(0); i < uint64(in.SomeNumbersLength()); i++ { + if in.SomeNumbersIndex(i) != out.SomeNumbersIndex(i) { + fmt.Println("in.SomeNumbers != out.SomeNumbers:\n", in.SomeNumbersIndex(i), out.SomeNumbersIndex(i)) + return + } + } + + if in.GetVehicleCodeAsString() != out.GetVehicleCodeAsString() { + fmt.Println("in.VehicleCode != out.VehicleCode:\n", in.GetVehicleCodeAsString(), out.GetVehicleCodeAsString()) + return + } + if in.Extras().String() != out.Extras().String() { + fmt.Println("in.Extras != out.Extras:\n", in.Extras().String(), out.Extras().String()) + return + } + if baseline.Model_C != out.DiscountedModel() { + fmt.Println("in.DiscountedModel != out.DiscountedModel:\n", in.DiscountedModel(), out.DiscountedModel()) + return + } + if in.Engine().String() != out.Engine().String() { + fmt.Println("in.Engine != out.Engine:\n", in.Engine().String(), "\n", out.Engine().String()) + return + } + + inFuelFigures, outFuelFigures := in.FuelFigures(), out.FuelFigures() + if inFuelFigures.Count() != outFuelFigures.Count() { + fmt.Println("in.FuelFiguresCount() != out.FuelFiguresCount():\n", + inFuelFigures.Count(), outFuelFigures.Count()) + return + } + for i := uint64(0); i < inFuelFigures.Count(); i++ { + inFuelFigures, outFuelFigures = inFuelFigures.Next(), outFuelFigures.Next() + if e, a := inFuelFigures.String(), outFuelFigures.String(); e != a { + fmt.Println("in.FuelFigures != out.FuelFigures:\n", e, a) + return + } + } + + inPerformanceFigures, outPerformanceFigures := in.PerformanceFigures(), out.PerformanceFigures() + if inPerformanceFigures.Count() != outPerformanceFigures.Count() { + fmt.Println("in.PerformanceFiguresCount() != out.PerformanceFiguresCount():\n", + inPerformanceFigures.Count(), outPerformanceFigures.Count()) + return + } + for i := uint64(0); i < inPerformanceFigures.Count(); i++ { + inPerformanceFigures, outPerformanceFigures = inPerformanceFigures.Next(), outPerformanceFigures.Next() + if e, a := inPerformanceFigures.String(), outPerformanceFigures.String(); e != a { + fmt.Println("in.PerformanceFigures != out.PerformanceFigures:\n", e, a) + return + } + } + + if e, a := in.ActivationCode(), out.ActivationCode(); e != a { + fmt.Println("in.ActivationCode != out.ActivationCode:\n", e, a) + return + } + // Output: +} + +// Helper to make a Car object as per the Java example +func makeCar(messageHeader *baseline.MessageHeader, car *baseline.Car, buffer []byte, bufferIndex uint64) { + messageHeader.Wrap(buffer, bufferIndex, uint64(messageHeader.SbeSchemaVersion()), uint64(len(buffer))) + + car.WrapAndApplyHeader(buffer, bufferIndex, uint64(len(buffer))-uint64(messageHeader.BlockLength())). + SetSerialNumber(1234). + SetModelYear(2013). + SetAvailable(baseline.BooleanType_T). + SetCode(baseline.Model_A). + PutVehicleCode(vehicleCode[:]) + + size := car.SomeNumbersLength() + for i := 0; i < size; i++ { + car.SetSomeNumbersIndex(uint64(i), uint32(i)) + } + + car.Extras().Clear(). + SetSportsPack(true). + SetSunRoof(true) + + car.Engine(). + SetCapacity(2000). + SetNumCylinders(4). + SetManufacturerCode(string(manufacturerCode[:])). + SetEfficiency(35). + SetBoosterEnabled(baseline.BooleanType_T). + Booster(). + SetBoostType(baseline.BoostType_NITROUS). + SetHorsePower(200) + + car.FuelFiguresCount(3).Next(). + SetSpeed(30).SetMpg(35.9).PutUsageDescription(string(urban[:])).Next(). + SetSpeed(55).SetMpg(49.0).PutUsageDescription(string(combined[:])).Next(). + SetSpeed(75).SetMpg(40.0).PutUsageDescription(string(highway[:])) + + perfFigures := car.PerformanceFiguresCount(2) + perfFigures.Next(). + SetOctaneRating(95). + AccelerationCount(3).Next(). + SetMph(30).SetSeconds(4.0).Next(). + SetMph(60).SetSeconds(7.5).Next(). + SetMph(100).SetSeconds(12.2) + perfFigures.Next(). + SetOctaneRating(99). + AccelerationCount(3).Next(). + SetMph(30).SetSeconds(3.8).Next(). + SetMph(60).SetSeconds(7.1).Next(). + SetMph(100).SetSeconds(11.8) + + car.PutManufacturer(string(manufacturer)) + car.PutModel(string(model)) + car.PutActivationCode(string(activationCode)) +} + +func makeExtension(messageHeader *extension.MessageHeader, car *extension.Car, buffer []byte, bufferIndex uint64) { + // Helper to make an Extension (car with cupholder) object + messageHeader.Wrap(buffer, bufferIndex, uint64(messageHeader.SbeSchemaVersion()), uint64(len(buffer))) + + car.WrapAndApplyHeader(buffer, bufferIndex, uint64(len(buffer))-uint64(messageHeader.BlockLength())). + SetSerialNumber(1234). + SetModelYear(2013). + SetAvailable(extension.BooleanType_T). + SetCode(extension.Model_A). + PutVehicleCode(vehicleCode[:]). + SetUuidIndex(0, 119). + SetUuidIndex(1, 120). + SetCupHolderCount(121) + + size := car.SomeNumbersLength() + for i := 0; i < size; i++ { + car.SetSomeNumbersIndex(uint64(i), uint32(i)) + } + + car.Extras().Clear(). + SetSportsPack(true). + SetSunRoof(true) + + car.Engine(). + SetCapacity(2000). + SetNumCylinders(4). + SetManufacturerCode(string(manufacturerCode[:])). + SetEfficiency(35). + SetBoosterEnabled(extension.BooleanType_T). + Booster(). + SetBoostType(extension.BoostType_NITROUS). + SetHorsePower(200) + + car.FuelFiguresCount(3).Next(). + SetSpeed(30).SetMpg(35.9).PutUsageDescription(string(urban[:])).Next(). + SetSpeed(55).SetMpg(49.0).PutUsageDescription(string(combined[:])).Next(). + SetSpeed(75).SetMpg(40.0).PutUsageDescription(string(highway[:])) + + perfFigures := car.PerformanceFiguresCount(2) + perfFigures.Next(). + SetOctaneRating(95). + AccelerationCount(3).Next(). + SetMph(30).SetSeconds(4.0).Next(). + SetMph(60).SetSeconds(7.5).Next(). + SetMph(100).SetSeconds(12.2) + perfFigures.Next(). + SetOctaneRating(99). + AccelerationCount(3).Next(). + SetMph(30).SetSeconds(3.8).Next(). + SetMph(60).SetSeconds(7.1).Next(). + SetMph(100).SetSeconds(11.8) + + car.PutManufacturer(string(manufacturer)) + car.PutModel(string(model)) + car.PutActivationCode(string(activationCode)) +} + +// The byte array can be made at ~rust/car_example/car_example_data.sbe by running gradlew generateCarExampleDataFile +// This can then be decoded using od -tu1 +var data = []byte{45, 0, 1, 0, 1, 0, 0, 0, 210, 4, 0, 0, 0, 0, 0, 0, 221, 7, 1, 65, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 97, 98, 99, 100, 101, 102, 6, 208, 7, 4, 49, 50, 51, 35, 1, 78, 200, 6, 0, 3, 0, 30, 0, 154, 153, 15, 66, 11, 0, 0, 0, 85, 114, 98, 97, 110, 32, 67, 121, 99, 108, 101, 55, 0, 0, 0, 68, 66, 14, 0, 0, 0, 67, 111, 109, 98, 105, 110, 101, 100, 32, 67, 121, 99, 108, 101, 75, 0, 0, 0, 32, 66, 13, 0, 0, 0, 72, 105, 103, 104, 119, 97, 121, 32, 67, 121, 99, 108, 101, 1, 0, 2, 0, 95, 6, 0, 3, 0, 30, 0, 0, 0, 128, 64, 60, 0, 0, 0, 240, 64, 100, 0, 51, 51, 67, 65, 99, 6, 0, 3, 0, 30, 0, 51, 51, 115, 64, 60, 0, 51, 51, 227, 64, 100, 0, 205, 204, 60, 65, 5, 0, 0, 0, 72, 111, 110, 100, 97, 9, 0, 0, 0, 67, 105, 118, 105, 99, 32, 86, 84, 105, 6, 0, 0, 0, 97, 98, 99, 100, 101, 102} diff --git a/gocode/flyweight/src/group/SBE tests/TestMessage1_test.go b/gocode/flyweight/src/group/SBE tests/TestMessage1_test.go new file mode 100644 index 0000000000..1525462f9f --- /dev/null +++ b/gocode/flyweight/src/group/SBE tests/TestMessage1_test.go @@ -0,0 +1,55 @@ +package sbe_tests + +import ( + "testing" +) + +func TestEncodeDecodeTestMessage1(t *testing.T) { + + var data [256]byte + var in TestMessage1 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.SetTag1(44) + in.EntriesCount(1).Next(). + SetTagGroup1("abcdefghijklmnopqrst"). + SetTagGroup2(7) + + in.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + var out TestMessage1 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + if in.Tag1() != out.Tag1() { + t.Log("in != out:\n", in.Tag1(), out.Tag1()) + t.Fail() + } + inEntries, outEntries := in.Entries(), out.Entries() + if inEntries.Count() != outEntries.Count() { + t.Logf("len(in.Entries)(%d) != len(out.Entries)(%d):\n", inEntries.Count(), outEntries.Count()) + t.Fail() + } + for i := uint64(0); i < inEntries.Count(); i++ { + outEntries = outEntries.Next() + inEntries = inEntries.Next() + if inEntries.String() != outEntries.String() { + t.Logf("in.Entries[%d] != out.Entries[%d]: %s %s\n", i, i, inEntries.String(), outEntries.String()) + t.Fail() + } + } + + return + +} diff --git a/gocode/flyweight/src/group_with_data/TestMessages_test.go b/gocode/flyweight/src/group_with_data/TestMessages_test.go new file mode 100644 index 0000000000..73d8066e3f --- /dev/null +++ b/gocode/flyweight/src/group_with_data/TestMessages_test.go @@ -0,0 +1,200 @@ +package group_with_data + +import ( + _ "fmt" + "testing" +) + +func TestEncodeDecodeTestMessage1(t *testing.T) { + var data [256]byte + var in TestMessage1 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.SetTag1(1234) + in.EntriesCount(1).Next(). + SetTagGroup1("123456789"). + SetTagGroup2(123456789). + PutVarDataField("abcdef") + + var out TestMessage1 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + expected := `{"Name": "TestMessage1", "sbeTemplateId": 1, "Tag1": "1234", "Entries": [{"TagGroup1": "123456789", "TagGroup2": "123456789", "varDataField": "abcdef"}]}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} + +func TestEncodeDecodeTestMessage2(t *testing.T) { + var data [256]byte + var in TestMessage2 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + tag1 := uint32(1234) + tagGroup1 := "123456789" + tagGroup2 := int64(123456789) + varDataField1 := "abcdef" + varDataField2 := "ghij" + + in.SetTag1(tag1) + entries := in.EntriesCount(2) + for i := 0; i < 2; i++ { + entry := entries.Next() + entry.SetTagGroup1(tagGroup1). + SetTagGroup2(tagGroup2). + PutVarDataField1(varDataField1). + PutVarDataField2(varDataField2) + } + + var out TestMessage2 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + if out.Tag1() != tag1 { + t.Logf("Tag1 failed, expected %d, got %d", tag1, out.Tag1()) + t.Fail() + } + outEntries := out.Entries() + for i := 0; i < 2; i++ { + entry := outEntries.Next() + if entry.GetTagGroup1AsString() != tagGroup1 { + t.Logf("TagGroup1 failed at index %d, expected %s, got %s", i, tagGroup1, entry.GetTagGroup1AsString()) + t.Fail() + } + if entry.TagGroup2() != tagGroup2 { + t.Logf("TagGroup2 failed at index %d, expected %d, got %d", i, tagGroup2, entry.TagGroup2()) + t.Fail() + } + if entry.VarDataField1() != varDataField1 { + t.Logf("VarDataField1 failed at index %d, expected %s, got %s", i, varDataField1, entry.VarDataField1()) + t.Fail() + } + if entry.VarDataField2() != varDataField2 { + t.Logf("VarDataField2 failed at index %d, expected %s, got %s", i, varDataField2, entry.VarDataField2()) + t.Fail() + } + } +} + +func TestEncodeDecodeTestMessage3(t *testing.T) { + var data [256]byte + var in TestMessage3 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + tag1 := uint32(1234) + tagGroup1 := "123456789" + varDataField := "middle" + tagGroup2Nested := int64(99887766) + varDataFieldNested := "nested" + + in.SetTag1(tag1) + entries := in.EntriesCount(2) + for i := 0; i < 2; i++ { + entry := entries.Next() + entry.SetTagGroup1(tagGroup1). + PutVarDataField(varDataField). + NestedEntriesCount(1).Next(). + SetTagGroup2(tagGroup2Nested). + PutVarDataFieldNested(varDataFieldNested) + } + + in.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + var out TestMessage3 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + if out.Tag1() != tag1 { + t.Logf("Tag1 failed, expected %d, got %d", tag1, out.Tag1()) + t.Fail() + } + outEntries := out.Entries() + for i := 0; i < 2; i++ { + entry := outEntries.Next() + if entry.GetTagGroup1AsString() != tagGroup1 { + t.Logf("TagGroup1 failed at index %d, expected %s, got %s", i, tagGroup1, entry.GetTagGroup1AsString()) + t.Fail() + } + if entry.VarDataField() != varDataField { + t.Logf("VarDataField failed at index %d, expected %s, got %s", i, varDataField, entry.VarDataField()) + t.Fail() + } + nestedEntry := entry.NestedEntries().Next() + if nestedEntry.TagGroup2() != tagGroup2Nested { + t.Logf("TagGroup2Nested failed at index %d, expected %d, got %d", i, tagGroup2Nested, nestedEntry.TagGroup2()) + t.Fail() + } + if nestedEntry.VarDataFieldNested() != varDataFieldNested { + t.Logf("VarDataFieldNested failed at index %d, expected %s, got %s", i, varDataFieldNested, nestedEntry.VarDataFieldNested()) + t.Fail() + } + } +} + +func TestEncodeDecodeTestMessage4(t *testing.T) { + var data [256]byte + var in TestMessage4 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + tag1 := uint32(9876) + varDataField1 := "abcdef" + varDataField2 := "ghij" + + in.SetTag1(tag1) + entries := in.EntriesCount(3) + for i := 0; i < 3; i++ { + entry := entries.Next() + entry.PutVarDataField1(varDataField1). + PutVarDataField2(varDataField2) + } + + var out TestMessage4 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + if out.Tag1() != tag1 { + t.Logf("Tag1 failed, expected %d, got %d", tag1, out.Tag1()) + t.Fail() + } + + outEntries := out.Entries() + for i := 0; i < 3; i++ { + entry := outEntries.Next() + if entry.VarDataField1() != varDataField1 { + t.Logf("VarDataField1 failed at index %d, expected %s, got %s", i, varDataField1, entry.VarDataField1()) + t.Fail() + } + if entry.VarDataField2() != varDataField2 { + t.Logf("VarDataField2 failed at index %d, expected %s, got %s", i, varDataField2, entry.VarDataField2()) + t.Fail() + } + } +} diff --git a/gocode/flyweight/src/group_with_data_extension/Extension_test.go b/gocode/flyweight/src/group_with_data_extension/Extension_test.go new file mode 100644 index 0000000000..2f9547b94a --- /dev/null +++ b/gocode/flyweight/src/group_with_data_extension/Extension_test.go @@ -0,0 +1,210 @@ +package group_with_data_extension + +import ( + "fmt" + "group_with_data" + "math" + "testing" +) + +// Note, this is a copy of group-with-data that we extended to test +// message extensions within a nested group and vardata +func makeTestMessage3Extension() (data []byte, msg *TestMessage3) { + data = make([]byte, 256) + var t TestMessage3 + t.WrapForEncode(data[:], 0, uint64(len(data))) + + t.SetTag1(1234) + + entries := t.EntriesCount(2) // Assuming 2 entries + for i := 0; i < 2; i++ { + entry := entries.Next() + entry.SetTagGroup1("123456789") + + nestedEntries := entry.NestedEntriesCount(1) // Assuming 1 nested entry + nestedEntry := nestedEntries.Next() + nestedEntry.SetTagGroup2(99887766) + nestedEntry.SetInnerExtension(11112222) + nestedEntry.PutVarDataFieldNested("nested") + + entry.PutVarDataField("middle") + } + + return data, &t +} + +func makeTestMessage3Original() (data []byte, msg *group_with_data.TestMessage3) { + data = make([]byte, 256) + var t group_with_data.TestMessage3 + t.WrapForEncode(data[:], 0, uint64(len(data))) + + t.SetTag1(1234) + + entries := t.EntriesCount(2) // Assuming 2 entries + for i := 0; i < 2; i++ { + entry := entries.Next() + entry.SetTagGroup1("123456789") + + nestedEntries := entry.NestedEntriesCount(1) // Assuming 1 nested entry + nestedEntry := nestedEntries.Next() + nestedEntry.SetTagGroup2(99887766) + nestedEntry.PutVarDataFieldNested("") + + entry.PutVarDataField("middle") + } + + return data, &t +} + +// Basic test of new message +func TestEncodeDecodeNewtoNew(t *testing.T) { + data, in := makeTestMessage3Extension() + + var out TestMessage3 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + if in.Tag1() != out.Tag1() { + t.Logf("in.Tag1 != out.Tag1") + t.Fail() + } + + entries := out.Entries() + for i := 0; i < int(entries.Count()); i++ { + entry := entries.Next() + if entry.GetTagGroup1AsString() != "123456789" { + t.Logf("entry.TagGroup1 != out.Entries[0].TagGroup1") + fmt.Printf("%+v\n%+v\n", in, out) + t.Fail() + } + + nestedEntry := entry.NestedEntries().Next() + if nestedEntry.TagGroup2() != 99887766 { + t.Logf("nestedEntry.TagGroup2 != out.Entries[0].NestedEntries[0].TagGroup2") + fmt.Printf("%+v\n%+v\n", in, out) + t.Fail() + } + + if nestedEntry.InnerExtension() != 11112222 { + t.Logf("n.Entries[0].NestedEntries[0].InnerExtension != out.Entries[0].NestedEntries[0].InnerExtension") + fmt.Printf("%+v\n%+v\n", in, out) + t.Fail() + } + + if nestedEntry.VarDataFieldNested() != "nested" { + t.Logf("in.Entries[0].NestedEntries[0].VarDataFieldNested != out.Entries[0].NestedEntries[0].VarDataFieldNested") + fmt.Printf("%+v\n%+v\n", in, out) + t.Fail() + } + + if value := entry.VarDataField(); value != "middle" { + t.Logf("in.Entries[%d].VarDataField (%v) != entry.VarDataField (%v)", i, value, "middle") + t.Fail() + } + } +} + +// Test of New to Old +func TestEncodeDecodeNewToOld(t *testing.T) { + data, in := makeTestMessage3Extension() + + var out group_with_data.TestMessage3 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + if in.Tag1() != out.Tag1() { + t.Logf("in.Tag1 != out.Tag1") + t.Fail() + } + + entries := out.Entries() + for i := 0; i < int(entries.Count()); i++ { + entry := entries.Next() + if value := entry.GetTagGroup1AsString(); value != "123456789" { + t.Logf("entry.TagGroup1 (%s) != out.Entries[0].TagGroup1 (%s)", + value, "123456789") + t.Fail() + } + + nestedEntry := entry.NestedEntries().Next() + if nestedEntry.TagGroup2() != 99887766 { + t.Logf("nestedEntry.TagGroup2 (%d) != out.Entries[0].NestedEntries[0].TagGroup2 (%d)", + nestedEntry.TagGroup2(), 99887766) + t.Fail() + } + + if nestedEntry.VarDataFieldNested() != "nested" { + t.Logf("in.Entries[0].NestedEntries[0].VarDataFieldNested (%s) != out.Entries[0].NestedEntries[0].VarDataFieldNested (%s)", + nestedEntry.VarDataFieldNested(), "nested") + t.Fail() + } + + if value := entry.VarDataField(); value != "middle" { + t.Logf("in.Entries[%d].VarDataField (%v) != entry.VarDataField (%v)", i, value, "middle") + t.Fail() + } + } +} + +// Test of Old to New +func TestEncodeDecodeOldToNew(t *testing.T) { + data, in := makeTestMessage3Original() + + var out TestMessage3 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + if in.Tag1() != out.Tag1() { + t.Logf("in.Tag1 != out.Tag1") + t.Fail() + } + + entries := out.Entries() + for i := 0; i < int(entries.Count()); i++ { + entry := entries.Next() + if entry.GetTagGroup1AsString() != "123456789" { + t.Logf("entry.TagGroup1 != out.Entries[0].TagGroup1") + fmt.Printf("%+v\n%+v\n", in, out) + t.Fail() + } + + nestedEntry := entry.NestedEntries().Next() + if nestedEntry.TagGroup2() != 99887766 { + t.Logf("nestedEntry.TagGroup2 (%d) != out.Entries[0].NestedEntries[0].TagGroup2 (%d)", + nestedEntry.TagGroup2(), 99887766) + t.Fail() + } + + if nestedEntry.InnerExtension() != math.MinInt64 { + t.Logf("n.Entries[0].NestedEntries[0].InnerExtension (%d) != out.Entries[0].NestedEntries[0].InnerExtension (%d)", + nestedEntry.InnerExtension(), math.MinInt64) + t.Fail() + } + + if value := nestedEntry.VarDataFieldNested(); value != "" { + t.Logf("in.Entries[0].NestedEntries[0].VarDataFieldNested (%s) != out.Entries[0].NestedEntries[0].VarDataFieldNested (%s)", + value, "") + t.Fail() + } + + if value := entry.VarDataField(); value != "middle" { + t.Logf("in.Entries[%d].VarDataField (%v) != entry.VarDataField (%v)", i, value, "middle") + t.Fail() + } + } +} diff --git a/gocode/flyweight/src/issue435/Issue435_test.go b/gocode/flyweight/src/issue435/Issue435_test.go new file mode 100644 index 0000000000..170967fc28 --- /dev/null +++ b/gocode/flyweight/src/issue435/Issue435_test.go @@ -0,0 +1,48 @@ +package issue435 + +import ( + "testing" +) + +func TestEncodeDecode(t *testing.T) { + + var data [256]byte + + var in Issue435 + + // Non-standard header so we use the generated one + var hdr MessageHeader + hdr.Wrap(data[:], 0, 0, uint64(len(data))) + hdr.S().SetTwo(true) + + in.WrapForEncode(data[:], hdr.EncodedLength(), uint64(len(data))-hdr.EncodedLength()) + in.Example().SetE(EnumRef_Two) + + var outHdr MessageHeader + outHdr.Wrap(data[:], 0, 0, uint64(len(data))) + + if !outHdr.S().Two() { + t.Logf("Failed to decode, expected Two to be true") + t.Fail() + } + + var out Issue435 + + out.WrapForDecode( + data[:], + hdr.EncodedLength(), + uint64(outHdr.BlockLength()), + outHdr.ActingVersion(), + uint64(len(data))) + + if out.Example().E() != EnumRef_Two { + t.Logf("Failed to decode, expected EnumRef_Two, got %d", out.Example().E()) + t.Fail() + } + + expected := `{"Name": "Issue435", "sbeTemplateId": 1, "example": {"e": "Two"}}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} diff --git a/gocode/flyweight/src/issue472/Issue472_test.go b/gocode/flyweight/src/issue472/Issue472_test.go new file mode 100644 index 0000000000..151dd62ccc --- /dev/null +++ b/gocode/flyweight/src/issue472/Issue472_test.go @@ -0,0 +1,27 @@ +package issue472 + +import ( + "testing" +) + +func TestEncodeDecode(t *testing.T) { + var data [256]byte + // in contains a single optional field which is not initialized + var in Issue472 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + var out Issue472 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + expected := `{"Name": "Issue472", "sbeTemplateId": 1, "optional": "0"}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} diff --git a/gocode/flyweight/src/issue483/Issue483_test.go b/gocode/flyweight/src/issue483/Issue483_test.go new file mode 100644 index 0000000000..7af235b396 --- /dev/null +++ b/gocode/flyweight/src/issue483/Issue483_test.go @@ -0,0 +1,35 @@ +package issue483 + +import ( + "testing" +) + +func TestPresence(t *testing.T) { + var issue483 Issue483 + + if issue483.UnsetMetaAttribute("PRESENCE") != "required" { + t.Log("Unset attribute's presence should be 'required'") + t.Fail() + } + + if issue483.RequiredMetaAttribute("PRESENCE") != "required" { + t.Log("Required attribute's presence should be 'required'") + t.Fail() + } + + if issue483.ConstantMetaAttribute("PRESENCE") != "constant" { + t.Log("Constant attribute's presence should be 'constant'") + t.Fail() + } + + // Check contant value is set by init func + if issue483.Constant() != 1 { + t.Log("Constant's value should be 1") + t.Fail() + } + + if issue483.OptionalMetaAttribute("PRESENCE") != "optional" { + t.Log("Optional attribute's presence should be 'optional'") + t.Fail() + } +} diff --git a/gocode/flyweight/src/issue488/Issue488_test.go b/gocode/flyweight/src/issue488/Issue488_test.go new file mode 100644 index 0000000000..5a01a98a15 --- /dev/null +++ b/gocode/flyweight/src/issue488/Issue488_test.go @@ -0,0 +1,9 @@ +package issue488 + +import ( + "testing" +) + +func TestPresence(t *testing.T) { + // placeholder, really just looking for clean builds +} diff --git a/gocode/flyweight/src/issue560/Issue560_test.go b/gocode/flyweight/src/issue560/Issue560_test.go new file mode 100644 index 0000000000..48756aff24 --- /dev/null +++ b/gocode/flyweight/src/issue560/Issue560_test.go @@ -0,0 +1,28 @@ +package issue560 + +import ( + "testing" +) + +func TestEncodeDecode(t *testing.T) { + var data [256]byte + + // in contains a single optional field which is not initialized + var in Issue560 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + var out Issue560 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + expected := `{"Name": "Issue560", "sbeTemplateId": 1, "discountedModel": "C"}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} diff --git a/gocode/src/issue847/issue847_test.go b/gocode/flyweight/src/issue847/issue847_test.go similarity index 100% rename from gocode/src/issue847/issue847_test.go rename to gocode/flyweight/src/issue847/issue847_test.go diff --git a/gocode/src/issue848/issue848_test.go b/gocode/flyweight/src/issue848/issue848_test.go similarity index 100% rename from gocode/src/issue848/issue848_test.go rename to gocode/flyweight/src/issue848/issue848_test.go diff --git a/gocode/src/issue849/issue849_test.go b/gocode/flyweight/src/issue849/issue849_test.go similarity index 100% rename from gocode/src/issue849/issue849_test.go rename to gocode/flyweight/src/issue849/issue849_test.go diff --git a/gocode/src/mktdata/fixme_test.go b/gocode/flyweight/src/mktdata/fixme_test.go similarity index 100% rename from gocode/src/mktdata/fixme_test.go rename to gocode/flyweight/src/mktdata/fixme_test.go diff --git a/gocode/flyweight/src/otf/go.mod b/gocode/flyweight/src/otf/go.mod new file mode 100644 index 0000000000..fbe2902e53 --- /dev/null +++ b/gocode/flyweight/src/otf/go.mod @@ -0,0 +1,10 @@ +module github.com/real-logic/simple-binary-encoding/otf/test + +require ( + github.com/real-logic/simple-binary-encoding v0.0.0-00010101000000-000000000000 + github.com/stretchr/testify v1.8.4 +) + +replace github.com/real-logic/simple-binary-encoding => ../../../../sbe-tool/src/main/golang + +go 1.12 diff --git a/gocode/flyweight/src/otf/go.sum b/gocode/flyweight/src/otf/go.sum new file mode 100644 index 0000000000..673e9186f2 --- /dev/null +++ b/gocode/flyweight/src/otf/go.sum @@ -0,0 +1,18 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gocode/flyweight/src/otf/json_test.go b/gocode/flyweight/src/otf/json_test.go new file mode 100644 index 0000000000..7f694d3fbd --- /dev/null +++ b/gocode/flyweight/src/otf/json_test.go @@ -0,0 +1,114 @@ +package otf + +import ( + "github.com/real-logic/simple-binary-encoding/json" + "github.com/real-logic/simple-binary-encoding/otf" + "github.com/real-logic/simple-binary-encoding/otf/test/code_generation_test" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestJson(t *testing.T) { + assert := assert.New(t) + + ir := otf.NewIrDecoder() + if ir.DecodeFile(SchemaFilename) < 0 { + t.Errorf("Error decoding %s", SchemaFilename) + t.Fail() + } + printer, err := json.NewJsonPrinter(ir) + assert.NoErrorf(err, "Error creating JsonPrinter: %v", err) + assert.NotNil(printer) + + var car code_generation_test.Car + buffer := make([]byte, MsgBufferCapacity) + encodeCar(&car, buffer) + + headerDecoder, _ := otf.NewOtfHeaderDecoder(ir.Header()) + bufferOffset := 0 + schemaId, _ := headerDecoder.SchemaId(buffer[bufferOffset:]) + + if uint16(schemaId) != car.SbeSchemaId() { + t.Errorf("Invalid schema id: %d", schemaId) + } + + str, err := printer.PrintJson(buffer) + assert.NoErrorf(err, "Error printing JSON: %v", err) + expected := `{ + "serialNumber": 1234, + "modelYear": 2013, + "available": "T", + "code": "A", + "someNumbers": [0, 1, 2, 3, 4], + "vehicleCode": ["a", "b", "c", "d", "e", "f"], + "extras": { "sunRoof": false, "sportsPack": false, "cruiseControl": false }, + "discountedModel": "C", + "Engine": + { + "capacity": 2000, + "numCylinders": 4, + "maxRpm": "9000", + "manufacturerCode": ["1", "2", "3"], + "fuel": "Petrol", + "booster": + { + "BoostType": "NITROUS", + "horsePower": 200 + } + }, + "fuelFigures": [ + { + "speed": 30, + "mpg": 35.900001525878906, + "usageDescription": "Urban Cycle" + }, + { + "speed": 55, + "mpg": 49, + "usageDescription": "Combined Cycle" + }, + { + "speed": 75, + "mpg": 40, + "usageDescription": "Highway Cycle" + }], + "performanceFigures": [ + { + "octaneRating": 95, + "acceleration": [ + { + "mph": 30, + "seconds": 4 + }, + { + "mph": 60, + "seconds": 7.5 + }, + { + "mph": 100, + "seconds": 12.199999809265137 + }] + }, + { + "octaneRating": 99, + "acceleration": [ + { + "mph": 30, + "seconds": 3.799999952316284 + }, + { + "mph": 60, + "seconds": 7.099999904632568 + }, + { + "mph": 100, + "seconds": 11.800000190734863 + }] + }], + "manufacturer": "Honda", + "model": "Civic VTi", + "activationCode": "abcdef", + "color": "" +}` + assert.EqualValues(expected, str, "Message printer") +} diff --git a/gocode/flyweight/src/otf/otf_test.go b/gocode/flyweight/src/otf/otf_test.go new file mode 100644 index 0000000000..babb370693 --- /dev/null +++ b/gocode/flyweight/src/otf/otf_test.go @@ -0,0 +1,159 @@ +package otf + +import ( + "github.com/real-logic/simple-binary-encoding/otf" + "github.com/real-logic/simple-binary-encoding/otf/test/code_generation_test" + "github.com/stretchr/testify/assert" + "testing" +) + +//go:generate java -Dsbe.output.dir=. -Dsbe.target.language=golang -Dsbe.go.generate.generate.flyweights=true -Dsbe.generate.ir=true -jar ../../../${SBE_JAR} ../../../../sbe-tool/src/test/resources/code-generation-schema.xml + +const SchemaFilename = "code-generation-schema.sbeir" +const MsgBufferCapacity = 4 * 1024 + +func TestOtf(t *testing.T) { + assert := assert.New(t) + + ir := otf.NewIrDecoder() + if ir.DecodeFile(SchemaFilename) < 0 { + t.Errorf("Error decoding %s", SchemaFilename) + } + + var car code_generation_test.Car + buffer := make([]byte, MsgBufferCapacity) + encodedLength := encodeCar(&car, buffer) + + headerDecoder, _ := otf.NewOtfHeaderDecoder(ir.Header()) + bufferOffset := 0 + templateId, _ := headerDecoder.TemplateId(buffer[bufferOffset:]) + schemaId, _ := headerDecoder.SchemaId(buffer[bufferOffset:]) + actingVersion, _ := headerDecoder.SchemaVersion(buffer[bufferOffset:]) + blockLength, _ := headerDecoder.BlockLength(buffer[bufferOffset:]) + + if uint16(schemaId) != car.SbeSchemaId() { + t.Errorf("Invalid schema id: %d", schemaId) + } + + bufferOffset += int(headerDecoder.EncodedLength()) + listener := &TestListener{} + tokens := ir.MessageByID(int32(templateId)) + bufferOffset = otf.Decode( + buffer[bufferOffset:], + actingVersion, + blockLength, + tokens, + listener, + ) + + assert.EqualValues(bufferOffset, encodedLength, "Message not fully decoded") + expected := `Car.serialNumber=1234 +Car.modelYear=2013 +Car.available=T +Car.code=A +Car.someNumbers=01234 +Car.vehicleCode=abcdef +Car.extras: sunRoof=false sportsPack=false cruiseControl=false +Car.discountedModel=C +Car.engine.capacity=2000 +Car.engine.numCylinders=4 +Car.engine.maxRpm=9000 +Car.engine.manufacturerCode=123 +Car.engine.fuel=Petrol +Car.engine.booster.BoostType=NITROUS +Car.engine.booster.horsePower=200 +Car.fuelFigures Group Header : numInGroup=3 +Car.fuelFigures.speed=30 +Car.fuelFigures.mpg=35.900001525878906 +Car.fuelFigures.usageDescription=Urban Cycle +Car.fuelFigures.speed=55 +Car.fuelFigures.mpg=49 +Car.fuelFigures.usageDescription=Combined Cycle +Car.fuelFigures.speed=75 +Car.fuelFigures.mpg=40 +Car.fuelFigures.usageDescription=Highway Cycle +Car.performanceFigures Group Header : numInGroup=2 +Car.performanceFigures.octaneRating=95 +Car.performanceFigures.acceleration Group Header : numInGroup=3 +Car.performanceFigures.acceleration.mph=30 +Car.performanceFigures.acceleration.seconds=4 +Car.performanceFigures.acceleration.mph=60 +Car.performanceFigures.acceleration.seconds=7.5 +Car.performanceFigures.acceleration.mph=100 +Car.performanceFigures.acceleration.seconds=12.199999809265137 +Car.performanceFigures.octaneRating=99 +Car.performanceFigures.acceleration Group Header : numInGroup=3 +Car.performanceFigures.acceleration.mph=30 +Car.performanceFigures.acceleration.seconds=3.799999952316284 +Car.performanceFigures.acceleration.mph=60 +Car.performanceFigures.acceleration.seconds=7.099999904632568 +Car.performanceFigures.acceleration.mph=100 +Car.performanceFigures.acceleration.seconds=11.800000190734863 +Car.manufacturer=Honda +Car.model=Civic VTi +Car.activationCode=abcdef +Car.color= +` + assert.EqualValues(expected, listener.out.String()) +} + +func encodeCar(car *code_generation_test.Car, buffer []byte) int { + const vehicleCode = "abcdef" + const manufacturerCode = "123" + const activationCode = "abcdef" + const manufacturer = "Honda" + const model = "Civic VTi" + + car.WrapAndApplyHeader(buffer, 0, uint64(len(buffer))). + SetSerialNumber(1234). + SetModelYear(2013). + SetAvailable(code_generation_test.BooleanType_T). + SetCode(code_generation_test.Model_A). + SetVehicleCode(vehicleCode) + + // change this to a loop + for i := 0; i < car.SomeNumbersLength(); i++ { + car.SetSomeNumbersIndex(uint64(i), int32(i)) + } + + car.Extras(). + Clear(). + SetCruiseControl(true). + SetSportsPack(true). + SetSunRoof(false) + + car.Engine(). + SetCapacity(2000). + SetNumCylinders(4). + SetManufacturerCode(manufacturerCode). + Booster(). + SetBoostType(code_generation_test.BoostType_NITROUS). + SetHorsePower(200) + + car.FuelFiguresCount(3). + Next().SetSpeed(30).SetMpg(35.9).PutUsageDescription("Urban Cycle"). + Next().SetSpeed(55).SetMpg(49.0).PutUsageDescription("Combined Cycle"). + Next().SetSpeed(75).SetMpg(40.0).PutUsageDescription("Highway Cycle") + + figures := car.PerformanceFiguresCount(2) + figures.Next(). + SetOctaneRating(95). + AccelerationCount(3). + Next().SetMph(30).SetSeconds(4.0). + Next().SetMph(60).SetSeconds(7.5). + Next().SetMph(100).SetSeconds(12.2) + figures.Next(). + SetOctaneRating(99). + AccelerationCount(3). + Next().SetMph(30).SetSeconds(3.8). + Next().SetMph(60).SetSeconds(7.1). + Next().SetMph(100).SetSeconds(11.8) + + car.PutManufacturer(manufacturer). + PutModel(model). + PutActivationCode(activationCode). + PutColor("") + + // var hdr code_generation_test.MessageHeader + return int(car.EncodedLength()) +} diff --git a/gocode/flyweight/src/otf/testlistener.go b/gocode/flyweight/src/otf/testlistener.go new file mode 100644 index 0000000000..18bc73724f --- /dev/null +++ b/gocode/flyweight/src/otf/testlistener.go @@ -0,0 +1,311 @@ +package otf + +import ( + "fmt" + "github.com/real-logic/simple-binary-encoding/otf" + "strconv" + "strings" +) + +type TestListener struct { + out strings.Builder + compositeLevel int + namedScope []string +} + +func (t *TestListener) OnBeginMessage(token otf.Token) { + t.namedScope = append(t.namedScope, token.Name()+".") +} + +func (t *TestListener) OnEndMessage(token otf.Token) { + t.namedScope = t.namedScope[:len(t.namedScope)-1] +} + +func (t *TestListener) OnEncoding(fieldToken otf.Token, buffer []byte, typeToken otf.Token, actingVersion uint64) { + value := t.readEncodingAsString(buffer, fieldToken, typeToken, uint64(fieldToken.TokenVersion()), actingVersion) + + t.printScope() + if t.compositeLevel > 0 { + t.out.WriteString(typeToken.Name()) + } else { + t.out.WriteString(fieldToken.Name()) + } + t.out.WriteString("=") + t.out.WriteString(value) + t.out.WriteString("\n") + +} + +func (t *TestListener) printScope() { + for i := range t.namedScope { + t.out.WriteString(t.namedScope[i]) + } +} + +func (t *TestListener) determineName( + thresholdLevel int, + fieldToken otf.Token, + tokens []otf.Token, + fromIndex int, +) string { + if t.compositeLevel > thresholdLevel { + return tokens[fromIndex].Name() + } else { + return fieldToken.Name() + } +} + +func (t *TestListener) readEncodingAsString( + buffer []byte, + fieldToken otf.Token, + typeToken otf.Token, + fieldVersion uint64, + actingVersion uint64, +) string { + constOrNotPresentValue := t.constOrNotPresentValue(typeToken, fieldVersion, actingVersion) + if constOrNotPresentValue.PrimitiveType != otf.NONE { + encoding := typeToken.Encoding() + characterEncoding := encoding.CharacterEncoding() + if constOrNotPresentValue.Size() == 1 && characterEncoding == "" { + // TODO java uses this + // final byte[] bytes = { (byte)constOrNotPresentValue.longValue() }; + // return new String(bytes, characterEncoding); + return constOrNotPresentValue.String() + } else { + value := constOrNotPresentValue.String() + size := typeToken.ArrayLength() + if size < 2 { + return value + } + sb := strings.Builder{} + more := false + for i := int32(0); i < size; i++ { + if more { + sb.WriteString(", ") + more = true + } + sb.WriteString(value) + } + return sb.String() + } + } + + sb := strings.Builder{} + encoding := typeToken.Encoding() + elementSize := int32(encoding.PrimitiveType().Size()) + + more := false + for i := int32(0); i < typeToken.ArrayLength(); i++ { + if more { + sb.WriteString(", ") + more = true + } + arrayValue := otf.NewPrimitiveValue(encoding.PrimitiveType(), buffer[i*elementSize:(i+1)*elementSize]) + sb.WriteString(arrayValue.String()) + } + return sb.String() +} + +func (t *TestListener) readEncodingAsInt( + buffer []byte, + typeToken otf.Token, + fieldVersion uint64, + actingVersion uint64, +) int64 { + constOrNotPresentValue := t.constOrNotPresentValue(typeToken, fieldVersion, actingVersion) + if constOrNotPresentValue.PrimitiveType != otf.NONE { + return constOrNotPresentValue.AsInt() + } + typeTokenEncoding := typeToken.Encoding() + v, _ := otf.GetAsInt(typeTokenEncoding.PrimitiveType(), typeTokenEncoding.ByteOrder(), buffer) + return v +} + +func (t *TestListener) readEncodingAsUInt( + buffer []byte, + typeToken otf.Token, + fieldVersion uint64, + actingVersion uint64, +) uint64 { + constOrNotPresentValue := t.constOrNotPresentValue(typeToken, fieldVersion, actingVersion) + if constOrNotPresentValue.PrimitiveType != otf.NONE { + return constOrNotPresentValue.AsUInt() + } + typeTokenEncoding := typeToken.Encoding() + v, _ := otf.GetAsUInt(typeTokenEncoding.PrimitiveType(), typeTokenEncoding.ByteOrder(), buffer) + return v +} + +func (t *TestListener) constOrNotPresentValue( + typeToken otf.Token, + fieldVersion uint64, + actingVersion uint64, +) otf.PrimitiveValue { + typeTokenEncoding := typeToken.Encoding() + if typeToken.IsConstantEncoding() { + return typeTokenEncoding.ConstValue() + } else if typeToken.IsOptionalEncoding() && actingVersion < fieldVersion { + return typeTokenEncoding.ApplicableNullValue() + } else { + return otf.PrimitiveValue{} + } +} + +func (t *TestListener) OnEnum( + fieldToken otf.Token, + buffer []byte, + tokens []otf.Token, + fromIndex int, + toIndex int, + actingVersion uint64, +) { + typeToken := tokens[fromIndex+1] + encoding := typeToken.Encoding() + + value := "" + if fieldToken.IsConstantEncoding() { + encoding := fieldToken.Encoding() + refValue := encoding.ConstValue() + indexOfDot := strings.LastIndex(refValue.String(), ".") + if indexOfDot == -1 { + value = refValue.String() + } else { + value = refValue.String()[indexOfDot+1:] + } + } else if encoding.PrimitiveType().IsUnsigned() { + encodedValue := t.readEncodingAsUInt( + buffer, + typeToken, + uint64(fieldToken.TokenVersion()), + actingVersion, + ) + for i := fromIndex + 1; i < toIndex; i++ { + encoding := tokens[i].Encoding() + constValue := encoding.ConstValue() + if constValue.AsUInt() == encodedValue { + value = tokens[i].Name() + break + } + } + } else { + encodedValue := t.readEncodingAsInt( + buffer, + typeToken, + uint64(fieldToken.TokenVersion()), + actingVersion, + ) + for i := fromIndex + 1; i < toIndex; i++ { + encoding := tokens[i].Encoding() + constValue := encoding.ConstValue() + if constValue.AsInt() == encodedValue { + value = tokens[i].Name() + break + } + } + } + + t.printScope() + t.out.WriteString(t.determineName(0, fieldToken, tokens, fromIndex)) + t.out.WriteString("=") + t.out.WriteString(value) + t.out.WriteString("\n") +} + +func (t *TestListener) OnBitSet( + fieldToken otf.Token, + buffer []byte, + tokens []otf.Token, + fromIndex int, + toIndex int, + actingVersion uint64, +) { + typeToken := tokens[fromIndex+1] + encodedValue := t.readEncodingAsInt( + buffer, + typeToken, + uint64(fieldToken.TokenVersion()), + actingVersion, + ) + t.printScope() + t.out.WriteString(t.determineName(0, fieldToken, tokens, fromIndex)) + t.out.WriteString(":") + for i := fromIndex + 1; i < toIndex; i++ { + t.out.WriteString(" ") + t.out.WriteString(tokens[i].Name()) + t.out.WriteString("=") + encoding := tokens[i].Encoding() + constValue := encoding.ConstValue() + bitPosition := constValue.AsInt() + flag := (encodedValue & (1 << uint64(bitPosition))) != 0 + t.out.WriteString(strconv.FormatBool(flag)) + } + t.out.WriteString("\n") +} + +func (t *TestListener) OnBeginComposite( + fieldToken otf.Token, + tokens []otf.Token, + fromIndex int, + toIndex int, +) { + t.compositeLevel++ + t.namedScope = append(t.namedScope, t.determineName(1, fieldToken, tokens, fromIndex)+".") +} + +func (t *TestListener) OnEndComposite( + token otf.Token, + tokens []otf.Token, + fromIndex int, + toIndex int, +) { + t.compositeLevel-- + t.namedScope = t.namedScope[:len(t.namedScope)-1] +} + +func (t *TestListener) OnGroupHeader( + token otf.Token, + numInGroup uint64, +) { + t.printScope() + t.out.WriteString(token.Name()) + t.out.WriteString(" Group Header : numInGroup=") + t.out.WriteString(strconv.FormatUint(numInGroup, 10)) + t.out.WriteString("\n") +} + +func (t *TestListener) OnBeginGroup( + token otf.Token, + groupIndex uint64, + numInGroup uint64, +) { + t.namedScope = append(t.namedScope, token.Name()+".") +} + +func (t *TestListener) OnEndGroup( + token otf.Token, + groupIndex uint64, + numInGroup uint64, +) { + t.namedScope = t.namedScope[:len(t.namedScope)-1] +} + +func (t *TestListener) OnVarData( + fieldToken otf.Token, + buffer []byte, + length uint64, + typeToken otf.Token, +) { + value := "" + typeTokenEncoding := typeToken.Encoding() + if characterEncoding := typeTokenEncoding.CharacterEncoding(); characterEncoding == "" { + value = fmt.Sprintf("%d bytes of raw data", length) + } else { + value = string(buffer[:length]) + } + + t.printScope() + t.out.WriteString(fieldToken.Name()) + t.out.WriteString("=") + t.out.WriteString(value) + t.out.WriteString("\n") +} diff --git a/gocode/flyweight/src/simple/simple_test.go b/gocode/flyweight/src/simple/simple_test.go new file mode 100644 index 0000000000..b15a3c2bad --- /dev/null +++ b/gocode/flyweight/src/simple/simple_test.go @@ -0,0 +1,46 @@ +package simple + +import ( + "testing" +) + +func TestEncodeDecode(t *testing.T) { + var data [256]byte + var in Simple0 + in.WrapForEncode(data[:], 0, uint64(len(data))) + + in.SetU64nv(2863311530) + in.SetU64(2863311530) + in.SetU32(123456) + in.SetU16(7890) + in.SetU8(63) + in.SetS8(-8) + in.SetS16(-16) + in.SetS32(-32) + in.SetS64(-64) + in.SetF32(3.14) + in.SetD64(-3.14e7) + in.SetString6ASCII("abcdef") + in.SetString1ASCII('A') + in.PutInt2Values(254, 255) + + var out Simple0 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + expected := `{"Name": "Simple0", "sbeTemplateId": 11, "U64nv": "2863311530", "U64": "2863311530", "U32": "123456", "U16": "7890", "U8": "63", "S8": "-8", "S16": "-16", "S32": "-32", "S64": "-64", "F32": "3.14", "D64": "-3.14e+07", "String6ASCII": "abcdef", "String1ASCII": "A", "Int2": [254,255]}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } + + if in.U64SinceVersion() != 1 { + t.Log("in.U64SinceVersion() should be 1 and is", in.U64SinceVersion()) + t.Fail() + } +} diff --git a/gocode/flyweight/src/since-deprecated/SinceDeprecated_test.go b/gocode/flyweight/src/since-deprecated/SinceDeprecated_test.go new file mode 100644 index 0000000000..1dcf5f416d --- /dev/null +++ b/gocode/flyweight/src/since-deprecated/SinceDeprecated_test.go @@ -0,0 +1,23 @@ +package since_deprecated + +import ( + "testing" +) + +func TestSinceDeprecated(t *testing.T) { + + sv := SinceDeprecated{} + + // V1 has always been there + if sv.V1SinceVersion() != 0 { + t.Fail() + } + // V2 was introduced in version 2 + if sv.V2SinceVersion() != 2 { + t.Fail() + } + // V3 was introduced in version 3 and deprecated in version 4 + if sv.V3SinceVersion() != 3 { + t.Fail() + } +} diff --git a/gocode/flyweight/src/vardata/SBE tests/TestMessage1_test.go b/gocode/flyweight/src/vardata/SBE tests/TestMessage1_test.go new file mode 100644 index 0000000000..237ddb7d5c --- /dev/null +++ b/gocode/flyweight/src/vardata/SBE tests/TestMessage1_test.go @@ -0,0 +1,27 @@ +package sbe_tests + +import ( + "testing" +) + +func TestEncodeDecodeTestMessage1(t *testing.T) { + var data [256]byte + var in TestMessage1 + in.WrapForEncode(data[:], 0, uint64(len(data))) + in.PutEncryptedNewPassword("abcdefghijklmnopqrst") + + var out TestMessage1 + out.WrapForDecode( + data[:], + 0, + uint64(in.SbeBlockLength()), + uint64(in.SbeSchemaVersion()), + uint64(len(data)), + ) + + expected := `{"Name": "TestMessage1", "sbeTemplateId": 1, "encryptedNewPassword": "abcdefghijklmnopqrst"}` + if actual := out.String(); actual != expected { + t.Logf("Failed to decode, expected %s, got %s", expected, actual) + t.Fail() + } +} diff --git a/gocode/go.mod b/gocode/go.mod new file mode 100644 index 0000000000..af460264e6 --- /dev/null +++ b/gocode/go.mod @@ -0,0 +1,7 @@ +module github.com/real-logic/simple-binary-encoding + +go 1.12 + +require ( + github.com/stretchr/testify v1.7.0 +) diff --git a/gocode/go.sum b/gocode/go.sum new file mode 100644 index 0000000000..af7675440c --- /dev/null +++ b/gocode/go.sum @@ -0,0 +1,7 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gocode/src/baseline-bigendian/Car_test.go b/gocode/struct/src/baseline-bigendian/Car_test.go similarity index 100% rename from gocode/src/baseline-bigendian/Car_test.go rename to gocode/struct/src/baseline-bigendian/Car_test.go diff --git a/gocode/src/baseline/Car_test.go b/gocode/struct/src/baseline/Car_test.go similarity index 100% rename from gocode/src/baseline/Car_test.go rename to gocode/struct/src/baseline/Car_test.go diff --git a/gocode/src/basic/SBE tests/ENUM_test.go b/gocode/struct/src/basic/SBE tests/ENUM_test.go similarity index 100% rename from gocode/src/basic/SBE tests/ENUM_test.go rename to gocode/struct/src/basic/SBE tests/ENUM_test.go diff --git a/gocode/src/basic/SBE tests/Message1_test.go b/gocode/struct/src/basic/SBE tests/Message1_test.go similarity index 100% rename from gocode/src/basic/SBE tests/Message1_test.go rename to gocode/struct/src/basic/SBE tests/Message1_test.go diff --git a/gocode/src/basic/SBE tests/SET_test.go b/gocode/struct/src/basic/SBE tests/SET_test.go similarity index 100% rename from gocode/src/basic/SBE tests/SET_test.go rename to gocode/struct/src/basic/SBE tests/SET_test.go diff --git a/gocode/src/composite/Composite_test.go b/gocode/struct/src/composite/Composite_test.go similarity index 100% rename from gocode/src/composite/Composite_test.go rename to gocode/struct/src/composite/Composite_test.go diff --git a/gocode/src/composite_elements/Message_test.go b/gocode/struct/src/composite_elements/Message_test.go similarity index 100% rename from gocode/src/composite_elements/Message_test.go rename to gocode/struct/src/composite_elements/Message_test.go diff --git a/gocode/src/example-schema/CarExample.go b/gocode/struct/src/example-schema/CarExample.go similarity index 100% rename from gocode/src/example-schema/CarExample.go rename to gocode/struct/src/example-schema/CarExample.go diff --git a/gocode/src/example-schema/CarExample_test.go b/gocode/struct/src/example-schema/CarExample_test.go similarity index 100% rename from gocode/src/example-schema/CarExample_test.go rename to gocode/struct/src/example-schema/CarExample_test.go diff --git a/gocode/src/example-socket-clientserver/clientserver.go b/gocode/struct/src/example-socket-clientserver/clientserver.go similarity index 100% rename from gocode/src/example-socket-clientserver/clientserver.go rename to gocode/struct/src/example-socket-clientserver/clientserver.go diff --git a/gocode/src/group/SBE tests/TestMessage1_test.go b/gocode/struct/src/group/SBE tests/TestMessage1_test.go similarity index 100% rename from gocode/src/group/SBE tests/TestMessage1_test.go rename to gocode/struct/src/group/SBE tests/TestMessage1_test.go diff --git a/gocode/src/group_with_data/TestMessages_test.go b/gocode/struct/src/group_with_data/TestMessages_test.go similarity index 100% rename from gocode/src/group_with_data/TestMessages_test.go rename to gocode/struct/src/group_with_data/TestMessages_test.go diff --git a/gocode/src/group_with_data_extension/Extension_test.go b/gocode/struct/src/group_with_data_extension/Extension_test.go similarity index 100% rename from gocode/src/group_with_data_extension/Extension_test.go rename to gocode/struct/src/group_with_data_extension/Extension_test.go diff --git a/gocode/src/issue435/Issue435_test.go b/gocode/struct/src/issue435/Issue435_test.go similarity index 100% rename from gocode/src/issue435/Issue435_test.go rename to gocode/struct/src/issue435/Issue435_test.go diff --git a/gocode/src/issue472/Issue472_test.go b/gocode/struct/src/issue472/Issue472_test.go similarity index 100% rename from gocode/src/issue472/Issue472_test.go rename to gocode/struct/src/issue472/Issue472_test.go diff --git a/gocode/src/issue483/Issue483_test.go b/gocode/struct/src/issue483/Issue483_test.go similarity index 100% rename from gocode/src/issue483/Issue483_test.go rename to gocode/struct/src/issue483/Issue483_test.go diff --git a/gocode/src/issue488/Issue488_test.go b/gocode/struct/src/issue488/Issue488_test.go similarity index 100% rename from gocode/src/issue488/Issue488_test.go rename to gocode/struct/src/issue488/Issue488_test.go diff --git a/gocode/src/issue505/Issue505_test.go b/gocode/struct/src/issue505/Issue505_test.go similarity index 100% rename from gocode/src/issue505/Issue505_test.go rename to gocode/struct/src/issue505/Issue505_test.go diff --git a/gocode/src/issue560/Issue560_test.go b/gocode/struct/src/issue560/Issue560_test.go similarity index 100% rename from gocode/src/issue560/Issue560_test.go rename to gocode/struct/src/issue560/Issue560_test.go diff --git a/gocode/struct/src/issue847/issue847_test.go b/gocode/struct/src/issue847/issue847_test.go new file mode 100644 index 0000000000..1fb14887ad --- /dev/null +++ b/gocode/struct/src/issue847/issue847_test.go @@ -0,0 +1,9 @@ +package issue847 + +import ( + "testing" +) + +func TestNothing(t *testing.T) { + // placeholder, really just looking for clean builds +} diff --git a/gocode/struct/src/issue848/issue848_test.go b/gocode/struct/src/issue848/issue848_test.go new file mode 100644 index 0000000000..1106e74b01 --- /dev/null +++ b/gocode/struct/src/issue848/issue848_test.go @@ -0,0 +1,9 @@ +package issue848 + +import ( + "testing" +) + +func TestNothing(t *testing.T) { + // placeholder, really just looking for clean builds +} diff --git a/gocode/struct/src/issue849/issue849_test.go b/gocode/struct/src/issue849/issue849_test.go new file mode 100644 index 0000000000..0149615810 --- /dev/null +++ b/gocode/struct/src/issue849/issue849_test.go @@ -0,0 +1,9 @@ +package issue849 + +import ( + "testing" +) + +func TestNothing(t *testing.T) { + // placeholder, really just looking for clean builds +} diff --git a/gocode/struct/src/mktdata/fixme_test.go b/gocode/struct/src/mktdata/fixme_test.go new file mode 100644 index 0000000000..6792aa42e5 --- /dev/null +++ b/gocode/struct/src/mktdata/fixme_test.go @@ -0,0 +1,10 @@ +package mktdata + +import ( + "fmt" + "testing" +) + +func TestFixme(t *testing.T) { + fmt.Println("No tests implemented here") +} diff --git a/gocode/src/mktdata/preallocated_test.go b/gocode/struct/src/mktdata/preallocated_test.go similarity index 100% rename from gocode/src/mktdata/preallocated_test.go rename to gocode/struct/src/mktdata/preallocated_test.go diff --git a/gocode/src/simple/simple_test.go b/gocode/struct/src/simple/simple_test.go similarity index 100% rename from gocode/src/simple/simple_test.go rename to gocode/struct/src/simple/simple_test.go diff --git a/gocode/src/since-deprecated/SinceDeprecated_test.go b/gocode/struct/src/since-deprecated/SinceDeprecated_test.go similarity index 100% rename from gocode/src/since-deprecated/SinceDeprecated_test.go rename to gocode/struct/src/since-deprecated/SinceDeprecated_test.go diff --git a/gocode/src/test973/EventType.go b/gocode/struct/src/test973/EventType.go similarity index 100% rename from gocode/src/test973/EventType.go rename to gocode/struct/src/test973/EventType.go diff --git a/gocode/src/test973/MessageHeader.go b/gocode/struct/src/test973/MessageHeader.go similarity index 100% rename from gocode/src/test973/MessageHeader.go rename to gocode/struct/src/test973/MessageHeader.go diff --git a/gocode/src/test973/SbeMarshalling.go b/gocode/struct/src/test973/SbeMarshalling.go similarity index 100% rename from gocode/src/test973/SbeMarshalling.go rename to gocode/struct/src/test973/SbeMarshalling.go diff --git a/gocode/src/test973/SomeMessage.go b/gocode/struct/src/test973/SomeMessage.go similarity index 100% rename from gocode/src/test973/SomeMessage.go rename to gocode/struct/src/test973/SomeMessage.go diff --git a/gocode/src/test973/test973_test.go b/gocode/struct/src/test973/test973_test.go similarity index 100% rename from gocode/src/test973/test973_test.go rename to gocode/struct/src/test973/test973_test.go diff --git a/gocode/src/vardata/SBE tests/TestMessage1_test.go b/gocode/struct/src/vardata/SBE tests/TestMessage1_test.go similarity index 100% rename from gocode/src/vardata/SBE tests/TestMessage1_test.go rename to gocode/struct/src/vardata/SBE tests/TestMessage1_test.go diff --git a/sbe-tool/src/main/golang/.gitignore b/sbe-tool/src/main/golang/.gitignore new file mode 100644 index 0000000000..aafd6f4184 --- /dev/null +++ b/sbe-tool/src/main/golang/.gitignore @@ -0,0 +1 @@ +uk_co_real_logic_sbe_ir_generated/* diff --git a/sbe-tool/src/main/golang/go.mod b/sbe-tool/src/main/golang/go.mod new file mode 100644 index 0000000000..0a6dd9e719 --- /dev/null +++ b/sbe-tool/src/main/golang/go.mod @@ -0,0 +1,3 @@ +module github.com/real-logic/simple-binary-encoding + +go 1.12 diff --git a/sbe-tool/src/main/golang/go.sum b/sbe-tool/src/main/golang/go.sum new file mode 100644 index 0000000000..479781e603 --- /dev/null +++ b/sbe-tool/src/main/golang/go.sum @@ -0,0 +1,17 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sbe-tool/src/main/golang/json/json_printer.go b/sbe-tool/src/main/golang/json/json_printer.go new file mode 100644 index 0000000000..d6ec189f7f --- /dev/null +++ b/sbe-tool/src/main/golang/json/json_printer.go @@ -0,0 +1,76 @@ +package json + +import ( + "fmt" + "strings" + + "github.com/real-logic/simple-binary-encoding/otf" +) + +// JsonPrinter pretty prints JSON based upon the given Ir. +type JsonPrinter struct { + headerDecoder *otf.OftHeaderDecoder + ir *otf.IrDecoder +} + +// NewJsonPrinter creates a new JsonPrinter for a given message Ir. +func NewJsonPrinter(ir *otf.IrDecoder) (*JsonPrinter, error) { + d, err := otf.NewOtfHeaderDecoder(ir.Header()) + return &JsonPrinter{ + headerDecoder: d, + ir: ir, + }, err +} + +// Print the encoded message to the output. +func (printer *JsonPrinter) Print(buffer []byte, output *strings.Builder) error { + blockLength, err := printer.headerDecoder.BlockLength(buffer) + if err != nil { + return fmt.Errorf("Error getting blockLength: %s", err) + } + templateId, err := printer.headerDecoder.TemplateId(buffer) + if err != nil { + return fmt.Errorf("Error getting templateId: %s", err) + } + schemaId, err := printer.headerDecoder.SchemaId(buffer) + if err != nil { + return fmt.Errorf("Error getting schemaId: %s", err) + } + actingVersion, err := printer.headerDecoder.SchemaVersion(buffer) + if err != nil { + return fmt.Errorf("Error getting schemaVersion: %s", err) + } + err = printer.validateId(schemaId) + if err != nil { + return err + } + + messageOffset := printer.headerDecoder.EncodedLength() + msgTokens := printer.ir.MessageByID(int32(templateId)) + + otf.Decode( + buffer[messageOffset:], + actingVersion, + blockLength, + msgTokens, + newJsonTokenListener(output), + ) + + return nil +} + +func (printer *JsonPrinter) validateId(schemaId uint64) error { + if schemaId != uint64(printer.ir.Id()) { + return fmt.Errorf("Required schema id %d but was %d", printer.ir.Id(), schemaId) + } + return nil +} + +// PrintJson the encoded message to a String. +func (printer *JsonPrinter) PrintJson(buffer []byte) (string, error) { + sb := strings.Builder{} + if err := printer.Print(buffer, &sb); err != nil { + return "", err + } + return sb.String(), nil +} diff --git a/sbe-tool/src/main/golang/json/json_token_listener.go b/sbe-tool/src/main/golang/json/json_token_listener.go new file mode 100644 index 0000000000..af7c711f64 --- /dev/null +++ b/sbe-tool/src/main/golang/json/json_token_listener.go @@ -0,0 +1,410 @@ +package json + +import ( + "encoding/hex" + "strconv" + "strings" + + "github.com/real-logic/simple-binary-encoding/otf" +) + +// JsonTokenListener dynamically decodes to convert them to JSON for output. +type JsonTokenListener struct { + output *strings.Builder + indentation int + compositeLevel int + more bool +} + +func newJsonTokenListener(output *strings.Builder) *JsonTokenListener { + return &JsonTokenListener{ + output: output, + } +} + +func (t *JsonTokenListener) printScope() { + for i := 0; i < t.compositeLevel; i++ { + t.output.WriteString(" ") + } +} + +func isLastGroup(groupIndex uint64, numInGroup uint64) bool { + return groupIndex == numInGroup-1 +} + +func (t *JsonTokenListener) startObject() { + t.indent() + t.output.WriteString("{\n") + t.indentation++ + t.more = false +} + +func (t *JsonTokenListener) endObject() { + t.output.WriteString("\n") + t.indentation-- + t.indent() + t.output.WriteString("}") + t.more = true +} + +func (t *JsonTokenListener) property(name string) { + t.indent() + t.doubleQuote() + t.output.WriteString(name) + t.output.WriteString("\": ") +} + +func (t *JsonTokenListener) indent() { + for i := 0; i < t.indentation; i++ { + t.output.WriteString(" ") + } +} + +func (t *JsonTokenListener) doubleQuote() { + t.output.WriteString("\"") +} + +func (t *JsonTokenListener) prev() { + if t.more { + t.output.WriteString(",\n") + } +} + +func (t *JsonTokenListener) next() { + t.more = true +} + +func (t *JsonTokenListener) escapePrintableChar(buffer []byte, index int, size int, elementSize int) { + for i := 0; i < size; i++ { + c := buffer[index+i*elementSize] + if c > 0 { + t.escape(rune(c)) + } else { + break + } + } +} + +func (t *JsonTokenListener) escapeString(str string) { + for _, c := range str { + t.escape(c) + } +} + +func (t *JsonTokenListener) escape(c rune) { + if c == '"' || c == '\\' || c == '\b' || c == '\f' || c == '\n' || c == '\r' || c == '\t' { + t.output.WriteString("\\") + } + + t.output.WriteRune(c) +} + +func (t *JsonTokenListener) determineName( + thresholdLevel int, + fieldToken otf.Token, + tokens []otf.Token, + fromIndex int, +) string { + if t.compositeLevel > thresholdLevel { + return tokens[fromIndex].Name() + } else { + return fieldToken.Name() + } + +} + +func (t *JsonTokenListener) OnBeginMessage(token otf.Token) { + t.startObject() +} + +func (t *JsonTokenListener) OnEndMessage(token otf.Token) { + t.endObject() +} + +func (t *JsonTokenListener) OnEncoding(fieldToken otf.Token, buffer []byte, typeToken otf.Token, actingVersion uint64) { + t.prev() + name := fieldToken.Name() + if t.compositeLevel > 0 { + name = fieldToken.Name() + } + t.property(name) + t.appendEncodingAsString(buffer, typeToken, uint64(fieldToken.TokenVersion()), actingVersion) + t.next() +} + +func (t *JsonTokenListener) appendEncodingAsString( + buffer []byte, + typeToken otf.Token, + fieldVersion uint64, + actingVersion uint64, +) { + arrayLength := typeToken.ArrayLength() + encoding := typeToken.Encoding() + constOrNotPresentValue := t.constOrNotPresentValue(typeToken, fieldVersion, actingVersion) + if constOrNotPresentValue.PrimitiveType != otf.NONE { + characterEncoding := encoding.CharacterEncoding() + if characterEncoding == "" { + t.doubleQuote() + t.escapeString(constOrNotPresentValue.String()) + t.doubleQuote() + } else { + if arrayLength < 2 { + t.doubleQuote() + t.escapeString(constOrNotPresentValue.String()) + t.doubleQuote() + } else { + t.output.WriteString("[") + for i := int32(0); i < arrayLength; i++ { + if i > 0 { + t.output.WriteString(", ") + } + t.doubleQuote() + t.escapeString(constOrNotPresentValue.String()) + t.doubleQuote() + } + t.output.WriteString("]") + } + } + } else { + elementSize := encoding.PrimitiveType().Size() + if arrayLength < 1 && encoding.PrimitiveType() == otf.CHAR { + t.doubleQuote() + t.escapePrintableChar(buffer, 0, int(arrayLength), elementSize) + } else { + encoding := typeToken.Encoding() + elementSize := int32(encoding.PrimitiveType().Size()) + if arrayLength == 1 { + otf.AppendPrimitiveValueJson(t.output, otf.NewPrimitiveValue(encoding.PrimitiveType(), buffer)) + } else { + t.output.WriteString("[") + for i := int32(0); i < typeToken.ArrayLength(); i++ { + if i > 0 { + t.output.WriteString(", ") + } + otf.AppendPrimitiveValueJson(t.output, otf.NewPrimitiveValue(encoding.PrimitiveType(), + buffer[i*elementSize:(i+1)*elementSize])) + } + t.output.WriteString("]") + } + } + } +} + +func (t *JsonTokenListener) readEncodingAsInt( + buffer []byte, + typeToken otf.Token, + fieldVersion uint64, + actingVersion uint64, +) int64 { + constOrNotPresentValue := t.constOrNotPresentValue(typeToken, fieldVersion, actingVersion) + if constOrNotPresentValue.PrimitiveType != otf.NONE { + return constOrNotPresentValue.AsInt() + } + typeTokenEncoding := typeToken.Encoding() + v, _ := otf.GetAsInt(typeTokenEncoding.PrimitiveType(), typeTokenEncoding.ByteOrder(), buffer) + return v +} + +func (t *JsonTokenListener) readEncodingAsUInt( + buffer []byte, + typeToken otf.Token, + fieldVersion uint64, + actingVersion uint64, +) uint64 { + constOrNotPresentValue := t.constOrNotPresentValue(typeToken, fieldVersion, actingVersion) + if constOrNotPresentValue.PrimitiveType != otf.NONE { + return constOrNotPresentValue.AsUInt() + } + typeTokenEncoding := typeToken.Encoding() + v, _ := otf.GetAsUInt(typeTokenEncoding.PrimitiveType(), typeTokenEncoding.ByteOrder(), buffer) + return v +} + +func (t *JsonTokenListener) constOrNotPresentValue( + typeToken otf.Token, + fieldVersion uint64, + actingVersion uint64, +) otf.PrimitiveValue { + typeTokenEncoding := typeToken.Encoding() + if typeToken.IsConstantEncoding() { + return typeTokenEncoding.ConstValue() + } else if typeToken.IsOptionalEncoding() && actingVersion < fieldVersion { + return typeTokenEncoding.ApplicableNullValue() + } else { + return otf.PrimitiveValue{} + } +} + +func (t *JsonTokenListener) OnEnum( + fieldToken otf.Token, + buffer []byte, + tokens []otf.Token, + fromIndex int, + toIndex int, + actingVersion uint64, +) { + t.prev() + typeToken := tokens[fromIndex+1] + encoding := typeToken.Encoding() + + value := "" + if fieldToken.IsConstantEncoding() { + encoding := fieldToken.Encoding() + refValue := encoding.ConstValue() + indexOfDot := strings.LastIndex(refValue.String(), ".") + if indexOfDot == -1 { + value = refValue.String() + } else { + value = refValue.String()[indexOfDot+1:] + } + } else if encoding.PrimitiveType().IsUnsigned() { + encodedValue := t.readEncodingAsUInt( + buffer, + typeToken, + uint64(fieldToken.TokenVersion()), + actingVersion, + ) + for i := fromIndex + 1; i < toIndex; i++ { + encoding := tokens[i].Encoding() + constValue := encoding.ConstValue() + if constValue.AsUInt() == encodedValue { + value = tokens[i].Name() + break + } + } + } else { + encodedValue := t.readEncodingAsInt( + buffer, + typeToken, + uint64(fieldToken.TokenVersion()), + actingVersion, + ) + for i := fromIndex + 1; i < toIndex; i++ { + encoding := tokens[i].Encoding() + constValue := encoding.ConstValue() + if constValue.AsInt() == encodedValue { + value = tokens[i].Name() + break + } + } + } + + t.property(t.determineName(0, fieldToken, tokens, fromIndex)) + t.doubleQuote() + t.output.WriteString(value) + t.doubleQuote() + t.next() +} + +func (t *JsonTokenListener) OnBitSet( + fieldToken otf.Token, + buffer []byte, + tokens []otf.Token, + fromIndex int, + toIndex int, + actingVersion uint64, +) { + t.prev() + typeToken := tokens[fromIndex+1] + encodedValue := t.readEncodingAsInt( + buffer, + typeToken, + uint64(fieldToken.TokenVersion()), + actingVersion, + ) + t.property(t.determineName(0, fieldToken, tokens, fromIndex)) + + t.output.WriteString("{ ") + for i := fromIndex + 1; i < toIndex; i++ { + t.output.WriteString(`"`) + t.output.WriteString(tokens[i].Name()) + t.output.WriteString(`": `) + encoding := tokens[i].Encoding() + constValue := encoding.ConstValue() + bitPosition := constValue.AsInt() + flag := (encodedValue & (1 << uint64(bitPosition))) != 0 + t.output.WriteString(strconv.FormatBool(flag)) + if i < toIndex-1 { + t.output.WriteString(", ") + } + } + t.output.WriteString(` }`) + t.next() +} + +func (t *JsonTokenListener) OnBeginComposite( + fieldToken otf.Token, + tokens []otf.Token, + fromIndex int, + toIndex int, +) { + t.prev() + t.compositeLevel++ + t.property(t.determineName(0, fieldToken, tokens, fromIndex)) + t.output.WriteString("\n") + t.startObject() +} + +func (t *JsonTokenListener) OnEndComposite( + token otf.Token, + tokens []otf.Token, + fromIndex int, + toIndex int, +) { + t.compositeLevel-- + t.endObject() +} + +func (t *JsonTokenListener) OnGroupHeader( + token otf.Token, + numInGroup uint64, +) { + t.prev() + t.property(token.Name()) + if numInGroup > 0 { + t.output.WriteString("[\n") + t.more = false + } else { + t.output.WriteString("[]") + } +} + +func (t *JsonTokenListener) OnBeginGroup( + token otf.Token, + groupIndex uint64, + numInGroup uint64, +) { + t.prev() + t.startObject() +} + +func (t *JsonTokenListener) OnEndGroup( + token otf.Token, + groupIndex uint64, + numInGroup uint64, +) { + t.endObject() + if isLastGroup(groupIndex, numInGroup) { + t.output.WriteString("]") + } +} + +func (t *JsonTokenListener) OnVarData( + fieldToken otf.Token, + buffer []byte, + length uint64, + typeToken otf.Token, +) { + t.prev() + t.property(fieldToken.Name()) + t.doubleQuote() + + typeTokenEncoding := typeToken.Encoding() + if characterEncoding := typeTokenEncoding.CharacterEncoding(); characterEncoding == "" { + t.escapeString(hex.EncodeToString(buffer[:length])) + } else { + t.escapeString(string(buffer[:length])) + } + t.doubleQuote() + t.next() +} diff --git a/sbe-tool/src/main/golang/main.go b/sbe-tool/src/main/golang/main.go new file mode 100644 index 0000000000..3b246a530c --- /dev/null +++ b/sbe-tool/src/main/golang/main.go @@ -0,0 +1,3 @@ +package sbe + +//go:generate java -Dsbe.output.dir=. -Dsbe.target.language=golang -Dsbe.go.generate.generate.flyweights=true -jar ${SBE_JAR} ../resources/sbe-ir.xml diff --git a/sbe-tool/src/main/golang/otf/encoding.go b/sbe-tool/src/main/golang/otf/encoding.go new file mode 100644 index 0000000000..a10fef5b2d --- /dev/null +++ b/sbe-tool/src/main/golang/otf/encoding.go @@ -0,0 +1,673 @@ +// Copyright 2013-2024 Real Logic Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package otf + +import ( + "encoding/binary" + "errors" + "fmt" + "math" + "strconv" + "strings" +) + +type ByteOrder int + +const ( + SbeLittleEndian ByteOrder = iota + SbeBigEndian +) + +// String returns the string representation of the ByteOrder. +func (o ByteOrder) String() string { + switch o { + case SbeLittleEndian: + return "SbeLittleEndian" + case SbeBigEndian: + return "SbeBigEndian" + default: + return "Unknown" + } +} + +type PrimitiveType int + +const ( + NONE PrimitiveType = iota + CHAR + INT8 + INT16 + INT32 + INT64 + UINT8 + UINT16 + UINT32 + UINT64 + FLOAT + DOUBLE +) + +func (p PrimitiveType) String() string { + switch p { + case NONE: + return "NONE" + case CHAR: + return "CHAR" + case INT8: + return "INT8" + case INT16: + return "INT16" + case INT32: + return "INT32" + case INT64: + return "INT64" + case UINT8: + return "UINT8" + case UINT16: + return "UINT16" + case UINT32: + return "UINT32" + case UINT64: + return "UINT64" + case FLOAT: + return "FLOAT" + case DOUBLE: + return "DOUBLE" + default: + return "Unknown" + } +} + +func (p PrimitiveType) Size() int { + switch p { + case CHAR, INT8, UINT8: + return 1 + case INT16, UINT16: + return 2 + case INT32, UINT32, FLOAT: + return 4 + case INT64, UINT64, DOUBLE: + return 8 + default: + return 0 + } +} + +// IsUnsigned returns true if the type is unsigned. +func (p PrimitiveType) IsUnsigned() bool { + switch p { + case UINT8, UINT16, UINT32, UINT64: + return true + default: + return false + } +} + +type Presence int + +const ( + SbeRequired Presence = iota + SbeOptional + SbeConstant +) + +func (p Presence) String() string { + switch p { + case SbeRequired: + return "SbeRequired" + case SbeOptional: + return "SbeOptional" + case SbeConstant: + return "SbeConstant" + default: + return "Unknown" + } +} + +type PrimitiveValue struct { + PrimitiveType + size int + asInt int64 + asUInt uint64 + asDouble float64 + arrayValue string +} + +// String returns the string representation of the value. +func (p *PrimitiveValue) String() string { + switch p.PrimitiveType { + case CHAR: + if p.size > 1 { + return p.arrayValue + } + return string(byte(p.asInt)) + case INT8, INT16, INT32, INT64: + return strconv.FormatInt(p.asInt, 10) + case UINT8, UINT16, UINT32, UINT64: + return strconv.FormatUint(p.asUInt, 10) + case FLOAT, DOUBLE: + return strconv.FormatFloat(p.asDouble, 'f', -1, 64) + default: + return "" + } +} + +func AppendPrimitiveValue(sb *strings.Builder, p PrimitiveValue) { + switch p.PrimitiveType { + case CHAR: + if p.size > 1 { + sb.WriteString(p.arrayValue) + return + } + sb.WriteByte(byte(p.asInt)) + case INT8, INT16, INT32, INT64: + sb.WriteString(strconv.FormatInt(p.asInt, 10)) + case UINT8, UINT16, UINT32, UINT64: + sb.WriteString(strconv.FormatUint(p.asUInt, 10)) + case FLOAT, DOUBLE: + sb.WriteString(strconv.FormatFloat(p.asDouble, 'f', -1, 64)) + } +} + +func AppendPrimitiveValueJson(sb *strings.Builder, p PrimitiveValue) { + switch p.PrimitiveType { + case CHAR: + if p.size > 1 { + sb.WriteString(p.arrayValue) + return + } + sb.WriteRune('"') + sb.WriteByte(byte(p.asInt)) + sb.WriteRune('"') + case INT8, INT16, INT32, INT64: + sb.WriteString(strconv.FormatInt(p.asInt, 10)) + case UINT8: + sb.WriteString(strconv.FormatUint(p.asUInt&0xFF, 10)) + case UINT16: + sb.WriteString(strconv.FormatUint(p.asUInt&0xFFFF, 10)) + case UINT32: + sb.WriteString(strconv.FormatUint(p.asUInt&0xFFFFFFFF, 10)) + case UINT64: + sb.WriteString(strconv.FormatUint(p.asUInt, 10)) + case FLOAT, DOUBLE: + sb.WriteString(strconv.FormatFloat(p.asDouble, 'f', -1, 64)) + } +} + +func NewPrimitiveValue(t PrimitiveType, value []byte) PrimitiveValue { + p := PrimitiveValue{PrimitiveType: t} + + if len(value) == 0 { + return p + } + + switch t { + case CHAR: + if len(value) > 1 { + p.arrayValue = string(value) + p.size = len(value) + } else { + p.asInt = int64(value[0]) + p.size = 1 + } + case INT8: + p.asInt = int64(value[0]) + p.size = 1 + case INT16: + p.asInt = int64(binary.LittleEndian.Uint16(value)) + p.size = 2 + case INT32: + p.asInt = int64(binary.LittleEndian.Uint32(value)) + p.size = 4 + case INT64: + p.asInt = int64(binary.LittleEndian.Uint64(value)) + p.size = 8 + case UINT8: + p.asUInt = uint64(value[0]) + p.size = 1 + case UINT16: + p.asUInt = uint64(binary.LittleEndian.Uint16(value)) + p.size = 2 + case UINT32: + p.asUInt = uint64(binary.LittleEndian.Uint32(value)) + p.size = 4 + case UINT64: + p.asUInt = binary.LittleEndian.Uint64(value) + p.size = 8 + case FLOAT: + p.asDouble = float64(math.Float32frombits(binary.LittleEndian.Uint32(value))) + p.size = 4 + case DOUBLE: + p.asDouble = math.Float64frombits(binary.LittleEndian.Uint64(value)) + p.size = 8 + default: + p.PrimitiveType = NONE + p.size = 0 + } + + return p +} + +func ParsePrimitiveValue(t PrimitiveType, value []byte) (PrimitiveValue, error) { + p := PrimitiveValue{PrimitiveType: t} + + var err error + + switch t { + case CHAR: + if len(value) > 1 { + p.arrayValue = string(value) + p.size = len(value) + } else { + p.asInt = int64(value[0]) + p.size = 1 + } + case INT8: + p.asInt, err = strconv.ParseInt(string(value), 10, 8) + p.size = 1 + case INT16: + p.asInt, err = strconv.ParseInt(string(value), 10, 16) + p.size = 2 + case INT32: + p.asInt, err = strconv.ParseInt(string(value), 10, 32) + p.size = 4 + case INT64: + p.asInt, err = strconv.ParseInt(string(value), 10, 64) + p.size = 8 + case UINT8: + p.asUInt, err = strconv.ParseUint(string(value), 10, 8) + p.size = 1 + case UINT16: + p.asUInt, err = strconv.ParseUint(string(value), 10, 16) + p.size = 2 + case UINT32: + p.asUInt, err = strconv.ParseUint(string(value), 10, 32) + p.size = 4 + case UINT64: + p.asUInt, err = strconv.ParseUint(string(value), 10, 64) + p.size = 8 + case FLOAT: + p.asDouble, err = strconv.ParseFloat(string(value), 32) + p.size = 4 + case DOUBLE: + p.asDouble, err = strconv.ParseFloat(string(value), 64) + p.size = 8 + default: + p.PrimitiveType = NONE + p.size = 0 + } + + return p, err +} + +func NewNoneValue() PrimitiveValue { + return PrimitiveValue{} +} + +func NewCharValue(value byte) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: CHAR, + size: 1, + asInt: int64(value), + } +} + +func NewStringValue(value string) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: CHAR, + size: len(value), + arrayValue: value, + } +} + +func NewInt8Value(value int8) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: INT8, + size: 1, + asInt: int64(value), + } +} + +func NewInt16Value(value int16) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: INT16, + size: 2, + asInt: int64(value), + } +} + +func NewInt32Value(value int32) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: INT32, + size: 4, + asInt: int64(value), + } +} + +func NewInt64Value(value int64) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: INT64, + size: 8, + asInt: value, + } +} + +func NewUInt8Value(value uint8) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: UINT8, + size: 1, + asUInt: uint64(value), + } +} + +func NewUInt16Value(value uint16) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: UINT16, + size: 2, + asUInt: uint64(value), + } +} + +func NewUInt32Value(value uint32) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: UINT32, + size: 4, + asUInt: uint64(value), + } +} + +func NewUInt64Value(value uint64) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: UINT64, + size: 8, + asUInt: value, + } +} + +func NewFloatValue(value float32) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: FLOAT, + size: 4, + asDouble: float64(value), + } +} + +func NewDoubleValue(value float64) PrimitiveValue { + return PrimitiveValue{ + PrimitiveType: DOUBLE, + size: 8, + asDouble: value, + } +} + +func (p *PrimitiveValue) AsInt() int64 { + return p.asInt +} + +func (p *PrimitiveValue) AsUInt() uint64 { + return p.asUInt +} + +func (p *PrimitiveValue) AsDouble() float64 { + return p.asDouble +} + +func (p *PrimitiveValue) GetArray() string { + return p.arrayValue +} + +func (p *PrimitiveValue) AsString() string { + if p.size <= 1 { + return string(byte(p.asInt)) + } + for i := 0; i < len(p.arrayValue); i++ { + if p.arrayValue[i] == 0 { + return p.arrayValue[:i] + } + } + return p.arrayValue +} + +func (p *PrimitiveValue) Size() int { + return p.size +} + +type Encoding struct { + presence Presence + primitiveType PrimitiveType + byteOrder ByteOrder + minValue PrimitiveValue + maxValue PrimitiveValue + nullValue PrimitiveValue + constValue PrimitiveValue + characterEncoding string + epoch string + timeUnit string + semanticType string +} + +func (e *Encoding) String() string { + return fmt.Sprintf( + "Encoding{presence: %s primitiveType: %s, byteOrder: %s, minValue: %s, maxValue: %s, nullValue: %s, constValue: %s, characterEncoding: %s, epoch: %s, timeUnit: %s, semanticType: %s}", + e.presence, + e.primitiveType, + e.byteOrder, + &e.minValue, + &e.maxValue, + &e.nullValue, + &e.constValue, + e.characterEncoding, + e.epoch, + e.timeUnit, + e.semanticType, + ) +} + +func NewEncoding( + primitiveType PrimitiveType, + presence Presence, + byteOrder ByteOrder, + minValue, maxValue, nullValue, constValue PrimitiveValue, + characterEncoding, epoch, timeUnit, semanticType string) Encoding { + return Encoding{ + presence: presence, + primitiveType: primitiveType, + byteOrder: byteOrder, + minValue: minValue, + maxValue: maxValue, + nullValue: nullValue, + constValue: constValue, + characterEncoding: characterEncoding, + epoch: epoch, + timeUnit: timeUnit, + semanticType: semanticType, + } +} + +func GetChar(buffer []byte) byte { + return buffer[0] +} + +func GetInt8(buffer []byte) int8 { + return int8(buffer[0]) +} + +func GetInt16(buffer []byte, order ByteOrder) int16 { + if order == SbeLittleEndian { + return int16(binary.LittleEndian.Uint16(buffer)) + } + return int16(binary.BigEndian.Uint16(buffer)) +} + +func GetInt32(buffer []byte, order ByteOrder) int32 { + if order == SbeLittleEndian { + return int32(binary.LittleEndian.Uint32(buffer)) + } + return int32(binary.BigEndian.Uint32(buffer)) +} + +func GetInt64(buffer []byte, order ByteOrder) int64 { + if order == SbeLittleEndian { + return int64(binary.LittleEndian.Uint64(buffer)) + } + return int64(binary.BigEndian.Uint64(buffer)) +} + +func GetUInt8(buffer []byte) uint8 { + return buffer[0] +} + +func GetUInt16(buffer []byte, order ByteOrder) uint16 { + if order == SbeLittleEndian { + return binary.LittleEndian.Uint16(buffer) + } + return binary.BigEndian.Uint16(buffer) +} + +func GetUInt32(buffer []byte, order ByteOrder) uint32 { + if order == SbeLittleEndian { + return binary.LittleEndian.Uint32(buffer) + } + return binary.BigEndian.Uint32(buffer) +} + +func GetUInt64(buffer []byte, order ByteOrder) uint64 { + if order == SbeLittleEndian { + return binary.LittleEndian.Uint64(buffer) + } + return binary.BigEndian.Uint64(buffer) +} + +func GetFloat(buffer []byte, order ByteOrder) float32 { + if order == SbeLittleEndian { + return math.Float32frombits(binary.LittleEndian.Uint32(buffer)) + } + return math.Float32frombits(binary.BigEndian.Uint32(buffer)) +} + +func GetDouble(buffer []byte, order ByteOrder) float64 { + if order == SbeLittleEndian { + return math.Float64frombits(binary.LittleEndian.Uint64(buffer)) + } + return math.Float64frombits(binary.BigEndian.Uint64(buffer)) +} + +func GetAsInt(primitiveType PrimitiveType, byteOrder ByteOrder, buffer []byte) (int64, error) { + switch primitiveType { + case CHAR: + return int64(GetChar(buffer)), nil + case INT8: + return int64(GetInt8(buffer)), nil + case INT16: + return int64(GetInt16(buffer, byteOrder)), nil + case INT32: + return int64(GetInt32(buffer, byteOrder)), nil + case INT64: + return GetInt64(buffer, byteOrder), nil + default: + return 0, errors.New("incorrect type for Encoding.GetAsInt") + } +} + +func GetAsUInt(primitiveType PrimitiveType, byteOrder ByteOrder, buffer []byte) (uint64, error) { + switch primitiveType { + case UINT8: + return uint64(GetUInt8(buffer)), nil + case UINT16: + return uint64(GetUInt16(buffer, byteOrder)), nil + case UINT32: + return uint64(GetUInt32(buffer, byteOrder)), nil + case UINT64: + return GetUInt64(buffer, byteOrder), nil + default: + return 0, errors.New("incorrect type for Encoding.GetAsUInt") + } +} + +func GetAsDouble(primitiveType PrimitiveType, byteOrder ByteOrder, buffer []byte) (float64, error) { + switch primitiveType { + case FLOAT: + return float64(GetFloat(buffer, byteOrder)), nil + case DOUBLE: + return GetDouble(buffer, byteOrder), nil + default: + return 0, errors.New("incorrect type for Encoding.GetAsDouble") + } +} + +func (e *Encoding) GetAsInt(buffer []byte) (int64, error) { + return GetAsInt(e.primitiveType, e.byteOrder, buffer) +} + +func (e *Encoding) GetAsUInt(buffer []byte) (uint64, error) { + return GetAsUInt(e.primitiveType, e.byteOrder, buffer) +} + +func (e *Encoding) GetAsDouble(buffer []byte) (float64, error) { + return GetAsDouble(e.primitiveType, e.byteOrder, buffer) +} + +func (e *Encoding) Presence() Presence { + return e.presence +} + +func (e *Encoding) PrimitiveType() PrimitiveType { + return e.primitiveType +} + +func (e *Encoding) ByteOrder() ByteOrder { + return e.byteOrder +} + +func (e *Encoding) MinValue() PrimitiveValue { + return e.minValue +} + +func (e *Encoding) MaxValue() PrimitiveValue { + return e.maxValue +} + +func (e *Encoding) NullValue() PrimitiveValue { + return e.nullValue +} + +func (e *Encoding) ConstValue() PrimitiveValue { + return e.constValue +} + +func (e *Encoding) CharacterEncoding() string { + return e.characterEncoding +} + +func (e *Encoding) Epoch() string { + return e.epoch +} + +func (e *Encoding) TimeUnit() string { + return e.timeUnit +} + +func (e *Encoding) SemanticType() string { + return e.semanticType +} + +func (e *Encoding) ApplicableNullValue() PrimitiveValue { + if e.nullValue.PrimitiveType != NONE { + return e.nullValue + } + return PrimitiveValue{ + PrimitiveType: e.primitiveType, + } +} diff --git a/sbe-tool/src/main/golang/otf/irdecoder.go b/sbe-tool/src/main/golang/otf/irdecoder.go new file mode 100644 index 0000000000..d90876e637 --- /dev/null +++ b/sbe-tool/src/main/golang/otf/irdecoder.go @@ -0,0 +1,355 @@ +package otf + +import ( + "os" + "sort" + "strings" + + ir "github.com/real-logic/simple-binary-encoding/uk_co_real_logic_sbe_ir_generated" +) + +type IrDecoder struct { + headerTokens []Token + messages [][]Token + buffer []byte + length uint64 + id int32 + typesByName map[string][]Token +} + +func NewIrDecoder() *IrDecoder { + return &IrDecoder{ + typesByName: make(map[string][]Token), + } +} + +func (decoder *IrDecoder) Decode(irBuffer []byte) int { + length := uint64(len(irBuffer)) + decoder.length = length + if length == 0 { + return -1 + } + decoder.buffer = make([]byte, length) + copy(decoder.buffer, irBuffer) + return decoder.decodeIr() +} + +func (decoder *IrDecoder) DecodeFile(filename string) int { + fileStat, err := os.Stat(filename) + if err != nil { + return -1 + } + + decoder.length = uint64(fileStat.Size()) + if decoder.length == 0 { + return -1 + } + decoder.buffer = make([]byte, decoder.length) + + if err := readFileIntoBuffer(decoder.buffer, filename, decoder.length); err != nil { + return -1 + } + + return decoder.decodeIr() +} + +func (decoder *IrDecoder) Header() []Token { + return decoder.headerTokens +} + +func (decoder *IrDecoder) Messages() [][]Token { + return decoder.messages +} + +func (decoder *IrDecoder) Message(id int32, version int32) []Token { + for _, tokens := range decoder.messages { + token := &tokens[0] + if token.Signal() == SignalBeginMessage && token.FieldId() == id && token.TokenVersion() == version { + return tokens + } + } + return nil +} + +func (decoder *IrDecoder) MessageByID(id int32) []Token { + for _, tokens := range decoder.messages { + token := &tokens[0] + if token.Signal() == SignalBeginMessage && token.FieldId() == id { + return tokens + } + } + return nil +} + +// TypeByName gets the type representation for a given type name. +func (decoder *IrDecoder) TypeByName(name string) []Token { + return decoder.typesByName[name] +} + +func (decoder *IrDecoder) decodeIr() int { + var frame ir.FrameCodec + offset := uint64(0) + var tmp [256]byte + + frame.WrapForDecode( + decoder.buffer, + offset, + uint64(frame.SbeBlockLength()), + uint64(frame.SbeSchemaVersion()), + decoder.length, + ) + + frame.GetPackageName(tmp[:]) + + if frame.IrVersion() != 0 { + return -1 + } + + frame.GetNamespaceName(tmp[:]) + frame.GetSemanticVersion(tmp[:]) + + offset += frame.EncodedLength() + + decoder.headerTokens = make([]Token, 0) + + headerLength := decoder.readHeader(offset) + + decoder.id = frame.IrId() + + offset += headerLength + + for offset < decoder.length { + offset += decoder.readMessage(offset) + } + + decoder.captureTypes(decoder.headerTokens, 0, len(decoder.headerTokens)-1) + + return 0 +} +func (decoder *IrDecoder) decodeAndAddToken(tokens *[]Token, offset uint64) uint64 { + var tokenCodec ir.TokenCodec + tokenCodec.WrapForDecode( + decoder.buffer, + offset, + uint64(tokenCodec.SbeBlockLength()), + uint64(tokenCodec.SbeSchemaVersion()), + decoder.length, + ) + + signal := Signal(tokenCodec.Signal()) + primitiveType := PrimitiveType(tokenCodec.PrimitiveType()) + presence := Presence(tokenCodec.Presence()) + byteOrder := ByteOrder(tokenCodec.ByteOrder()) + tokenOffset := tokenCodec.TokenOffset() + tokenSize := tokenCodec.TokenSize() + id := tokenCodec.FieldId() + version := tokenCodec.TokenVersion() + componentTokenCount := tokenCodec.ComponentTokenCount() + + name := tokenCodec.GetNameAsString() + + tmpBuffer := [256]byte{} + tmpLength := tokenCodec.GetConstValue(tmpBuffer[:]) + constValue := NewPrimitiveValue(primitiveType, tmpBuffer[:tmpLength]) + tmpLength = tokenCodec.GetMinValue(tmpBuffer[:]) + minValue := NewPrimitiveValue(primitiveType, tmpBuffer[:tmpLength]) + tmpLength = tokenCodec.GetMaxValue(tmpBuffer[:]) + maxValue := NewPrimitiveValue(primitiveType, tmpBuffer[:tmpLength]) + tmpLength = tokenCodec.GetNullValue(tmpBuffer[:]) + nullValue := NewPrimitiveValue(primitiveType, tmpBuffer[:tmpLength]) + + characterEncoding := tokenCodec.GetCharacterEncodingAsString() + epoch := tokenCodec.GetEpochAsString() + timeUnit := tokenCodec.GetTimeUnitAsString() + semanticType := tokenCodec.GetSemanticTypeAsString() + description := tokenCodec.GetDescriptionAsString() + referencedName := tokenCodec.GetReferencedNameAsString() + + encoding := NewEncoding( + primitiveType, + presence, + byteOrder, + minValue, + maxValue, + nullValue, + constValue, + characterEncoding, + epoch, + timeUnit, + semanticType, + ) + + token := Token{ + offset: tokenOffset, + fieldId: id, + version: version, + encodedLength: tokenSize, + componentTokenCount: componentTokenCount, + signal: signal, + name: name, + referencedName: referencedName, + description: description, + encoding: encoding, + } + + *tokens = append(*tokens, token) + + return tokenCodec.EncodedLength() +} + +func (decoder *IrDecoder) readHeader(offset uint64) uint64 { + size := uint64(0) + for offset+size < decoder.length { + size += decoder.decodeAndAddToken(&decoder.headerTokens, offset+size) + token := &decoder.headerTokens[len(decoder.headerTokens)-1] + if token.signal == SignalEndComposite { + break + } + } + return size +} + +func (decoder *IrDecoder) readMessage(offset uint64) uint64 { + size := uint64(0) + tokensForMessage := make([]Token, 0) + for offset+size < decoder.length { + size += decoder.decodeAndAddToken(&tokensForMessage, offset+size) + token := &tokensForMessage[len(tokensForMessage)-1] + if token.signal == SignalEndMessage { + break + } + } + + decoder.captureTypes(tokensForMessage, 0, len(tokensForMessage)-1) + decoder.updateComponentTokenCounts(tokensForMessage) + + decoder.messages = append(decoder.messages, tokensForMessage) + return size +} + +func (decoder *IrDecoder) Id() int32 { + return decoder.id +} + +func readFileIntoBuffer(buffer []byte, filename string, length uint64) error { + f, err := os.Open(filename) + if err != nil { + return err + } + defer f.Close() + + var remaining = length + for remaining > 0 { + bytes := uint(4098) + if remaining < 4098 { + bytes = uint(remaining) + } + sz, err := f.Read(buffer[length-remaining : length-remaining+uint64(bytes)]) + if err != nil { + return err + } + remaining -= uint64(sz) + } + + return nil +} + +func (decoder *IrDecoder) captureTypes(tokens []Token, beginIndex, endIndex int) { + for i := beginIndex; i < endIndex; i++ { + token := tokens[i] + typeBeginIndex := i + switch token.Signal() { + case SignalBeginComposite: + i = decoder.captureType( + tokens, + i, + SignalEndComposite, + token.Name(), + token.ReferencedName(), + ) + decoder.captureTypes(tokens, typeBeginIndex+1, i-1) + case SignalBeginEnum: + i = decoder.captureType( + tokens, + i, + SignalEndEnum, + token.Name(), + token.ReferencedName(), + ) + case SignalBeginSet: + i = decoder.captureType( + tokens, + i, + SignalEndSet, + token.Name(), + token.ReferencedName(), + ) + default: + } + } +} + +func (decoder *IrDecoder) captureType( + tokens []Token, + index int, + endSignal Signal, + name, referencedName string, +) int { + var typeTokens []Token + i := index + token := tokens[i] + typeTokens = append(typeTokens, token) + for { + i++ + token = tokens[i] + typeTokens = append(typeTokens, token) + if token.Signal() == endSignal || name == token.Name() { + break + } + } + + decoder.updateComponentTokenCounts(typeTokens) + + typeName := referencedName + if typeName == "" { + typeName = name + } + decoder.typesByName[typeName] = typeTokens + return i +} + +// updateComponentTokenCounts iterates over a list of Tokens and updates +// their counts of how many tokens make up each component. +func (decoder *IrDecoder) updateComponentTokenCounts(tokens []Token) { + beginIndexMap := make(map[string][]int) + for i, size := 0, len(tokens); i < size; i++ { + token := tokens[i] + signal := token.Signal() + if strings.HasPrefix(signal.String(), "Begin") { + componentType := signal.String()[5:] + beginIndexMap[componentType] = append(beginIndexMap[componentType], i) + } else if strings.HasPrefix(signal.String(), "End") { + componentType := signal.String()[3:] + beginIndices := beginIndexMap[componentType] + last := len(beginIndices) - 1 + beginIndex := beginIndices[last] + beginIndexMap[componentType] = beginIndices[:last] + componentTokenCount := int32((i - beginIndex) + 1) + tokens[beginIndex].componentTokenCount = componentTokenCount + token.componentTokenCount = componentTokenCount + } + } +} + +func (decoder *IrDecoder) Types() [][]Token { + var typeNames []string + for name := range decoder.typesByName { + typeNames = append(typeNames, name) + } + sort.Strings(typeNames) + var types [][]Token + for _, name := range typeNames { + types = append(types, decoder.typesByName[name]) + } + return types +} diff --git a/sbe-tool/src/main/golang/otf/otfheaderdecoder.go b/sbe-tool/src/main/golang/otf/otfheaderdecoder.go new file mode 100644 index 0000000000..5905437fa1 --- /dev/null +++ b/sbe-tool/src/main/golang/otf/otfheaderdecoder.go @@ -0,0 +1,105 @@ +package otf + +import "fmt" + +type OftHeaderDecoder struct { + encodedLength int32 + blockLengthOffset int32 + templateIdOffset int32 + schemaIdOffset int32 + schemaVersionOffset int32 + blockLengthType PrimitiveType + templateIdType PrimitiveType + schemaIdType PrimitiveType + schemaVersionType PrimitiveType + blockLengthByteOrder ByteOrder + templateIdByteOrder ByteOrder + schemaIdByteOrder ByteOrder + schemaVersionByteOrder ByteOrder +} + +func NewOtfHeaderDecoder(tokens []Token) (*OftHeaderDecoder, error) { + decoder := &OftHeaderDecoder{ + encodedLength: tokens[0].EncodedLength(), + } + + var blockLengthToken, + templateIdToken, + schemaIdToken, + versionToken *Token + + for i := range tokens { + token := tokens[i] + name := token.Name() + switch name { + case "blockLength": + blockLengthToken = &token + case "templateId": + templateIdToken = &token + case "schemaId": + schemaIdToken = &token + case "version": + versionToken = &token + } + } + + if blockLengthToken == nil { + return nil, fmt.Errorf("blockLength token not found") + } + + decoder.blockLengthOffset = blockLengthToken.Offset() + encoding := blockLengthToken.Encoding() + decoder.blockLengthType = encoding.PrimitiveType() + decoder.blockLengthByteOrder = encoding.ByteOrder() + + if templateIdToken == nil { + return nil, fmt.Errorf("templateId token not found") + } + + decoder.templateIdOffset = templateIdToken.Offset() + templateIdEncoding := templateIdToken.Encoding() + decoder.templateIdType = templateIdEncoding.PrimitiveType() + decoder.templateIdByteOrder = templateIdEncoding.ByteOrder() + + if schemaIdToken == nil { + return nil, fmt.Errorf("schemaId token not found") + } + + decoder.schemaIdOffset = schemaIdToken.Offset() + schemaIdEncoding := schemaIdToken.Encoding() + decoder.schemaIdType = schemaIdEncoding.PrimitiveType() + decoder.schemaIdByteOrder = schemaIdEncoding.ByteOrder() + + if versionToken == nil { + return nil, fmt.Errorf("version token not found") + } + + decoder.schemaVersionOffset = versionToken.Offset() + versionEncoding := versionToken.Encoding() + decoder.schemaVersionType = versionEncoding.PrimitiveType() + decoder.schemaVersionByteOrder = versionEncoding.ByteOrder() + + return decoder, nil +} + +func (o *OftHeaderDecoder) EncodedLength() int32 { + return o.encodedLength +} + +// All elements must be unsigned integers according to Specification + +func (o *OftHeaderDecoder) TemplateId(headerBuffer []byte) (uint64, error) { + return GetAsUInt(o.templateIdType, o.templateIdByteOrder, headerBuffer[o.templateIdOffset:]) +} + +func (o *OftHeaderDecoder) SchemaId(headerBuffer []byte) (uint64, error) { + return GetAsUInt(o.schemaIdType, o.schemaIdByteOrder, headerBuffer[o.schemaIdOffset:]) +} + +func (o *OftHeaderDecoder) SchemaVersion(headerBuffer []byte) (uint64, error) { + return GetAsUInt(o.schemaVersionType, o.schemaVersionByteOrder, headerBuffer[o.schemaVersionOffset:]) +} + +func (o *OftHeaderDecoder) BlockLength(headerBuffer []byte) (uint64, error) { + return GetAsUInt(o.blockLengthType, o.blockLengthByteOrder, headerBuffer[o.blockLengthOffset:]) +} diff --git a/sbe-tool/src/main/golang/otf/otfmessagedecoder.go b/sbe-tool/src/main/golang/otf/otfmessagedecoder.go new file mode 100644 index 0000000000..09e070e120 --- /dev/null +++ b/sbe-tool/src/main/golang/otf/otfmessagedecoder.go @@ -0,0 +1,311 @@ +package otf + +import "fmt" + +type OnBeginMessage func(token Token) +type OnEndMessage func(token Token) +type OnEncoding func(token Token, buffer []byte, actingVersion uint64) +type OnEnum func(token Token, buffer []byte, tokens []Token, fromIndex int, toIndex int, actingVersion uint64) +type OnBitSet func(token Token, buffer []byte, tokens []Token, fromIndex int, toIndex int, actingVersion uint64) +type OnBeginComposite func(token Token, tokens []Token, fromIndex int, toIndex int) +type OnEndComposite func(token Token, tokens []Token, fromIndex int, toIndex int) +type OnGroupHeader func(token Token, numInGroup uint64) +type OnBeginGroup func(token Token, groupIndex uint64, numInGroup uint64) +type OnEndGroup func(token Token, groupIndex uint64, numInGroup uint64) +type OnVarData func(token Token, buffer []byte, length uint64, typeToken Token) + +type TokenListener interface { + OnBeginMessage(token Token) + OnEndMessage(token Token) + OnEncoding(fieldToken Token, buffer []byte, typeToken Token, actingVersion uint64) + OnEnum(fieldToken Token, buffer []byte, tokens []Token, fromIndex int, toIndex int, actingVersion uint64) + OnBitSet(fieldToken Token, buffer []byte, tokens []Token, fromIndex int, toIndex int, actingVersion uint64) + OnBeginComposite(fieldToken Token, tokens []Token, fromIndex int, toIndex int) + OnEndComposite(fieldToken Token, tokens []Token, fromIndex int, toIndex int) + OnGroupHeader(token Token, numInGroup uint64) + OnBeginGroup(token Token, groupIndex uint64, numInGroup uint64) + OnEndGroup(token Token, groupIndex uint64, numInGroup uint64) + OnVarData(fieldToken Token, buffer []byte, length uint64, typeToken Token) +} + +func DecodeComposite( + fieldToken Token, + buffer []byte, + bufferIndex int, + length uint64, + tokens []Token, + tokenIndex int, + toIndex int, + actingVersion uint64, + listener TokenListener) int { + listener.OnBeginComposite(fieldToken, tokens, tokenIndex, toIndex) + for i := tokenIndex + 1; i < toIndex; { + token := tokens[i] + nextFieldIndex := i + int(token.ComponentTokenCount()) + offset := int(token.Offset()) + switch token.Signal() { + case SignalBeginComposite: + DecodeComposite( + fieldToken, + buffer, + bufferIndex+offset, + length, + tokens, + i, + nextFieldIndex-1, + actingVersion, + listener) + case SignalBeginEnum: + listener.OnEnum( + fieldToken, + buffer[bufferIndex+offset:], + tokens, + i, + nextFieldIndex-1, + actingVersion) + case SignalBeginSet: + listener.OnBitSet( + fieldToken, + buffer[bufferIndex+offset:], + tokens, + i, + nextFieldIndex-1, + actingVersion) + case SignalEncoding: + listener.OnEncoding(token, buffer[bufferIndex+offset:], token, actingVersion) + } + i += int(token.ComponentTokenCount()) + } + listener.OnEndComposite(fieldToken, tokens, tokenIndex, toIndex) + return tokenIndex +} + +func DecodeFields( + buffer []byte, + bufferIndex int, + length uint64, + actingVersion uint64, + tokens []Token, + tokenIndex int, + numTokens int, + listener TokenListener) int { + + for tokenIndex < numTokens { + fieldToken := tokens[tokenIndex] + if SignalBeginField != fieldToken.Signal() { + break + } + nextFieldIndex := tokenIndex + int(fieldToken.ComponentTokenCount()) + tokenIndex++ + + typeToken := tokens[tokenIndex] + offset := bufferIndex + int(typeToken.Offset()) + switch typeToken.Signal() { + case SignalBeginComposite: + DecodeComposite( + fieldToken, + buffer, + offset, + length, + tokens, + tokenIndex, + nextFieldIndex-2, + actingVersion, + listener) + case SignalBeginEnum: + listener.OnEnum( + fieldToken, + buffer[offset:], + tokens, + tokenIndex, + nextFieldIndex-2, + actingVersion) + case SignalBeginSet: + listener.OnBitSet( + fieldToken, + buffer[offset:], + tokens, + tokenIndex, + nextFieldIndex-2, + actingVersion) + case SignalEncoding: + listener.OnEncoding(fieldToken, buffer[offset:], typeToken, actingVersion) + } + tokenIndex = nextFieldIndex + } + + return tokenIndex +} + +func DecodeData( + buffer []byte, + bufferIndex int, + length uint64, + tokens []Token, + tokenIndex int, + numTokens int, + actingVersion uint64, + listener TokenListener) int { + for tokenIndex < numTokens { + token := tokens[tokenIndex] + if SignalBeginVarData != token.Signal() { + break + } + isPresent := token.TokenVersion() <= int32(actingVersion) + lengthToken := tokens[tokenIndex+2] + dataToken := tokens[tokenIndex+3] + if (uint64(bufferIndex) + uint64(dataToken.Offset())) > length { + panic("length too short for data length field") + } + dataLength := uint64(0) + if isPresent { + lengthTokenEncoding := lengthToken.Encoding() + + var err error + dataLength, err = lengthTokenEncoding.GetAsUInt(buffer[bufferIndex+int(lengthToken.Offset()):]) + if err != nil { + panic(fmt.Errorf("invalid length encoding %s", err)) + } + bufferIndex += int(dataToken.Offset()) + } + + if (uint64(bufferIndex) + dataLength) > length { + panic("length too short for data field") + } + listener.OnVarData(token, buffer[bufferIndex:], dataLength, dataToken) + + bufferIndex += int(dataLength) + tokenIndex += int(token.ComponentTokenCount()) + } + return bufferIndex +} + +func DecodeGroups( + buffer []byte, + bufferIndex int, + length uint64, + actingVersion uint64, + tokens []Token, + tokenIndex int, + numTokens int, + listener TokenListener) (int, int) { + for tokenIndex < numTokens { + token := tokens[tokenIndex] + if SignalBeginGroup != token.Signal() { + break + } + isPresent := token.TokenVersion() <= int32(actingVersion) + dimensionsTypeComposite := tokens[tokenIndex+1] + dimensionsLength := int(dimensionsTypeComposite.EncodedLength()) + if (uint64(bufferIndex) + uint64(dimensionsLength)) > length { + panic("length too short for dimensions composite") + } + + blockLengthToken := tokens[tokenIndex+2] + numInGroupToken := tokens[tokenIndex+3] + blockLength := uint64(0) + numInGroup := uint64(0) + if isPresent { + blockLengthTokenEncoding := blockLengthToken.Encoding() + var err error + blockLength, err = blockLengthTokenEncoding.GetAsUInt(buffer[bufferIndex+int(blockLengthToken.Offset()):]) + if err != nil { + panic(fmt.Errorf("invalid block length encoding %s", err)) + } + numInGroupTokenEncoding := numInGroupToken.Encoding() + numInGroup, err = numInGroupTokenEncoding.GetAsUInt(buffer[bufferIndex+int(numInGroupToken.Offset()):]) + if err != nil { + panic(fmt.Errorf("invalid num in group encoding %s", err)) + } + bufferIndex += dimensionsLength + } + + beginFieldsIndex := tokenIndex + int(dimensionsTypeComposite.ComponentTokenCount()) + 1 + listener.OnGroupHeader(token, numInGroup) + for i := uint64(0); i < numInGroup; i++ { + listener.OnBeginGroup(token, i, numInGroup) + if (uint64(bufferIndex) + blockLength) > length { + panic("length too short for group blockLength") + } + afterFieldsIndex := DecodeFields( + buffer, + bufferIndex, + length, + actingVersion, + tokens, + beginFieldsIndex, + numTokens, + listener) + bufferIndex += int(blockLength) + groupIndex, groupNumTokens := DecodeGroups( + buffer, + bufferIndex, + length, + actingVersion, + tokens, + afterFieldsIndex, + numTokens, + listener) + bufferIndex = DecodeData( + buffer, + groupIndex, + length, + tokens, + groupNumTokens, + numTokens, + actingVersion, + listener, + ) + listener.OnEndGroup(token, i, numInGroup) + } + tokenIndex += int(token.ComponentTokenCount()) + } + return bufferIndex, tokenIndex +} + +func Decode( + buffer []byte, + actingVersion uint64, + blockLength uint64, + tokens []Token, + listener TokenListener) int { + listener.OnBeginMessage(tokens[0]) + length := uint64(len(buffer)) + if length < blockLength { + panic("length too short for message blockLength") + } + numTokens := len(tokens) + tokenIndex := DecodeFields( + buffer, + 0, + length, + actingVersion, + tokens, + 1, + numTokens, + listener, + ) + bufferIndex := int(blockLength) + groupIndex, groupNumTokens := DecodeGroups( + buffer, + bufferIndex, + length, + actingVersion, + tokens, + tokenIndex, + numTokens, + listener, + ) + bufferIndex = DecodeData( + buffer, + groupIndex, + length, + tokens, + groupNumTokens, + numTokens, + actingVersion, + listener, + ) + listener.OnEndMessage(tokens[numTokens-1]) + return bufferIndex +} diff --git a/sbe-tool/src/main/golang/otf/token.go b/sbe-tool/src/main/golang/otf/token.go new file mode 100644 index 0000000000..442b6d5d80 --- /dev/null +++ b/sbe-tool/src/main/golang/otf/token.go @@ -0,0 +1,162 @@ +package otf + +import ( + "fmt" +) + +type Signal int + +const ( + SignalBeginMessage Signal = 1 + SignalEndMessage Signal = 2 + SignalBeginComposite Signal = 3 + SignalEndComposite Signal = 4 + SignalBeginField Signal = 5 + SignalEndField Signal = 6 + SignalBeginGroup Signal = 7 + SignalEndGroup Signal = 8 + SignalBeginEnum Signal = 9 + SignalValidValue Signal = 10 + SignalEndEnum Signal = 11 + SignalBeginSet Signal = 12 + SignalChoice Signal = 13 + SignalEndSet Signal = 14 + SignalBeginVarData Signal = 15 + SignalEndVarData Signal = 16 + SignalEncoding Signal = 17 +) + +func (s Signal) String() string { + switch s { + case SignalBeginMessage: + return "BeginMessage" + case SignalEndMessage: + return "EndMessage" + case SignalBeginComposite: + return "BeginComposite" + case SignalEndComposite: + return "EndComposite" + case SignalBeginField: + return "BeginField" + case SignalEndField: + return "EndField" + case SignalBeginGroup: + return "BeginGroup" + case SignalEndGroup: + return "EndGroup" + case SignalBeginEnum: + return "BeginEnum" + case SignalValidValue: + return "ValidValue" + case SignalEndEnum: + return "EndEnum" + case SignalBeginSet: + return "BeginSet" + case SignalChoice: + return "Choice" + case SignalEndSet: + return "EndSet" + case SignalBeginVarData: + return "BeginVarData" + case SignalEndVarData: + return "EndVarData" + case SignalEncoding: + return "Encoding" + default: + return "Unknown" + } +} + +type Token struct { + offset int32 + fieldId int32 + version int32 + encodedLength int32 + componentTokenCount int32 + signal Signal + name string + referencedName string + description string + encoding Encoding +} + +func (token Token) ReferencedName() string { + return token.referencedName +} + +func (token Token) Signal() Signal { + return token.signal +} + +func (token Token) Name() string { + return token.name +} + +func (token Token) Description() string { + return token.description +} + +func (token Token) FieldId() int32 { + return token.fieldId +} + +func (token Token) TokenVersion() int32 { + return token.version +} + +// ApplicableTypeName returns the name of the type that should be applied in context. +func (token Token) ApplicableTypeName() string { + if token.referencedName == "" { + return token.name + } + return token.referencedName +} + +func (token Token) Encoding() Encoding { + return token.encoding +} + +// EncodedLength returns the length of the encoded primitive in bytes. +func (token Token) EncodedLength() int32 { + return token.encodedLength +} + +// ArrayLength returns the number of encoded primitives in this type. +func (token Token) ArrayLength() int32 { + if token.encoding.PrimitiveType() == NONE || token.encodedLength == 0 { + return 0 + } + return token.encodedLength / int32(token.encoding.PrimitiveType().Size()) +} + +func (token Token) Offset() int32 { + return token.offset +} + +func (token Token) ComponentTokenCount() int32 { + return token.componentTokenCount +} + +// IsConstantEncoding returns true if the encoding presence is constant or false if not. +func (token Token) IsConstantEncoding() bool { + return token.encoding.presence == SbeConstant +} + +// IsOptionalEncoding returns true if the encoding presence is optional or false if not. +func (token Token) IsOptionalEncoding() bool { + return token.encoding.presence == SbeOptional +} + +func (token Token) String() string { + return fmt.Sprintf( + "Token{signal: %s, name: %s, description: %s, fieldId: %d, tokenVersion: %d, encoding: %s, encodedLength: %d, offset: %d, componentTokenCount: %d}", + token.signal, + token.name, + token.description, + token.fieldId, + token.version, + &token.encoding, + token.encodedLength, + token.offset, + token.componentTokenCount) +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index 3d95be6172..9c0ab8df4b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -242,6 +242,12 @@ public class SbeTool */ public static final String JAVA_PRECEDENCE_CHECKS_PROPERTY_NAME = "sbe.java.precedence.checks.property.name"; + /** + * Boolean system property to generate flyweights instead of structs in generated Go code. + * Defaults to false + */ + public static final String GO_GENERATE_FLYWEIGHTS = "sbe.go.generate.generate.flyweights"; + /** * Main entry point for the SBE Tool. * diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index fbf7a9d0f0..4edea4f8b4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -21,8 +21,10 @@ import uk.co.real_logic.sbe.generation.cpp.CppDtoGenerator; import uk.co.real_logic.sbe.generation.cpp.CppGenerator; import uk.co.real_logic.sbe.generation.cpp.NamespaceOutputManager; -import uk.co.real_logic.sbe.generation.golang.GolangGenerator; -import uk.co.real_logic.sbe.generation.golang.GolangOutputManager; +import uk.co.real_logic.sbe.generation.golang.struct.GolangGenerator; +import uk.co.real_logic.sbe.generation.golang.struct.GolangOutputManager; +import uk.co.real_logic.sbe.generation.golang.flyweight.GolangFlyweightGenerator; +import uk.co.real_logic.sbe.generation.golang.flyweight.GolangFlyweightOutputManager; import uk.co.real_logic.sbe.generation.java.JavaDtoGenerator; import uk.co.real_logic.sbe.generation.java.JavaGenerator; import uk.co.real_logic.sbe.generation.java.JavaOutputManager; @@ -128,7 +130,19 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new GolangGenerator(ir, new GolangOutputManager(outputDir, ir.applicableNamespace())); + if ("true".equals(System.getProperty(GO_GENERATE_FLYWEIGHTS))) + { + return new GolangFlyweightGenerator( + ir, + "true".equals(System.getProperty(DECODE_UNKNOWN_ENUM_VALUES)), + new GolangFlyweightOutputManager(outputDir, ir.applicableNamespace())); + } + else + { + return new GolangGenerator( + ir, + new GolangOutputManager(outputDir, ir.applicableNamespace())); + } } }, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java new file mode 100644 index 0000000000..de9d86f8cc --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java @@ -0,0 +1,3382 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.golang.flyweight; + +import org.agrona.Strings; +import org.agrona.Verify; +import org.agrona.generation.OutputManager; +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Encoding; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.Signal; +import uk.co.real_logic.sbe.ir.Token; + +import java.io.IOException; +import java.io.Writer; +import java.nio.ByteOrder; +import java.util.*; + +import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; +import static uk.co.real_logic.sbe.generation.golang.flyweight.GolangFlyweightUtil.*; +import static uk.co.real_logic.sbe.ir.GenerationUtil.*; + +/** + * Codec generator for the Go programming language using flyweights. + */ +@SuppressWarnings("MethodLength") +public class GolangFlyweightGenerator implements CodeGenerator +{ + private static final String BASE_INDENT = ""; + private static final String INDENT = " "; + + private final Ir ir; + private final OutputManager outputManager; + private final boolean shouldDecodeUnknownEnumValues; + + private final Set includes = new TreeSet<>(); + + /** + * Create a new Golang language {@link CodeGenerator}. + * + * @param ir for the messages and types. + * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. + * @param outputManager for generating the codecs to. + */ + public GolangFlyweightGenerator( + final Ir ir, + final boolean shouldDecodeUnknownEnumValues, + final OutputManager outputManager) + { + Verify.notNull(ir, "ir"); + Verify.notNull(outputManager, "outputManager"); + + this.ir = ir; + this.shouldDecodeUnknownEnumValues = shouldDecodeUnknownEnumValues; + this.outputManager = outputManager; + } + + private static void generateGroupClassHeader( + final StringBuilder sb, + final String groupClassName, + final List tokens, + final int index, + final String indent, + final List fields, + final List groups) + { + final String dimensionsClassName = formatClassName(tokens.get(index + 1).name()); + final int dimensionHeaderLength = tokens.get(index + 1).encodedLength(); + final int blockLength = tokens.get(index).encodedLength(); + final Token blockLengthToken = Generators.findFirst("blockLength", tokens, index); + final Token numInGroupToken = Generators.findFirst("numInGroup", tokens, index); + final String golangTypeBlockLength = goTypeName(blockLengthToken.encoding().primitiveType()); + final String golangTypeNumInGroup = goTypeName(numInGroupToken.encoding().primitiveType()); + + new Formatter(sb).format("\n" + + indent + "type %1$s struct {\n" + + indent + " buffer []byte\n" + + indent + " bufferLength uint64\n" + + indent + " initialPosition uint64\n" + + indent + " positionPtr *uint64\n" + + indent + " blockLength uint64\n" + + indent + " count uint64\n" + + indent + " index uint64\n" + + indent + " offset uint64\n" + + indent + " actingVersion uint64\n", + groupClassName); + + for (int i = 0, size = fields.size(); i < size; i++) + { + final Token signalToken = fields.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = fields.get(i + 1); + final String propertyName = formatPropertyName(signalToken.name()); + final String typeName = formatClassName(encodingToken.applicableTypeName()); + + switch (encodingToken.signal()) + { + case BEGIN_SET: + case BEGIN_COMPOSITE: + new Formatter(sb).format(indent + " _%1$s %2$s\n", + propertyName, + typeName); + break; + + default: + break; + } + } + } + + for (int i = 0, size = groups.size(); i < size; ) + { + final Token token = groups.get(i); + if (token.signal() == Signal.BEGIN_GROUP) + { + final String propertyName = formatPropertyName(token.name()); + final String groupName = groupClassName + formatClassName(token.name()); + + new Formatter(sb).format(indent + " _%1$s %2$s\n", + propertyName, + groupName); + i += token.componentTokenCount(); + } + } + + new Formatter(sb).format( + indent + "}\n\n" + + indent + "func (g *%1$s) sbePositionPtr() *uint64 {\n" + + indent + " return g.positionPtr\n" + + indent + "}\n\n", + groupClassName); + + new Formatter(sb).format( + indent + "func (g *%3$s) WrapForDecode(\n" + + indent + " buffer []byte,\n" + + indent + " pos *uint64,\n" + + indent + " actingVersion uint64,\n" + + indent + " bufferLength uint64) {\n" + + indent + " dimensions := %2$s{}\n" + + indent + " dimensions.Wrap(buffer, *pos, actingVersion, bufferLength)\n" + + indent + " g.buffer = buffer\n" + + indent + " g.bufferLength = bufferLength\n" + + indent + " g.blockLength = uint64(dimensions.BlockLength())\n" + + indent + " g.count = uint64(dimensions.NumInGroup())\n" + + indent + " g.index = 0\n" + + indent + " g.actingVersion = actingVersion\n" + + indent + " g.initialPosition = *pos\n" + + indent + " g.positionPtr = pos\n" + + indent + " *g.positionPtr = *g.positionPtr + %1$d\n" + + indent + "}\n", + dimensionHeaderLength, dimensionsClassName, groupClassName); + + final long minCount = numInGroupToken.encoding().applicableMinValue().longValue(); + final String minCheck = minCount > 0 ? "count < " + minCount + " || " : ""; + + new Formatter(sb).format("\n" + + indent + "func (g *%8$s) WrapForEncode(\n" + + indent + " buffer []byte,\n" + + indent + " count %3$s,\n" + + indent + " pos *uint64,\n" + + indent + " actingVersion uint64,\n" + + indent + " bufferLength uint64) {\n" + + indent + " if %5$scount > %6$d {\n" + + indent + " panic(\"count outside of allowed range [E110]\")\n" + + indent + " }\n" + + indent + " g.buffer = buffer\n" + + indent + " g.bufferLength = bufferLength\n" + + indent + " dimensions := %7$s{}\n" + + indent + " dimensions.Wrap(buffer, *pos, actingVersion, bufferLength)\n" + + indent + " dimensions.SetBlockLength(%2$d)\n" + + indent + " dimensions.SetNumInGroup(count)\n" + + indent + " g.index = 0\n" + + indent + " g.count = uint64(count)\n" + + indent + " g.blockLength = %2$d\n" + + indent + " g.actingVersion = actingVersion\n" + + indent + " g.initialPosition = *pos\n" + + indent + " g.positionPtr = pos\n" + + indent + " *g.positionPtr = *g.positionPtr + %4$d\n" + + indent + "}\n", + golangTypeBlockLength, + blockLength, + golangTypeNumInGroup, + dimensionHeaderLength, + minCheck, + numInGroupToken.encoding().applicableMaxValue().longValue(), + dimensionsClassName, + groupClassName); + + new Formatter(sb).format("\n" + + indent + "func (g *%3$s) SbeHeaderSize() uint64 {\n" + + indent + " return %1$d\n" + + indent + "}\n\n" + + + indent + "func (g *%3$s) SbeBlockLength() uint64 {\n" + + indent + " return %2$d\n" + + indent + "}\n\n" + + + indent + "func (g *%3$s) SbePosition() uint64 {\n" + + indent + " return *g.positionPtr\n" + + indent + "}\n\n" + + + indent + "func (g *%3$s) SbeCheckPosition(position uint64) uint64 {\n" + + indent + " if position > g.bufferLength {\n" + + indent + " panic(\"buffer too short [E100]\")\n" + + indent + " }\n" + + indent + " return position\n" + + indent + "}\n\n" + + + indent + "func (g *%3$s) SetSbePosition(position uint64) {\n" + + indent + " *g.positionPtr = g.SbeCheckPosition(position)\n" + + indent + "}\n\n" + + + indent + "func (g *%3$s) Count() uint64 {\n" + + indent + " return g.count\n" + + indent + "}\n\n" + + + indent + "func (g *%3$s) HasNext() bool {\n" + + indent + " return g.index < g.count\n" + + indent + "}\n\n" + + + indent + "func (g *%3$s) Next() *%3$s {\n" + + indent + " if g.index >= g.count {\n" + + indent + " panic(\"index >= count [E108]\")\n" + + indent + " }\n" + + indent + " g.offset = *g.positionPtr\n" + + indent + " if g.offset+g.blockLength > g.bufferLength {\n" + + indent + " panic(\"buffer too short for next group index [E108]\")\n" + + indent + " }\n" + + indent + " *g.positionPtr = g.offset + g.blockLength\n" + + indent + " g.index++\n\n" + + + indent + " return g\n" + + indent + "}\n", + dimensionHeaderLength, + blockLength, + groupClassName); + sb.append("\n") + .append(indent).append("func (g *").append(groupClassName) + .append(") ResetCountToIndex() uint64 {\n") + .append(indent).append(" g.count = g.index\n") + .append(indent).append(" dimensions := ").append(dimensionsClassName).append("{}\n") + .append(indent).append(" dimensions.Wrap") + .append("(g.buffer, g.initialPosition, g.actingVersion, g.bufferLength)\n") + .append(indent) + .append(" dimensions.SetNumInGroup(").append(golangTypeNumInGroup).append("(g.count))\n") + .append(indent).append(" return g.count\n") + .append(indent).append("}\n\n"); + + sb.append("\n") + .append(indent).append("func (g *").append(groupClassName) + .append(") ForEach(fn func(group *").append(groupClassName).append(")) {\n") + .append(indent).append(" for g.HasNext() {\n") + .append(indent).append(" g.Next()\n") + .append(indent).append(" fn(g)\n") + .append(indent).append(" }\n") + .append(indent).append("}\n\n"); + } + + private static void generateGroupProperty( + final StringBuilder sb, + final String groupName, + final String groupClassName, + final String outerClassName, + final Token token, + final String goTypeForNumInGroup, + final String indent) + { + final String propertyName = formatPropertyName(groupName); + + new Formatter(sb).format( + indent + " func (m *%3$s) %1$sId() int {\n" + + indent + " return %2$d\n" + + indent + " }\n", + propertyName, + token.id(), + outerClassName); + + + new Formatter(sb).format("\n" + + indent + "func (m *%1$s) %2$s() *%3$s {\n" + + indent + " m._%2$s.WrapForDecode(m.buffer, m.sbePositionPtr(), m.actingVersion, m.bufferLength)\n" + + indent + " return &m._%2$s\n" + + indent + "}\n", + outerClassName, + propertyName, + groupClassName); + + new Formatter(sb).format("\n" + + indent + "func (m *%1$s) %2$sCount(count %3$s) *%4$s {\n" + + indent + + " m._%2$s.WrapForEncode(m.buffer, count, m.sbePositionPtr(), m.actingVersion, m.bufferLength)\n" + + indent + " return &m._%2$s\n" + + indent + "}\n", + outerClassName, + propertyName, + goTypeForNumInGroup, + groupClassName); + + final int version = token.version(); + final String versionCheck = 0 == version ? + " return true\n" : " return m.actingVersion >= m.%1$sSinceVersion()\n"; + new Formatter(sb).format("\n" + + indent + "func (m *%3$s) %1$sSinceVersion() uint64 {\n" + + indent + " return %2$d\n" + + indent + "}\n\n" + + + indent + "func (m *%3$s) %1$sInActingVersion() bool {\n" + + indent + versionCheck + + indent + "}\n", + propertyName, + version, + outerClassName); + } + + private static CharSequence generateChoiceNotPresentCondition(final int sinceVersion) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + " if m.actingVersion < %1$d {\n" + + " return false\n" + + " }\n\n", + sinceVersion); + } + + private static CharSequence generateArrayFieldNotPresentCondition( + final int sinceVersion, final String indent) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + indent + " if m.actingVersion < %1$d {\n" + + indent + " return nil\n" + + indent + " }\n\n", + sinceVersion); + } + + private static CharSequence generateArrayLengthNotPresentCondition( + final int sinceVersion, final String indent) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + indent + " if m.actingVersion < %1$d {\n" + + indent + " return 0\n" + + indent + " }\n\n", + sinceVersion); + } + + private static CharSequence generateArrayFieldNotPresentConditionWithErr( + final int sinceVersion, final String indent) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + indent + " if m.actingVersion < %1$d {\n" + + indent + " return 0, nil\n" + + indent + " }\n\n", + sinceVersion); + } + + private static CharSequence generateStringNotPresentCondition( + final int sinceVersion, final String indent) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + indent + " if m.actingVersion < %1$d {\n" + + indent + " return \"\"\n" + + indent + " }\n\n", + sinceVersion); + } + + private static CharSequence generateTypeFieldNotPresentCondition( + final int sinceVersion, final String indent) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + indent + " if m.actingVersion < %1$d {\n" + + indent + " return \"\"\n" + + indent + " }\n\n", + sinceVersion); + } + + private static CharSequence generateClassDeclaration(final String className) + { + return + "type " + className + " struct {\n"; + } + + private static CharSequence generateEnumDeclaration(final String name, final Token encodingToken) + { + final Encoding encoding = encodingToken.encoding(); + return "type " + name + " " + goTypeName(encoding.primitiveType()) + "\n"; + } + + private static CharSequence generateConstructorsAndOperators(final String className) + { + return String.format( + " func %1$s() {\n\n" + + + " func %1$s(\n" + + " buffer []byte,\n" + + " offset uint64,\n" + + " bufferLength uint64,\n" + + " actingBlockLength uint64,\n" + + " actingVersion uint64) {\n" + + " m.buffer := buffer\n" + + " m.bufferLength := bufferLength\n" + + " m.offset := offset\n" + + " m.position := sbeCheckPosition(offset + actingBlockLength)\n" + + " m.actingBlockLength := actingBlockLength\n" + + " m.actingVersion := actingVersion\n" + + " }\n\n", + className); + } + + private static void generateFieldMetaAttributeMethod( + final StringBuilder sb, final Token token, final String indent, final String className) + { + final Encoding encoding = token.encoding(); + final String propertyName = toUpperFirstChar(token.name()); + final String epoch = encoding.epoch() == null ? "" : encoding.epoch(); + final String timeUnit = encoding.timeUnit() == null ? "" : encoding.timeUnit(); + final String semanticType = encoding.semanticType() == null ? "" : encoding.semanticType(); + + sb.append("\n") + .append(indent).append("func (m *").append(className) + .append(") ").append(propertyName).append("MetaAttribute(metaAttribute string) string {\n") + .append(indent).append(" switch metaAttribute {\n"); + + if (!Strings.isEmpty(epoch)) + { + sb.append(indent) + .append(" case \"EPOCH\": return \"").append(epoch).append("\"\n"); + } + + if (!Strings.isEmpty(timeUnit)) + { + sb.append(indent) + .append(" case \"TIME_UNIT\": return \"").append(timeUnit).append("\"\n"); + } + + if (!Strings.isEmpty(semanticType)) + { + sb.append(indent) + .append(" case \"SEMANTIC_TYPE\": return \"").append(semanticType) + .append("\"\n"); + } + + sb + .append(indent).append(" case \"PRESENCE\": return \"") + .append(encoding.presence().toString().toLowerCase()).append("\"\n") + .append(indent).append(" default: return \"\"\n") + .append(indent).append(" }\n") + .append(indent).append("}\n"); + } + + private static CharSequence generateEnumFieldNotPresentCondition( + final int sinceVersion, final String enumName, final String indent) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + indent + " if m.actingVersion < %1$d {\n" + + indent + " return %2$s_NULL_VALUE\n" + + indent + " }\n\n", + sinceVersion, + enumName); + } + + private static void generateBitsetProperty( + final StringBuilder sb, + final String propertyName, + final Token token, + final String indent, + final String className) + { + final String bitsetName = formatClassName(token.applicableTypeName()); + final int offset = token.offset(); + + new Formatter(sb).format( + indent + " func (m *%4$s) %2$s() *%1$s {\n" + + indent + " m._%2$s.Wrap(m.buffer, m.offset + %3$d, m.actingVersion, m.bufferLength)\n" + + indent + " return &m._%2$s\n" + + indent + " }\n", + bitsetName, + propertyName, + offset, + className); + + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %1$sEncodingLength() int {\n" + + indent + " return %2$d\n" + + indent + " }\n", + propertyName, + token.encoding().primitiveType().size(), + className); + } + + private static void generateCompositeProperty( + final StringBuilder sb, + final String propertyName, + final Token token, + final String indent, + final String className) + { + final String compositeName = formatClassName(token.applicableTypeName()); + + new Formatter(sb).format( + indent + " func (m *%4$s) %2$s() *%1$s {\n" + + indent + " m._%2$s.Wrap(m.buffer, m.offset + %3$d, m.actingVersion, m.bufferLength)\n" + + indent + " return &m._%2$s\n" + + indent + " }\n", + compositeName, + propertyName, + token.offset(), + className); + } + + /** + * Generate the composites for dealing with the message header. + * + * @throws IOException if an error is encountered when writing the output. + */ + public void generateMessageHeaderStub() throws IOException + { + generateComposite(ir.headerStructure().tokens()); + } + + private void generateTypeStubs() throws IOException + { + for (final List tokens : ir.types()) + { + switch (tokens.get(0).signal()) + { + case BEGIN_ENUM: + generateEnum(tokens); + break; + + case BEGIN_SET: + generateChoiceSet(tokens); + break; + + case BEGIN_COMPOSITE: + generateComposite(tokens); + break; + + default: + break; + } + } + } + + /** + * {@inheritDoc} + */ + public void generate() throws IOException + { + + generateUtils(ir.namespaces()); + + generateMessageHeaderStub(); + generateTypeStubs(); + + for (final List tokens : ir.messages()) + { + includes.clear(); + + final Token msgToken = tokens.get(0); + final String className = formatClassName(msgToken.name()); + + try (Writer fileOut = outputManager.createOutput(className)) + { + final StringBuilder out = new StringBuilder(); + out.append(generateClassDeclaration(className)); + + final List messageBody = tokens.subList(1, tokens.size() - 1); + int i = 0; + + final List fields = new ArrayList<>(); + i = collectFields(messageBody, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(messageBody, i, groups); + + final List varData = new ArrayList<>(); + collectVarData(messageBody, i, varData); + + out.append(generateMessageFlyweightCode(className, msgToken, fields, groups)); + + final StringBuilder sb = new StringBuilder(); + generateFields(sb, className, fields, BASE_INDENT); + generateGroups(sb, groups, BASE_INDENT, className); + generateVarData(sb, className, varData, BASE_INDENT); + generateDisplay(sb, msgToken.name(), className, fields, groups, varData); + sb.append(generateMessageLength(groups, varData, BASE_INDENT, className)); + out.append(sb); + + fileOut.append(generateFileHeader(ir.namespaces())); + fileOut.append(out); + } + } + } + + private void generateUtils(final String[] namespaces) throws IOException + { + + try (Writer out = outputManager.createOutput("Utils")) + { + out.append("/* Generated SBE (Simple Binary Encoding) message codec */\n"); + + out.append(String.format("// Code generated by SBE. DO NOT EDIT.\n\n" + + + "package %1$s\n\n" + + + "import (\n" + + "\t\"math\"\n" + + "\t\"math/bits\"\n" + + ")\n\n" + + + "// SbeBigEndianEncode16 encodes a 16-bit value into big endian byte order\n" + + "func SbeBigEndianEncode16(v uint16) uint16 {\n" + + "\treturn bits.ReverseBytes16(v)\n" + + "}\n\n" + + + "// SbeBigEndianEncode32 encodes a 32-bit value into big endian byte order\n" + + "func SbeBigEndianEncode32(v uint32) uint32 {\n" + + "\treturn bits.ReverseBytes32(v)\n" + + "}\n\n" + + + "// SbeBigEndianEncode64 encodes a 64-bit value into big endian byte order\n" + + "func SbeBigEndianEncode64(v uint64) uint64 {\n" + + "\treturn bits.ReverseBytes64(v)\n" + + "}\n\n" + + + "// SbeLittleEndianEncode16 encodes a 16-bit value into little endian byte order\n" + + "func SbeLittleEndianEncode16(v uint16) uint16 {\n" + + "\treturn v\n" + + "}\n\n" + + + "// SbeLittleEndianEncode32 encodes a 32-bit value into little endian byte order\n" + + "func SbeLittleEndianEncode32(v uint32) uint32 {\n" + + "\treturn v\n" + + "}\n\n" + + + "// SbeLittleEndianEncode64 encodes a 64-bit value into little endian byte order\n" + + "func SbeLittleEndianEncode64(v uint64) uint64 {\n" + + "\treturn v\n" + + "}\n\n" + + + "// SbeNullValueFloat returns the null value for a float\n" + + "func SbeNullValueFloat() float32 {\n" + + "\treturn float32(math.NaN())\n" + + "}\n\n" + + + "// SbeNullValueDouble returns the null value for a double\n" + + "func SbeNullValueDouble() float64 {\n" + + "\treturn math.NaN()\n" + + "}\n\n" + + + "// SbeNullValueByte returns the null value for a byte\n" + + "func SbeNullValueByte() byte {\n" + + "\treturn byte(math.MaxUint8)\n" + + "}\n\n" + + + "// SbeNullValueInt8 returns the null value for an 8-bit integer\n" + + "func SbeNullValueInt8() int8 {\n" + + "\treturn math.MinInt8\n" + + "}\n\n" + + + "// SbeNullValueInt16 returns the null value for a 16-bit integer\n" + + "func SbeNullValueInt16() int16 {\n" + + "\treturn math.MinInt16\n" + + "}\n\n" + + + "// SbeNullValueInt32 returns the null value for a 32-bit integer\n" + + "func SbeNullValueInt32() int32 {\n" + + "\treturn math.MinInt32\n" + + "}\n\n" + + + "// SbeNullValueInt64 returns the null value for a 64-bit integer\n" + + "func SbeNullValueInt64() int64 {\n" + + "\treturn math.MinInt64\n" + + "}\n\n" + + + "// SbeNullValueUint8 returns the null value for an 8-bit unsigned integer\n" + + "func SbeNullValueUint8() uint8 {\n" + + "\treturn math.MaxUint8\n" + + "}\n\n" + + + "// SbeNullValueUint16 returns the null value for a 16-bit unsigned integer\n" + + "func SbeNullValueUint16() uint16 {\n" + + "\treturn math.MaxUint16\n" + + "}\n\n" + + + "// SbeNullValueUint32 returns the null value for a 32-bit unsigned integer\n" + + "func SbeNullValueUint32() uint32 {\n" + + "\treturn math.MaxUint32\n" + + "}\n\n" + + + "// SbeNullValueUint64 returns the null value for a 64-bit unsigned integer\n" + + "func SbeNullValueUint64() uint64 {\n" + + "\treturn math.MaxUint64\n" + + "}\n\n" + + + "type MetaAttribute int\n" + + "const (\n" + + " EPOCH MetaAttribute = iota\n" + + " TIME_UNIT\n" + + " SEMANTIC_TYPE\n" + + " PRESENCE\n" + + ")\n\n" + + + "var SbeNoBoundsCheck = false\n\n" + + "// LittleEndian\n" + + "\n" + + "func ByteLittleEndian(b []byte) byte {\n" + + "\treturn b[0]\n" + + "}\n" + + "\n" + + "func PutByteLittleEndian(b []byte, v byte) {\n" + + "\tb[0] = v\n" + + "}\n" + + "\n" + + "func Uint8LittleEndian(b []byte) uint8 {\n" + + "\treturn b[0]\n" + + "}\n" + + "\n" + + "func PutUint8LittleEndian(b []byte, v uint8) {\n" + + "\tb[0] = v\n" + + "}\n" + + "\n" + + "func Int8LittleEndian(b []byte) int8 {\n" + + "\treturn int8(Uint8LittleEndian(b))\n" + + "}\n" + + "\n" + + "func PutInt8LittleEndian(b []byte, v int8) {\n" + + "\tPutUint8LittleEndian(b, uint8(v))\n" + + "}\n" + + "\n" + + "func Uint16LittleEndian(b []byte) uint16 {\n" + + "\t_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808\n" + + "\treturn uint16(b[0]) | uint16(b[1])<<8\n" + + "}\n" + + "\n" + + "func PutUint16LittleEndian(b []byte, v uint16) {\n" + + "\t_ = b[1] // early bounds check to guarantee safety of writes below\n" + + "\tb[0] = byte(v)\n" + + "\tb[1] = byte(v >> 8)\n" + + "}\n" + + "\n" + + "func Int16LittleEndian(b []byte) int16 {\n" + + "\treturn int16(Uint16LittleEndian(b))\n" + + "}\n" + + "\n" + + "func PutInt16LittleEndian(b []byte, v int16) {\n" + + "\tPutUint16LittleEndian(b, uint16(v))\n" + + "}\n" + + "\n" + + "func Uint32LittleEndian(b []byte) uint32 {\n" + + "\t_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808\n" + + "\treturn uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24\n" + + "}\n" + + "\n" + + "func PutUint32LittleEndian(b []byte, v uint32) {\n" + + "\t_ = b[3] // early bounds check to guarantee safety of writes below\n" + + "\tb[0] = byte(v)\n" + + "\tb[1] = byte(v >> 8)\n" + + "\tb[2] = byte(v >> 16)\n" + + "\tb[3] = byte(v >> 24)\n" + + "}\n" + + "\n" + + "func Int32LittleEndian(b []byte) int32 {\n" + + "\treturn int32(Uint32LittleEndian(b))\n" + + "}\n" + + "\n" + + "func PutInt32LittleEndian(b []byte, v int32) {\n" + + "\tPutUint32LittleEndian(b, uint32(v))\n" + + "}\n" + + "\n" + + "func Uint64LittleEndian(b []byte) uint64 {\n" + + "\t_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808\n" + + "\treturn uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |\n" + + "\t\tuint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56\n" + + "}\n" + + "\n" + + "func PutUint64LittleEndian(b []byte, v uint64) {\n" + + "\t_ = b[7] // early bounds check to guarantee safety of writes below\n" + + "\tb[0] = byte(v)\n" + + "\tb[1] = byte(v >> 8)\n" + + "\tb[2] = byte(v >> 16)\n" + + "\tb[3] = byte(v >> 24)\n" + + "\tb[4] = byte(v >> 32)\n" + + "\tb[5] = byte(v >> 40)\n" + + "\tb[6] = byte(v >> 48)\n" + + "\tb[7] = byte(v >> 56)\n" + + "}\n" + + "\n" + + "func Int64LittleEndian(b []byte) int64 {\n" + + "\treturn int64(Uint64LittleEndian(b))\n" + + "}\n" + + "\n" + + "func PutInt64LittleEndian(b []byte, v int64) {\n" + + "\tPutUint64LittleEndian(b, uint64(v))\n" + + "}\n" + + "\n" + + "func FloatLittleEndian(b []byte) float32 {\n" + + "\treturn math.Float32frombits(Uint32LittleEndian(b))\n" + + "}\n" + + "\n" + + "func PutFloatLittleEndian(b []byte, v float32) {\n" + + "\tPutUint32LittleEndian(b, math.Float32bits(v))\n" + + "}\n" + + "\n" + + "func DoubleLittleEndian(b []byte) float64 {\n" + + "\treturn math.Float64frombits(Uint64LittleEndian(b))\n" + + "}\n" + + "\n" + + "func PutDoubleLittleEndian(b []byte, v float64) {\n" + + "\tPutUint64LittleEndian(b, math.Float64bits(v))\n" + + "}\n" + + "\n" + + "// BigEndian\n" + + "\n" + + "func ByteBigEndian(b []byte) byte {\n" + + "\treturn b[0]\n" + + "}\n" + + "\n" + + "func PutByteBigEndian(b []byte, v byte) {\n" + + "\tb[0] = v\n" + + "}\n" + + "\n" + + "func Uint8BigEndian(b []byte) uint8 {\n" + + "\treturn b[0]\n" + + "}\n" + + "\n" + + "func PutUint8BigEndian(b []byte, v uint8) {\n" + + "\tb[0] = byte(v)\n" + + "}\n" + + "\n" + + "func Int8BigEndian(b []byte) int8 {\n" + + "\treturn int8(Uint8BigEndian(b))\n" + + "}\n" + + "\n" + + "func PutInt8BigEndian(b []byte, v int8) {\n" + + "\tPutUint8BigEndian(b, uint8(v))\n" + + "}\n" + + "\n" + + "func Uint16BigEndian(b []byte) uint16 {\n" + + "\t_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808\n" + + "\treturn uint16(b[1]) | uint16(b[0])<<8\n" + + "}\n" + + "\n" + + "func PutUint16BigEndian(b []byte, v uint16) {\n" + + "\t_ = b[1] // early bounds check to guarantee safety of writes below\n" + + "\tb[0] = byte(v >> 8)\n" + + "\tb[1] = byte(v)\n" + + "}\n" + + "\n" + + "func Int16BigEndian(b []byte) int16 {\n" + + "\treturn int16(Uint16BigEndian(b))\n" + + "}\n" + + "\n" + + "func PutInt16BigEndian(b []byte, v int16) {\n" + + "\tPutUint16BigEndian(b, uint16(v))\n" + + "}\n" + + "\n" + + "func Uint32BigEndian(b []byte) uint32 {\n" + + "\t_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808\n" + + "\treturn uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24\n" + + "}\n" + + "\n" + + "func PutUint32BigEndian(b []byte, v uint32) {\n" + + "\t_ = b[3] // early bounds check to guarantee safety of writes below\n" + + "\tb[0] = byte(v >> 24)\n" + + "\tb[1] = byte(v >> 16)\n" + + "\tb[2] = byte(v >> 8)\n" + + "\tb[3] = byte(v)\n" + + "}\n" + + "\n" + + "func Int32BigEndian(b []byte) int32 {\n" + + "\treturn int32(Uint32BigEndian(b))\n" + + "}\n" + + "\n" + + "func PutInt32BigEndian(b []byte, v int32) {\n" + + "\tPutUint32BigEndian(b, uint32(v))\n" + + "}\n" + + "\n" + + "func Uint64BigEndian(b []byte) uint64 {\n" + + "\t_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808\n" + + "\treturn uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |\n" + + "\t\tuint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56\n" + + "}\n" + + "\n" + + "func PutUint64BigEndian(b []byte, v uint64) {\n" + + "\t_ = b[7] // early bounds check to guarantee safety of writes below\n" + + "\tb[0] = byte(v >> 56)\n" + + "\tb[1] = byte(v >> 48)\n" + + "\tb[2] = byte(v >> 40)\n" + + "\tb[3] = byte(v >> 32)\n" + + "\tb[4] = byte(v >> 24)\n" + + "\tb[5] = byte(v >> 16)\n" + + "\tb[6] = byte(v >> 8)\n" + + "\tb[7] = byte(v)\n" + + "}\n" + + "\n" + + "func Int64BigEndian(b []byte) int64 {\n" + + "\treturn int64(Uint64BigEndian(b))\n" + + "}\n" + + "\n" + + "func PutInt64BigEndian(b []byte, v int64) {\n" + + "\tPutUint64BigEndian(b, uint64(v))\n" + + "}\n" + + "\n" + + "func FloatBigEndian(b []byte) float32 {\n" + + "\treturn math.Float32frombits(Uint32BigEndian(b))\n" + + "}\n" + + "\n" + + "func PutFloatBigEndian(b []byte, v float32) {\n" + + "\tPutUint32BigEndian(b, math.Float32bits(v))\n" + + "}\n" + + "\n" + + "func DoubleBigEndian(b []byte) float64 {\n" + + "\treturn math.Float64frombits(Uint64BigEndian(b))\n" + + "}\n" + + "\n" + + "func PutDoubleBigEndian(b []byte, v float64) {\n" + + "\tPutUint64BigEndian(b, math.Float64bits(v))\n" + + "}\n", + + namespacesToPackageName(namespaces))); + } + } + + private String formatIncludes(final Set includes) + { + final StringBuilder sb = new StringBuilder(); + + boolean first = true; + for (final String s : includes) + { + if (!first) + { + sb.append("\n"); + } + sb.append('"').append(s).append('"'); + first = false; + } + return sb.toString(); + } + + private void generateGroups( + final StringBuilder sb, + final List tokens, + final String indent, + final String outerClassName) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + final String groupName = groupToken.name(); + final String groupClassName = formatClassName(outerClassName + formatClassName(groupToken.name())); + final Token numInGroupToken = Generators.findFirst("numInGroup", tokens, i); + final String goTypeForNumInGroup = goTypeName(numInGroupToken.encoding().primitiveType()); + + final int groupStart = i; + + ++i; + final int groupHeaderTokenCount = tokens.get(i).componentTokenCount(); + i += groupHeaderTokenCount; + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + generateGroupClassHeader(sb, groupClassName, tokens, groupStart, + indent + INDENT, fields, groups); + + generateFields(sb, groupClassName, fields, indent + INDENT); + generateGroups(sb, groups, indent + INDENT, groupClassName); + + final List varData = new ArrayList<>(); + i = collectVarData(tokens, i, varData); + generateVarData(sb, groupClassName, varData, indent + INDENT); + + sb.append(generateGroupDisplay(groupClassName, fields, groups, varData, indent + INDENT + INDENT)); + sb.append(generateMessageLength(groups, varData, indent + INDENT + INDENT, groupClassName)); + + generateGroupProperty(sb, groupName, groupClassName, outerClassName, groupToken, goTypeForNumInGroup, + indent); + } + } + + private void generateVarData( + final StringBuilder sb, + final String className, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; ) + { + final Token token = tokens.get(i); + if (token.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + token); + } + + final String propertyName = toUpperFirstChar(token.name()); + final Token lengthToken = Generators.findFirst("length", tokens, i); + final Token varDataToken = Generators.findFirst("varData", tokens, i); + final String characterEncoding = varDataToken.encoding().characterEncoding(); + final int lengthOfLengthField = lengthToken.encodedLength(); + final String lengthGoType = goTypeName(lengthToken.encoding().primitiveType()); + final String lengthByteOrderReadStr = formatReadBytes( + lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType()); + + generateFieldMetaAttributeMethod(sb, token, indent, className); + + generateVarDataDescriptors( + sb, token, propertyName, characterEncoding, lengthToken, + lengthOfLengthField, lengthGoType, indent, className); + + new Formatter(sb).format("\n" + + indent + " func (m *%5$s) Skip%1$s() uint64 {\n" + + "%2$s" + + indent + " lengthOfLengthField := uint64(%3$d)\n" + + indent + " lengthPosition := m.SbePosition()\n" + + indent + + " dataLength := uint64(%4$s(m.buffer[lengthPosition : lengthPosition+lengthOfLengthField]))\n" + + indent + " m.SetSbePosition(lengthPosition + lengthOfLengthField + dataLength)\n" + + indent + " return dataLength\n" + + indent + " }\n", + propertyName, + generateArrayLengthNotPresentCondition(token.version(), indent), + lengthOfLengthField, + lengthByteOrderReadStr, + className); + + + new Formatter(sb).format("\n" + + indent + "func (m *%6$s) %1$s() string {\n" + + "%2$s" + + indent + " lengthFieldValue := uint64(%4$s(m.buffer[m.SbePosition():m.SbePosition()+%3$d]))\n" + + indent + " m.SetSbePosition(m.SbePosition() + uint64(%3$d))\n" + + indent + " pos := m.SbePosition()\n" + + indent + " m.SetSbePosition(pos + lengthFieldValue)\n" + + indent + " return string(m.buffer[pos:pos+lengthFieldValue])\n" + + indent + "}\n", + formatPropertyName(propertyName), + generateTypeFieldNotPresentCondition(token.version(), indent), + lengthOfLengthField, + lengthByteOrderReadStr, + lengthGoType, + className); + + new Formatter(sb).format("\n" + + indent + "func (m *%5$s) Get%1$s(dst []byte) int {\n" + + "%2$s" + + indent + " lengthOfLengthField := uint64(%3$d)\n" + + indent + " lengthPosition := m.SbePosition()\n" + + indent + " m.SetSbePosition(m.SbePosition() + lengthOfLengthField)\n" + + indent + + " dataLength := uint64(%4$s(m.buffer[lengthPosition:lengthPosition+lengthOfLengthField]))\n" + + indent + " bytesToCopy := dataLength\n" + + indent + " if uint64(len(dst)) < dataLength {\n" + + indent + " bytesToCopy = uint64(len(dst))\n" + + indent + " }\n" + + indent + " pos := m.SbePosition()\n" + + indent + " m.SetSbePosition(pos + dataLength)\n" + + indent + " copy(dst, m.buffer[pos:pos+bytesToCopy])\n" + + indent + " return int(bytesToCopy)\n" + + indent + "}\n", + propertyName, + generateArrayLengthNotPresentCondition(token.version(), indent), + lengthOfLengthField, + lengthByteOrderReadStr, + className); + + final String lengthByteOrderWriteStr = formatWriteBytes( + lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType()); + new Formatter(sb).format("\n" + + indent + "func (m *%5$s) Put%1$sLen(src string, length %3$s) *%5$s {\n" + + indent + " lengthOfLengthField := uint64(%2$d)\n" + + indent + " lengthPosition := m.SbePosition()\n" + + indent + " m.SetSbePosition(lengthPosition + lengthOfLengthField)\n" + + indent + " %4$s(m.buffer[lengthPosition:], length)\n" + + indent + " if length != %3$s(0) {\n" + + indent + " pos := m.SbePosition()\n" + + indent + " m.SetSbePosition(pos + uint64(length))\n" + + indent + " copy(m.buffer[pos:], src)\n" + + indent + " }\n" + + indent + " return m\n" + + indent + "}\n", + propertyName, + lengthOfLengthField, + lengthGoType, + lengthByteOrderWriteStr, + className, + lengthByteOrderReadStr); + + new Formatter(sb).format("\n" + + indent + "func (m *%6$s) Get%1$sAsString() string {\n" + + "%2$s" + + indent + " lengthOfLengthField := uint64(%3$d)\n" + + indent + " lengthPosition := m.SbePosition()\n" + + indent + + " dataLength := uint64(%4$s(m.buffer[lengthPosition:lengthPosition+lengthOfLengthField]))\n" + + indent + " m.SetSbePosition(lengthPosition + lengthOfLengthField)\n" + + indent + " pos := m.SbePosition()\n" + + indent + " m.SetSbePosition(pos + dataLength)\n" + + indent + " return string(m.buffer[pos:pos+dataLength])\n" + + indent + "}\n", + propertyName, + generateStringNotPresentCondition(token.version(), indent), + lengthOfLengthField, + lengthByteOrderReadStr, + lengthGoType, + className); + + generateJsonEscapedStringGetter(sb, token, indent, propertyName, className); + + new Formatter(sb).format("\n" + + indent + "func (m *%1$s) Put%2$s(str string) *%1$s {\n" + + indent + " if len(str) > %4$d {\n" + + indent + " panic(\"string too long for length type [E109]\")\n" + + indent + " }\n" + + indent + " return m.Put%2$sLen(str, %3$s(len(str)))\n" + + indent + "}\n", + className, + propertyName, + lengthGoType, + lengthToken.encoding().applicableMaxValue().longValue()); + + i += token.componentTokenCount(); + } + } + + private void generateVarDataDescriptors( + final StringBuilder sb, + final Token token, + final String propertyName, + final String characterEncoding, + final Token lengthToken, + final Integer sizeOfLengthField, + final String lengthGoType, + final String indent, + final String className) + { + new Formatter(sb).format("\n" + + indent + "func (m *%3$s) %1$sCharacterEncoding() string {\n" + + indent + " return \"%2$s\"\n" + + indent + " }\n", + formatPropertyName(propertyName), + characterEncoding, + className); + + final int version = token.version(); + final String versionCheck = 0 == version ? + " return true\n" : " return m.actingVersion >= m.%1$sSinceVersion()\n"; + new Formatter(sb).format("\n" + + indent + "func (m *%4$s) %1$sSinceVersion() uint64 {\n" + + indent + " return %2$d\n" + + indent + " }\n\n" + + + indent + "func (m *%4$s) %1$sInActingVersion() bool {\n" + + indent + versionCheck + + indent + " }\n\n" + + + indent + "func (m *%4$s) %1$sId() uint16 {\n" + + indent + " return %3$d\n" + + indent + " }\n", + formatPropertyName(propertyName), + version, + token.id(), + className); + + + new Formatter(sb).format("\n" + + indent + "func (m *%3$s) %1$sHeaderLength() uint64 {\n" + + indent + " return %2$d\n" + + indent + "}\n", + formatPropertyName(propertyName), + sizeOfLengthField, + className); + + new Formatter(sb).format("\n" + + indent + "func (m *%5$s) %1$sLength() %4$s {\n" + + "%2$s" + + indent + " return %3$s(m.buffer[m.SbePosition():])\n" + + indent + "}\n", + formatPropertyName(propertyName), + generateArrayLengthNotPresentCondition(version, BASE_INDENT), + formatReadBytes(lengthToken.encoding().byteOrder(), lengthToken.encoding().primitiveType()), + lengthGoType, + className); + } + + private void generateChoiceSet(final List tokens) throws IOException + { + final Token token = tokens.get(0); + final String bitSetName = formatClassName(token.applicableTypeName()); + + try (Writer fileOut = outputManager.createOutput(bitSetName)) + { + includes.clear(); + final StringBuilder out = new StringBuilder(); + + out.append(generateClassDeclaration(bitSetName)); + out.append(generateFixedFlyweightCode(bitSetName, token.encodedLength(), tokens)); + + final Encoding encoding = token.encoding(); + new Formatter(out).format("\n" + + " func (bs *%1$s) Clear() *%1$s {\n" + + " %2$s(bs.buffer[bs.offset:], 0)\n" + + " return bs\n" + + " }\n", + bitSetName, + formatWriteBytes(token.encoding().byteOrder(), encoding.primitiveType())); + + new Formatter(out).format("\n" + + " func (bs *%1$s) IsEmpty() bool {\n" + + " return %2$s(bs.buffer[bs.offset:]) == 0\n" + + " }\n", + bitSetName, + formatReadBytes(token.encoding().byteOrder(), encoding.primitiveType())); + + new Formatter(out).format("\n" + + " func (bs *%1$s) RawValue() %2$s {\n" + + " return %2$s(bs.buffer[bs.offset])\n" + + " }\n", + bitSetName, + goTypeName(encoding.primitiveType())); + + out.append(generateChoices(bitSetName, tokens.subList(1, tokens.size() - 1))); + out.append(generateChoicesDisplay(bitSetName, tokens.subList(1, tokens.size() - 1))); + out.append("\n"); + + fileOut.append(generateFileHeader(ir.namespaces())); + fileOut.append(out); + } + } + + private void generateEnum(final List tokens) throws IOException + { + final Token enumToken = tokens.get(0); + final String enumName = formatClassName(tokens.get(0).applicableTypeName()); + + try (Writer fileOut = outputManager.createOutput(enumName)) + { + includes.clear(); + final StringBuilder out = new StringBuilder(); + + out.append(generateEnumDeclaration(enumName, enumToken)); + + out.append(generateEnumValues(tokens.subList(1, tokens.size() - 1), enumName, enumToken)); + + out.append(generateEnumLookupMethod(tokens.subList(1, tokens.size() - 1), enumToken)); + + out.append(generateEnumDisplay(tokens.subList(1, tokens.size() - 1), enumToken)); + + out.append("\n"); + + fileOut.append(generateEnumFileHeader(ir.namespaces())); + fileOut.append(out); + } + } + + private void generateComposite(final List tokens) throws IOException + { + final String compositeName = formatClassName(tokens.get(0).applicableTypeName()); + + try (Writer fileOut = outputManager.createOutput(compositeName)) + { + includes.clear(); + final StringBuilder out = new StringBuilder(); + + out.append(generateClassDeclaration(compositeName)); + out.append(generateFixedFlyweightCode(compositeName, tokens.get(0).encodedLength(), tokens)); + + out.append(generateCompositePropertyElements( + compositeName, tokens.subList(1, tokens.size() - 1), BASE_INDENT)); + + out.append(generateCompositeDisplay( + tokens.get(0).applicableTypeName(), tokens.subList(1, tokens.size() - 1))); + + fileOut.append(generateFileHeader(ir.namespaces())); + fileOut.append(out); + } + } + + private CharSequence generateChoices(final String bitsetClassName, final List tokens) + { + final StringBuilder sb = new StringBuilder(); + + tokens + .stream() + .filter((token) -> token.signal() == Signal.CHOICE) + .forEach((token) -> + { + final String choiceName = formatPropertyName(token.name()); + final PrimitiveType type = token.encoding().primitiveType(); + final String typeName = goTypeName(type); + final String choiceBitPosition = token.encoding().constValue().toString(); + final CharSequence constantOne = generateLiteral(type, "1"); + + new Formatter(sb).format("\n" + + " func (m *%5$s) %1$sValue(bits %2$s) bool {\n" + + " return (bits & (%4$s << %3$s)) != 0\n" + + " }\n", + choiceName, + typeName, + choiceBitPosition, + constantOne, + bitsetClassName); + + new Formatter(sb).format("\n" + + " func (m *%5$s) Set%1$sValue(bits %2$s, value bool) %2$s {\n" + + " if value {\n" + + " return bits | (%4$s << %3$s)\n" + + " }\n" + + " return bits & ^(%4$s << %3$s)\n" + + " }\n", + choiceName, + typeName, + choiceBitPosition, + constantOne, + bitsetClassName); + + + new Formatter(sb).format("\n" + + "func (m *%1$s) %2$s() bool {\n" + + "%3$s" + + " return m.%2$sValue(%4$s(m.buffer[m.offset:]))\n" + + "}\n", + bitsetClassName, + choiceName, + generateChoiceNotPresentCondition(token.version()), + formatReadBytes(token.encoding().byteOrder(), type)); + + new Formatter(sb).format("\n" + + "func (m *%1$s) Set%2$s(value bool) *%1$s{\n" + + " bits := %7$s(m.buffer[m.offset:])\n" + + " if value {\n" + + " bits = %3$s(%3$s(bits) | (%6$s << %5$s))\n" + + " } else {\n" + + " bits = %3$s(%3$s(bits) & ^(%6$s << %5$s))\n" + + " }\n" + + " %4$s(m.buffer[m.offset:], bits)\n" + + " return m\n" + + "}\n", + bitsetClassName, + choiceName, + typeName, + formatWriteBytes(token.encoding().byteOrder(), type), + choiceBitPosition, + constantOne, + formatReadBytes(token.encoding().byteOrder(), type)); + }); + + return sb; + } + + private CharSequence generateEnumValues( + final List tokens, + final String enumName, + final Token encodingToken) + { + final StringBuilder sb = new StringBuilder(); + final Encoding encoding = encodingToken.encoding(); + + sb.append(" const (\n"); + + for (final Token token : tokens) + { + final CharSequence constVal = generateLiteral( + token.encoding().primitiveType(), token.encoding().constValue().toString()); + sb.append(" ").append(enumName).append("_").append(token.name()).append(" ").append(enumName) + .append(" = ").append(enumName).append("(").append(constVal).append(")\n"); + } + + final CharSequence nullLiteral = generateLiteral( + encoding.primitiveType(), encoding.applicableNullValue().toString()); + if (shouldDecodeUnknownEnumValues) + { + sb.append(" ").append(enumName).append("_").append("UNKNOWN") + .append(" ").append(enumName).append(" = ").append(enumName) + .append("(").append(nullLiteral).append(")\n"); + } + + sb.append(" ").append(enumName).append("_").append("NULL_VALUE") + .append(" ").append(enumName) + .append(" = ").append(enumName).append("(") + .append(nullLiteral).append(")\n"); + sb.append("\n )\n\n"); + + return sb; + } + + + private CharSequence generateEnumLookupMethod(final List tokens, final Token encodingToken) + { + final String enumName = formatClassName(encodingToken.applicableTypeName()); + final StringBuilder sb = new StringBuilder(); + final String goTypeName = goTypeName(encodingToken.encoding().primitiveType()); + + addInclude("errors"); + new Formatter(sb).format( + " var %1$sLookupErr = errors.New(\"unknown value for enum %1$s [E103]\")\n" + + " func Lookup%1$s(value %2$s) (%1$s, error) {\n" + + " switch value {\n", + enumName, + goTypeName); + + for (final Token token : tokens) + { + final CharSequence constVal = generateLiteral( + token.encoding().primitiveType(), token.encoding().constValue().toString()); + + sb.append(" case ").append(constVal) + .append(": return ").append(enumName).append("_") + .append(token.name()).append(", nil\n"); + } + + final CharSequence nullVal = generateLiteral( + encodingToken.encoding().primitiveType(), encodingToken.encoding().applicableNullValue().toString()); + + sb.append(" case ").append(nullVal).append(": return ") + .append(enumName).append("_").append("NULL_VALUE, nil\n") + .append(" }\n\n"); + + if (shouldDecodeUnknownEnumValues) + { + + sb.append(" return ").append(enumName).append("_").append("UNKNOWN").append(", nil\n}\n"); + } + else + { + new Formatter(sb).format(" return 0, %1$sLookupErr\n}\n", + enumName); + } + + return sb; + } + + + private CharSequence generateFieldNotPresentCondition( + final int sinceVersion, final Encoding encoding, final String indent) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + indent + " if m.actingVersion < %1$d {\n" + + indent + " return %2$s\n" + + indent + " }\n\n", + sinceVersion, + generateLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString())); + } + + + private String namespacesToPackageName(final CharSequence[] namespaces) + { + return String.join("_", namespaces).toLowerCase().replace('.', '_').replace(' ', '_').replace('-', '_'); + } + + private CharSequence generateFileHeader(final CharSequence[] namespaces) + { + final StringBuilder sb = new StringBuilder(); + + sb.append("/* Generated SBE (Simple Binary Encoding) message codec */\n"); + + + sb.append(String.format( + "// Code generated by SBE. DO NOT EDIT.\n\n" + + + "package %1$s\n\n" + + + "import (\n" + + "%2$s\n" + + ")\n\n", + namespacesToPackageName(namespaces), + formatIncludes(includes))); + + return sb; + } + + private CharSequence generateEnumFileHeader(final CharSequence[] namespaces) + { + final StringBuilder sb = new StringBuilder(); + + sb.append("/* Generated SBE (Simple Binary Encoding) message codec */\n"); + + sb.append(String.format( + "// Code generated by SBE. DO NOT EDIT.\n\n" + + + "package %1$s\n\n" + + + "import (\n" + + "%2$s\n" + + ")\n\n", + namespacesToPackageName(namespaces), + formatIncludes(includes))); + + return sb; + } + + private CharSequence generateCompositePropertyElements( + final String containingClassName, final List tokens, final String indent) + { + final StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < tokens.size(); ) + { + final Token fieldToken = tokens.get(i); + final String propertyName = formatPropertyName(fieldToken.name()); + + generateFieldMetaAttributeMethod(sb, fieldToken, indent, containingClassName); + generateFieldCommonMethods(indent, sb, fieldToken, fieldToken, propertyName, containingClassName); + + switch (fieldToken.signal()) + { + case ENCODING: + generatePrimitiveProperty(sb, containingClassName, propertyName, fieldToken, fieldToken, indent); + break; + + case BEGIN_ENUM: + generateEnumProperty(sb, containingClassName, fieldToken, propertyName, fieldToken, indent); + break; + + case BEGIN_SET: + generateBitsetProperty(sb, propertyName, fieldToken, indent, containingClassName); + break; + + case BEGIN_COMPOSITE: + generateCompositeProperty(sb, propertyName, fieldToken, indent, containingClassName); + break; + + default: + break; + } + + i += tokens.get(i).componentTokenCount(); + } + + return sb; + } + + private void generatePrimitiveProperty( + final StringBuilder sb, + final String containingClassName, + final String propertyName, + final Token propertyToken, + final Token encodingToken, + final String indent) + { + generatePrimitiveFieldMetaData(sb, propertyName, encodingToken, indent, containingClassName); + + if (encodingToken.isConstantEncoding()) + { + generateConstPropertyMethods(sb, containingClassName, propertyName, encodingToken, indent); + } + else + { + generatePrimitivePropertyMethods( + sb, containingClassName, propertyName, propertyToken, encodingToken, indent); + } + } + + private void generatePrimitivePropertyMethods( + final StringBuilder sb, + final String containingClassName, + final String propertyName, + final Token propertyToken, + final Token encodingToken, + final String indent) + { + final int arrayLength = encodingToken.arrayLength(); + if (arrayLength == 1) + { + generateSingleValueProperty(sb, containingClassName, propertyName, propertyToken, encodingToken, indent); + } + else if (arrayLength > 1) + { + generateArrayProperty(sb, containingClassName, propertyName, propertyToken, encodingToken, indent); + } + } + + private void generatePrimitiveFieldMetaData( + final StringBuilder sb, + final String propertyName, + final Token token, + final String indent, + final String className) + { + final Encoding encoding = token.encoding(); + final PrimitiveType primitiveType = encoding.primitiveType(); + final String goTypeName = goTypeName(primitiveType); + final CharSequence nullValueString = generateNullValueLiteral(primitiveType, encoding); + + new Formatter(sb).format("\n" + + indent + " func (m *%4$s) %1$sNullValue() %2$s {\n" + + indent + " return %3$s\n" + + indent + " }\n", + propertyName, + goTypeName, + nullValueString, + className); + + new Formatter(sb).format("\n" + + indent + " func (m *%4$s) %1$sMinValue() %2$s {\n" + + indent + " return %3$s\n" + + indent + " }\n", + propertyName, + goTypeName, + generateLiteral(primitiveType, token.encoding().applicableMinValue().toString()), + className); + + new Formatter(sb).format("\n" + + indent + " func (m *%4$s) %1$sMaxValue() %2$s {\n" + + indent + " return %3$s\n" + + indent + " }\n", + propertyName, + goTypeName, + generateLiteral(primitiveType, token.encoding().applicableMaxValue().toString()), + className); + + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %1$sEncodingLength() int {\n" + + indent + " return %2$d\n" + + indent + " }\n", + propertyName, + token.encoding().primitiveType().size() * token.arrayLength(), + className); + } + + private CharSequence generateLoadValue( + final PrimitiveType primitiveType, + final String offsetStr, + final ByteOrder byteOrder, + final String indent) + { + final String goTypeName = goTypeName(primitiveType); + final StringBuilder sb = new StringBuilder(); + + new Formatter(sb).format( + indent + " return %3$s(m.buffer[(m.offset + %1$s):])\n", + offsetStr, + goTypeName, + formatReadBytes(byteOrder, primitiveType)); + + return sb; + } + + private CharSequence generateStoreValue( + final PrimitiveType primitiveType, + final String valueSuffix, + final String offsetStr, + final ByteOrder byteOrder, + final String indent) + { + final String goTypeName = goTypeName(primitiveType); + final String goMarshalType = golangMarshalType(primitiveType); + final StringBuilder sb = new StringBuilder(); + + new Formatter(sb).format( + indent + " %3$s(m.buffer[(m.offset + %4$s):], value%2$s)\n", + goTypeName, + valueSuffix, + formatWriteBytes(byteOrder, primitiveType), + offsetStr, + goMarshalType); + + return sb; + } + + private void generateSingleValueProperty( + final StringBuilder sb, + final String containingClassName, + final String propertyName, + final Token propertyToken, + final Token encodingToken, + final String indent) + { + final PrimitiveType primitiveType = encodingToken.encoding().primitiveType(); + final String goTypeName = goTypeName(primitiveType); + final int offset = encodingToken.offset(); + + new Formatter(sb).format("\n" + + indent + " func (m *%1$s) %2$s() %3$s {\n" + + "%4$s" + + "%5$s" + + indent + " }\n", + containingClassName, + propertyName, + goTypeName, + generateFieldNotPresentCondition(propertyToken.version(), encodingToken.encoding(), indent), + generateLoadValue(primitiveType, Integer.toString(offset), encodingToken.encoding().byteOrder(), indent)); + + final CharSequence storeValue = generateStoreValue( + primitiveType, "", Integer.toString(offset), encodingToken.encoding().byteOrder(), indent); + + new Formatter(sb).format("\n" + + indent + " func (m *%1$s) Set%2$s(value %3$s) *%1$s {\n" + + "%4$s" + + indent + " return m\n" + + indent + " }\n", + containingClassName, + propertyName, + goTypeName, + storeValue); + } + + private void generateArrayProperty( + final StringBuilder sb, + final String containingClassName, + final String propertyName, + final Token propertyToken, + final Token encodingToken, + final String indent) + { + final PrimitiveType primitiveType = encodingToken.encoding().primitiveType(); + final String goTypeName = goTypeName(primitiveType); + final int offset = encodingToken.offset(); + + final int arrayLength = encodingToken.arrayLength(); + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %1$sLength() int {\n" + + indent + " return %2$d\n" + + indent + " }\n", + propertyName, + arrayLength, + formatClassName(containingClassName)); + + new Formatter(sb).format("\n" + + indent + "func (m *%6$s) %2$s() []byte {\n" + + "%4$s" + + indent + " return m.buffer[m.offset+%5$d:m.offset+%5$d+%3$d]\n" + + indent + "}\n", + goTypeName, + toUpperFirstChar(propertyName), + arrayLength, + generateArrayFieldNotPresentCondition(propertyToken.version(), indent), + offset, + formatClassName(containingClassName)); + + final CharSequence loadValue = generateLoadValue( + primitiveType, + String.format("%d + (index * %d)", offset, primitiveType.size()), + encodingToken.encoding().byteOrder(), + indent); + + new Formatter(sb).format("\n" + + indent + " func (m *%6$s) %2$sIndex(index uint64) %1$s {\n" + + indent + " if (index >= %3$d) {\n" + + indent + " panic(\"index out of range for %2$s [E104]\")\n" + + indent + " }\n\n" + + "%4$s" + + "%5$s" + + indent + " }\n", + goTypeName, + propertyName, + arrayLength, + generateFieldNotPresentCondition(propertyToken.version(), encodingToken.encoding(), indent), + loadValue, + formatClassName(containingClassName)); + + final CharSequence storeValue = generateStoreValue( + primitiveType, + "", + String.format("%d + (index * %d)", offset, primitiveType.size()), + encodingToken.encoding().byteOrder(), + indent); + + new Formatter(sb).format("\n" + + indent + " func (m *%6$s) Set%2$sIndex(index uint64, value %3$s) *%6$s {\n" + + indent + " if (index >= %4$d) {\n" + + indent + " panic(\"index out of range for %2$s [E105]\")\n" + + indent + " }\n\n" + + + "%5$s" + + indent + " return m\n" + + indent + " }\n", + containingClassName, + propertyName, + goTypeName, + arrayLength, + storeValue, + formatClassName(containingClassName)); + + + addInclude("fmt"); + new Formatter(sb).format("\n" + + indent + "func (m *%6$s) Get%2$s(dst []byte) (uint64, error) {\n" + + indent + " if len(dst) > %3$d {\n" + + indent + " return 0, fmt.Errorf(\"length too large for get%2$s [E106]\")\n" + + indent + " }\n\n" + + + "%4$s" + + indent + " copy(dst, m.buffer[m.offset+%5$d:])\n" + + indent + " return %3$d, nil\n" + + indent + "}\n", + goTypeName, + toUpperFirstChar(propertyName), + arrayLength, + generateArrayFieldNotPresentConditionWithErr(propertyToken.version(), indent), + offset, + formatClassName(containingClassName)); + + new Formatter(sb).format("\n" + + indent + "func (m *%1$s) Put%2$s(src []byte) *%1$s {\n" + + indent + " copy(m.buffer[(m.offset+%3$d):], src)\n" + + indent + " return m\n" + + indent + "}\n", + formatClassName(containingClassName), + formatPropertyName(propertyName), + offset); + + if (arrayLength > 1 && arrayLength <= 4) + { + sb.append("\n").append(indent).append("func (m *") + .append(formatClassName(containingClassName)).append(") Put") + .append(formatPropertyName(propertyName)) + .append("Values (\n"); + + for (int i = 0; i < arrayLength; i++) + { + sb.append(indent).append(" value").append(i) + .append(" ") + .append(goTypeName); + + if (i < (arrayLength - 1)) + { + sb.append(",\n"); + } + } + + sb.append(")") + .append(" *") + .append(formatClassName(containingClassName)) + .append(" {\n"); + + for (int i = 0; i < arrayLength; i++) + { + sb.append(generateStoreValue( + primitiveType, + Integer.toString(i), + Integer.toString(offset + (i * primitiveType.size())), + encodingToken.encoding().byteOrder(), + indent)); + } + + sb.append("\n"); + sb.append(indent).append(" return m\n"); + sb.append(indent).append("}\n"); + } + + + if (encodingToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + new Formatter(sb).format("\n" + + indent + " func (m *%4$s) Get%1$sAsString() string {\n" + + indent + " offset := m.offset + %2$d\n" + + indent + " length := uint64(0)\n\n" + + indent + " for length < %3$d && m.buffer[offset + length] != '\\x00' {\n" + + indent + " length++\n" + + indent + " }\n" + + indent + " return string(m.buffer[offset:offset + length])\n" + + indent + " }\n", + toUpperFirstChar(propertyName), + offset, + arrayLength, + formatClassName(containingClassName)); + + generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName, containingClassName); + + new Formatter(sb).format("\n" + + indent + "func (m *%1$s) Set%2$s(src string) *%1$s {\n" + + indent + " copy(m.buffer[(m.offset+%3$d):], []byte(src))\n" + + indent + " return m\n" + + indent + "}\n", + formatClassName(containingClassName), + formatPropertyName(propertyName), + offset); + } + } + + private void generateJsonEscapedStringGetter( + final StringBuilder sb, + final Token token, + final String indent, + final String propertyName, + final String className) + { + addInclude("strings"); + addInclude("fmt"); + new Formatter(sb).format("\n" + + indent + "func (m *%3$s) Get%1$sAsJsonEscapedString() string {\n" + + "%2$s" + + indent + " oss := strings.Builder{}\n" + + indent + " s := m.Get%1$sAsString()\n\n" + + indent + " for _, c := range s {\n" + + indent + " switch c {\n" + + indent + " case '\"': oss.WriteString(\"\\\\\\\"\")\n" + + indent + " case '\\\\': oss.WriteString(\"\\\\\\\\\")\n" + + indent + " case '\\b': oss.WriteString(\"\\\\b\")\n" + + indent + " case '\\f': oss.WriteString(\"\\\\f\")\n" + + indent + " case '\\n': oss.WriteString(\"\\\\n\")\n" + + indent + " case '\\r': oss.WriteString(\"\\\\r\")\n" + + indent + " case '\\t': oss.WriteString(\"\\\\t\")\n\n" + + indent + " default:\n" + + indent + " if '\\x00' <= c && c <= '\\x1f' {\n" + + indent + " fmt.Fprintf(&oss, \"%%x\", c)\n" + + indent + " } else {\n" + + indent + " oss.WriteString(string(c))\n" + + indent + " }\n" + + indent + " }\n" + + indent + " }\n\n" + + indent + " return oss.String()\n" + + indent + "}\n", + toUpperFirstChar(propertyName), + generateStringNotPresentCondition(token.version(), indent), + className); + } + + private void generateConstPropertyMethods( + final StringBuilder sb, + final String className, + final String propertyName, + final Token token, + final String indent) + { + final String goTypeName = goTypeName(token.encoding().primitiveType()); + + if (token.encoding().primitiveType() != PrimitiveType.CHAR) + { + new Formatter(sb).format("\n" + + indent + " func (m *%4$s) %2$s() %1$s {\n" + + indent + " return %3$s\n" + + indent + " }\n", + goTypeName, + propertyName, + generateLiteral(token.encoding().primitiveType(), token.encoding().constValue().toString()), + className); + + return; + } + + final byte[] constantValue = token.encoding().constValue().byteArrayValue(token.encoding().primitiveType()); + final StringBuilder values = new StringBuilder(); + for (final byte b : constantValue) + { + values.append(b).append(", "); + } + + if (values.length() > 0) + { + values.setLength(values.length() - 2); + } + + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %1$sLength() uint64 {\n" + + indent + " return %2$d\n" + + indent + " }\n", + propertyName, + constantValue.length, + className); + + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %1$s() string {\n" + + indent + " %1$sValues := []uint8{ %2$s, 0 }\n\n" + + indent + " return string(%1$sValues)\n" + + indent + " }\n", + propertyName, + values, + className); + + sb.append(String.format("\n" + + indent + " func (m *%4$s) %2$sIndex(index uint64) %1$s {\n" + + indent + " %2$sValues := []uint8{ %3$s, 0 }\n\n" + + indent + " return byte(%2$sValues[index])\n" + + indent + " }\n", + goTypeName, + propertyName, + values, + className)); + + new Formatter(sb).format("\n" + + indent + " func (m *%4$s) Get%1$s(dst []byte, length uint64) uint64 {\n" + + indent + " %2$sValues := []uint8{ %3$s }\n" + + indent + " bytesToCopy := uint64(len(%2$sValues))\n" + + indent + " if length < uint64(len(%2$sValues)) {\n" + + indent + " bytesToCopy = length\n" + + indent + " }\n" + + indent + " copy(dst, %2$sValues[:bytesToCopy])\n" + + indent + " return bytesToCopy\n" + + indent + " }\n", + toUpperFirstChar(propertyName), + propertyName, + values, + className); + + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) Get%1$sAsString() string {\n" + + indent + " %1$sValues := []uint8{ %2$s, 0 }\n\n" + + indent + " return string(%1$sValues)\n" + + indent + " }\n", + propertyName, + values, + className); + + generateJsonEscapedStringGetter(sb, token, indent, propertyName, className); + } + + private CharSequence generateFixedFlyweightCode( + final String className, + final int size, + final List fields) + { + final String schemaIdType = goTypeName(ir.headerStructure().schemaIdType()); + final String schemaVersionType = goTypeName(ir.headerStructure().schemaVersionType()); + + final StringBuilder sb = new StringBuilder(); + for (int i = 1, fieldSize = fields.size(); i < fieldSize; ) + { + final Token signalToken = fields.get(i); + final String propertyName = formatPropertyName(signalToken.name()); + final String typeName = formatClassName(signalToken.applicableTypeName()); + + switch (signalToken.signal()) + { + case BEGIN_SET: + case BEGIN_COMPOSITE: + new Formatter(sb).format(" _%1$s %2$s\n", + propertyName, + typeName); + break; + + default: + break; + } + + i += fields.get(i).componentTokenCount(); + } + + String sizeValue = String.format("%1$d", size); + if (size == -1) + { + addInclude("math"); + sizeValue = "math.MaxUint64"; + } + + return String.format( + " buffer []byte\n" + + " bufferLength uint64\n" + + " offset uint64\n" + + " actingVersion uint64\n" + + "%7$s\n" + + "}\n\n" + + + " const (\n" + + " %1$sEncodedLength uint64 = %2$s\n" + + " %1$sSbeSchemaID %3$s = %4$s\n" + + " %1$sSbeSchemaVersion %5$s = %6$s\n" + + " )\n\n" + + + " func (m *%1$s) Wrap(\n" + + " buffer []byte,\n" + + " offset uint64,\n" + + " actingVersion uint64,\n" + + " bufferLength uint64) {\n" + + " m.buffer = buffer\n" + + " m.bufferLength = bufferLength\n" + + " m.offset = offset\n" + + " m.actingVersion = actingVersion\n" + + " if !SbeNoBoundsCheck && ((m.offset + %2$s) > m.bufferLength) {\n" + + " panic(\"buffer too short for flyweight [E107]\")\n" + + " }\n" + + " }\n\n" + + + " func (m *%1$s) EncodedLength() uint64 {\n" + + " return %2$s\n" + + " }\n\n" + + + " func (m *%1$s) Offset() uint64 {\n" + + " return m.offset\n" + + " }\n\n" + + + " func (m *%1$s) Buffer() []byte {\n" + + " return m.buffer\n" + + " }\n\n" + + + " func (m *%1$s) BufferLength() uint64 {\n" + + " return m.bufferLength\n" + + " }\n\n" + + + " func (m *%1$s) ActingVersion() uint64 {\n" + + " return m.actingVersion\n" + + " }\n\n" + + + " func (m *%1$s) SbeSchemaId() %3$s {\n" + + " return %4$s\n" + + " }\n\n" + + + " func (m *%1$s) SbeSchemaVersion() %5$s {\n" + + " return %6$s\n" + + " }\n", + + className, + sizeValue, + schemaIdType, + generateLiteral(ir.headerStructure().schemaIdType(), Integer.toString(ir.id())), + schemaVersionType, + generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), + sb); + } + + private CharSequence generateMessageFlyweightCode( + final String className, + final Token token, + final List fields, + final List groups) + { + final StringBuilder sb = new StringBuilder(); + final String blockLengthType = goTypeName(ir.headerStructure().blockLengthType()); + final String templateIdType = goTypeName(ir.headerStructure().templateIdType()); + final String schemaIdType = goTypeName(ir.headerStructure().schemaIdType()); + final String schemaVersionType = goTypeName(ir.headerStructure().schemaVersionType()); + final String semanticType = token.encoding().semanticType() == null ? "" : token.encoding().semanticType(); + final String headerType = ir.headerStructure().tokens().get(0).name(); + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); + + sb.append(" buffer []byte\n" + + " bufferLength uint64\n" + + " offset uint64\n" + + " position uint64\n" + + " actingBlockLength uint64\n" + + " actingVersion uint64\n"); + + for (int i = 0, size = fields.size(); i < size; i++) + { + final Token signalToken = fields.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = fields.get(i + 1); + final String propertyName = formatPropertyName(signalToken.name()); + final String typeName = formatClassName(encodingToken.applicableTypeName()); + + switch (encodingToken.signal()) + { + case BEGIN_SET: + case BEGIN_COMPOSITE: + new Formatter(sb).format(" _%1$s %2$s\n", + propertyName, + typeName); + break; + + default: + break; + } + } + } + + for (int i = 0, size = groups.size(); i < size; ) + { + final Token groupToken = groups.get(i); + if (groupToken.signal() == Signal.BEGIN_GROUP) + { + final String propertyName = formatPropertyName(groupToken.name()); + final String groupName = className + formatClassName(groupToken.name()); + + new Formatter(sb).format(" _%1$s %2$s\n", + propertyName, + groupName); + + i += groupToken.componentTokenCount(); + } + } + + sb.append("}\n\n"); + + sb.append(String.format( + " func (m *%10$s) sbePositionPtr() *uint64 {\n" + + " return &m.position\n" + + " }\n\n" + + + " const (\n" + + " %10$sSbeBlockLength %1$s = %2$s\n" + + " %10$sSbeTemplateID %3$s = %4$s\n" + + " %10$sSbeSchemaID %5$s = %6$s\n" + + " %10$sSbeSchemaVersion %7$s = %8$s\n" + + " %10$sSbeSemanticVersion string = \"%13$s\"\n" + + " )\n\n" + + + " func (m *%10$s) SbeBlockLength() %1$s {\n" + + " return %2$s\n" + + " }\n\n" + + + " func (m *%10$s) SbeBlockAndHeaderLength() uint64 {\n" + + " return MessageHeaderEncodedLength + uint64(m.SbeBlockLength())\n" + + " }\n\n" + + + " func (m *%10$s) SbeTemplateId() %3$s {\n" + + " return %4$s\n" + + " }\n\n" + + + " func (m *%10$s) SbeSchemaId() %5$s {\n" + + " return %6$s\n" + + " }\n\n" + + + " func (m *%10$s) SbeSchemaVersion() %7$s {\n" + + " return %8$s\n" + + " }\n\n" + + + " func (m *%10$s) SbeSemanticVersion() string {\n" + + " return \"%13$s\"\n" + + " }\n\n" + + + " func (m *%10$s) SbeSemanticType() string {\n" + + " return \"%9$s\"\n" + + " }\n\n" + + + " func (m *%10$s) Offset() uint64 {\n" + + " return m.offset\n" + + " }\n\n" + + + " func (m *%10$s) Wrap(\n" + + " buffer []byte,\n" + + " offset uint64,\n" + + " bufferLength uint64,\n" + + " actingBlockLength uint64,\n" + + " actingVersion uint64) *%10$s {\n" + + " m.buffer = buffer\n" + + " m.bufferLength = bufferLength\n" + + " m.offset = offset\n" + + " m.position = m.SbeCheckPosition(offset + actingBlockLength)\n" + + " m.actingBlockLength = actingBlockLength\n" + + " m.actingVersion = actingVersion\n" + + " return m\n" + + " }\n\n" + + + " func (m *%10$s) WrapForEncode(buffer []byte, offset uint64, bufferLength uint64) *%10$s {\n" + + " return m.Wrap(buffer, offset, bufferLength,\n" + + " uint64(m.SbeBlockLength()), uint64(m.SbeSchemaVersion()))\n" + + " }\n\n" + + + " func (m *%10$s) WrapAndApplyHeader(buffer []byte, offset uint64, bufferLength uint64) *%10$s {\n" + + " var hdr MessageHeader\n" + + " hdr.Wrap(buffer, offset, uint64(m.SbeSchemaVersion()), bufferLength)\n\n" + + + " hdr.SetBlockLength(m.SbeBlockLength()).\n" + + " SetTemplateId(m.SbeTemplateId()).\n" + + " SetSchemaId(m.SbeSchemaId()).\n" + + " SetVersion(m.SbeSchemaVersion())\n\n" + + + " return m.Wrap(\n" + + " buffer,\n" + + " offset + hdr.EncodedLength(),\n" + + " bufferLength,\n" + + " uint64(m.SbeBlockLength()),\n" + + " uint64(m.SbeSchemaVersion()))\n" + + " }\n\n" + + + " func (m *%10$s) WrapForDecode(\n" + + " buffer []byte,\n" + + " offset uint64,\n" + + " actingBlockLength uint64,\n" + + " actingVersion uint64,\n" + + " bufferLength uint64) *%10$s {\n" + + " return m.Wrap(\n" + + " buffer,\n" + + " offset,\n" + + " bufferLength,\n" + + " actingBlockLength,\n" + + " actingVersion)\n" + + " }\n\n" + + + " func (m *%10$s) sbeRewind() *%10$s {\n" + + " return m.WrapForDecode(" + + "m.buffer, m.offset, m.actingBlockLength, m.actingVersion, m.bufferLength)\n" + + " }\n\n" + + + " func (m *%10$s) SbePosition() uint64 {\n" + + " return m.position\n" + + " }\n\n" + + + " func (m *%10$s) SbeCheckPosition(position uint64) uint64 {\n" + + " if !SbeNoBoundsCheck && (position > m.bufferLength) {\n" + + " panic(\"buffer too short [E100]\")\n" + + " }\n" + + " return position\n" + + " }\n\n" + + + " func (m *%10$s) SetSbePosition(position uint64) {\n" + + " m.position = m.SbeCheckPosition(position)\n" + + " }\n\n" + + + " func (m *%10$s) EncodedLength() uint64 {\n" + + " return m.SbePosition() - m.offset\n" + + " }\n\n" + + + " func (m *%10$s) DecodeLength() uint64 {\n" + + " var skipper %10$s\n" + + " skipper.WrapForDecode(m.buffer, m.offset, uint64(m.SbeBlockLength()),\n" + + " uint64(m.ActingVersion()), m.bufferLength)\n" + + " skipper.Skip()\n" + + " return skipper.EncodedLength()\n" + + " }\n\n" + + + " func (m *%10$s) Buffer() []byte {\n" + + " return m.buffer\n" + + " }\n\n" + + + " func (m *%10$s) BufferLength() uint64 {\n" + + " return m.bufferLength\n" + + " }\n\n" + + + " func (m *%10$s) ActingVersion() uint64 {\n" + + " return m.actingVersion\n" + + " }\n", + blockLengthType, + generateLiteral(ir.headerStructure().blockLengthType(), Integer.toString(token.encodedLength())), + templateIdType, + generateLiteral(ir.headerStructure().templateIdType(), Integer.toString(token.id())), + schemaIdType, + generateLiteral(ir.headerStructure().schemaIdType(), Integer.toString(ir.id())), + schemaVersionType, + generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), + semanticType, + className, + generateConstructorsAndOperators(className), + formatClassName(headerType), + semanticVersion)); + return sb.toString(); + } + + private void generateFields( + final StringBuilder sb, + final String containingClassName, + final List tokens, + final String indent) + { + for (int i = 0, size = tokens.size(); i < size; i++) + { + final Token signalToken = tokens.get(i); + if (signalToken.signal() == Signal.BEGIN_FIELD) + { + final Token encodingToken = tokens.get(i + 1); + final String propertyName = formatPropertyName(signalToken.name()); + + generateFieldMetaAttributeMethod(sb, signalToken, indent, containingClassName); + generateFieldCommonMethods(indent, sb, signalToken, encodingToken, propertyName, containingClassName); + + switch (encodingToken.signal()) + { + case ENCODING: + generatePrimitiveProperty( + sb, containingClassName, propertyName, signalToken, encodingToken, indent); + break; + + case BEGIN_ENUM: + generateEnumProperty(sb, containingClassName, signalToken, propertyName, encodingToken, indent); + break; + + case BEGIN_SET: + generateBitsetProperty(sb, propertyName, encodingToken, indent, containingClassName); + break; + + case BEGIN_COMPOSITE: + generateCompositeProperty(sb, propertyName, encodingToken, indent, containingClassName); + break; + + default: + break; + } + } + } + } + + private void generateFieldCommonMethods( + final String indent, + final StringBuilder sb, + final Token fieldToken, + final Token encodingToken, + final String propertyName, + final String className) + { + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %1$sId() int {\n" + + indent + " return %2$d\n" + + indent + " }\n", + propertyName, + fieldToken.id(), + className); + + final int version = fieldToken.version(); + final String versionCheck = 0 == version ? + " return true\n" : " return m.actingVersion >= m.%1$sSinceVersion()\n"; + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %1$sSinceVersion() uint64 {\n" + + indent + " return %2$d\n" + + indent + " }\n\n" + + + indent + " func (m *%3$s) %1$sInActingVersion() bool {\n" + + indent + versionCheck + + indent + " }\n", + propertyName, + version, + className); + + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %1$sEncodingOffset() uint {\n" + + indent + " return %2$d\n" + + indent + " }\n", + propertyName, + encodingToken.offset(), + className); + } + + private void generateEnumProperty( + final StringBuilder sb, + final String containingClassName, + final Token fieldToken, + final String propertyName, + final Token encodingToken, + final String indent) + { + final String enumName = formatClassName(encodingToken.applicableTypeName()); + final PrimitiveType primitiveType = encodingToken.encoding().primitiveType(); + final String typeName = goTypeName(primitiveType); + final int offset = encodingToken.offset(); + + new Formatter(sb).format("\n" + + indent + " func (m *%1$s) %2$sEncodingLength() int {\n" + + indent + " return %3$d\n" + + indent + " }\n", + containingClassName, + propertyName, + fieldToken.encodedLength()); + + if (fieldToken.isConstantEncoding()) + { + final String constValue = fieldToken.encoding().constValue().toString(); + + new Formatter(sb).format("\n" + + indent + " func (m *%1$s) %2$sConstValue() %4$s {\n" + + indent + " return %4$s_%3$s\n" + + indent + " }\n", + containingClassName, + propertyName, + constValue.substring(constValue.indexOf(".") + 1), + enumName); + + new Formatter(sb).format("\n" + + indent + " func (m *%1$s) %2$s() %5$s {\n" + + "%3$s" + + indent + " return %5$s_%4$s\n" + + indent + " }\n", + containingClassName, + propertyName, + generateEnumFieldNotPresentCondition(fieldToken.version(), enumName, indent), + constValue.substring(constValue.indexOf(".") + 1), + enumName); + + new Formatter(sb).format("\n" + + indent + " func (m *%3$s) %2$sRaw() %1$s {\n" + + indent + " return %1$s(%5$s_%4$s)\n" + + indent + " }\n", + typeName, + propertyName, + containingClassName, + constValue.substring(constValue.indexOf(".") + 1), + enumName); + + } + else + { + final String offsetStr = Integer.toString(offset); + new Formatter(sb).format("\n" + + indent + " func (m *%5$s) %2$sRaw() %1$s {\n" + + "%3$s" + + "%4$s" + + indent + " }\n", + typeName, + propertyName, + generateFieldNotPresentCondition(fieldToken.version(), encodingToken.encoding(), indent), + generateLoadValue(primitiveType, offsetStr, encodingToken.encoding().byteOrder(), indent), + containingClassName); + + new Formatter(sb).format("\n" + + indent + " func (m *%1$s) %2$s() %7$s {\n" + + "%3$s" + + indent + " return %7$s(%4$s(m.buffer[(m.offset + %6$d):]))\n" + + indent + " }\n", + containingClassName, + propertyName, + generateEnumFieldNotPresentCondition(fieldToken.version(), enumName, indent), + formatReadBytes(encodingToken.encoding().byteOrder(), primitiveType), + typeName, + offset, + enumName); + + new Formatter(sb).format("\n" + + indent + " func (m *%1$s) Set%2$s(value %3$s) *%1$s {\n" + + indent + " val := %4$s(value)\n" + + indent + " %6$s(m.buffer[(m.offset + %5$d):], val)\n" + + indent + " return m\n" + + indent + " }\n", + formatClassName(containingClassName), + propertyName, + enumName, + typeName, + offset, + formatWriteBytes(encodingToken.encoding().byteOrder(), primitiveType)); + } + } + + private CharSequence generateNullValueLiteral( + final PrimitiveType primitiveType, + final Encoding encoding) + { + // Go does not handle minimum integer values properly + // So null values get special handling + if (null == encoding.nullValue()) + { + switch (primitiveType) + { + case CHAR: + return "SbeNullValueByte()"; + case FLOAT: + return "SbeNullValueFloat()"; + case DOUBLE: + return "SbeNullValueDouble()"; + case INT8: + return "SbeNullValueInt8()"; + case INT16: + return "SbeNullValueInt16()"; + case INT32: + return "SbeNullValueInt32()"; + case INT64: + return "SbeNullValueInt64()"; + case UINT8: + return "SbeNullValueUint8()"; + case UINT16: + return "SbeNullValueUint16()"; + case UINT32: + return "SbeNullValueUint32()"; + case UINT64: + return "SbeNullValueUint64()"; + } + } + + return generateLiteral(primitiveType, encoding.applicableNullValue().toString()); + } + + + private CharSequence generateLiteral(final PrimitiveType type, final String value) + { + String literal = ""; + + switch (type) + { + case CHAR: + literal = "byte(" + value + ")"; + break; + case UINT8: + literal = "uint8(" + value + ")"; + break; + case UINT16: + literal = "uint16(" + value + ")"; + break; + case INT8: + literal = "int8(" + value + ")"; + break; + case INT16: + literal = "int16(" + value + ")"; + break; + + case UINT32: + literal = "uint32(0x" + Integer.toHexString((int)Long.parseLong(value)) + ")"; + break; + + case INT32: + final long intValue = Long.parseLong(value); + if (intValue == Integer.MIN_VALUE) + { + literal = "math.MinInt32"; + addInclude("math"); + } + else + { + literal = "int32(" + value + ")"; + } + break; + + case FLOAT: + if (value.endsWith("NaN")) + { + literal = "math.NaN()"; + } + else + { + literal = value; + } + break; + + case INT64: + final long longValue = Long.parseLong(value); + if (longValue == Long.MIN_VALUE) + { + literal = "math.MinInt64"; + addInclude("math"); + } + else + { + literal = "int64(" + value + ")"; + } + break; + + case UINT64: + literal = "uint64(0x" + Long.toHexString(Long.parseLong(value)) + ")"; + break; + + case DOUBLE: + if (value.endsWith("NaN")) + { + literal = "math.NaN()"; + addInclude("math"); + } + else + { + literal = value; + } + break; + } + + return literal; + } + + private void addInclude(final String name) + { + includes.add(name); + } + + + private void generateDisplay( + final StringBuilder sb, + final String containingClassName, + final String name, + final List fields, + final List groups, + final List varData) + { + addInclude("strings"); + addInclude("fmt"); + new Formatter(sb).format("\n" + + "func (writer *%1$s) String() string {\n" + + " var builder strings.Builder\n" + + " builder.WriteString(\"{\\\"Name\\\": \\\"%1$s\\\", \")\n" + + " builder.WriteString(fmt.Sprintf(\"\\\"sbeTemplateId\\\": %%d\", writer.SbeTemplateId()))\n" + + " builder.WriteString(\", \")\n\n" + + "%2$s" + + " builder.WriteString(\"}\")\n\n" + + " return builder.String()\n" + + "}\n", + formatClassName(name), + appendDisplay(containingClassName, fields, groups, varData, INDENT)); + } + + + private CharSequence generateGroupDisplay( + final String groupClassName, + final List fields, + final List groups, + final List varData, + final String indent) + { + addInclude("strings"); + return String.format("\n" + + indent + "func (writer *%1$s) String() string {\n" + + indent + " builder := strings.Builder{}\n" + + indent + " builder.WriteString(\"{\")\n" + + "%2$s" + + indent + " builder.WriteString(\"}\")\n\n" + + indent + " return builder.String()\n" + + indent + "}\n", + groupClassName, + appendDisplay(groupClassName, fields, groups, varData, indent + INDENT)); + } + + + private CharSequence generateCompositeDisplay(final String name, final List tokens) + { + addInclude("strings"); + return String.format("\n" + + "func (writer *%1$s) String() string {\n" + + " builder := strings.Builder{}\n" + + " builder.WriteString(\"{\")\n" + + "%2$s" + + " builder.WriteString(\"}\")\n\n" + + " return builder.String()\n" + + "}\n\n", + formatClassName(name), + appendDisplay(formatClassName(name), tokens, new ArrayList<>(), new ArrayList<>(), INDENT)); + } + + + private CharSequence appendDisplay( + final String containingClassName, + final List fields, + final List groups, + final List varData, + final String indent) + { + final StringBuilder sb = new StringBuilder(); + final boolean[] atLeastOne = {false}; + + for (int i = 0, size = fields.size(); i < size; ) + { + final Token fieldToken = fields.get(i); + final Token encodingToken = fields.get(fieldToken.signal() == Signal.BEGIN_FIELD ? i + 1 : i); + + writeTokenDisplay(sb, fieldToken.name(), encodingToken, atLeastOne, indent); + i += fieldToken.componentTokenCount(); + } + + for (int i = 0, size = groups.size(); i < size; i++) + { + final Token groupToken = groups.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + if (atLeastOne[0]) + { + sb.append(indent).append("builder.WriteString(\", \")\n"); + } + atLeastOne[0] = true; + + new Formatter(sb).format( + indent + "{\n" + + indent + " atLeastOne := false\n" + + indent + " builder.WriteString(`\"%3$s\": [`)\n" + + indent + " writer.%2$s().ForEach(\n" + + indent + " func(value *%1$s) {\n" + + indent + " if atLeastOne {\n" + + indent + " builder.WriteString(\", \")\n" + + indent + " }\n" + + indent + " atLeastOne = true\n" + + indent + " builder.WriteString(value.String())\n" + + indent + " })\n" + + indent + " builder.WriteString(\"]\")\n" + + indent + "}\n\n", + containingClassName + formatClassName(groupToken.name()), + formatPropertyName(groupToken.name()), + groupToken.name()); + + i = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); + } + + for (int i = 0, size = varData.size(); i < size; ) + { + final Token varDataToken = varData.get(i); + if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); + } + + if (atLeastOne[0]) + { + sb.append(indent).append("builder.WriteString(\", \")\n"); + } + atLeastOne[0] = true; + + final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); + sb.append(indent).append("builder.WriteString(`\"").append(varDataToken.name()).append("\": `)\n"); + + if (null == characterEncoding) + { + final String skipFunction = "writer.Skip" + toUpperFirstChar(varDataToken.name()) + "()"; + + sb.append(indent).append("builder.WriteString(`\"`)\n") + .append(indent).append(INDENT).append(skipFunction).append("\n") + .append(INDENT).append("builder.WriteString(\" bytes of raw data\")\n"); + } + else + { + final String getAsStringFunction = + "writer.Get" + toUpperFirstChar(varDataToken.name()) + "AsJsonEscapedString()"; + + sb.append(indent).append("builder.WriteString(`\"` + ") + .append(getAsStringFunction).append(" + `\"`);\n\n"); + } + + i += varDataToken.componentTokenCount(); + } + + return sb; + } + + private void writeTokenDisplay( + final StringBuilder sb, + final String fieldTokenName, + final Token typeToken, + final boolean[] atLeastOne, + final String indent) + { + if (typeToken.encodedLength() <= 0 || typeToken.isConstantEncoding()) + { + return; + } + + if (atLeastOne[0]) + { + sb.append(indent).append("builder.WriteString(\", \")\n"); + } + else + { + atLeastOne[0] = true; + } + + sb.append(indent).append("builder.WriteString(`\"").append(fieldTokenName).append("\": `)\n"); + final String fieldName = "writer." + formatPropertyName(fieldTokenName); + + switch (typeToken.signal()) + { + case ENCODING: + if (typeToken.arrayLength() > 1) + { + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + final String getAsStringFunction = + "writer.Get" + toUpperFirstChar(fieldTokenName) + "AsJsonEscapedString()"; + + sb.append(indent).append("builder.WriteString(`\"` +\n").append(indent).append(INDENT) + .append(getAsStringFunction).append(" + `\"`)\n"); + } + else + { + addInclude("fmt"); + sb.append( + indent + "builder.WriteString(\"[\")\n" + + indent + "for i := 0; i < " + fieldName + "Length(); i++ {\n" + + indent + " if i > 0 {\n" + + indent + " builder.WriteString(\",\")\n" + + indent + " }\n" + + indent + " builder.WriteString(fmt.Sprintf(\"%v\", " + fieldName + + "Index(uint64(i))))\n" + + indent + "}\n" + + indent + "builder.WriteString(\"]\")\n"); + } + } + else + { + addInclude("fmt"); + + if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + sb.append(indent).append("builder.WriteString(fmt.Sprintf(`\"%c\"`, ").append(fieldName) + .append("()))\n"); + } + else + { + sb.append(indent).append("builder.WriteString(fmt.Sprintf(`\"%v\"`, ").append(fieldName) + .append("()))\n"); + } + } + break; + + case BEGIN_ENUM: + addInclude("fmt"); + sb.append(indent).append("builder.WriteString(fmt.Sprintf(`\"%v\"`, ").append(fieldName) + .append("()))\n"); + break; + + case BEGIN_SET: + case BEGIN_COMPOSITE: + if (0 == typeToken.version()) + { + sb.append(indent).append("builder.WriteString(").append(fieldName).append("().String())\n"); + } + else + { + new Formatter(sb).format( + indent + "if (%1$sInActingVersion()) {\n" + + indent + " builder.WriteString(%1$s().String())\n" + + indent + "} else {\n" + + indent + " builder.WriteString(%2$s)\n" + + indent + "}\n", + fieldName, + typeToken.signal() == Signal.BEGIN_SET ? "\"[]\"" : "\"{}\""); + } + break; + + default: + break; + } + + sb.append('\n'); + } + + + private CharSequence generateChoicesDisplay( + final String name, + final List tokens) + { + final String indent = INDENT; + final StringBuilder sb = new StringBuilder(); + final List choiceTokens = new ArrayList<>(); + + collect(Signal.CHOICE, tokens, 0, choiceTokens); + + addInclude("strings"); + new Formatter(sb).format("\n" + + indent + "func (writer %1$s) String() string {\n" + + indent + " builder := strings.Builder{}\n" + + indent + " builder.WriteString(\"[\")\n", + name); + + if (choiceTokens.size() > 1) + { + sb.append(indent + " atLeastOne := false\n"); + } + + for (int i = 0, size = choiceTokens.size(); i < size; i++) + { + final Token token = choiceTokens.get(i); + final String choiceName = "writer." + formatPropertyName(token.name()); + + sb.append(indent + " if ").append(choiceName).append("() {\n"); + + if (i > 0) + { + sb.append( + indent + " if (atLeastOne) {\n" + + indent + " builder.WriteString(\",\")\n" + + indent + " }\n"); + } + sb.append(indent + " builder.WriteString(`\"").append(formatPropertyName(token.name())) + .append("\"`)\n"); + + if (i < (size - 1)) + { + sb.append(indent + " atLeastOne = true\n"); + } + + sb.append(indent + " }\n"); + } + + sb.append( + indent + " builder.WriteString(\"]\")\n" + + indent + " return builder.String()\n" + + indent + "}\n"); + + return sb; + } + + + private CharSequence generateEnumDisplay( + final List tokens, + final Token encodingToken) + { + final String enumName = formatClassName(encodingToken.applicableTypeName()); + final StringBuilder sb = new StringBuilder(); + + new Formatter(sb).format("\n" + + " func (value %1$s) String() string {\n" + + " switch value {\n", + enumName); + + for (final Token token : tokens) + { + new Formatter(sb).format( + " case %2$s_%1$s: return \"%1$s\"\n", + token.name(), + enumName); + } + + sb.append(" case ").append(enumName) + .append("_NULL_VALUE: return \"NULL_VALUE\"\n").append(" }\n\n"); + + if (shouldDecodeUnknownEnumValues) + { + sb.append(" return \"SBE_UNKNOWN\"\n").append(" }\n\n"); + } + else + { + addInclude("fmt"); + new Formatter(sb).format( + " panic(fmt.Sprintf(\"unknown value for enum %1$s [E103]: %%d\", value))\n" + + " }\n\n", + enumName); + } + + return sb; + } + + private Object[] generateMessageLengthArgs( + final List groups, + final List varData, + final String indent, + final boolean inStruct) + { + final StringBuilder sb = new StringBuilder(); + int count = 0; + + for (int i = 0, size = groups.size(); i < size; i++) + { + final Token groupToken = groups.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + final int endSignal = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); + final String groupName = formatPropertyName(groupToken.name()); + + if (count > 0) + { + if (inStruct) + { + sb.append("; ").append(indent); + } + else + { + sb.append(",\n").append(indent); + } + } + + final List thisGroup = groups.subList(i, endSignal + 1); + + if (isMessageConstLength(thisGroup)) + { + sb.append(" ").append(groupName).append("Length ").append("int"); + } + else + { + sb.append(groupName).append("ItemLengths ").append("[]struct{"); + sb.append(generateMessageLengthArgs(thisGroup, indent + INDENT, true)[0]); + sb.append("}"); + } + + count += 1; + + i = endSignal; + } + + for (int i = 0, size = varData.size(); i < size; ) + { + final Token varDataToken = varData.get(i); + if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); + } + + if (count > 0) + { + if (inStruct) + { + sb.append("; ").append(indent); + } + else + { + sb.append(",\n").append(indent); + } + } + + sb.append(" ").append(formatPropertyName(varDataToken.name())).append("Length").append(" int"); + + count += 1; + + i += varDataToken.componentTokenCount(); + } + + CharSequence result = sb; + if (count > 1) + { + result = "\n" + indent + result; + } + + return new Object[] {result, count}; + } + + + private Object[] generateMessageLengthArgs(final List tokens, final String indent, final boolean inStruct) + { + int i = 0; + + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + ++i; + final int groupHeaderTokenCount = tokens.get(i).componentTokenCount(); + i += groupHeaderTokenCount; + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + final List varData = new ArrayList<>(); + collectVarData(tokens, i, varData); + + return generateMessageLengthArgs(groups, varData, indent, inStruct); + } + + private boolean isMessageConstLength(final List tokens) + { + final Integer count = (Integer)generateMessageLengthArgs(tokens, BASE_INDENT, false)[1]; + + return count == 0; + } + + private String generateMessageLengthCallHelper( + final List groups, + final List varData) + { + final StringBuilder sb = new StringBuilder(); + int count = 0; + + for (int i = 0, size = groups.size(); i < size; i++) + { + final Token groupToken = groups.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + final int endSignal = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); + final String groupName = formatPropertyName(groupToken.name()); + + if (count > 0) + { + sb.append(", "); + } + + final List thisGroup = groups.subList(i, endSignal + 1); + + if (isMessageConstLength(thisGroup)) + { + sb.append("e.").append(groupName).append("Length"); + } + else + { + sb.append("e.").append(groupName).append("ItemLengths"); + } + + count += 1; + + i = endSignal; + } + + for (int i = 0, size = varData.size(); i < size; ) + { + final Token varDataToken = varData.get(i); + if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); + } + + if (count > 0) + { + sb.append(", "); + } + + sb.append("e.").append(formatPropertyName(varDataToken.name())).append("Length"); + + count += 1; + + i += varDataToken.componentTokenCount(); + } + + return sb.toString(); + } + + private CharSequence generateMessageLengthCallHelper(final List tokens) + { + int i = 0; + + final Token groupToken = tokens.get(i); + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + ++i; + final int groupHeaderTokenCount = tokens.get(i).componentTokenCount(); + i += groupHeaderTokenCount; + + final List fields = new ArrayList<>(); + i = collectFields(tokens, i, fields); + + final List groups = new ArrayList<>(); + i = collectGroups(tokens, i, groups); + + final List varData = new ArrayList<>(); + collectVarData(tokens, i, varData); + + return generateMessageLengthCallHelper(groups, varData); + } + + private CharSequence generateMessageLength( + final List groups, + final List varData, + final String indent, + final String className) + { + final StringBuilder sbEncode = new StringBuilder(); + final StringBuilder sbSkip = new StringBuilder(); + + for (int i = 0, size = groups.size(); i < size; i++) + { + final Token groupToken = groups.get(i); + + if (groupToken.signal() != Signal.BEGIN_GROUP) + { + throw new IllegalStateException("tokens must begin with BEGIN_GROUP: token=" + groupToken); + } + + final int endSignal = findEndSignal(groups, i, Signal.END_GROUP, groupToken.name()); + final List thisGroup = groups.subList(i, endSignal + 1); + + final Token numInGroupToken = Generators.findFirst("numInGroup", groups, i); + final long minCount = numInGroupToken.encoding().applicableMinValue().longValue(); + final long maxCount = numInGroupToken.encoding().applicableMaxValue().longValue(); + + final String countName = isMessageConstLength(thisGroup) ? + formatPropertyName(groupToken.name()) + "Length" : + "len(" + formatPropertyName(groupToken.name()) + "ItemLengths)"; + + final String minCheck = minCount > 0 ? countName + " < " + minCount + " || " : ""; + final String maxCheck = countName + " > " + maxCount; + + new Formatter(sbEncode).format("\n" + + indent + " length += m.%1$s().SbeHeaderSize()\n", + formatPropertyName(groupToken.name())); + + if (isMessageConstLength(thisGroup)) + { + addInclude("fmt"); + new Formatter(sbEncode).format( + indent + " if (%3$s%4$s) {\n" + + indent + " panic(fmt.Sprintf(\"%5$s outside of allowed range [E110]\"))\n" + + indent + " }\n" + + indent + " length += uint64(%1$sLength) * m.%1$s().SbeBlockLength()\n", + formatPropertyName(groupToken.name()), + formatClassName(groupToken.name()), + minCheck, + maxCheck, + countName); + } + else + { + new Formatter(sbEncode).format( + indent + " if (%3$s%4$s) {\n" + + indent + " panic(\"%5$s outside of allowed range [E110]\")\n" + + indent + " }\n\n" + + indent + " for _, e := range %1$sItemLengths {\n" + + indent + " l, err := m.%1$s().ComputeLength(%6$s)\n" + + indent + " if err != nil {\n" + + indent + " return 0, err\n" + + indent + " }\n" + + indent + " length += uint64(l)\n" + + indent + " }\n", + formatPropertyName(groupToken.name()), + formatClassName(groupToken.name()), + minCheck, + maxCheck, + countName, + generateMessageLengthCallHelper(thisGroup)); + } + + new Formatter(sbSkip).format( + indent + (" for %1$sGroup := m.%1$s(); %1$sGroup.HasNext(); {\n") + + indent + (" %1$sGroup.Next().Skip()\n") + + indent + (" }\n"), + formatPropertyName(groupToken.name())); + + i = endSignal; + } + for (int i = 0, size = varData.size(); i < size; ) + { + final Token varDataToken = varData.get(i); + + if (varDataToken.signal() != Signal.BEGIN_VAR_DATA) + { + throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + varDataToken); + } + + final Token lengthToken = Generators.findFirst("length", varData, i); + + addInclude("fmt"); + new Formatter(sbEncode).format("\n" + + indent + " length += m.%1$sHeaderLength()\n" + + indent + " if m.%1$sLength() > %2$d {\n" + + indent + " return 0, fmt.Errorf(\"%1$sLength too long for length type [E109]\")\n" + + indent + " }\n" + + indent + " length += uint64(m.%1$sLength())\n", + formatPropertyName(varDataToken.name()), + lengthToken.encoding().applicableMaxValue().longValue()); + + new Formatter(sbSkip).format( + indent + " m.Skip%1$s()\n", + toUpperFirstChar(varDataToken.name())); + + i += varDataToken.componentTokenCount(); + } + + final StringBuilder sb = new StringBuilder(); + + new Formatter(sb).format("\n" + + indent + "func (m *%2$s) Skip() {\n" + + sbSkip + + indent + "}\n\n" + + + indent + "func (m *%2$s) IsConstLength() bool {\n" + + indent + " return " + (groups.isEmpty() && varData.isEmpty()) + "\n" + + indent + "}\n\n" + + + indent + "func (m *%2$s) ComputeLength(%1$s) (int, error) {\n" + + indent + " length := uint64(m.SbeBlockLength())\n" + + sbEncode + "\n" + + indent + " return int(length), nil\n" + + indent + "}\n", + generateMessageLengthArgs(groups, varData, indent + INDENT, false)[0], + className); + + return sb; + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightOutputManager.java new file mode 100644 index 0000000000..3b9e72b716 --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightOutputManager.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.golang.flyweight; + +import org.agrona.generation.OutputManager; +import org.agrona.Verify; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +import static java.io.File.separatorChar; + +/** + * {@link OutputManager} for managing the creation of golang source files as the target of code generation. + * The character encoding for the {@link java.io.Writer} is UTF-8. + */ +public class GolangFlyweightOutputManager implements OutputManager +{ + private final File outputDir; + + /** + * Create a new {@link OutputManager} for generating golang source files into a given package. + * + * @param baseDirName for the generated source code. + * @param namespaceName for the generated source code relative to the baseDirName. + */ + public GolangFlyweightOutputManager(final String baseDirName, final String namespaceName) + { + Verify.notNull(baseDirName, "baseDirName"); + Verify.notNull(namespaceName, "applicableNamespace"); + + final String dirName = baseDirName.endsWith("" + separatorChar) ? baseDirName : baseDirName + separatorChar; + final String packageDirName = dirName + namespaceName.replace('.', '_'); + + outputDir = new File(packageDirName); + if (!outputDir.exists() && !outputDir.mkdirs()) + { + throw new IllegalStateException("Unable to create directory: " + packageDirName); + } + } + + /** + * Create a new output which will be a golang source file in the given package. + *

    + * The {@link java.io.Writer} should be closed once the caller has finished with it. The Writer is + * buffered for efficient IO operations. + * + * @param name the name of the golang class. + * @return a {@link java.io.Writer} to which the source code should be written. + * @throws IOException if an issue occurs when creating the file. + */ + public Writer createOutput(final String name) throws IOException + { + final File targetFile = new File(outputDir, name + ".go"); + + return Files.newBufferedWriter(targetFile.toPath(), StandardCharsets.UTF_8); + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java new file mode 100644 index 0000000000..78ac285b6c --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java @@ -0,0 +1,224 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.golang.flyweight; + +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.SbeTool; +import uk.co.real_logic.sbe.ValidationUtil; + +import java.nio.ByteOrder; +import java.util.EnumMap; +import java.util.Map; + +import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; + +/** + * Utilities for mapping between IR and the Golang language. + */ +public class GolangFlyweightUtil +{ + private static final Map PRIMITIVE_TYPE_STRING_ENUM_MAP = new EnumMap<>(PrimitiveType.class); + private static final Map MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP = + new EnumMap<>(PrimitiveType.class); + + static + { + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.CHAR, "byte"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.INT8, "int8"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.INT16, "int16"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.INT32, "int32"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.INT64, "int64"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.UINT8, "uint8"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.UINT16, "uint16"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.UINT32, "uint32"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.UINT64, "uint64"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.FLOAT, "float32"); + PRIMITIVE_TYPE_STRING_ENUM_MAP.put(PrimitiveType.DOUBLE, "float64"); + } + + static + { + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.CHAR, "Bytes"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.INT8, "Int8"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.INT16, "Int16"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.INT32, "Int32"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.INT64, "Int64"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.UINT8, "Uint8"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.UINT16, "Uint16"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.UINT32, "Uint32"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.UINT64, "Uint64"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.FLOAT, "Float32"); + MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.put(PrimitiveType.DOUBLE, "Float64"); + } + + /** + * Map the name of a {@link uk.co.real_logic.sbe.PrimitiveType} to a Golang primitive type name. + * + * @param primitiveType to map. + * @return the name of the Java primitive that most closely maps. + */ + public static String goTypeName(final PrimitiveType primitiveType) + { + return PRIMITIVE_TYPE_STRING_ENUM_MAP.get(primitiveType); + } + + /** + * Format a String as a class name. + * + * @param value to be formatted. + * @return the string formatted as a class name. + */ + public static String formatClassName(final String value) + { + return toUpperFirstChar(value); + } + + /** + * Map the name of a {@link uk.co.real_logic.sbe.PrimitiveType} to a Golang marhsalling function name. + * + * @param primitiveType to map. + * @return the name of the Java primitive that most closely maps. + */ + public static String golangMarshalType(final PrimitiveType primitiveType) + { + return MARSHAL_TYPE_BY_PRIMITIVE_TYPE_MAP.get(primitiveType); + } + + /** + * Format a String as a property name. + * + * @param value to be formatted. + * @return the string formatted as a property name. + */ + public static String formatPropertyName(final String value) + { + String formattedValue = toUpperFirstChar(value); + + if (ValidationUtil.isGolangKeyword(formattedValue)) + { + final String keywordAppendToken = System.getProperty(SbeTool.KEYWORD_APPEND_TOKEN); + if (null == keywordAppendToken) + { + throw new IllegalStateException( + "Invalid property name='" + formattedValue + + "' please correct the schema or consider setting system property: " + + SbeTool.KEYWORD_APPEND_TOKEN); + } + + formattedValue += keywordAppendToken; + } + + return formattedValue; + } + + /** + * Generate a count of closing braces, one on each line. + * + * @param count of closing braces. + * @return A string with count of closing braces. + */ + public static String closingBraces(final int count) + { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < count; i++) + { + sb.append("}\n"); + } + + return sb.toString(); + } + + /** + * Return the Golang formatted byte order encoding string to use to read for a given byte order and primitiveType + * + * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token} + * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token} + * @return the string formatted as the byte ordering encoding + */ + public static String formatReadBytes(final ByteOrder byteOrder, final PrimitiveType primitiveType) + { + final String suffix = (byteOrder == ByteOrder.BIG_ENDIAN ? + "BigEndian" : "LittleEndian"); + + switch (primitiveType) + { + case CHAR: + return "Byte" + suffix; + case FLOAT: + return "Float" + suffix; + case DOUBLE: + return "Double" + suffix; + case INT8: + return "Int8" + suffix; + case INT16: + return "Int16" + suffix; + case INT32: + return "Int32" + suffix; + case INT64: + return "Int64" + suffix; + case UINT8: + return "Uint8" + suffix; + case UINT16: + return "Uint16" + suffix; + case UINT32: + return "Uint32" + suffix; + case UINT64: + return "Uint64" + suffix; + } + return ""; + } + + /** + * Return the Golang formatted byte order encoding string to use to write for a given byte order and primitiveType + * + * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token} + * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token} + * @return the string formatted as the byte ordering encoding + */ + public static String formatWriteBytes(final ByteOrder byteOrder, final PrimitiveType primitiveType) + { + final String suffix = (byteOrder == ByteOrder.BIG_ENDIAN ? + "BigEndian" : "LittleEndian"); + + switch (primitiveType) + { + case CHAR: + return "PutByte" + suffix; + case FLOAT: + return "PutFloat" + suffix; + case DOUBLE: + return "PutDouble" + suffix; + case INT8: + return "PutInt8" + suffix; + case INT16: + return "PutInt16" + suffix; + case INT32: + return "PutInt32" + suffix; + case INT64: + return "PutInt64" + suffix; + case UINT8: + return "PutUint8" + suffix; + case UINT16: + return "PutUint16" + suffix; + case UINT32: + return "PutUint32" + suffix; + case UINT64: + return "PutUint64" + suffix; + } + return ""; + } + +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java similarity index 99% rename from sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java rename to sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java index 1c1582380a..58c357951d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package uk.co.real_logic.sbe.generation.golang; +package uk.co.real_logic.sbe.generation.golang.struct; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.generation.CodeGenerator; @@ -37,7 +37,7 @@ import static uk.co.real_logic.sbe.PrimitiveType.CHAR; import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; -import static uk.co.real_logic.sbe.generation.golang.GolangUtil.*; +import static uk.co.real_logic.sbe.generation.golang.struct.GolangUtil.*; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangOutputManager.java similarity index 98% rename from sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java rename to sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangOutputManager.java index 1675d69fed..a584396a09 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangOutputManager.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package uk.co.real_logic.sbe.generation.golang; +package uk.co.real_logic.sbe.generation.golang.struct; import org.agrona.generation.OutputManager; import org.agrona.Verify; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangUtil.java similarity index 98% rename from sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java rename to sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangUtil.java index 0aa379216b..2689da26de 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/GolangUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangUtil.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package uk.co.real_logic.sbe.generation.golang; +package uk.co.real_logic.sbe.generation.golang.struct; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.SbeTool; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java similarity index 99% rename from sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java rename to sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java index af647727f2..b4d6198680 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java @@ -18,6 +18,7 @@ import org.agrona.generation.StringWriterOutputManager; import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.generation.golang.struct.GolangGenerator; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; @@ -28,7 +29,7 @@ import static org.junit.jupiter.api.Assertions.*; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -class GolangGeneratorTest +class GolangStructGeneratorTest { @Test @SuppressWarnings("MethodLength") From 44f225686b1afc22bbe1b8a6a7c47341c228c23d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 29 Oct 2024 10:53:13 +0100 Subject: [PATCH 462/805] [CI] Attempt to fix Rust install. --- .github/workflows/ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bc6da223f..833df2a436 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -373,11 +373,8 @@ jobs: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Rust setup - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - override: true + uses: dtolnay/rust-toolchain@stable + toolchain: ${{ matrix.rust }} - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: From 354fb93a06318c3cade850ff265ba2b7d31b4a10 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 29 Oct 2024 10:56:42 +0100 Subject: [PATCH 463/805] Revert "[CI] Attempt to fix Rust install." This reverts commit 44f225686b1afc22bbe1b8a6a7c47341c228c23d. --- .github/workflows/ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 833df2a436..5bc6da223f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -373,8 +373,11 @@ jobs: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Rust setup - uses: dtolnay/rust-toolchain@stable - toolchain: ${{ matrix.rust }} + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: From ca86c353f44e2838b350b58f00fb543585c1f424 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 29 Oct 2024 10:57:00 +0100 Subject: [PATCH 464/805] Reapply "[CI] Attempt to fix Rust install." This reverts commit 354fb93a06318c3cade850ff265ba2b7d31b4a10. --- .github/workflows/ci.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bc6da223f..833df2a436 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -373,11 +373,8 @@ jobs: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Rust setup - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - override: true + uses: dtolnay/rust-toolchain@stable + toolchain: ${{ matrix.rust }} - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: From d4655418f0bf1f4a588c35a2267cc1b1914492f8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:06:03 +0100 Subject: [PATCH 465/805] [Java] Upgrade to Checkstyle 10.19.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e8889233da..d2692936f7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "1.23.1" -checkstyle = "10.18.2" +checkstyle = "10.19.0" junit = "5.11.3" jmh = "1.37" gradle = "8.10.2" From b7bd10409b05361462b57ad75abe835ac8b82e6d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 29 Oct 2024 11:06:09 +0100 Subject: [PATCH 466/805] [Java] Upgrade to Shadow 8.3.4. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d2692936f7..a19bc056c9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,4 +16,4 @@ jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-an [plugins] versions = { id = "com.github.ben-manes.versions", version = "0.51.0" } -shadow = { id = "com.gradleup.shadow", version = "8.3.3" } +shadow = { id = "com.gradleup.shadow", version = "8.3.4" } From 7a0ac0f63ed15982f14e66fa2c0afe2c7ff85a00 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:45:03 +0100 Subject: [PATCH 467/805] [CI] Temporarily disable Rust toolchain installation. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 833df2a436..f1e1f24e61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -372,9 +372,9 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - - name: Rust setup - uses: dtolnay/rust-toolchain@stable - toolchain: ${{ matrix.rust }} +# - name: Rust setup +# uses: dtolnay/rust-toolchain@stable +# toolchain: ${{ matrix.rust }} - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: From cd057964ad589f2c76c007b79065efdb73bbb8bd Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:56:58 +0100 Subject: [PATCH 468/805] Revert "[CI] Temporarily disable Rust toolchain installation." This reverts commit 7a0ac0f63ed15982f14e66fa2c0afe2c7ff85a00. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1e1f24e61..833df2a436 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -372,9 +372,9 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} -# - name: Rust setup -# uses: dtolnay/rust-toolchain@stable -# toolchain: ${{ matrix.rust }} + - name: Rust setup + uses: dtolnay/rust-toolchain@stable + toolchain: ${{ matrix.rust }} - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: From ae002c29a3378f2c184697465e73e256a96c9ac7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:58:24 +0100 Subject: [PATCH 469/805] [CI] Fix invocation syntax. --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 833df2a436..23be3be93a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -374,7 +374,8 @@ jobs: key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Rust setup uses: dtolnay/rust-toolchain@stable - toolchain: ${{ matrix.rust }} + with: + toolchain: ${{ matrix.rust }} - name: Setup java 17 to run the Gradle script uses: actions/setup-java@v4 with: From 4d37f331baaf9ee3f7211c6857af3d21e04964e4 Mon Sep 17 00:00:00 2001 From: Nate Bradac <38217740+nbradac@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:59:28 -0500 Subject: [PATCH 470/805] [Java] DTOs respect the optional package field in the schema definition (#1022) * [Java] DTOs respect the optional package field in the schema definition * [Java] checkstyle --- .../generation/TargetCodeGeneratorLoader.java | 8 +- .../sbe/generation/cpp/CppDtoGenerator.java | 4 +- .../sbe/generation/java/JavaDtoGenerator.java | 85 ++++++++++++++++--- .../sbe/generation/java/JavaDtos.java | 7 +- .../sbe/properties/DtosPropertyTest.java | 2 +- .../generation/java/JavaGeneratorTest.java | 36 ++++++++ 6 files changed, 126 insertions(+), 16 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index 4edea4f8b4..c09152fabf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -52,6 +52,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) { final JavaOutputManager outputManager = new JavaOutputManager(outputDir, ir.applicableNamespace()); + final boolean shouldSupportTypesPackageNames = Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE); final JavaGenerator codecGenerator = new JavaGenerator( ir, System.getProperty(JAVA_ENCODING_BUFFER_TYPE, JAVA_DEFAULT_ENCODING_BUFFER_TYPE), @@ -59,13 +60,16 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) Boolean.getBoolean(JAVA_GROUP_ORDER_ANNOTATION), Boolean.getBoolean(JAVA_GENERATE_INTERFACES), Boolean.getBoolean(DECODE_UNKNOWN_ENUM_VALUES), - Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE), + shouldSupportTypesPackageNames, precedenceChecks(), outputManager); if (Boolean.getBoolean(JAVA_GENERATE_DTOS)) { - final JavaDtoGenerator dtoGenerator = new JavaDtoGenerator(ir, outputManager); + final JavaDtoGenerator dtoGenerator = new JavaDtoGenerator( + ir, + shouldSupportTypesPackageNames, + outputManager); return () -> { codecGenerator.generate(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 39b59412e5..9c4064dbc9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -41,7 +41,7 @@ import static uk.co.real_logic.sbe.ir.GenerationUtil.collectVarData; /** - * DTO generator for the CSharp programming language. + * DTO generator for the C++ programming language. */ public class CppDtoGenerator implements CodeGenerator { @@ -52,7 +52,7 @@ public class CppDtoGenerator implements CodeGenerator private final OutputManager outputManager; /** - * Create a new C# DTO {@link CodeGenerator}. + * Create a new C++ DTO {@link CodeGenerator}. * * @param ir for the messages and types. * @param outputManager for generating the DTOs to. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index b922bd14ed..baf9f70342 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -24,12 +24,14 @@ import uk.co.real_logic.sbe.ir.Token; import org.agrona.LangUtil; import org.agrona.Verify; -import org.agrona.generation.OutputManager; +import org.agrona.generation.DynamicPackageOutputManager; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Predicate; import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; @@ -49,16 +51,23 @@ public class JavaDtoGenerator implements CodeGenerator private static final String BASE_INDENT = ""; private final Ir ir; - private final OutputManager outputManager; + private final DynamicPackageOutputManager outputManager; + private final boolean shouldSupportTypesPackageNames; + private final Set packageNameByTypes = new HashSet<>(); /** - * Create a new C# DTO {@link CodeGenerator}. + * Create a new Java DTO {@link CodeGenerator}. * - * @param ir for the messages and types. - * @param outputManager for generating the DTOs to. + * @param ir for the messages and types. + * @param shouldSupportTypesPackageNames generator support for types in their own package. + * @param outputManager for generating the DTOs to. */ - public JavaDtoGenerator(final Ir ir, final OutputManager outputManager) + public JavaDtoGenerator( + final Ir ir, + final boolean shouldSupportTypesPackageNames, + final DynamicPackageOutputManager outputManager) { + this.shouldSupportTypesPackageNames = shouldSupportTypesPackageNames; Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); @@ -66,6 +75,24 @@ public JavaDtoGenerator(final Ir ir, final OutputManager outputManager) this.outputManager = outputManager; } + /** + * Fetch the type's explicit package - if set and should be supported. + * + * @param token the 0-th token of the type. + * @param ir the intermediate representation. + * @return the overridden package name of the type if set and supported, or {@link Ir#applicableNamespace()}. + */ + private String fetchTypesPackageName(final Token token, final Ir ir) + { + if (shouldSupportTypesPackageNames && token.packageName() != null) + { + outputManager.setPackageName(token.packageName()); + return token.packageName(); + } + + return ir.applicableNamespace(); + } + /** * {@inheritDoc} */ @@ -110,9 +137,10 @@ public void generate() throws IOException generateDisplay(classBuilder, encoderClassName, "computeEncodedLength()", BASE_INDENT + INDENT); + final String packageName = fetchTypesPackageName(msgToken, ir); try (Writer out = outputManager.createOutput(dtoClassName)) { - out.append(generateDtoFileHeader(ir.applicableNamespace())); + out.append(generateDtoFileHeader(packageName)); out.append("import org.agrona.DirectBuffer;\n"); out.append("import org.agrona.MutableDirectBuffer;\n"); out.append("import org.agrona.concurrent.UnsafeBuffer;\n\n"); @@ -1582,6 +1610,19 @@ private static String formatDtoClassName(final String name) private void generateDtosForTypes() throws IOException { + if (shouldSupportTypesPackageNames) + { + for (final List tokens : ir.types()) + { + final String packageName = tokens.get(0).packageName(); + + if (packageName != null) + { + packageNameByTypes.add(packageName); + } + } + } + for (final List tokens : ir.types()) { switch (tokens.get(0).signal()) @@ -1607,10 +1648,11 @@ private void generateComposite(final List tokens) throws IOException final String encoderClassName = encoderName(name); final String decoderClassName = decoderName(name); + final String packageName = fetchTypesPackageName(tokens.get(0), ir); try (Writer out = outputManager.createOutput(className)) { final List compositeTokens = tokens.subList(1, tokens.size() - 1); - out.append(generateDtoFileHeader(ir.applicableNamespace())); + out.append(generateDtoFileHeader(packageName)); out.append("import org.agrona.DirectBuffer;\n"); out.append("import org.agrona.MutableDirectBuffer;\n"); out.append("import org.agrona.concurrent.UnsafeBuffer;\n\n"); @@ -1638,10 +1680,11 @@ private void generateChoiceSet(final List tokens) throws IOException final String encoderClassName = encoderName(name); final String decoderClassName = decoderName(name); + final String packageName = fetchTypesPackageName(tokens.get(0), ir); try (Writer out = outputManager.createOutput(className)) { final List setTokens = tokens.subList(1, tokens.size() - 1); - out.append(generateDtoFileHeader(ir.applicableNamespace())); + out.append(generateDtoFileHeader(packageName)); out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT, "public final"); @@ -1795,13 +1838,35 @@ private void generateCompositePropertyElements( } } - private static CharSequence generateDtoFileHeader(final String packageName) + private static StringBuilder generateImportStatements(final Set packages, final String currentPackage) + { + final StringBuilder importStatements = new StringBuilder(); + + for (final String candidatePackage : packages) + { + if (!candidatePackage.equals(currentPackage)) + { + importStatements.append("import ").append(candidatePackage).append(".*;\n"); + } + } + + if (!importStatements.isEmpty()) + { + importStatements.append("\n\n"); + } + + return importStatements; + } + + private CharSequence generateDtoFileHeader(final String packageName) { final StringBuilder sb = new StringBuilder(); sb.append("/* Generated SBE (Simple Binary Encoding) message DTO */\n"); sb.append("package ").append(packageName).append(";\n\n"); + sb.append(generateImportStatements(packageNameByTypes, packageName)); + return sb; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java index 45eeccff93..3d4dc61482 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java @@ -20,6 +20,8 @@ import uk.co.real_logic.sbe.generation.TargetCodeGenerator; import uk.co.real_logic.sbe.ir.Ir; +import static uk.co.real_logic.sbe.SbeTool.TYPES_PACKAGE_OVERRIDE; + /** * {@link CodeGenerator} factory for Java DTOs. */ @@ -30,6 +32,9 @@ public class JavaDtos implements TargetCodeGenerator */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new JavaDtoGenerator(ir, new JavaOutputManager(outputDir, ir.applicableNamespace())); + return new JavaDtoGenerator( + ir, + Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE), + new JavaOutputManager(outputDir, ir.applicableNamespace())); } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index 8df61fe2b3..7cb1aa03a1 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -87,7 +87,7 @@ void javaDtoEncodeShouldBeTheInverseOfDtoDecode( outputManager) .generate(); - new JavaDtoGenerator(encodedMessage.ir(), outputManager) + new JavaDtoGenerator(encodedMessage.ir(), false, outputManager) .generate(); } catch (final Exception generationException) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index e93a7c1eba..68679c15a1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -601,6 +601,42 @@ void shouldCreateTypesInSamePackageIfSupportDisabled() throws Exception } } + @Test + void dtosShouldReferenceTypesInDifferentPackages() throws Exception + { + try (InputStream in = Tests.getLocalResource("explicit-package-test-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + ir = irg.generate(schema); + + outputManager.clear(); + outputManager.setPackageName(ir.applicableNamespace()); + + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, true, outputManager + ); + generator.generate(); + + final JavaDtoGenerator javaDtoGenerator = new JavaDtoGenerator(ir, true, outputManager); + javaDtoGenerator.generate(); + + final Map sources = outputManager.getSources(); + assertNotNull(sources.get("test.message.schema.TestMessageDto")); + assertNotNull(sources.get("test.message.schema.MessageHeaderDto")); + assertNotNull(sources.get("test.message.schema.common.CarDto")); + assertNotNull(sources.get("test.message.schema.common.EngineDto")); + assertNotNull(sources.get("outside.schema.FuelSpecDto")); + assertNotNull(sources.get("outside.schema.DaysDto")); + assertNotNull(sources.get("outside.schema.FuelTypeDto")); + + assertNotNull(compile("test.message.schema.TestMessageDto")); + assertNotNull(compile("test.message.schema.common.CarDto")); + assertNotNull(compile("outside.schema.FuelSpecDto")); + } + } + @ParameterizedTest @CsvSource( { From 879e1ef61c384f1fef9d8434f6d46b2e9de7e6a9 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 6 Nov 2024 14:11:20 +0000 Subject: [PATCH 471/805] [CI] Update actions dependencies. --- .github/workflows/slow.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index e67cd05af7..a6700d95b2 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -33,7 +33,7 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - name: Setup java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -56,7 +56,7 @@ jobs: - name: Run property tests run: ./gradlew propertyTest - name: Upload test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: success() || failure() with: name: property-tests From 2f85ccb38b4074ba3d20f8f9869516c77367d962 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 7 Nov 2024 14:33:39 -0500 Subject: [PATCH 472/805] [Java] Upgrade to Shadow 8.3.5. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a19bc056c9..26cd83b807 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,4 +16,4 @@ jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-an [plugins] versions = { id = "com.github.ben-manes.versions", version = "0.51.0" } -shadow = { id = "com.gradleup.shadow", version = "8.3.4" } +shadow = { id = "com.gradleup.shadow", version = "8.3.5" } From 5ce95bca021e88af58b4c4b48baa698d2caf206d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 7 Nov 2024 14:35:57 -0500 Subject: [PATCH 473/805] [Java] Upgrade to Checkstyle 1.20.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 26cd83b807..c41a71d0e6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "1.23.1" -checkstyle = "10.19.0" +checkstyle = "10.20.1" junit = "5.11.3" jmh = "1.37" gradle = "8.10.2" From 018664bdf62e61996ad446422e24f5785d4172b8 Mon Sep 17 00:00:00 2001 From: Dan Shearer Date: Fri, 8 Nov 2024 15:23:57 +0000 Subject: [PATCH 474/805] 1.33.2 release --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6214e03b71..80c8c0bd36 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.34.0-SNAPSHOT +1.33.2 From 4484457a485a789cf75071529bf5b7c875a31164 Mon Sep 17 00:00:00 2001 From: Dan Shearer Date: Fri, 8 Nov 2024 15:24:38 +0000 Subject: [PATCH 475/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 80c8c0bd36..6214e03b71 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.33.2 +1.34.0-SNAPSHOT From 320850d938dfdfa578ea9e67703d0bbd3594d742 Mon Sep 17 00:00:00 2001 From: Elvis Wang Date: Wed, 13 Nov 2024 18:47:48 +0800 Subject: [PATCH 476/805] [Rust] Enhance enum supporting fromstr and display and into (#1020) * [Rust] impl FromStr for generated enum items * [Rust] impl Display for generate enum items * [Rust] impl Into for generated enum items * [Rust] reformat code according to checkstyle failure report * [Rust] split code in generateEnum to adress CI checkstyle method too log failure * [Rust] reformat code according to checkstyle failure * [Rust] fix CodeQL warning by removing unused argument * [Rust] fix CodeQL warning by removing unused argument --- rust/tests/baseline_enum_from_str.rs | 21 +++++ rust/tests/baseline_enum_into.rs | 14 +++ rust/tests/baseline_enum_to_str.rs | 14 +++ .../sbe/generation/rust/RustGenerator.java | 88 +++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 rust/tests/baseline_enum_from_str.rs create mode 100644 rust/tests/baseline_enum_into.rs create mode 100644 rust/tests/baseline_enum_to_str.rs diff --git a/rust/tests/baseline_enum_from_str.rs b/rust/tests/baseline_enum_from_str.rs new file mode 100644 index 0000000000..4e52fd4bf9 --- /dev/null +++ b/rust/tests/baseline_enum_from_str.rs @@ -0,0 +1,21 @@ +use examples_baseline::{ + boost_type::BoostType, +}; + +#[test] +fn test_boost_type_from_str() -> Result<(), ()> { + assert_eq!("TURBO".parse::()?, BoostType::TURBO, "Parse \"TURBO\" as BoostType"); + assert_eq!("SUPERCHARGER".parse::()?, BoostType::SUPERCHARGER, "Parse \"SUPERCHARGER\" as BoostType"); + assert_eq!("NITROUS".parse::()?, BoostType::NITROUS, "Parse \"NITROUS\" as BoostType"); + assert_eq!("KERS".parse::()?, BoostType::KERS, "Parse \"KERS\" as BoostType"); + + assert_eq!("Turbo".parse::()?, BoostType::NullVal, "Parse \"Turbo\" as BoostType"); + assert_eq!("Supercharger".parse::()?, BoostType::NullVal, "Parse \"Supercharger\" as BoostType"); + assert_eq!("Nitrous".parse::()?, BoostType::NullVal, "Parse \"Nitrous\" as BoostType"); + assert_eq!("Kers".parse::()?, BoostType::NullVal, "Parse \"Kers\" as BoostType"); + + assert_eq!("AA".parse::()?, BoostType::NullVal, "Parse \"AA\" as BoostType"); + assert_eq!("".parse::().unwrap(), BoostType::NullVal, "Parse \"\" as BoostType"); + + Ok(()) +} diff --git a/rust/tests/baseline_enum_into.rs b/rust/tests/baseline_enum_into.rs new file mode 100644 index 0000000000..9580e51b0d --- /dev/null +++ b/rust/tests/baseline_enum_into.rs @@ -0,0 +1,14 @@ +use examples_baseline::{ + boost_type::BoostType, +}; + +#[test] +fn test_boost_type_from_str() -> Result<(), ()> { + assert_eq!(>::into(BoostType::TURBO), 84_u8, "BoostType::TURBO into value"); + assert_eq!(>::into(BoostType::SUPERCHARGER), 83_u8, "BoostType::SUPERCHARGER into value"); + assert_eq!(>::into(BoostType::NITROUS), 78_u8, "BoostType::NITROUS into value"); + assert_eq!(>::into(BoostType::KERS), 75_u8, "BoostType::KERS into value"); + assert_eq!(>::into(BoostType::NullVal), 0_u8, "BoostType::NullVal into value"); + + Ok(()) +} diff --git a/rust/tests/baseline_enum_to_str.rs b/rust/tests/baseline_enum_to_str.rs new file mode 100644 index 0000000000..93f5206517 --- /dev/null +++ b/rust/tests/baseline_enum_to_str.rs @@ -0,0 +1,14 @@ +use examples_baseline::{ + boost_type::BoostType, +}; + +#[test] +fn test_boost_type_from_str() -> Result<(), ()> { + assert_eq!(format!("{}", BoostType::TURBO), "TURBO", "Display \"TURBO\""); + assert_eq!(format!("{}", BoostType::SUPERCHARGER), "SUPERCHARGER", "Display \"SUPERCHARGER\""); + assert_eq!(format!("{}", BoostType::NITROUS), "NITROUS", "Display \"NITROUS\""); + assert_eq!(format!("{}", BoostType::KERS), "KERS", "Display \"KERS\""); + assert_eq!(format!("{}", BoostType::NullVal), "NullVal", "Display \"NullVal\""); + + Ok(()) +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 5ed04fc9fb..7c2a492ce4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1266,6 +1266,24 @@ private static void generateEnum( indent(writer, 0, "}\n"); // From impl + generateFromImplForEnum(enumRustName, primitiveType, messageBody, writer); + + // Into impl + generateIntoImplForEnum(enumRustName, primitiveType, messageBody, writer); + + // FromStr impl + generateFromStrImplForEnum(enumRustName, primitiveType, messageBody, writer); + + // Display impl + generateDisplayImplForEnum(enumRustName, primitiveType, messageBody, writer); + } + + private static void generateFromImplForEnum( + final String enumRustName, + final String primitiveType, + final List messageBody, + final Appendable writer) throws IOException + { indent(writer, 0, "impl From<%s> for %s {\n", primitiveType, enumRustName); indent(writer, 1, "#[inline]\n"); indent(writer, 1, "fn from(v: %s) -> Self {\n", primitiveType); @@ -1285,6 +1303,76 @@ private static void generateEnum( indent(writer, 0, "}\n"); } + private static void generateIntoImplForEnum( + final String enumRustName, + final String primitiveType, + final List messageBody, + final Appendable writer) throws IOException + { + indent(writer, 0, "impl Into<%s> for %s {\n", primitiveType, enumRustName); + indent(writer, 1, "#[inline]\n"); + indent(writer, 1, "fn into(self) -> %s {\n", primitiveType); + indent(writer, 2, "match self {\n"); + for (final Token token : messageBody) + { + final Encoding encoding = token.encoding(); + final String literal = generateRustLiteral(encoding.primitiveType(), encoding.constValue().toString()); + indent(writer, 3, "Self::%s => %s, \n", token.name(), literal); + } + { + final Encoding encoding = messageBody.get(0).encoding(); + final CharSequence nullVal = generateRustLiteral(encoding.primitiveType(), + encoding.applicableNullValue().toString()); + indent(writer, 3, "Self::NullVal => %s,\n", nullVal); + } + indent(writer, 2, "}\n"); + indent(writer, 1, "}\n"); + indent(writer, 0, "}\n"); + } + + private static void generateFromStrImplForEnum( + final String enumRustName, + final String primitiveType, + final List messageBody, + final Appendable writer) throws IOException + { + indent(writer, 0, "impl core::str::FromStr for %s {\n", enumRustName); + indent(writer, 1, "type Err = ();\n\n"); + indent(writer, 1, "#[inline]\n"); + indent(writer, 1, "fn from_str(v: &str) -> core::result::Result {\n"); + indent(writer, 2, "match v {\n"); + for (final Token token : messageBody) + { + indent(writer, 3, "\"%1$s\" => core::result::Result::Ok(Self::%1$s), \n", token.name()); + } + // default => NullVal + indent(writer, 3, "_ => core::result::Result::Ok(Self::NullVal),\n"); + indent(writer, 2, "}\n"); + indent(writer, 1, "}\n"); + indent(writer, 0, "}\n"); + } + + private static void generateDisplayImplForEnum( + final String enumRustName, + final String primitiveType, + final List messageBody, + final Appendable writer) throws IOException + { + indent(writer, 0, "impl core::fmt::Display for %s {\n", enumRustName); + indent(writer, 1, "#[inline]\n"); + indent(writer, 1, "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n"); + indent(writer, 2, "match self {\n"); + for (final Token token : messageBody) + { + indent(writer, 3, "Self::%1$s => write!(f, \"%1$s\"), \n", token.name()); + } + // default => Err + indent(writer, 3, "Self::NullVal => write!(f, \"NullVal\"),\n"); + indent(writer, 2, "}\n"); + indent(writer, 1, "}\n"); + indent(writer, 0, "}\n"); + } + private static void generateComposites( final String schemaVersionType, final Ir ir, From d38b4bf87717a381992e7c27d999e9eccfc999df Mon Sep 17 00:00:00 2001 From: Elvis Wang Date: Wed, 13 Nov 2024 18:48:24 +0800 Subject: [PATCH 477/805] [Rust] generate message schema level info in lib.rs (#1019) * [Rust] generate message schema level info in lib.rs 1. add `SBE_SCHEMA_ID` 2. add `SBE_SCHEMA_VERSION` 3. add `SBE_SEMANTIC_VERSION` * [Rust] use pub use instead of duplicated defines for message schema items in message codec * [Rust] add tests for issue #1018 --- rust/tests/baseline_test.rs | 7 +++++++ .../real_logic/sbe/generation/rust/LibRsDef.java | 16 +++++++++++++++- .../sbe/generation/rust/RustGenerator.java | 15 +++++++-------- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index ab9eecb1fd..ab711b7c84 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -266,3 +266,10 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { let limit = car.get_limit(); Ok((limit, buffer)) } + +#[test] +fn test_issue_1018() { + assert_eq!(1, examples_baseline::SBE_SCHEMA_ID); + assert_eq!(0, examples_baseline::SBE_SCHEMA_VERSION); + assert_eq!("5.2", examples_baseline::SBE_SEMANTIC_VERSION); +} \ No newline at end of file diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index ad8a62c23e..f62aebe2d0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.stream.Stream; +import uk.co.real_logic.sbe.ir.Ir; import static java.nio.ByteOrder.LITTLE_ENDIAN; import static uk.co.real_logic.sbe.generation.rust.RustGenerator.*; @@ -54,7 +55,7 @@ class LibRsDef this.schemaVersionType = schemaVersionType; } - void generate() throws IOException + void generate(final Ir ir) throws IOException { try (Writer libRs = outputManager.createOutput("lib")) { @@ -84,6 +85,8 @@ void generate() throws IOException } indent(libRs, 0, "\n"); + generateSbeSchemaConsts(libRs, ir); + generateSbeErrorEnum(libRs); generateEitherEnum(libRs); @@ -123,6 +126,17 @@ static void generateDecoderTraits(final String schemaVersionType, final Writer w indent(writer, 0, "}\n\n"); } + static void generateSbeSchemaConsts(final Writer writer, final Ir ir) throws IOException + { + final String schemaIdType = rustTypeName(ir.headerStructure().schemaIdType()); + final String schemaVersionType = rustTypeName(ir.headerStructure().schemaVersionType()); + final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); + + indent(writer, 0, "pub const SBE_SCHEMA_ID: %s = %d;\n", schemaIdType, ir.id()); + indent(writer, 0, "pub const SBE_SCHEMA_VERSION: %s = %d;\n", schemaVersionType, ir.version()); + indent(writer, 0, "pub const SBE_SEMANTIC_VERSION: &str = \"%s\";\n\n", semanticVersion); + } + static void generateSbeErrorEnum(final Writer writer) throws IOException { indent(writer, 0, "pub type SbeResult = core::result::Result;\n\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 7c2a492ce4..29fd0da752 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -159,23 +159,22 @@ public void generate() throws IOException indent(out, 0, "use crate::*;\n\n"); indent(out, 0, "pub use decoder::%sDecoder;\n", formatStructName(msgToken.name())); indent(out, 0, "pub use encoder::%sEncoder;\n\n", formatStructName(msgToken.name())); + + indent(out, 0, "pub use crate::SBE_SCHEMA_ID;\n"); + indent(out, 0, "pub use crate::SBE_SCHEMA_VERSION;\n"); + indent(out, 0, "pub use crate::SBE_SEMANTIC_VERSION;\n\n"); + final String blockLengthType = blockLengthType(); final String templateIdType = rustTypeName(ir.headerStructure().templateIdType()); - final String schemaIdType = rustTypeName(ir.headerStructure().schemaIdType()); - final String schemaVersionType = schemaVersionType(); - final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); indent(out, 0, "pub const SBE_BLOCK_LENGTH: %s = %d;\n", blockLengthType, msgToken.encodedLength()); - indent(out, 0, "pub const SBE_TEMPLATE_ID: %s = %d;\n", templateIdType, msgToken.id()); - indent(out, 0, "pub const SBE_SCHEMA_ID: %s = %d;\n", schemaIdType, ir.id()); - indent(out, 0, "pub const SBE_SCHEMA_VERSION: %s = %d;\n", schemaVersionType, ir.version()); - indent(out, 0, "pub const SBE_SEMANTIC_VERSION: &str = \"%s\";\n\n", semanticVersion); + indent(out, 0, "pub const SBE_TEMPLATE_ID: %s = %d;\n\n", templateIdType, msgToken.id()); MessageCoderDef.generateEncoder(ir, out, msgToken, fields, groups, varData); MessageCoderDef.generateDecoder(ir, out, msgToken, fields, groups, varData); } } - libRsDef.generate(); + libRsDef.generate(ir); } String blockLengthType() From b385e9c794a2e6b1d28f3b335df893af272b0a67 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Wed, 13 Nov 2024 12:53:45 -0600 Subject: [PATCH 478/805] [C++] respect the package override option for C++ codecs and DTOs --- .../generation/TargetCodeGeneratorLoader.java | 12 ++- .../sbe/generation/cpp/CppDtoGenerator.java | 95 +++++++++++++--- .../sbe/generation/cpp/CppDtos.java | 2 +- .../sbe/generation/cpp/CppGenerator.java | 101 +++++++++++++++--- .../main/java/uk/co/real_logic/sbe/ir/Ir.java | 28 +++-- .../sbe/properties/DtosPropertyTest.java | 2 +- .../sbe/generation/cpp/CppGeneratorTest.java | 42 ++++++++ .../csharp/CSharpGeneratorTest.java | 81 ++++++++++++++ 8 files changed, 322 insertions(+), 41 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index c09152fabf..c979bede45 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -107,13 +107,21 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) final NamespaceOutputManager outputManager = new NamespaceOutputManager( outputDir, ir.applicableNamespace()); final boolean decodeUnknownEnumValues = Boolean.getBoolean(DECODE_UNKNOWN_ENUM_VALUES); + final boolean shouldSupportTypesPackageNames = Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE); - final CodeGenerator codecGenerator = new CppGenerator(ir, decodeUnknownEnumValues, precedenceChecks(), + final CodeGenerator codecGenerator = new CppGenerator( + ir, + decodeUnknownEnumValues, + precedenceChecks(), + shouldSupportTypesPackageNames, outputManager); if (Boolean.getBoolean(CPP_GENERATE_DTOS)) { - final CodeGenerator dtoGenerator = new CppDtoGenerator(ir, outputManager); + final CodeGenerator dtoGenerator = new CppDtoGenerator( + ir, + shouldSupportTypesPackageNames, + outputManager); return () -> { codecGenerator.generate(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 9c4064dbc9..b6f337a837 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -50,27 +50,65 @@ public class CppDtoGenerator implements CodeGenerator private final Ir ir; private final OutputManager outputManager; + private final boolean shouldSupportTypesPackageNames; + private final Map namespaceByType = new HashMap<>(); /** * Create a new C++ DTO {@link CodeGenerator}. * - * @param ir for the messages and types. - * @param outputManager for generating the DTOs to. + * @param ir for the messages and types. + * @param shouldSupportTypesPackageNames generator support for types in their own package. + * @param outputManager for generating the DTOs to. */ - public CppDtoGenerator(final Ir ir, final OutputManager outputManager) + public CppDtoGenerator( + final Ir ir, + final boolean shouldSupportTypesPackageNames, + final OutputManager outputManager) { Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); this.ir = ir; + this.shouldSupportTypesPackageNames = shouldSupportTypesPackageNames; this.outputManager = outputManager; } + private String[] fetchTypesPackageName(final Token token, final Ir ir) + { + if (!shouldSupportTypesPackageNames) + { + return ir.namespaces(); + } + + if (token.packageName() != null) + { + return Ir.getNamespaces(token.packageName()); + } + + return ir.namespaces(); + } + /** * {@inheritDoc} */ public void generate() throws IOException { + namespaceByType.clear(); + + if (shouldSupportTypesPackageNames) + { + for (final List tokens : ir.types()) + { + final Token token = tokens.get(0); + final String packageName = token.packageName(); + + if (packageName != null) + { + namespaceByType.put(token.applicableTypeName(), packageName); + } + } + } + generateDtosForTypes(); for (final List tokens : ir.messages()) @@ -116,13 +154,14 @@ public void generate() throws IOException final Set referencedTypes = generateTypesToIncludes(beginTypeTokensInSchema); referencedTypes.add(codecClassName); + final String[] namespaces = fetchTypesPackageName(msgToken, ir); out.append(generateDtoFileHeader( - ir.namespaces(), + namespaces, className, referencedTypes)); out.append(generateDocumentation(BASE_INDENT, msgToken)); classBuilder.appendTo(out); - out.append(CppUtil.closingBraces(ir.namespaces().length)); + out.append(CppUtil.closingBraces(namespaces.length)); out.append("#endif\n"); } } @@ -1732,7 +1771,8 @@ private void generateDtosForTypes() throws IOException private void generateComposite(final List tokens) throws IOException { - final String name = tokens.get(0).applicableTypeName(); + final Token token = tokens.get(0); + final String name = token.applicableTypeName(); final String className = formatDtoClassName(name); final String codecClassName = formatClassName(name); @@ -1741,8 +1781,9 @@ private void generateComposite(final List tokens) throws IOException final List compositeTokens = tokens.subList(1, tokens.size() - 1); final Set referencedTypes = generateTypesToIncludes(compositeTokens); referencedTypes.add(codecClassName); - out.append(generateDtoFileHeader(ir.namespaces(), className, referencedTypes)); - out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); + final String[] namespaces = fetchTypesPackageName(token, ir); + out.append(generateDtoFileHeader(namespaces, className, referencedTypes)); + out.append(generateDocumentation(BASE_INDENT, token)); final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT); @@ -1754,14 +1795,15 @@ private void generateComposite(final List tokens) throws IOException codecClassName + "::sbeSchemaVersion()", BASE_INDENT + INDENT); classBuilder.appendTo(out); - out.append(CppUtil.closingBraces(ir.namespaces().length)); + out.append(CppUtil.closingBraces(namespaces.length)); out.append("#endif\n"); } } private void generateChoiceSet(final List tokens) throws IOException { - final String name = tokens.get(0).applicableTypeName(); + final Token token = tokens.get(0); + final String name = token.applicableTypeName(); final String className = formatDtoClassName(name); final String codecClassName = formatClassName(name); @@ -1770,7 +1812,8 @@ private void generateChoiceSet(final List tokens) throws IOException final List setTokens = tokens.subList(1, tokens.size() - 1); final Set referencedTypes = generateTypesToIncludes(setTokens); referencedTypes.add(codecClassName); - out.append(generateDtoFileHeader(ir.namespaces(), className, referencedTypes)); + final String[] namespaces = fetchTypesPackageName(token, ir); + out.append(generateDtoFileHeader(namespaces, className, referencedTypes)); out.append(generateDocumentation(BASE_INDENT, tokens.get(0))); final ClassBuilder classBuilder = new ClassBuilder(className, BASE_INDENT); @@ -1780,7 +1823,7 @@ private void generateChoiceSet(final List tokens) throws IOException generateChoiceSetEncodeWith(classBuilder, className, codecClassName, setTokens, BASE_INDENT + INDENT); classBuilder.appendTo(out); - out.append(CppUtil.closingBraces(ir.namespaces().length)); + out.append(CppUtil.closingBraces(namespaces.length)); out.append("#endif\n"); } } @@ -1965,7 +2008,7 @@ private static CharSequence typeWithFieldOptionality( } } - private static CharSequence generateDtoFileHeader( + private CharSequence generateDtoFileHeader( final CharSequence[] namespaces, final String className, final Collection typesToInclude) @@ -2010,6 +2053,32 @@ private static CharSequence generateDtoFileHeader( sb.append(String.join(" {\nnamespace ", namespaces)); sb.append(" {\n\n"); + if (shouldSupportTypesPackageNames && typesToInclude != null && !typesToInclude.isEmpty()) + { + final Set namespacesToUse = namespaceByType + .entrySet() + .stream() + .filter(e -> typesToInclude.contains(e.getKey())) + .map(Map.Entry::getValue) + .collect(Collectors.toSet()); + + // remove the current namespace + namespacesToUse.remove(String.join(".", namespaces)); + + for (final String namespace : namespacesToUse) + { + sb + .append("using namespace ") + .append(namespace.replaceAll("\\.", "::")) + .append(";\n"); + } + + if (!namespacesToUse.isEmpty()) + { + sb.append("\n"); + } + } + return sb; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java index 09dbfb052f..6e59b6dd06 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java @@ -31,6 +31,6 @@ public class CppDtos implements TargetCodeGenerator */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new CppDtoGenerator(ir, new NamespaceOutputManager(outputDir, ir.applicableNamespace())); + return new CppDtoGenerator(ir, false, new NamespaceOutputManager(outputDir, ir.applicableNamespace())); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index cc6921a0bb..8533a4df84 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -33,6 +33,7 @@ import java.io.Writer; import java.nio.ByteOrder; import java.util.*; +import java.util.stream.Collectors; import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; @@ -58,6 +59,8 @@ public class CppGenerator implements CodeGenerator private final boolean shouldDecodeUnknownEnumValues; private final PrecedenceChecks precedenceChecks; private final String precedenceChecksFlagName; + private final boolean shouldSupportTypesPackageNames; + private final Map namespaceByType = new HashMap<>(); /** * Create a new Cpp language {@link CodeGenerator}. @@ -72,6 +75,7 @@ public CppGenerator(final Ir ir, final boolean shouldDecodeUnknownEnumValues, fi ir, shouldDecodeUnknownEnumValues, PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + false, outputManager ); } @@ -79,15 +83,17 @@ public CppGenerator(final Ir ir, final boolean shouldDecodeUnknownEnumValues, fi /** * Create a new Go language {@link CodeGenerator}. * - * @param ir for the messages and types. - * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. - * @param precedenceChecks whether and how to generate field precedence checks. - * @param outputManager for generating the codecs to. + * @param ir for the messages and types. + * @param shouldDecodeUnknownEnumValues generate support for unknown enum values when decoding. + * @param precedenceChecks whether and how to generate field precedence checks. + * @param shouldSupportTypesPackageNames generator support for types in their own package. + * @param outputManager for generating the codecs to. */ public CppGenerator( final Ir ir, final boolean shouldDecodeUnknownEnumValues, final PrecedenceChecks precedenceChecks, + final boolean shouldSupportTypesPackageNames, final OutputManager outputManager) { Verify.notNull(ir, "ir"); @@ -97,6 +103,7 @@ public CppGenerator( this.shouldDecodeUnknownEnumValues = shouldDecodeUnknownEnumValues; this.precedenceChecks = precedenceChecks; this.precedenceChecksFlagName = precedenceChecks.context().precedenceChecksFlagName(); + this.shouldSupportTypesPackageNames = shouldSupportTypesPackageNames; this.outputManager = outputManager; } @@ -140,6 +147,21 @@ private List generateTypeStubs() throws IOException return typesToInclude; } + private String[] fetchTypesPackageName(final Token token, final Ir ir) + { + if (!shouldSupportTypesPackageNames) + { + return ir.namespaces(); + } + + if (token.packageName() != null) + { + return Ir.getNamespaces(token.packageName()); + } + + return ir.namespaces(); + } + private List generateTypesToIncludes(final List tokens) { final List typesToInclude = new ArrayList<>(); @@ -167,6 +189,22 @@ private List generateTypesToIncludes(final List tokens) */ public void generate() throws IOException { + namespaceByType.clear(); + + if (shouldSupportTypesPackageNames) + { + for (final List tokens : ir.types()) + { + final Token token = tokens.get(0); + final String packageName = token.packageName(); + + if (packageName != null) + { + namespaceByType.put(token.applicableTypeName(), packageName); + } + } + } + generateMessageHeaderStub(); final List typesToInclude = generateTypeStubs(); @@ -192,7 +230,8 @@ public void generate() throws IOException final List varData = new ArrayList<>(); collectVarData(messageBody, i, varData); - out.append(generateFileHeader(ir.namespaces(), className, typesToInclude)); + final String[] namespaces = fetchTypesPackageName(msgToken, ir); + out.append(generateFileHeader(namespaces, className, typesToInclude)); out.append(generateClassDeclaration(className)); out.append(generateMessageFlyweightCode(className, msgToken, fieldPrecedenceModel)); out.append(generateFullyEncodedCheck(fieldPrecedenceModel)); @@ -205,7 +244,7 @@ public void generate() throws IOException sb.append(generateMessageLength(groups, varData, BASE_INDENT)); sb.append("};\n"); generateLookupTableDefinitions(sb, className, fieldPrecedenceModel); - sb.append(CppUtil.closingBraces(ir.namespaces().length)).append("#endif\n"); + sb.append(CppUtil.closingBraces(namespaces.length)).append("#endif\n"); out.append(sb); } } @@ -1277,7 +1316,8 @@ private void generateChoiceSet(final List tokens) throws IOException try (Writer out = outputManager.createOutput(bitSetName)) { - out.append(generateFileHeader(ir.namespaces(), bitSetName, null)); + final String[] namespaces = fetchTypesPackageName(token, ir); + out.append(generateFileHeader(namespaces, bitSetName, null)); out.append(generateClassDeclaration(bitSetName)); out.append(generateFixedFlyweightCode(bitSetName, token.encodedLength())); @@ -1322,7 +1362,7 @@ private void generateChoiceSet(final List tokens) throws IOException out.append(generateChoices(bitSetName, tokens.subList(1, tokens.size() - 1))); out.append(generateChoicesDisplay(bitSetName, tokens.subList(1, tokens.size() - 1))); out.append("};\n"); - out.append(CppUtil.closingBraces(ir.namespaces().length)).append("#endif\n"); + out.append(CppUtil.closingBraces(namespaces.length)).append("#endif\n"); } } @@ -1333,7 +1373,8 @@ private void generateEnum(final List tokens) throws IOException try (Writer out = outputManager.createOutput(enumName)) { - out.append(generateEnumFileHeader(ir.namespaces(), enumName)); + final String[] namespaces = fetchTypesPackageName(enumToken, ir); + out.append(generateEnumFileHeader(namespaces, enumName)); out.append(generateEnumDeclaration(enumName)); out.append(generateEnumValues(tokens.subList(1, tokens.size() - 1), enumToken)); @@ -1343,29 +1384,31 @@ private void generateEnum(final List tokens) throws IOException out.append(generateEnumDisplay(tokens.subList(1, tokens.size() - 1), enumToken)); out.append("};\n\n"); - out.append(CppUtil.closingBraces(ir.namespaces().length)).append("\n#endif\n"); + out.append(CppUtil.closingBraces(namespaces.length)).append("\n#endif\n"); } } private void generateComposite(final List tokens) throws IOException { - final String compositeName = formatClassName(tokens.get(0).applicableTypeName()); + final Token token = tokens.get(0); + final String compositeName = formatClassName(token.applicableTypeName()); try (Writer out = outputManager.createOutput(compositeName)) { - out.append(generateFileHeader(ir.namespaces(), compositeName, + final String[] namespaces = fetchTypesPackageName(token, ir); + out.append(generateFileHeader(namespaces, compositeName, generateTypesToIncludes(tokens.subList(1, tokens.size() - 1)))); out.append(generateClassDeclaration(compositeName)); - out.append(generateFixedFlyweightCode(compositeName, tokens.get(0).encodedLength())); + out.append(generateFixedFlyweightCode(compositeName, token.encodedLength())); out.append(generateCompositePropertyElements( compositeName, tokens.subList(1, tokens.size() - 1), BASE_INDENT)); out.append(generateCompositeDisplay( - tokens.get(0).applicableTypeName(), tokens.subList(1, tokens.size() - 1))); + token.applicableTypeName(), tokens.subList(1, tokens.size() - 1))); out.append("};\n\n"); - out.append(CppUtil.closingBraces(ir.namespaces().length)).append("\n#endif\n"); + out.append(CppUtil.closingBraces(namespaces.length)).append("\n#endif\n"); } } @@ -1614,7 +1657,7 @@ private static CharSequence generateTypeFieldNotPresentCondition(final int since sinceVersion); } - private static CharSequence generateFileHeader( + private CharSequence generateFileHeader( final CharSequence[] namespaces, final String className, final List typesToInclude) @@ -1720,6 +1763,32 @@ private static CharSequence generateFileHeader( sb.append(String.join(" {\nnamespace ", namespaces)); sb.append(" {\n\n"); + if (shouldSupportTypesPackageNames && typesToInclude != null && !typesToInclude.isEmpty()) + { + final Set namespacesToUse = namespaceByType + .entrySet() + .stream() + .filter(e -> typesToInclude.contains(e.getKey())) + .map(Map.Entry::getValue) + .collect(Collectors.toSet()); + + // remove the current namespace + namespacesToUse.remove(String.join(".", namespaces)); + + for (final String namespace : namespacesToUse) + { + sb + .append("using namespace ") + .append(namespace.replaceAll("\\.", "::")) + .append(";\n"); + } + + if (!namespacesToUse.isEmpty()) + { + sb.append("\n"); + } + } + return sb; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java index 3587a8a05f..87eba20050 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java @@ -79,14 +79,7 @@ public Ir( captureTypes(headerTokens, 0, headerTokens.size() - 1); - if ("true".equals(System.getProperty(SbeTool.CPP_NAMESPACES_COLLAPSE))) - { - this.namespaces = new String[]{ (namespaceName == null ? packageName : namespaceName).replace(".", "_") }; - } - else - { - this.namespaces = Pattern.compile("\\.").split(namespaceName == null ? packageName : namespaceName); - } + this.namespaces = Ir.getNamespaces(namespaceName == null ? packageName : namespaceName); } /** @@ -280,6 +273,25 @@ else if (signal.name().startsWith("END_")) } } + /** + * Construct an array of namespace strings based on the supplied namespaceName, + * accounting for the CPP_NAMESPACES_COLLAPSE option. + * + * @param namespaceName a namespace name that may contain period-separated nested namespaces + * @return an array of nested namespace strings + */ + public static String[] getNamespaces(final String namespaceName) + { + if ("true".equals(System.getProperty(SbeTool.CPP_NAMESPACES_COLLAPSE))) + { + return new String[]{ namespaceName.replace(".", "_") }; + } + else + { + return Pattern.compile("\\.").split(namespaceName); + } + } + private void captureTypes(final List tokens, final int beginIndex, final int endIndex) { for (int i = beginIndex; i <= endIndex; i++) diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index 7cb1aa03a1..8517894340 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -214,7 +214,7 @@ void cppDtoEncodeShouldBeTheInverseOfDtoDecode( { new CppGenerator(encodedMessage.ir(), true, outputManager) .generate(); - new CppDtoGenerator(encodedMessage.ir(), outputManager) + new CppDtoGenerator(encodedMessage.ir(), false, outputManager) .generate(); } catch (final Exception generationException) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index 8b3575e0ab..b8c969c8b8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -18,6 +18,7 @@ import org.agrona.generation.StringWriterOutputManager; import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; @@ -28,6 +29,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; class CppGeneratorTest @@ -72,4 +74,44 @@ void shouldUseConstexprWhenInitializingSemanticVersion() throws Exception assertThat(source, containsString("static constexpr const char* SBE_SEMANTIC_VERSION = \"5.2\"")); } } + + @Test + void dtosShouldReferenceTypesInDifferentPackages() throws Exception + { + try (InputStream in = Tests.getLocalResource("explicit-package-test-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CppGenerator generator = new CppGenerator( + ir, + false, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + true, + outputManager); + generator.generate(); + + final CppDtoGenerator dtoGenerator = new CppDtoGenerator(ir, true, outputManager); + dtoGenerator.generate(); + + final java.util.Map sources = outputManager.getSources(); + assertNotNull(sources.get("test.message.schema.TestMessageDto")); + assertNotNull(sources.get("test.message.schema.MessageHeaderDto")); + assertNotNull(sources.get("test.message.schema.CarDto")); + assertNotNull(sources.get("test.message.schema.EngineDto")); + + String source; + + source = sources.get("test.message.schema.TestMessageDto").toString(); + assertThat(source, containsString("using namespace outside::schema;")); + + source = sources.get("test.message.schema.TestMessage").toString(); + assertThat(source, containsString("using namespace outside::schema;")); + assertThat(source, containsString("using namespace test::message::schema::common;")); + } + } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java new file mode 100644 index 0000000000..3cc8fc3635 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013-2024 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.csharp; + +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +class CSharpGeneratorTest +{ + @Test + void dtosShouldReferenceTypesInDifferentPackages() throws Exception + { + try (InputStream in = Tests.getLocalResource("explicit-package-test-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CSharpGenerator generator = new CSharpGenerator(ir, outputManager); + generator.generate(); + + final CSharpDtoGenerator dtoGenerator = new CSharpDtoGenerator(ir, outputManager); + dtoGenerator.generate(); + + final java.util.Map sources = outputManager.getSources(); + /* + sources.forEach((s, cs) -> + { + System.out.println("----------------"); + System.out.println("FILE :: " + s); + System.out.println("----------------"); + System.out.println(cs); + System.out.println("----------------"); + }); + */ + + assertNotNull(sources.get("test.message.schema.TestMessageDto")); + assertNotNull(sources.get("test.message.schema.MessageHeaderDto")); + //assertNotNull(sources.get("test.message.schema.common.CarDto")); + //assertNotNull(sources.get("test.message.schema.common.EngineDto")); + assertNotNull(sources.get("test.message.schema.CarDto")); + assertNotNull(sources.get("test.message.schema.EngineDto")); + + /* + assertNotNull(sources.get("outside.schema.FuelSpecDto")); + assertNotNull(sources.get("outside.schema.DaysDto")); + assertNotNull(sources.get("outside.schema.FuelTypeDto")); + + assertNotNull(compile("test.message.schema.TestMessageDto")); + assertNotNull(compile("test.message.schema.common.CarDto")); + assertNotNull(compile("outside.schema.FuelSpecDto")); + */ + } + } +} From 4a31cc0b18f95b4de8b340010aa0b0d093459607 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Wed, 13 Nov 2024 18:21:45 -0600 Subject: [PATCH 479/805] [C#] respect the package override option for C# codecs and DTOs --- .../sbe/generation/csharp/CSharp.java | 10 +++- .../generation/csharp/CSharpDtoGenerator.java | 52 ++++++++++++++-- .../sbe/generation/csharp/CSharpDtos.java | 2 +- .../generation/csharp/CSharpGenerator.java | 60 +++++++++++++++---- .../sbe/generation/csharp/CSharpUtil.java | 25 +++++++- .../sbe/properties/DtosPropertyTest.java | 2 +- .../csharp/CSharpGeneratorTest.java | 38 +++++------- 7 files changed, 146 insertions(+), 43 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java index 8a88cbce56..f13b9cfab6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java @@ -21,6 +21,8 @@ import uk.co.real_logic.sbe.generation.TargetCodeGeneratorLoader; import uk.co.real_logic.sbe.ir.Ir; +import static uk.co.real_logic.sbe.SbeTool.TYPES_PACKAGE_OVERRIDE; + /** * {@link CodeGenerator} factory for the CSharp target programming language. */ @@ -33,15 +35,19 @@ public class CSharp implements TargetCodeGenerator */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { + final boolean shouldSupportTypesPackageNames = Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE); final CSharpGenerator flyweightGenerator = new CSharpGenerator( ir, TargetCodeGeneratorLoader.precedenceChecks(), + shouldSupportTypesPackageNames, new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); if (GENERATE_DTOS) { - final CSharpDtoGenerator dtoGenerator = - new CSharpDtoGenerator(ir, new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); + final CSharpDtoGenerator dtoGenerator = new CSharpDtoGenerator( + ir, + shouldSupportTypesPackageNames, + new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); return () -> { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index ad2e3068c7..b5225caa67 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -30,7 +30,9 @@ import java.io.IOException; import java.io.Writer; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Predicate; import static uk.co.real_logic.sbe.generation.csharp.CSharpUtil.*; @@ -49,27 +51,65 @@ public class CSharpDtoGenerator implements CodeGenerator private final Ir ir; private final OutputManager outputManager; + private final boolean shouldSupportTypesPackageNames; + private final Set packageNameByTypes = new HashSet<>(); /** * Create a new C# DTO {@link CodeGenerator}. * * @param ir for the messages and types. + * @param shouldSupportTypesPackageNames generator support for types in their own package. * @param outputManager for generating the DTOs to. */ - public CSharpDtoGenerator(final Ir ir, final OutputManager outputManager) + public CSharpDtoGenerator( + final Ir ir, + final boolean shouldSupportTypesPackageNames, + final OutputManager outputManager) { Verify.notNull(ir, "ir"); Verify.notNull(outputManager, "outputManager"); this.ir = ir; + this.shouldSupportTypesPackageNames = shouldSupportTypesPackageNames; this.outputManager = outputManager; } + private String fetchTypesPackageName(final Token token, final Ir ir) + { + if (!shouldSupportTypesPackageNames) + { + return ir.applicableNamespace(); + } + + if (token.packageName() != null) + { + return token.packageName(); + } + + return ir.applicableNamespace(); + } + /** * {@inheritDoc} */ public void generate() throws IOException { + packageNameByTypes.clear(); + + if (shouldSupportTypesPackageNames) + { + for (final List tokens : ir.types()) + { + final Token token = tokens.get(0); + final String packageName = token.packageName(); + + if (packageName != null) + { + packageNameByTypes.add(packageName); + } + } + } + generateDtosForTypes(); for (final List tokens : ir.messages()) @@ -110,7 +150,8 @@ public void generate() throws IOException try (Writer out = outputManager.createOutput(dtoClassName)) { out.append(generateFileHeader( - ir.applicableNamespace(), + fetchTypesPackageName(msgToken, ir), + packageNameByTypes, "#nullable enable\n\n", "using System.Collections.Generic;\n", "using System.Linq;\n")); @@ -1360,13 +1401,16 @@ private void generateDtosForTypes() throws IOException private void generateComposite(final List tokens) throws IOException { - final String name = tokens.get(0).applicableTypeName(); + final Token token = tokens.get(0); + final String name = token.applicableTypeName(); final String className = formatDtoClassName(name); final String codecClassName = formatClassName(name); try (Writer out = outputManager.createOutput(className)) { - out.append(generateFileHeader(ir.applicableNamespace(), + out.append(generateFileHeader( + fetchTypesPackageName(token, ir), + packageNameByTypes, "#nullable enable\n", "using System.Collections.Generic;\n", "using System.Linq;\n")); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java index 4fc0cc513f..d924e45b53 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java @@ -30,6 +30,6 @@ public class CSharpDtos implements TargetCodeGenerator */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new CSharpDtoGenerator(ir, new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); + return new CSharpDtoGenerator(ir, false, new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 8c06689da8..af9979879a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -60,6 +60,8 @@ public class CSharpGenerator implements CodeGenerator private final OutputManager outputManager; private final PrecedenceChecks precedenceChecks; private final String precedenceChecksFlagName; + private final boolean shouldSupportTypesPackageNames; + private final Set packageNameByTypes = new HashSet<>(); /** * Create a new C# language {@link CodeGenerator}. @@ -72,6 +74,7 @@ public CSharpGenerator(final Ir ir, final OutputManager outputManager) this( ir, PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + false, outputManager ); } @@ -79,13 +82,15 @@ public CSharpGenerator(final Ir ir, final OutputManager outputManager) /** * Create a new C# language {@link CodeGenerator}. * - * @param ir for the messages and types. - * @param precedenceChecks whether and how to perform field precedence checks. - * @param outputManager for generating the codecs to. + * @param ir for the messages and types. + * @param precedenceChecks whether and how to perform field precedence checks. + * @param shouldSupportTypesPackageNames generator support for types in their own package. + * @param outputManager for generating the codecs to. */ public CSharpGenerator( final Ir ir, final PrecedenceChecks precedenceChecks, + final boolean shouldSupportTypesPackageNames, final OutputManager outputManager) { Verify.notNull(ir, "ir"); @@ -94,6 +99,7 @@ public CSharpGenerator( this.ir = ir; this.precedenceChecks = precedenceChecks; this.precedenceChecksFlagName = precedenceChecks.context().precedenceChecksFlagName(); + this.shouldSupportTypesPackageNames = shouldSupportTypesPackageNames; this.outputManager = outputManager; } @@ -138,11 +144,42 @@ public void generateTypeStubs() throws IOException } } + private String fetchTypesPackageName(final Token token, final Ir ir) + { + if (!shouldSupportTypesPackageNames) + { + return ir.applicableNamespace(); + } + + if (token.packageName() != null) + { + return token.packageName(); + } + + return ir.applicableNamespace(); + } + /** * {@inheritDoc} */ public void generate() throws IOException { + packageNameByTypes.clear(); + + if (shouldSupportTypesPackageNames) + { + for (final List tokens : ir.types()) + { + final Token token = tokens.get(0); + final String packageName = token.packageName(); + + if (packageName != null) + { + packageNameByTypes.add(packageName); + } + } + } + generateMessageHeaderStub(); generateTypeStubs(); @@ -164,7 +201,7 @@ public void generate() throws IOException final List varData = new ArrayList<>(); collectVarData(messageBody, offset, varData); - out.append(generateFileHeader(ir.applicableNamespace())); + out.append(generateFileHeader(fetchTypesPackageName(msgToken, ir), packageNameByTypes)); out.append(generateDocumentation(BASE_INDENT, msgToken)); out.append(generateClassDeclaration(className)); out.append(generateMessageFlyweightCode(className, msgToken, fieldPrecedenceModel, BASE_INDENT)); @@ -662,7 +699,7 @@ private void generateBitSet(final List tokens) throws IOException try (Writer out = outputManager.createOutput(enumName)) { - out.append(generateFileHeader(ir.applicableNamespace())); + out.append(generateFileHeader(fetchTypesPackageName(enumToken, ir), packageNameByTypes)); out.append(generateDocumentation(INDENT, enumToken)); final String enumPrimitiveType = cSharpTypeName(enumToken.encoding().primitiveType()); out.append(generateEnumDeclaration(enumName, enumPrimitiveType, true)); @@ -682,7 +719,7 @@ private void generateEnum(final List tokens) throws IOException try (Writer out = outputManager.createOutput(enumName)) { - out.append(generateFileHeader(ir.applicableNamespace())); + out.append(generateFileHeader(fetchTypesPackageName(enumToken, ir), packageNameByTypes)); out.append(generateDocumentation(INDENT, enumToken)); final String enumPrimitiveType = cSharpTypeName(enumToken.encoding().primitiveType()); out.append(generateEnumDeclaration(enumName, enumPrimitiveType, false)); @@ -696,14 +733,15 @@ private void generateEnum(final List tokens) throws IOException private void generateComposite(final List tokens) throws IOException { - final String compositeName = CSharpUtil.formatClassName(tokens.get(0).applicableTypeName()); + final Token token = tokens.get(0); + final String compositeName = CSharpUtil.formatClassName(token.applicableTypeName()); try (Writer out = outputManager.createOutput(compositeName)) { - out.append(generateFileHeader(ir.applicableNamespace())); - out.append(generateDocumentation(INDENT, tokens.get(0))); + out.append(generateFileHeader(fetchTypesPackageName(token, ir), packageNameByTypes)); + out.append(generateDocumentation(INDENT, token)); out.append(generateClassDeclaration(compositeName)); - out.append(generateFixedFlyweightCode(tokens.get(0).encodedLength())); + out.append(generateFixedFlyweightCode(token.encodedLength())); out.append(generateCompositePropertyElements(tokens.subList(1, tokens.size() - 1), BASE_INDENT)); out.append(generateCompositeDisplay(tokens)); @@ -798,7 +836,7 @@ private void generateMetaAttributeEnum() throws IOException { try (Writer out = outputManager.createOutput(META_ATTRIBUTE_ENUM)) { - out.append(generateFileHeader(ir.applicableNamespace())); + out.append(generateFileHeader(ir.applicableNamespace(), null)); out.append( INDENT + "public enum MetaAttribute\n" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index 31c4444feb..a80ae7a295 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -24,6 +24,7 @@ import java.util.EnumMap; import java.util.Map; +import java.util.Set; /** * Utilities for mapping between IR and the C# language. @@ -87,8 +88,26 @@ static String generateLiteral(final PrimitiveType type, final String value) return literal; } - static CharSequence generateFileHeader(final String packageName, final String... topLevelStatements) + static CharSequence generateFileHeader( + final String packageName, + final Set packageNamesByTypes, + final String... topLevelStatements) { + final StringBuilder additionalUsingBuilder = new StringBuilder(); + if (packageNamesByTypes != null && !packageNamesByTypes.isEmpty()) + { + packageNamesByTypes + .stream() + .filter(p -> !packageName.equals(p)) + .forEach(p -> + additionalUsingBuilder + .append("using ") + .append(formatNamespace(p)) + .append(";\n")); + + additionalUsingBuilder.append("\n"); + } + return String.format( "// \n" + "// Generated SBE (Simple Binary Encoding) message codec\n" + @@ -98,9 +117,11 @@ static CharSequence generateFileHeader(final String packageName, final String... "using System;\n" + "using System.Text;\n" + "using Org.SbeTool.Sbe.Dll;\n\n" + - "namespace %2$s\n" + + "%2$s" + + "namespace %3$s\n" + "{\n", String.join("", topLevelStatements), + additionalUsingBuilder, formatNamespace(packageName)); } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index 8517894340..a8341e578c 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -152,7 +152,7 @@ void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( { new CSharpGenerator(encodedMessage.ir(), outputManager) .generate(); - new CSharpDtoGenerator(encodedMessage.ir(), outputManager) + new CSharpDtoGenerator(encodedMessage.ir(), false, outputManager) .generate(); } catch (final Exception generationException) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java index 3cc8fc3635..295ddd293b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java @@ -18,6 +18,7 @@ import org.agrona.generation.StringWriterOutputManager; import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; @@ -25,6 +26,8 @@ import java.io.InputStream; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; @@ -42,40 +45,31 @@ void dtosShouldReferenceTypesInDifferentPackages() throws Exception final StringWriterOutputManager outputManager = new StringWriterOutputManager(); outputManager.setPackageName(ir.applicableNamespace()); - final CSharpGenerator generator = new CSharpGenerator(ir, outputManager); + final CSharpGenerator generator = new CSharpGenerator( + ir, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + true, + outputManager); generator.generate(); - final CSharpDtoGenerator dtoGenerator = new CSharpDtoGenerator(ir, outputManager); + final CSharpDtoGenerator dtoGenerator = new CSharpDtoGenerator(ir, true, outputManager); dtoGenerator.generate(); final java.util.Map sources = outputManager.getSources(); - /* - sources.forEach((s, cs) -> - { - System.out.println("----------------"); - System.out.println("FILE :: " + s); - System.out.println("----------------"); - System.out.println(cs); - System.out.println("----------------"); - }); - */ assertNotNull(sources.get("test.message.schema.TestMessageDto")); assertNotNull(sources.get("test.message.schema.MessageHeaderDto")); - //assertNotNull(sources.get("test.message.schema.common.CarDto")); - //assertNotNull(sources.get("test.message.schema.common.EngineDto")); assertNotNull(sources.get("test.message.schema.CarDto")); assertNotNull(sources.get("test.message.schema.EngineDto")); - /* - assertNotNull(sources.get("outside.schema.FuelSpecDto")); - assertNotNull(sources.get("outside.schema.DaysDto")); - assertNotNull(sources.get("outside.schema.FuelTypeDto")); + String source; - assertNotNull(compile("test.message.schema.TestMessageDto")); - assertNotNull(compile("test.message.schema.common.CarDto")); - assertNotNull(compile("outside.schema.FuelSpecDto")); - */ + source = sources.get("test.message.schema.TestMessageDto").toString(); + assertThat(source, containsString("using Outside.Schema;")); + + source = sources.get("test.message.schema.TestMessage").toString(); + assertThat(source, containsString("using Outside.Schema;")); + assertThat(source, containsString("using Test.Message.Schema.Common;")); } } } From ea52edd5aa63ddd6a70498a22331551bfb4e65b1 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 15 Nov 2024 15:38:43 +0000 Subject: [PATCH 480/805] [C#] Test package override support compiles. Co-authored-by: Nate Bradac We've updated the C# generation tasks to include a schema that uses explicit package names on `types` blocks. We found processing this schema produces some build errors (albeit not affecting the exit code): ``` > Task :generateCSharpTestCodecs [Error] explicit-package-test-schema.xml:17:49: cvc-complex-type.3.2.2: Attribute 'package' is not allowed to appear in element 'types'. [Error] explicit-package-test-schema.xml:30:37: cvc-complex-type.3.2.2: Attribute 'package' is not allowed to appear in element 'types'. > Task :generateCSharpTestDtos [Error] explicit-package-test-schema.xml:17:49: cvc-complex-type.3.2.2: Attribute 'package' is not allowed to appear in element 'types'. [Error] explicit-package-test-schema.xml:30:37: cvc-complex-type.3.2.2: Attribute 'package' is not allowed to appear in element 'types'. ``` Therefore, we've put the new generation under tasks that don't validate against an XSD. We considered creating a new version of the XSD that properly describes what we support; however, the licence on the XSD seems prohibitive. --- .gitignore | 1 + build.gradle | 33 +++++++++++++++++-- .../sbe/generation/csharp/CSharpDtos.java | 9 ++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 4e46271843..fd7d72201b 100644 --- a/.gitignore +++ b/.gitignore @@ -94,6 +94,7 @@ csharp/sbe-generated/since-deprecated csharp/sbe-generated/order_check csharp/sbe-generated/mktdata/*.cs csharp/sbe-generated/uk_co_real_logic_sbe_benchmarks_fix +csharp/sbe-generated/test_message_schema csharp/sbe-tests/*.sbe csharp/nuget/ csharp/csharp.sln.DotSettings.user diff --git a/build.gradle b/build.gradle index 40bbbbef9c..9641c9972f 100644 --- a/build.gradle +++ b/build.gradle @@ -894,7 +894,8 @@ tasks.register('generateCSharpTestCodecs', JavaExec) { 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', 'sbe.xinclude.aware': 'true', 'sbe.validation.xsd': validationXsdPath, - 'sbe.generate.precedence.checks': 'true') + 'sbe.generate.precedence.checks': 'true', + 'sbe.types.package.override': 'true') args = ['sbe-tool/src/test/resources/FixBinary.xml', 'sbe-tool/src/test/resources/issue435.xml', 'sbe-tool/src/test/resources/issue483.xml', @@ -912,15 +913,41 @@ tasks.register('generateCSharpTestDtos', JavaExec) { 'sbe.output.dir': 'csharp/sbe-generated', 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharpDtos', 'sbe.xinclude.aware': 'true', - 'sbe.validation.xsd': validationXsdPath) + 'sbe.validation.xsd': validationXsdPath, + 'sbe.types.package.override': 'true') args = ['sbe-samples/src/main/resources/example-extension-schema.xml'] } +tasks.register('generateCSharpExplicitPackageOverrideCodecs', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'csharp/sbe-generated', + 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', + 'sbe.xinclude.aware': 'true', + 'sbe.generate.precedence.checks': 'true', + 'sbe.types.package.override': 'true') + args = ['sbe-tool/src/test/resources/explicit-package-test-schema.xml'] +} + +tasks.register('generateCSharpExplicitPackageOverrideDtos', JavaExec) { + mainClass.set('uk.co.real_logic.sbe.SbeTool') + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + systemProperties( + 'sbe.output.dir': 'csharp/sbe-generated', + 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharpDtos', + 'sbe.xinclude.aware': 'true', + 'sbe.types.package.override': 'true') + args = ['sbe-tool/src/test/resources/explicit-package-test-schema.xml'] +} + tasks.register('generateCSharpCodecs') { description = 'Generate csharp codecs' dependsOn 'generateCSharpTestCodecs', 'generateCSharpTestDtos', - 'generateCSharpCodecsWithXIncludes' + 'generateCSharpCodecsWithXIncludes', + 'generateCSharpExplicitPackageOverrideCodecs', + 'generateCSharpExplicitPackageOverrideDtos' } tasks.register('generateJavaIrCodecs', JavaExec) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java index d924e45b53..118b8e8d45 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java @@ -20,6 +20,8 @@ import uk.co.real_logic.sbe.generation.TargetCodeGenerator; import uk.co.real_logic.sbe.ir.Ir; +import static uk.co.real_logic.sbe.SbeTool.TYPES_PACKAGE_OVERRIDE; + /** * {@link CodeGenerator} factory for CSharp DTOs. */ @@ -30,6 +32,11 @@ public class CSharpDtos implements TargetCodeGenerator */ public CodeGenerator newInstance(final Ir ir, final String outputDir) { - return new CSharpDtoGenerator(ir, false, new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace())); + final boolean shouldSupportTypesPackageNames = Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE); + return new CSharpDtoGenerator( + ir, + shouldSupportTypesPackageNames, + new CSharpNamespaceOutputManager(outputDir, ir.applicableNamespace()) + ); } } From 8596f68decddda4783a592540ad9afc38eaf3069 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:05:30 +0100 Subject: [PATCH 481/805] [Java] Upgrade to jqwik 1.9.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c41a71d0e6..6e026b7e16 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ gradle = "8.10.2" agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23.1, 2.0[", require = "1.23.1" } } mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.2" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } -jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.0" } +jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.1" } json = { group = "org.json", name = "json", version = "20240303" } jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "jmh" } jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "jmh" } From b8c7056e96d208a17b4a2756814293b4b63a686b Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:06:31 +0100 Subject: [PATCH 482/805] [Java] Upgrade to Gradle 8.11. --- gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6e026b7e16..e0417abadb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ agrona = "1.23.1" checkstyle = "10.20.1" junit = "5.11.3" jmh = "1.37" -gradle = "8.10.2" +gradle = "8.11" [libraries] agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23.1, 2.0[", require = "1.23.1" } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 79eb9d003f..7cf748e743 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 7079133f0e0a7e547b5ce4ed777b393327329fb3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 26 Nov 2024 10:25:45 +0100 Subject: [PATCH 483/805] [Java] Upgrade to Gradle 8.11.1. --- gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e0417abadb..a21be421a2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ agrona = "1.23.1" checkstyle = "10.20.1" junit = "5.11.3" jmh = "1.37" -gradle = "8.11" +gradle = "8.11.1" [libraries] agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23.1, 2.0[", require = "1.23.1" } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7cf748e743..c1d5e01859 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 8af808ca64779bf722e196fa04e29a4180bad845 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 27 Nov 2024 13:07:37 +0000 Subject: [PATCH 484/805] [Java] Preserve byte order throughout IR transformations. Previously, the IrDecoder looked at the message header's BEGIN_COMPOSITE token to determine byte order; however, IrEncoder does not write the schema's byte order on tokens like these. Now, the IrDecoder finds the first real ENCODING token and reads the byte order from that. --- .../uk/co/real_logic/sbe/ir/IrDecoder.java | 11 ++++++- .../sbe/ir/BasicXmlIrGenerationTest.java | 30 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index b7da2ead1c..4db9e04a99 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -126,7 +126,16 @@ public Ir decode() i = captureHeader(tokens); } - final ByteOrder byteOrder = !tokens.isEmpty() ? tokens.get(0).encoding().byteOrder() : null; + ByteOrder byteOrder = null; + for (int j = 0; j < tokens.size(); j++) + { + if (tokens.get(j).signal() == Signal.ENCODING) + { + byteOrder = tokens.get(j).encoding().byteOrder(); + break; + } + } + final Ir ir = new Ir( irPackageName, irNamespaceName, irId, irVersion, null, semanticVersion, byteOrder, irHeader); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java index 7f89f2e18d..f3509f7d97 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package uk.co.real_logic.sbe.ir; -import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; +import org.junit.jupiter.api.Test; import java.io.InputStream; +import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.List; @@ -308,4 +310,30 @@ void shouldGenerateIrForMessageWithVariableLengthFieldWithEmbeddedLength() throw assertThat(tokens.get(dataEncIdx).encoding().primitiveType(), is(PrimitiveType.CHAR)); } } + + @Test + void shouldRegenerateIrWithSameByteOrder() throws Exception + { + try (InputStream in = getLocalResource("example-bigendian-test-schema.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final IrGenerator generator = new IrGenerator(); + final Ir firstIr = generator.generate(schema); + final ByteBuffer firstIrOutputBuffer = ByteBuffer.allocate(8 * 1024); + + final int length; + try (IrEncoder firstIrEncoder = new IrEncoder(firstIrOutputBuffer, firstIr)) + { + length = firstIrEncoder.encode(); + } + + final Ir secondIr; + try (IrDecoder firstIrDecoder = new IrDecoder(firstIrOutputBuffer.slice(0, length))) + { + secondIr = firstIrDecoder.decode(); + } + + assertThat(secondIr.byteOrder(), is(firstIr.byteOrder())); + } + } } From 4547fe6edd6d23d13248e006678288d0e8c8425b Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Thu, 28 Nov 2024 14:13:44 -0600 Subject: [PATCH 485/805] [Rust] codegen of primitive enums now implement 'From' instead of 'Into' (#1029) * [Rust] updated LibRsDef.generate() to add "#![allow(clippy::all)]" * [Rust] generating 'From for PRIMITIVE' instead of 'Into for ENUM' to satisfy 'from_over_into' lint * [Rust] removed unused method parameter * fixed formatting --------- Co-authored-by: Michael Ward --- .../sbe/generation/rust/LibRsDef.java | 2 +- .../sbe/generation/rust/RustGenerator.java | 27 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index f62aebe2d0..46897829cd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -60,7 +60,7 @@ void generate(final Ir ir) throws IOException try (Writer libRs = outputManager.createOutput("lib")) { indent(libRs, 0, "#![forbid(unsafe_code)]\n"); - indent(libRs, 0, "#![allow(clippy::upper_case_acronyms)]\n"); + indent(libRs, 0, "#![allow(clippy::all)]\n"); indent(libRs, 0, "#![allow(non_camel_case_types)]\n\n"); indent(libRs, 0, "#![allow(ambiguous_glob_reexports)]\n\n"); indent(libRs, 0, "use ::core::{convert::TryInto};\n\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 29fd0da752..0c03766553 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1265,19 +1265,19 @@ private static void generateEnum( indent(writer, 0, "}\n"); // From impl - generateFromImplForEnum(enumRustName, primitiveType, messageBody, writer); + generateFromPrimitiveForEnum(enumRustName, primitiveType, messageBody, writer); // Into impl - generateIntoImplForEnum(enumRustName, primitiveType, messageBody, writer); + generateFromEnumForPrimitive(enumRustName, primitiveType, messageBody, writer); // FromStr impl - generateFromStrImplForEnum(enumRustName, primitiveType, messageBody, writer); + generateFromStrImplForEnum(enumRustName, messageBody, writer); // Display impl generateDisplayImplForEnum(enumRustName, primitiveType, messageBody, writer); } - private static void generateFromImplForEnum( + private static void generateFromPrimitiveForEnum( final String enumRustName, final String primitiveType, final List messageBody, @@ -1302,27 +1302,29 @@ private static void generateFromImplForEnum( indent(writer, 0, "}\n"); } - private static void generateIntoImplForEnum( + private static void generateFromEnumForPrimitive( final String enumRustName, final String primitiveType, final List messageBody, final Appendable writer) throws IOException { - indent(writer, 0, "impl Into<%s> for %s {\n", primitiveType, enumRustName); + indent(writer, 0, "impl From<%s> for %s {\n", enumRustName, primitiveType); indent(writer, 1, "#[inline]\n"); - indent(writer, 1, "fn into(self) -> %s {\n", primitiveType); - indent(writer, 2, "match self {\n"); + indent(writer, 1, "fn from(v: %s) -> Self {\n", enumRustName); + indent(writer, 2, "match v {\n"); + for (final Token token : messageBody) { final Encoding encoding = token.encoding(); final String literal = generateRustLiteral(encoding.primitiveType(), encoding.constValue().toString()); - indent(writer, 3, "Self::%s => %s, \n", token.name(), literal); + indent(writer, 3, "%s::%s => %s, \n", enumRustName, token.name(), literal); } + { final Encoding encoding = messageBody.get(0).encoding(); final CharSequence nullVal = generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString()); - indent(writer, 3, "Self::NullVal => %s,\n", nullVal); + indent(writer, 3, "%s::NullVal => %s,\n", enumRustName, nullVal); } indent(writer, 2, "}\n"); indent(writer, 1, "}\n"); @@ -1331,7 +1333,6 @@ private static void generateIntoImplForEnum( private static void generateFromStrImplForEnum( final String enumRustName, - final String primitiveType, final List messageBody, final Appendable writer) throws IOException { @@ -1342,10 +1343,10 @@ private static void generateFromStrImplForEnum( indent(writer, 2, "match v {\n"); for (final Token token : messageBody) { - indent(writer, 3, "\"%1$s\" => core::result::Result::Ok(Self::%1$s), \n", token.name()); + indent(writer, 3, "\"%1$s\" => Ok(Self::%1$s), \n", token.name()); } // default => NullVal - indent(writer, 3, "_ => core::result::Result::Ok(Self::NullVal),\n"); + indent(writer, 3, "_ => Ok(Self::NullVal),\n"); indent(writer, 2, "}\n"); indent(writer, 1, "}\n"); indent(writer, 0, "}\n"); From 6784077a8d0d70a7c08abd4e969060a2436cb848 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Tue, 3 Dec 2024 14:01:09 +0000 Subject: [PATCH 486/805] Update Checkstyle and JQwik dependencies. --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a21be421a2..5cbe7ecda4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "1.23.1" -checkstyle = "10.20.1" +checkstyle = "10.20.2" junit = "5.11.3" jmh = "1.37" gradle = "8.11.1" @@ -9,7 +9,7 @@ gradle = "8.11.1" agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23.1, 2.0[", require = "1.23.1" } } mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.2" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } -jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.1" } +jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.2" } json = { group = "org.json", name = "json", version = "20240303" } jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "jmh" } jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "jmh" } From 72a8a7742fed2c865feecd7ffe5b525d6004d059 Mon Sep 17 00:00:00 2001 From: marc-adaptive Date: Tue, 3 Dec 2024 21:20:58 -0500 Subject: [PATCH 487/805] [Build] Remove draft release notes --- .github/workflows/release.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 837f2eaf09..7d7f62b227 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,14 +43,6 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.ref }} - - name: Create Release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} - draft: true - name: Setup java uses: actions/setup-java@v4 with: From eb24bb02595d4514b6ab5c2885e8fc1049751f23 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 4 Dec 2024 17:35:20 +0000 Subject: [PATCH 488/805] Update Checkstyle rules and apply them. --- config/checkstyle/checkstyle.xml | 16 +++++++-- .../uk/co/real_logic/sbe/PrimitiveValue.java | 8 ++--- .../uk/co/real_logic/sbe/ValidationUtil.java | 5 +-- .../co/real_logic/sbe/generation/c/CUtil.java | 8 ++--- .../sbe/generation/cpp/CppUtil.java | 8 ++--- .../sbe/generation/csharp/CSharpUtil.java | 8 ++--- .../golang/flyweight/GolangFlyweightUtil.java | 29 +++++++--------- .../sbe/generation/java/JavaUtil.java | 9 +++-- .../sbe/generation/rust/LibRsDef.java | 16 ++++++--- .../sbe/generation/rust/RustUtil.java | 4 +-- .../java/uk/co/real_logic/sbe/ir/Token.java | 12 +++---- .../real_logic/sbe/xml/EncodedDataType.java | 34 +++++++++---------- .../uk/co/real_logic/sbe/xml/EnumType.java | 16 ++++----- .../uk/co/real_logic/sbe/xml/Message.java | 20 +++++------ .../co/real_logic/sbe/xml/MessageSchema.java | 4 +-- .../uk/co/real_logic/sbe/xml/SetType.java | 18 +++++----- 16 files changed, 114 insertions(+), 101 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index f34d3bd2e5..abb1fc1efe 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -1,11 +1,17 @@ + "https://checkstyle.org/dtds/configuration_1_3.dtd"> + + + + + + @@ -22,8 +28,8 @@ - - + + @@ -33,9 +39,13 @@ + + + + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java index 0754d9a485..18b543aef6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java @@ -308,7 +308,7 @@ public Representation representation() } /** - * Parse constant value string and set representation based on type + * Parse constant value string and set representation based on type. * * @param value expressed as a String. * @param primitiveType that this is supposed to be. @@ -367,7 +367,7 @@ public static PrimitiveValue parse(final String value, final PrimitiveType primi } /** - * Parse constant value string and set representation based on type + * Parse constant value string and set representation based on type. * * @param value expressed as a String. * @param primitiveType that this is supposed to be. @@ -392,7 +392,7 @@ public static PrimitiveValue parse( } /** - * Parse constant value string and set representation based on type, length, and characterEncoding + * Parse constant value string and set representation based on type, length, and characterEncoding. * * @param value expressed as a String. * @param length of the type. @@ -469,7 +469,7 @@ public byte[] byteArrayValue() } /** - * Return byte array value for this PrimitiveValue given a particular type + * Return byte array value for this PrimitiveValue given a particular type. * * @param type of this value. * @return value expressed as a byte array. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index 74e58e3f5a..a7bb7e0d19 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -19,7 +19,7 @@ import java.util.regex.Pattern; /** - * Various validation utilities used across parser, IR, and generator + * Various validation utilities used across parser, IR, and generator. */ public class ValidationUtil { @@ -228,7 +228,7 @@ private static boolean isSbeCppIdentifierPart(final char c) *

    * Java JLS * - * @param value to check + * @param value to check. * @return true for validity as a Java name. false if not. */ public static boolean isSbeJavaName(final String value) @@ -391,6 +391,7 @@ private static boolean isSbeGolangIdentifierPart(final char c) } /** + * C# keywords. * * C# keywords * Note this does not include the contextual keywords diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java index fa0cbe1f10..518abd80b2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java @@ -108,11 +108,11 @@ public static String formatScopedName(final CharSequence[] scope, final String v } /** - * Return the C99 formatted byte order encoding string to use for a given byte order and primitiveType + * Return the C99 formatted byte order encoding string to use for a given byte order and primitiveType. * - * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token} - * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token} - * @return the string formatted as the byte ordering encoding + * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token}. + * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token}. + * @return the string formatted as the byte ordering encoding. */ public static String formatByteOrderEncoding(final ByteOrder byteOrder, final PrimitiveType primitiveType) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java index 534547a7fb..469faac27a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java @@ -106,11 +106,11 @@ public static String formatClassName(final String value) } /** - * Return the Cpp98 formatted byte order encoding string to use for a given byte order and primitiveType + * Return the Cpp98 formatted byte order encoding string to use for a given byte order and primitiveType. * - * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token} - * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token} - * @return the string formatted as the byte ordering encoding + * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token}. + * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token}. + * @return the string formatted as the byte ordering encoding. */ public static String formatByteOrderEncoding(final ByteOrder byteOrder, final PrimitiveType primitiveType) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index a80ae7a295..b4fee26faf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -322,11 +322,11 @@ public static String formatGetterName(final String propertyName) } /** - * Shortcut to append a line of generated code + * Shortcut to append a line of generated code. * - * @param builder string builder to which to append the line - * @param indent current text indentation - * @param line line to be appended + * @param builder string builder to which to append the line. + * @param indent current text indentation. + * @param line line to be appended. */ public static void append(final StringBuilder builder, final String indent, final String line) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java index 78ac285b6c..ba03adbc3b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java @@ -87,7 +87,7 @@ public static String formatClassName(final String value) } /** - * Map the name of a {@link uk.co.real_logic.sbe.PrimitiveType} to a Golang marhsalling function name. + * Map the name of a {@link uk.co.real_logic.sbe.PrimitiveType} to a Golang marshalling function name. * * @param primitiveType to map. * @return the name of the Java primitive that most closely maps. @@ -114,8 +114,8 @@ public static String formatPropertyName(final String value) { throw new IllegalStateException( "Invalid property name='" + formattedValue + - "' please correct the schema or consider setting system property: " + - SbeTool.KEYWORD_APPEND_TOKEN); + "' please correct the schema or consider setting system property: " + + SbeTool.KEYWORD_APPEND_TOKEN); } formattedValue += keywordAppendToken; @@ -142,16 +142,15 @@ public static String closingBraces(final int count) } /** - * Return the Golang formatted byte order encoding string to use to read for a given byte order and primitiveType + * Return the Golang formatted byte order encoding string to use to read for a given byte order and primitiveType. * - * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token} - * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token} - * @return the string formatted as the byte ordering encoding + * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token}. + * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token}. + * @return the string formatted as the byte ordering encoding. */ public static String formatReadBytes(final ByteOrder byteOrder, final PrimitiveType primitiveType) { - final String suffix = (byteOrder == ByteOrder.BIG_ENDIAN ? - "BigEndian" : "LittleEndian"); + final String suffix = byteOrder == ByteOrder.BIG_ENDIAN ? "BigEndian" : "LittleEndian"; switch (primitiveType) { @@ -182,16 +181,15 @@ public static String formatReadBytes(final ByteOrder byteOrder, final PrimitiveT } /** - * Return the Golang formatted byte order encoding string to use to write for a given byte order and primitiveType + * Return the Golang formatted byte order encoding string to use to write for a given byte order and primitiveType. * - * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token} - * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token} - * @return the string formatted as the byte ordering encoding + * @param byteOrder of the {@link uk.co.real_logic.sbe.ir.Token}. + * @param primitiveType of the {@link uk.co.real_logic.sbe.ir.Token}. + * @return the string formatted as the byte ordering encoding. */ public static String formatWriteBytes(final ByteOrder byteOrder, final PrimitiveType primitiveType) { - final String suffix = (byteOrder == ByteOrder.BIG_ENDIAN ? - "BigEndian" : "LittleEndian"); + final String suffix = byteOrder == ByteOrder.BIG_ENDIAN ? "BigEndian" : "LittleEndian"; switch (primitiveType) { @@ -220,5 +218,4 @@ public static String formatWriteBytes(final ByteOrder byteOrder, final Primitive } return ""; } - } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index d5d3ac6693..7f885f673c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -208,11 +208,11 @@ public static String formatClassName(final String className) } /** - * Shortcut to append a line of generated code + * Shortcut to append a line of generated code. * - * @param builder string builder to which to append the line - * @param indent current text indentation - * @param line line to be appended + * @param builder string builder to which to append the line. + * @param indent current text indentation. + * @param line line to be appended. */ public static void append(final StringBuilder builder, final String indent, final String line) { @@ -533,5 +533,4 @@ private static void escapeJavadoc(final StringBuilder sb, final String doc) } } } - } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 46897829cd..ae50c9bef7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -15,6 +15,8 @@ */ package uk.co.real_logic.sbe.generation.rust; +import uk.co.real_logic.sbe.ir.Ir; + import java.io.IOException; import java.io.Writer; import java.nio.ByteOrder; @@ -23,11 +25,15 @@ import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.stream.Stream; -import uk.co.real_logic.sbe.ir.Ir; import static java.nio.ByteOrder.LITTLE_ENDIAN; -import static uk.co.real_logic.sbe.generation.rust.RustGenerator.*; -import static uk.co.real_logic.sbe.generation.rust.RustUtil.*; +import static uk.co.real_logic.sbe.generation.rust.RustGenerator.BUF_LIFETIME; +import static uk.co.real_logic.sbe.generation.rust.RustGenerator.READ_BUF_TYPE; +import static uk.co.real_logic.sbe.generation.rust.RustGenerator.WRITE_BUF_TYPE; +import static uk.co.real_logic.sbe.generation.rust.RustUtil.TYPE_NAME_BY_PRIMITIVE_TYPE_MAP; +import static uk.co.real_logic.sbe.generation.rust.RustUtil.indent; +import static uk.co.real_logic.sbe.generation.rust.RustUtil.rustTypeName; +import static uk.co.real_logic.sbe.generation.rust.RustUtil.toLowerSnakeCase; /** * Generates `lib.rs` specific code. @@ -39,11 +45,11 @@ class LibRsDef private final String schemaVersionType; /** - * Create a new 'lib.rs' for the library being generated + * Create a new 'lib.rs' for the library being generated. * * @param outputManager for generating the codecs to. * @param byteOrder for the Encoding. - * @param schemaVersionType for acting_version type + * @param schemaVersionType for acting_version type. */ LibRsDef( final RustOutputManager outputManager, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 8f2724759f..43b9c8ba8a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -70,7 +70,7 @@ static String generateRustLiteral(final PrimitiveType type, final String value) Verify.notNull(type, "type"); Verify.notNull(value, "value"); final String typeName = rustTypeName(type); - if (typeName == null) + if (null == typeName) { throw new IllegalArgumentException("Unknown Rust type name found for primitive " + type.primitiveName()); } @@ -178,7 +178,7 @@ static String characterEncoding(final Encoding encoding) /** * Converts to 'snake_case' but will also handle when there are multiple - * upper case characters in a row 'UPPERCase' => 'upper_case' + * upper case characters in a row 'UPPERCase' => 'upper_case'. * * @param value to be formatted * @return the string formatted to 'lower_snake_case' diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java index 83ab2d1538..6d97572727 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java @@ -71,7 +71,7 @@ public class Token public static final int INVALID_ID = -1; /** - * Length not determined + * Length not determined. */ public static final int VARIABLE_LENGTH = -1; @@ -148,9 +148,9 @@ public Signal signal() } /** - * Return the name of the token + * Return the name of the token. * - * @return name of the token + * @return name of the token. */ public String name() { @@ -158,7 +158,7 @@ public String name() } /** - * Return the packageName of the token + * Return the packageName of the token. * * @return packageName of the token or null, if it was not set explicitly. */ @@ -188,9 +188,9 @@ public String description() } /** - * Return the ID of the token assigned by the specification + * Return the ID of the token assigned by the specification. * - * @return ID of the token assigned by the specification + * @return ID of the token assigned by the specification. */ public int id() { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index 981bcaa8db..78fe6e10a0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -55,7 +55,7 @@ public class EncodedDataType extends Type /** * Construct a new encodedDataType from XML Schema. * - * @param node from the XML Schema Parsing + * @param node from the XML Schema Parsing. */ public EncodedDataType(final Node node) { @@ -258,9 +258,9 @@ public EncodedDataType( } /** - * Return the length attribute of the type + * Return the length attribute of the type. * - * @return length attribute of the type + * @return length attribute of the type. */ public int length() { @@ -268,9 +268,9 @@ public int length() } /** - * Return the variableLength attribute of the type + * Return the variableLength attribute of the type. * - * @return variableLength boolean of the type + * @return variableLength boolean of the type. */ public boolean isVariableLength() { @@ -288,9 +288,9 @@ public void variableLength(final boolean variableLength) } /** - * Return the primitiveType attribute of the type + * Return the primitiveType attribute of the type. * - * @return primitiveType attribute of the type + * @return primitiveType attribute of the type. */ public PrimitiveType primitiveType() { @@ -318,9 +318,9 @@ public int encodedLength() } /** - * The constant value of the type if specified + * The constant value of the type if specified. * - * @return value of the constant for this type + * @return value of the constant for this type. */ public PrimitiveValue constVal() { @@ -333,9 +333,9 @@ public PrimitiveValue constVal() } /** - * The minValue of the type + * The minValue of the type. * - * @return value of the minValue + * @return value of the minValue. */ public PrimitiveValue minValue() { @@ -343,9 +343,9 @@ public PrimitiveValue minValue() } /** - * The maxValue of the type + * The maxValue of the type. * - * @return value of the maxValue + * @return value of the maxValue. */ public PrimitiveValue maxValue() { @@ -353,9 +353,9 @@ public PrimitiveValue maxValue() } /** - * The nullValue of the type + * The nullValue of the type. * - * @return value of the nullValue primitiveType or type + * @return value of the nullValue primitiveType or type. */ public PrimitiveValue nullValue() { @@ -363,9 +363,9 @@ public PrimitiveValue nullValue() } /** - * The character encoding of the type + * The character encoding of the type. * - * @return value representing the encoding + * @return value representing the encoding. */ public String characterEncoding() { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java index 60a9cdc66e..b2566ea787 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java @@ -174,9 +174,9 @@ public PrimitiveType encodingType() } /** - * The encodedLength (in octets) of the encodingType + * The encodedLength (in octets) of the encodingType. * - * @return encodedLength of the encodingType + * @return encodedLength of the encodingType. */ public int encodedLength() { @@ -191,7 +191,7 @@ public int encodedLength() /** * Get the {@link ValidValue} represented by a {@link PrimitiveValue}. * - * @param value to lookup + * @param value to lookup. * @return the {@link ValidValue} represented by a {@link PrimitiveValue} or null. */ public ValidValue getValidValue(final PrimitiveValue value) @@ -202,7 +202,7 @@ public ValidValue getValidValue(final PrimitiveValue value) /** * Get the {@link ValidValue} represented by a string name. * - * @param name to lookup + * @param name to lookup. * @return the {@link ValidValue} represented by a string name or null. */ public ValidValue getValidValue(final String name) @@ -265,8 +265,8 @@ public static class ValidValue /** * Construct a ValidValue given the XML node and the encodingType. * - * @param node that contains the validValue - * @param encodingType for the enum + * @param node that contains the validValue. + * @param encodingType for the enum. */ public ValidValue(final Node node, final PrimitiveType encodingType) { @@ -310,9 +310,9 @@ public String description() } /** - * The sinceVersion value of the {@link ValidValue} + * The sinceVersion value of the {@link ValidValue}. * - * @return the sinceVersion value of the {@link ValidValue} + * @return the sinceVersion value of the {@link ValidValue}. */ public int sinceVersion() { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java index 3c1e6a78f2..90695b736a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java @@ -98,9 +98,9 @@ public Message(final Node messageNode, final Map typeByNameMap) th } /** - * Return the template schemaId of the message + * Return the template schemaId of the message. * - * @return schemaId of the message + * @return schemaId of the message. */ public int id() { @@ -108,9 +108,9 @@ public int id() } /** - * Return the name of the message + * Return the name of the message. * - * @return name of the message + * @return name of the message. */ public String name() { @@ -118,9 +118,9 @@ public String name() } /** - * The description of the message (if set) or null + * The description of the message (if set) or null. * - * @return description set by the message or null + * @return description set by the message or null. */ public String description() { @@ -128,9 +128,9 @@ public String description() } /** - * The semanticType of the message (if set) or null + * The semanticType of the message (if set) or null. * - * @return the semanticType of the message (if set) or null + * @return the semanticType of the message (if set) or null. */ public String semanticType() { @@ -158,9 +158,9 @@ public int deprecated() } /** - * Return the list of fields in the message + * Return the list of fields in the message. * - * @return {@link java.util.List} of the Field objects in this Message + * @return {@link java.util.List} of the Field objects in this Message. */ public List fields() { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index 46dac06dfd..5203939b4d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -96,7 +96,7 @@ public class MessageSchema /** * The Schema headerType for message headers. This should be a {@link CompositeType}. * - * @return the Schema headerType for message headers + * @return the Schema headerType for message headers. */ public CompositeType messageHeader() { @@ -196,7 +196,7 @@ public Collection types() } /** - * Return the byte order specified by the messageSchema + * Return the byte order specified by the messageSchema. * * @return {@link ByteOrder} of the message encoding. */ diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java index fb6914774f..ff5b025ae4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java @@ -134,9 +134,9 @@ public PrimitiveType encodingType() } /** - * The encodedLength (in octets) of the encodingType + * The encodedLength (in octets) of the encodingType. * - * @return encodedLength of the encodingType + * @return encodedLength of the encodingType. */ public int encodedLength() { @@ -146,7 +146,7 @@ public int encodedLength() /** * Get the {@link Choice} represented by a {@link PrimitiveValue}. * - * @param value to get + * @param value to get. * @return the {@link Choice} represented by a {@link PrimitiveValue} or null if not found. */ public Choice getChoice(final PrimitiveValue value) @@ -157,7 +157,7 @@ public Choice getChoice(final PrimitiveValue value) /** * Get the {@link Choice} represented by a String name. * - * @param name to get + * @param name to get. * @return the {@link Choice} represented by a String name or null if not found. */ public Choice getChoice(final String name) @@ -209,10 +209,10 @@ public static class Choice private final int deprecated; /** - * Construct a Choice given the XML node and the encodingType + * Construct a Choice given the XML node and the encodingType. * - * @param node that contains the validValue - * @param encodingType for the enum + * @param node that contains the validValue. + * @param encodingType for the enum. */ public Choice(final Node node, final PrimitiveType encodingType) { @@ -262,9 +262,9 @@ public String description() } /** - * The sinceVersion value of the {@link Choice} + * The sinceVersion value of the {@link Choice}. * - * @return the sinceVersion value of the {@link Choice} + * @return the sinceVersion value of the {@link Choice}. */ public int sinceVersion() { From 68aeb1a9a5f06b83c07d02c57fec1972ca527dd1 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 6 Dec 2024 17:46:28 +0000 Subject: [PATCH 489/805] [Java] Prevent collision when field name is 'value'. `value` is used as a parameter name in some DTO methods. When an SBE field was named `value` it caused an issue due to a collision. We now make sure to reference fields more explicitly via `this.fieldName`. --- .../sbe/generation/java/JavaDtoGenerator.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index baf9f70342..8c5bfb8b02 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -291,7 +291,7 @@ private void generateGroups( .append(indent).append("public List<").append(qualifiedDtoClassName).append("> ") .append(formattedPropertyName).append("()\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") @@ -299,7 +299,7 @@ private void generateGroups( .append(indent).append("public void ").append(formattedPropertyName).append("(") .append("List<").append(qualifiedDtoClassName).append("> value)") .append(indent).append("{\n") - .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") .append(indent).append("}\n"); } } @@ -350,7 +350,7 @@ private void generateComputeEncodedLength( .append(indent).append(INDENT).append("encodedLength += ") .append(groupDecoderClassName).append(".sbeHeaderSize();\n\n") .append(indent).append(INDENT).append("for (").append(groupDtoClassName).append(" group : ") - .append(fieldName).append(")\n") + .append("this.").append(fieldName).append(")\n") .append(indent).append(INDENT).append("{\n") .append(indent).append(INDENT).append(INDENT) .append("encodedLength += group.computeEncodedLength();\n") @@ -373,7 +373,7 @@ private void generateComputeEncodedLength( final String characterEncoding = varDataToken.encoding().characterEncoding(); final String lengthAccessor = characterEncoding == null ? ".length" : ".length()"; lengthBuilder.append(indent).append(INDENT).append("encodedLength += ") - .append(fieldName).append(lengthAccessor); + .append("this.").append(fieldName).append(lengthAccessor); final int elementByteLength = varDataToken.encoding().primitiveType().size(); if (elementByteLength != 1) @@ -1255,7 +1255,7 @@ private void generateComplexProperty( .append(indent).append("public ").append(typeName).append(" ") .append(formattedPropertyName).append("()\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") @@ -1263,7 +1263,7 @@ private void generateComplexProperty( .append(indent).append("public void ") .append(formattedPropertyName).append("(").append(typeName).append(" value)\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") .append(indent).append("}\n"); } @@ -1304,7 +1304,7 @@ private void generateEnumProperty( .append(indent).append("public ").append(enumName).append(" ") .append(formattedPropertyName).append("()\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") @@ -1312,7 +1312,7 @@ private void generateEnumProperty( .append(indent).append("public void ").append(formattedPropertyName) .append("(").append(enumName).append(" value)\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") .append(indent).append("}\n"); } } @@ -1382,7 +1382,7 @@ private void generateArrayProperty( .append(indent).append("public ").append(typeName).append(" ") .append(formattedPropertyName).append("()\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") @@ -1391,7 +1391,7 @@ private void generateArrayProperty( .append("(").append(typeName).append(" value)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(validateMethod).append("(value);\n") - .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") .append(indent).append("}\n"); generateArrayValidateMethod( @@ -1416,7 +1416,7 @@ private void generateArrayProperty( .append(indent).append("public ").append(typeName).append(" ") .append(formattedPropertyName).append("()\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") @@ -1425,7 +1425,7 @@ private void generateArrayProperty( .append(typeName).append(" value").append(")\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(validateMethod).append("(value);\n") - .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") .append(indent).append("}\n"); generateArrayValidateMethod( @@ -1519,7 +1519,7 @@ private void generateSingleValueProperty( .append(indent).append("public ").append(typeName).append(" ") .append(formattedPropertyName).append("()\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") @@ -1528,7 +1528,7 @@ private void generateSingleValueProperty( .append(typeName).append(" value)\n") .append(indent).append("{\n") .append(validationCall) - .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") .append(indent).append("}\n"); } @@ -1590,14 +1590,14 @@ private void generateVarData( .append(indent).append("public ").append(dtoType).append(" ") .append(formattedPropertyName).append("()\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") .append(indent).append("public void ").append(formattedPropertyName) .append("(").append(dtoType).append(" value)\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") .append(indent).append("}\n"); } } @@ -1777,7 +1777,7 @@ private void generateChoices( .append("\n") .append(indent).append("public boolean ").append(formattedPropertyName).append("()\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic() @@ -1785,7 +1785,7 @@ private void generateChoices( .append(indent).append(dtoClassName).append(" ") .append(formattedPropertyName).append("(boolean value)\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append(fieldName).append(" = value;\n") + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") .append(indent).append(INDENT).append("return this;\n") .append(indent).append("}\n"); } From d3f3bf436f822f0a809479f4db8ebeb3146093c7 Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Mon, 9 Dec 2024 15:06:10 -0600 Subject: [PATCH 490/805] [C++] use constexpr to define precedence checks lookup tables --- .../sbe/generation/cpp/CppGenerator.java | 28 +++++++------------ .../sbe/generation/cpp/CppGeneratorTest.java | 26 +++++++++++++++++ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 8533a4df84..65d6a627e6 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -243,7 +243,6 @@ public void generate() throws IOException generateDisplay(sb, msgToken.name(), fields, groups, varData); sb.append(generateMessageLength(groups, varData, BASE_INDENT)); sb.append("};\n"); - generateLookupTableDefinitions(sb, className, fieldPrecedenceModel); sb.append(CppUtil.closingBraces(namespaces.length)).append("#endif\n"); out.append(sb); } @@ -2975,12 +2974,8 @@ private static CharSequence generateLookupTableDeclarations(final FieldPrecedenc } final StringBuilder sb = new StringBuilder(); - sb.append(INDENT).append("static const std::string STATE_NAME_LOOKUP[") - .append(fieldPrecedenceModel.stateCount()) - .append("];\n"); - sb.append(INDENT).append("static const std::string STATE_TRANSITIONS_LOOKUP[") - .append(fieldPrecedenceModel.stateCount()) - .append("];\n\n"); + + generateLookupTableDefinitions(sb, fieldPrecedenceModel); sb.append(INDENT).append("static std::string codecStateName(CodecState state)\n") .append(INDENT).append("{\n") @@ -2997,7 +2992,6 @@ private static CharSequence generateLookupTableDeclarations(final FieldPrecedenc private static void generateLookupTableDefinitions( final StringBuilder sb, - final String className, final FieldPrecedenceModel fieldPrecedenceModel) { if (null == fieldPrecedenceModel) @@ -3005,19 +2999,17 @@ private static void generateLookupTableDefinitions( return; } - sb.append("\n").append("const std::string ").append(className).append("::STATE_NAME_LOOKUP[") - .append(fieldPrecedenceModel.stateCount()).append("] =\n") - .append("{\n"); + sb.append(INDENT).append("static constexpr const char *STATE_NAME_LOOKUP[] =\n") + .append(INDENT).append("{\n"); fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> - sb.append(INDENT).append("\"").append(state.name()).append("\",\n")); - sb.append("};\n\n"); + sb.append(INDENT).append(INDENT).append("\"").append(state.name()).append("\",\n")); + sb.append(INDENT).append("};\n\n"); - sb.append("const std::string ").append(className).append("::STATE_TRANSITIONS_LOOKUP[") - .append(fieldPrecedenceModel.stateCount()).append("] =\n") - .append("{\n"); + sb.append(INDENT).append("static constexpr const char *STATE_TRANSITIONS_LOOKUP[] =\n") + .append(INDENT).append("{\n"); fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> { - sb.append(INDENT).append("\""); + sb.append(INDENT).append(INDENT).append("\""); final MutableBoolean isFirst = new MutableBoolean(true); final Set transitionDescriptions = new HashSet<>(); fieldPrecedenceModel.forEachTransitionFrom(state, (transitionGroup) -> @@ -3038,7 +3030,7 @@ private static void generateLookupTableDefinitions( }); sb.append("\",\n"); }); - sb.append("};\n\n"); + sb.append(INDENT).append("};\n\n"); } private static CharSequence qualifiedStateCase(final FieldPrecedenceModel.State state) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index b8c969c8b8..79c1651c03 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -114,4 +114,30 @@ void dtosShouldReferenceTypesInDifferentPackages() throws Exception assertThat(source, containsString("using namespace test::message::schema::common;")); } } + + @Test + void shouldUseConstexprWhenDefiningPrecedenceChecksLookupTables() throws Exception + { + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CppGenerator generator = new CppGenerator( + ir, + false, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context().shouldGeneratePrecedenceChecks(true)), + false, + outputManager); + generator.generate(); + + final String source = outputManager.getSource("code.generation.test.Car").toString(); + assertThat(source, containsString("static constexpr const char *STATE_NAME_LOOKUP[] =")); + assertThat(source, containsString("static constexpr const char *STATE_TRANSITIONS_LOOKUP[] =")); + } + } } From daf02836cd7e1e3f6541f861724e3e88ef83b0af Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Tue, 10 Dec 2024 16:37:14 -0600 Subject: [PATCH 491/805] [C++] add definitions of constexpr lookup tables --- .../sbe/generation/cpp/CppGenerator.java | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 65d6a627e6..e1ae7e16fc 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -243,6 +243,7 @@ public void generate() throws IOException generateDisplay(sb, msgToken.name(), fields, groups, varData); sb.append(generateMessageLength(groups, varData, BASE_INDENT)); sb.append("};\n"); + generateLookupTableDefinitions(sb, className, fieldPrecedenceModel); sb.append(CppUtil.closingBraces(namespaces.length)).append("#endif\n"); out.append(sb); } @@ -2975,30 +2976,6 @@ private static CharSequence generateLookupTableDeclarations(final FieldPrecedenc final StringBuilder sb = new StringBuilder(); - generateLookupTableDefinitions(sb, fieldPrecedenceModel); - - sb.append(INDENT).append("static std::string codecStateName(CodecState state)\n") - .append(INDENT).append("{\n") - .append(TWO_INDENT).append("return STATE_NAME_LOOKUP[static_cast(state)];\n") - .append(INDENT).append("}\n\n"); - - sb.append(INDENT).append("static std::string codecStateTransitions(CodecState state)\n") - .append(INDENT).append("{\n") - .append(TWO_INDENT).append("return STATE_TRANSITIONS_LOOKUP[static_cast(state)];\n") - .append(INDENT).append("}\n\n"); - - return sb; - } - - private static void generateLookupTableDefinitions( - final StringBuilder sb, - final FieldPrecedenceModel fieldPrecedenceModel) - { - if (null == fieldPrecedenceModel) - { - return; - } - sb.append(INDENT).append("static constexpr const char *STATE_NAME_LOOKUP[] =\n") .append(INDENT).append("{\n"); fieldPrecedenceModel.forEachStateOrderedByStateNumber((state) -> @@ -3031,6 +3008,37 @@ private static void generateLookupTableDefinitions( sb.append("\",\n"); }); sb.append(INDENT).append("};\n\n"); + + sb.append(INDENT).append("static std::string codecStateName(CodecState state)\n") + .append(INDENT).append("{\n") + .append(TWO_INDENT).append("return STATE_NAME_LOOKUP[static_cast(state)];\n") + .append(INDENT).append("}\n\n"); + + sb.append(INDENT).append("static std::string codecStateTransitions(CodecState state)\n") + .append(INDENT).append("{\n") + .append(TWO_INDENT).append("return STATE_TRANSITIONS_LOOKUP[static_cast(state)];\n") + .append(INDENT).append("}\n\n"); + + return sb; + } + + private static void generateLookupTableDefinitions( + final StringBuilder sb, + final String className, + final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return; + } + + sb + .append("\nconstexpr const char *") + .append(className) + .append("::STATE_NAME_LOOKUP[];\n") + .append("constexpr const char *") + .append(className) + .append("::STATE_TRANSITIONS_LOOKUP[];\n\n"); } private static CharSequence qualifiedStateCase(final FieldPrecedenceModel.State state) From 0c48ee3f52f4d1b2201db985ea44bab3a5a7af81 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Wed, 11 Dec 2024 10:17:51 +0000 Subject: [PATCH 492/805] [C++] Fix field precedence check issue #1031. (#1033) There were a couple of problems here: 1. "wrapping constructors" did not initialize the codec state (for precedence checks) correctly, and 2. the methods returning a JSON encoded string would attempt to transition twice. These problems are now resolved. I have also made a technically breaking change. I have removed an unnecessary constructor that took in the codec state. I think it is highly unlikely that anyone was using this constructor; therefore, it should be okay to make the change. --- .../sbe/generation/cpp/CppGenerator.java | 79 ++++++---------- .../test/cpp/FieldAccessOrderCheckTest.cpp | 93 +++++++++++++++++++ 2 files changed, 120 insertions(+), 52 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index e1ae7e16fc..846a289e11 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1201,7 +1201,7 @@ private void generateVarData( lengthCppType, accessOrderListenerCall); - generateJsonEscapedStringGetter(sb, token, indent, propertyName, accessOrderListenerCall); + generateJsonEscapedStringGetter(sb, token, indent, propertyName); new Formatter(sb).format("\n" + indent + " #if __cplusplus >= 201703L\n" + @@ -2307,7 +2307,7 @@ private void generateArrayProperty( generateStringNotPresentCondition(propertyToken.version(), indent), accessOrderListenerCall); - generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName, accessOrderListenerCall); + generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName); new Formatter(sb).format("\n" + indent + " #if __cplusplus >= 201703L\n" + @@ -2381,14 +2381,12 @@ private void generateJsonEscapedStringGetter( final StringBuilder sb, final Token token, final String indent, - final String propertyName, - final CharSequence accessOrderListenerCall) + final String propertyName) { new Formatter(sb).format("\n" + indent + " std::string get%1$sAsJsonEscapedString()\n" + indent + " {\n" + "%2$s" + - "%3$s" + indent + " std::ostringstream oss;\n" + indent + " std::string s = get%1$sAsString();\n\n" + indent + " for (const auto c : s)\n" + @@ -2417,8 +2415,7 @@ private void generateJsonEscapedStringGetter( indent + " return oss.str();\n" + indent + " }\n", toUpperFirstChar(propertyName), - generateStringNotPresentCondition(token.version(), indent), - accessOrderListenerCall); + generateStringNotPresentCondition(token.version(), indent)); } private void generateConstPropertyMethods( @@ -2505,7 +2502,7 @@ private void generateConstPropertyMethods( values, constantValue.length); - generateJsonEscapedStringGetter(sb, token, indent, propertyName, ""); + generateJsonEscapedStringGetter(sb, token, indent, propertyName); } private CharSequence generateFixedFlyweightCode(final String className, final int size) @@ -2654,34 +2651,13 @@ private static String generateHiddenCopyConstructor(final String indent, final S return DISABLE_IMPLICIT_COPYING ? ctorAndCopyAssignmentDeletion : ""; } - private static CharSequence generateConstructorsAndOperators( + private CharSequence generateConstructorsAndOperators( final String className, final FieldPrecedenceModel fieldPrecedenceModel) { - final String constructorWithCodecState = null == fieldPrecedenceModel ? "" : String.format( - " %1$s(\n" + - " char *buffer,\n" + - " const std::uint64_t offset,\n" + - " const std::uint64_t bufferLength,\n" + - " const std::uint64_t actingBlockLength,\n" + - " const std::uint64_t actingVersion,\n" + - " CodecState codecState) :\n" + - " m_buffer(buffer),\n" + - " m_bufferLength(bufferLength),\n" + - " m_offset(offset),\n" + - " m_position(sbeCheckPosition(offset + actingBlockLength)),\n" + - " m_actingBlockLength(actingBlockLength),\n" + - " m_actingVersion(actingVersion),\n" + - " m_codecState(codecState)\n" + - " {\n" + - " }\n\n", - className); - return String.format( " %1$s() = default;\n\n" + - "%2$s" + - " %1$s(\n" + " char *buffer,\n" + " const std::uint64_t offset,\n" + @@ -2695,6 +2671,7 @@ private static CharSequence generateConstructorsAndOperators( " m_actingBlockLength(actingBlockLength),\n" + " m_actingVersion(actingVersion)\n" + " {\n" + + "%2$s" + " }\n\n" + " %1$s(char *buffer, const std::uint64_t bufferLength) :\n" + @@ -2711,7 +2688,7 @@ private static CharSequence generateConstructorsAndOperators( " {\n" + " }\n\n", className, - constructorWithCodecState); + generateCodecStateTransitionForWrapping(fieldPrecedenceModel)); } private CharSequence generateMessageFlyweightCode( @@ -2728,26 +2705,25 @@ private CharSequence generateMessageFlyweightCode( final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); - final String codecStateArgument = null == fieldPrecedenceModel ? "" : ", m_codecState"; - return String.format( "private:\n" + + "%14$s" + "%15$s" + - "%16$s" + " char *m_buffer = nullptr;\n" + " std::uint64_t m_bufferLength = 0;\n" + " std::uint64_t m_offset = 0;\n" + " std::uint64_t m_position = 0;\n" + " std::uint64_t m_actingBlockLength = 0;\n" + " std::uint64_t m_actingVersion = 0;\n" + - "%17$s" + + "%16$s" + " inline std::uint64_t *sbePositionPtr() SBE_NOEXCEPT\n" + " {\n" + " return &m_position;\n" + " }\n\n" + - "%22$s" + + "%19$s" + + "%21$s" + "public:\n" + " static constexpr %1$s SBE_BLOCK_LENGTH = %2$s;\n" + @@ -2775,7 +2751,7 @@ private CharSequence generateMessageFlyweightCode( " using messageHeader = %12$s;\n\n" + - "%18$s" + + "%17$s" + "%11$s" + " SBE_NODISCARD static SBE_CONSTEXPR %1$s sbeBlockLength() SBE_NOEXCEPT\n" + @@ -2826,7 +2802,7 @@ private CharSequence generateMessageFlyweightCode( " m_actingBlockLength = sbeBlockLength();\n" + " m_actingVersion = sbeSchemaVersion();\n" + " m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" + - "%19$s" + + "%18$s" + " return *this;\n" + " }\n\n" + @@ -2847,12 +2823,10 @@ private CharSequence generateMessageFlyweightCode( " m_actingBlockLength = sbeBlockLength();\n" + " m_actingVersion = sbeSchemaVersion();\n" + " m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" + - "%19$s" + + "%18$s" + " return *this;\n" + " }\n\n" + - "%20$s" + - " %10$s &wrapForDecode(\n" + " char *buffer,\n" + " const std::uint64_t offset,\n" + @@ -2866,7 +2840,7 @@ private CharSequence generateMessageFlyweightCode( " m_actingBlockLength = actingBlockLength;\n" + " m_actingVersion = actingVersion;\n" + " m_position = sbeCheckPosition(m_offset + m_actingBlockLength);\n" + - "%21$s" + + "%20$s" + " return *this;\n" + " }\n\n" + @@ -2903,7 +2877,7 @@ private CharSequence generateMessageFlyweightCode( " SBE_NODISCARD std::uint64_t decodeLength() const\n" + " {\n" + - " %10$s skipper(m_buffer, m_offset, m_bufferLength, sbeBlockLength(), m_actingVersion%14$s);\n" + + " %10$s skipper(m_buffer, m_offset, m_bufferLength, sbeBlockLength(), m_actingVersion);\n" + " skipper.skip();\n" + " return skipper.encodedLength();\n" + " }\n\n" + @@ -2940,14 +2914,13 @@ private CharSequence generateMessageFlyweightCode( generateConstructorsAndOperators(className, fieldPrecedenceModel), formatClassName(headerType), semanticVersion, - codecStateArgument, generateFieldOrderStateEnum(fieldPrecedenceModel), generateLookupTableDeclarations(fieldPrecedenceModel), generateFieldOrderStateMember(fieldPrecedenceModel), generateAccessOrderErrorType(fieldPrecedenceModel), - generateEncoderWrapListener(fieldPrecedenceModel), - generateDecoderWrapListener(fieldPrecedenceModel), - generateDecoderWrapListenerCall(fieldPrecedenceModel), + generateCodecStateTransitionForWrappingLatestVersion(fieldPrecedenceModel), + generateOnWrappedListener(fieldPrecedenceModel), + generateCodecStateTransitionForWrapping(fieldPrecedenceModel), generateHiddenCopyConstructor(" ", className)); } @@ -3118,7 +3091,7 @@ private static CharSequence generateFieldOrderStateMember(final FieldPrecedenceM return sb; } - private static CharSequence generateDecoderWrapListener(final FieldPrecedenceModel fieldPrecedenceModel) + private static CharSequence generateOnWrappedListener(final FieldPrecedenceModel fieldPrecedenceModel) { if (null == fieldPrecedenceModel) { @@ -3131,7 +3104,7 @@ private static CharSequence generateDecoderWrapListener(final FieldPrecedenceMod } final StringBuilder sb = new StringBuilder(); - sb.append(INDENT).append("void onWrapForDecode(std::uint64_t actingVersion)\n") + sb.append(INDENT).append("void onWrapped(std::uint64_t actingVersion)\n") .append(INDENT).append("{\n"); final MutableBoolean actingVersionCanBeTooLowToBeValid = new MutableBoolean(true); @@ -3168,7 +3141,7 @@ private static CharSequence generateDecoderWrapListener(final FieldPrecedenceMod } - private CharSequence generateDecoderWrapListenerCall(final FieldPrecedenceModel fieldPrecedenceModel) + private CharSequence generateCodecStateTransitionForWrapping(final FieldPrecedenceModel fieldPrecedenceModel) { if (null == fieldPrecedenceModel) { @@ -3185,10 +3158,12 @@ private CharSequence generateDecoderWrapListenerCall(final FieldPrecedenceModel return sb; } - return generateAccessOrderListenerCall(fieldPrecedenceModel, TWO_INDENT, "onWrapForDecode", "actingVersion"); + return generateAccessOrderListenerCall(fieldPrecedenceModel, TWO_INDENT, "onWrapped", "actingVersion"); } - private CharSequence generateEncoderWrapListener(final FieldPrecedenceModel fieldPrecedenceModel) + private CharSequence generateCodecStateTransitionForWrappingLatestVersion( + final FieldPrecedenceModel fieldPrecedenceModel + ) { if (null == fieldPrecedenceModel) { diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp index ef2b58d75c..24ad58c9b8 100644 --- a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include "gtest/gtest.h" #include "gmock/gmock.h" #include "order_check/MultipleVarLength.h" @@ -4955,3 +4956,95 @@ TEST_F(FieldAccessOrderCheckTest, allowsSkippingFutureGroupWhenDecodingFromVersi EXPECT_EQ(decoder.a(), 42); EXPECT_EQ(decoder.getBAsString(), "abc"); } + +TEST_F(FieldAccessOrderCheckTest, worksWithWrappingConstructors1) +{ + MultipleVarLength encoder(m_buffer, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder(m_buffer, BUFFER_LEN); + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, worksWithWrappingConstructors2) +{ + MultipleVarLength encoder( + m_buffer, + BUFFER_LEN, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion() + ); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder( + m_buffer, + BUFFER_LEN, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion() + ); + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, worksWithWrappingConstructors3) +{ + MultipleVarLength encoder( + m_buffer, + OFFSET, + BUFFER_LEN, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion() + ); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder( + m_buffer, + OFFSET, + BUFFER_LEN, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion() + ); + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); +} + +TEST_F(FieldAccessOrderCheckTest, worksWithInsertionOperator) +{ + MultipleVarLength encoder( + m_buffer, + OFFSET, + BUFFER_LEN, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion() + ); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder( + m_buffer, + BUFFER_LEN + ); + std::stringstream stream; + stream << decoder; + + const std::string expected = "\"a\": 42, \"b\": \"abc\", \"c\": \"def\""; + EXPECT_THAT(stream.str(), HasSubstr(expected)); + EXPECT_EQ(decoder.a(), 42); + EXPECT_EQ(decoder.getBAsString(), "abc"); + EXPECT_EQ(decoder.getCAsString(), "def"); +} From 91813eafd488ee47f43054f8efcd63ab1ab00249 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 11 Dec 2024 12:02:05 +0000 Subject: [PATCH 493/805] Fix warning about used args in GolangFlyweightGenerator. --- .../golang/flyweight/GolangFlyweightGenerator.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java index de9d86f8cc..8d824112fc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java @@ -2236,7 +2236,7 @@ private CharSequence generateMessageFlyweightCode( " %10$sSbeTemplateID %3$s = %4$s\n" + " %10$sSbeSchemaID %5$s = %6$s\n" + " %10$sSbeSchemaVersion %7$s = %8$s\n" + - " %10$sSbeSemanticVersion string = \"%13$s\"\n" + + " %10$sSbeSemanticVersion string = \"%11$s\"\n" + " )\n\n" + " func (m *%10$s) SbeBlockLength() %1$s {\n" + @@ -2260,7 +2260,7 @@ private CharSequence generateMessageFlyweightCode( " }\n\n" + " func (m *%10$s) SbeSemanticVersion() string {\n" + - " return \"%13$s\"\n" + + " return \"%11$s\"\n" + " }\n\n" + " func (m *%10$s) SbeSemanticType() string {\n" + @@ -2375,9 +2375,8 @@ private CharSequence generateMessageFlyweightCode( generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), semanticType, className, - generateConstructorsAndOperators(className), - formatClassName(headerType), - semanticVersion)); + generateConstructorsAndOperators(className))); + return sb.toString(); } From fad6442a3c7627442368277a2489dbfb75c2eb36 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 11 Dec 2024 12:11:44 +0000 Subject: [PATCH 494/805] Fix warning about used args in GolangFlyweightGenerator. --- .../generation/golang/flyweight/GolangFlyweightGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java index 8d824112fc..5a44da3e67 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java @@ -2375,7 +2375,7 @@ private CharSequence generateMessageFlyweightCode( generateLiteral(ir.headerStructure().schemaVersionType(), Integer.toString(ir.version())), semanticType, className, - generateConstructorsAndOperators(className))); + semanticVersion)); return sb.toString(); } From bcb2e06b426e9408eba7a2f22fd97c58752dd358 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 11 Dec 2024 12:25:18 +0000 Subject: [PATCH 495/805] Fix warning about used variable in GolangFlyweightGenerator. --- .../generation/golang/flyweight/GolangFlyweightGenerator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java index 5a44da3e67..259c461408 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java @@ -2174,7 +2174,6 @@ private CharSequence generateMessageFlyweightCode( final String schemaIdType = goTypeName(ir.headerStructure().schemaIdType()); final String schemaVersionType = goTypeName(ir.headerStructure().schemaVersionType()); final String semanticType = token.encoding().semanticType() == null ? "" : token.encoding().semanticType(); - final String headerType = ir.headerStructure().tokens().get(0).name(); final String semanticVersion = ir.semanticVersion() == null ? "" : ir.semanticVersion(); sb.append(" buffer []byte\n" + From 3199ae72b7077ce862236ea961b5b1657349907b Mon Sep 17 00:00:00 2001 From: Nate Bradac <38217740+nbradac@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:26:42 -0500 Subject: [PATCH 496/805] [C++] hide the m_codecStatePtr behind ifdefs to avoid overhead when precedence checking is disabled (#1036) --- .../sbe/generation/cpp/CppGenerator.java | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 846a289e11..99f00e0ffc 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -694,6 +694,7 @@ private void generateGroupClassHeader( if (null != fieldPrecedenceModel) { + sb.append("#if defined(").append(precedenceChecksFlagName).append(")\n"); new Formatter(sb).format( indent + " CodecState *m_codecStatePtr = nullptr;\n\n" + @@ -710,19 +711,38 @@ private void generateGroupClassHeader( indent + " void codecState(CodecState codecState)\n" + indent + " {\n" + indent + " *m_codecStatePtr = codecState;\n" + - indent + " }\n\n" + indent + " }\n" ); + sb.append("#else\n"); + new Formatter(sb).format( + indent + " CodecState codecState() const SBE_NOEXCEPT\n" + + indent + " {\n" + + indent + " return " + qualifiedStateCase(fieldPrecedenceModel.notWrappedState()) + ";\n" + + indent + " }\n\n" + + + indent + " CodecState *codecStatePtr()\n" + + indent + " {\n" + + indent + " return nullptr;\n" + + indent + " }\n\n" + + + indent + " void codecState(CodecState codecState)\n" + + indent + " {\n" + + indent + " }\n" + ); + sb.append("#endif\n\n"); } sb.append(generateHiddenCopyConstructor(indent + " ", groupClassName)); final String codecStateParameter = null == fieldPrecedenceModel ? ")\n" : - ",\n " + indent + " CodecState *codecState)\n"; + ",\n" + indent + " CodecState *codecState)\n"; final String codecStateAssignment = null == fieldPrecedenceModel ? "" : - indent + " m_codecStatePtr = codecState;\n"; + "#if defined(" + precedenceChecksFlagName + ")\n" + + indent + " m_codecStatePtr = codecState;\n" + + "#endif\n"; new Formatter(sb).format( indent + "public:\n" + @@ -802,7 +822,9 @@ private void generateGroupClassHeader( { final String codecStateNullAssignment = null == fieldPrecedenceModel ? "" : - indent + " m_codecStatePtr = nullptr;\n"; + "#if defined(" + precedenceChecksFlagName + ")\n" + + indent + " m_codecStatePtr = nullptr;\n" + + "#endif\n"; new Formatter(sb).format( indent + " inline void notPresent(std::uint64_t actingVersion)\n" + From 75a56d5f262e714eea189533533c73e13e35ed9f Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Fri, 13 Dec 2024 09:44:13 -0600 Subject: [PATCH 497/805] [Rust] Updated code generator to resolve Issue #1028 (#1037) * [Rust] updated LibRsDef.generate() to add "#![allow(clippy::all)]" * [Rust] generating 'From for PRIMITIVE' instead of 'Into for ENUM' to satisfy 'from_over_into' lint * [Rust] removed unused method parameter * fixed formatting * [Rust] Updated code generator to resolve Issue #1022 * [Rust] meant issue #1028 not 1022 (renamed files accordingly) --------- Co-authored-by: Michael Ward --- build.gradle | 3 +- rust/Cargo.toml | 1 + .../sbe/generation/rust/RustGenerator.java | 2 +- sbe-tool/src/test/resources/issue1028.xml | 30 +++++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 sbe-tool/src/test/resources/issue1028.xml diff --git a/build.gradle b/build.gradle index 9641c9972f..6a20ee7201 100644 --- a/build.gradle +++ b/build.gradle @@ -653,6 +653,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe-tool/src/test/resources/issue972.xml', 'sbe-tool/src/test/resources/issue984.xml', 'sbe-tool/src/test/resources/issue987.xml', + 'sbe-tool/src/test/resources/issue1028.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', 'sbe-tool/src/test/resources/nested-composite-name.xml', ] @@ -866,7 +867,7 @@ tasks.register('generateGolangCodecs') { 'generateGolangFlyweightCodecTestComposite', 'generateGolangFlyweightCodecsWithXIncludes', 'generateGolangFlyweightCodecsWithXSD', - 'generateIrCodecs', + 'generateIrCodecs', ':sbe-all:jar' } diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6b265a3020..f15d4d2f6d 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -16,6 +16,7 @@ issue_895 = { path = "../generated/rust/issue895" } issue_972 = { path = "../generated/rust/issue972" } issue_984 = { path = "../generated/rust/issue984" } issue_987 = { path = "../generated/rust/issue987" } +issue_1028 = { path = "../generated/rust/issue1028" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } nested_composite_name = { path = "../generated/rust/nested-composite-name" } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 0c03766553..f78899cb4b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1580,7 +1580,7 @@ private static void generateCompositeDecoder( indent(out, 2, "offset: usize,\n"); indent(out, 1, "}\n\n"); - final int version = tokens.stream().findFirst().get().version(); + final int version = tokens.get(1).version(); // skip BEGIN_COMPOSITE appendImplReaderForComposite(schemaVersionType, version, out, 1, decoderName); // impl<'a, P> start diff --git a/sbe-tool/src/test/resources/issue1028.xml b/sbe-tool/src/test/resources/issue1028.xml new file mode 100644 index 0000000000..2a88c59c1b --- /dev/null +++ b/sbe-tool/src/test/resources/issue1028.xml @@ -0,0 +1,30 @@ + + + + 0 + + + + + + + + + + + + + + + + \ No newline at end of file From 1d6e3f1688678ababa7b8119c16c1636c581636f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 13 Dec 2024 17:26:12 +0100 Subject: [PATCH 498/805] [Java] Upgrade to Checkstyle 10.21.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5cbe7ecda4..ec0df3ab1c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "1.23.1" -checkstyle = "10.20.2" +checkstyle = "10.21.0" junit = "5.11.3" jmh = "1.37" gradle = "8.11.1" From ec42a79fab4eadc5fc248c06fef453a39258573d Mon Sep 17 00:00:00 2001 From: Nate Bradac <38217740+nbradac@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:09:02 -0500 Subject: [PATCH 499/805] Std span (#1038) * [C++] Integrate std::span support for flyweight API The impetus was a bug that we ran into when writing a string-literal to a fixed-width char field: ```c++ flyweight.putFixedChar("hello"); ``` This is unsafe: - If the field size is less than 6, we overrun the buffer and corrupt it. - If the field size is more than 6, we don't zero pad the rest of it. Instead, we build on support for the std::string_view getters and setters, which do length checking. std::span generalizes this to fixed-width fields of all types. Notably, if the size of the std::span is knowable at compile time, we pay no runtime cost for the length checking, and we should get similar performance to the existing API which takes a raw pointer. Further, we add a sbetool option to disable accepting arrays by raw pointer, which should prevent memcpy operation without bounds checking. This is off by default to avoid a breaking change. * [C++] hide USE_SPAN behind ENABLE_SPAN * [C++] add macro guards --------- Co-authored-by: Matt Stern --- .../sbe/generation/cpp/CppGenerator.java | 138 +++++++++++++++++- sbe-tool/src/test/cpp/CMakeLists.txt | 13 +- sbe-tool/src/test/cpp/CodeGenTest.cpp | 62 ++++++++ 3 files changed, 207 insertions(+), 6 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 99f00e0ffc..b8d427241a 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -49,6 +49,8 @@ public class CppGenerator implements CodeGenerator { private static final boolean DISABLE_IMPLICIT_COPYING = Boolean.parseBoolean( System.getProperty("sbe.cpp.disable.implicit.copying", "false")); + private static final boolean DISABLE_RAW_ARRAYS = Boolean.parseBoolean( + System.getProperty("sbe.cpp.disable.raw.arrays", "false")); private static final String BASE_INDENT = ""; private static final String INDENT = " "; private static final String TWO_INDENT = INDENT + INDENT; @@ -1634,6 +1636,23 @@ private static CharSequence generateArrayFieldNotPresentCondition(final int sinc sinceVersion); } + private static CharSequence generateSpanFieldNotPresentCondition( + final int sinceVersion, final String indent, final String cppTypeName) + { + if (0 == sinceVersion) + { + return ""; + } + + return String.format( + indent + " if (m_actingVersion < %1$d)\n" + + indent + " {\n" + + indent + " return std::span();\n" + + indent + " }\n\n", + sinceVersion, + cppTypeName); + } + private static CharSequence generateStringNotPresentCondition(final int sinceVersion, final String indent) { if (0 == sinceVersion) @@ -1703,10 +1722,20 @@ private CharSequence generateFileHeader( "#if __cplusplus >= 201703L\n" + "# include \n" + "# define SBE_NODISCARD [[nodiscard]]\n" + + "# if !defined(SBE_USE_STRING_VIEW)\n" + + "# define SBE_USE_STRING_VIEW 1\n" + + "# endif\n" + "#else\n" + "# define SBE_NODISCARD\n" + "#endif\n\n" + + "#if __cplusplus >= 202002L\n" + + "# include \n" + + "# if !defined(SBE_USE_SPAN)\n" + + "# define SBE_USE_SPAN 1\n" + + "# endif\n" + + "#endif\n\n" + + "#if !defined(__STDC_LIMIT_MACROS)\n" + "# define __STDC_LIMIT_MACROS 1\n" + "#endif\n\n" + @@ -2258,12 +2287,38 @@ private void generateArrayProperty( accessOrderListenerCall); new Formatter(sb).format("\n" + - indent + " %1$s &put%2$s(const char *const src)%7$s\n" + + indent + " #ifdef SBE_USE_SPAN\n" + + indent + " SBE_NODISCARD std::span get%1$sAsSpan() const%7$s\n" + + indent + " {\n" + + "%3$s" + + "%6$s" + + indent + " const char *buffer = m_buffer + m_offset + %4$d;\n" + + indent + " return std::span(reinterpret_cast(buffer), %2$d);\n" + + indent + " }\n" + + indent + " #endif\n", + toUpperFirstChar(propertyName), + arrayLength, + generateSpanFieldNotPresentCondition(propertyToken.version(), indent, cppTypeName), + offset, + cppTypeName, + accessOrderListenerCall, + noexceptDeclaration); + + new Formatter(sb).format("\n" + + indent + " #ifdef SBE_USE_SPAN\n" + + indent + " template \n" + + indent + " %1$s &put%2$s(std::span src)%7$s\n" + indent + " {\n" + + indent + " static_assert(N <= %5$d, \"array too large for put%2$s\");\n\n" + "%6$s" + - indent + " std::memcpy(m_buffer + m_offset + %3$d, src, sizeof(%4$s) * %5$d);\n" + + indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * N);\n" + + indent + " for (std::size_t start = N; start < %5$d; ++start)\n" + + indent + " {\n" + + indent + " m_buffer[m_offset + %3$d + start] = 0;\n" + + indent + " }\n\n" + indent + " return *this;\n" + - indent + " }\n", + indent + " }\n" + + indent + " #endif\n", containingClassName, toUpperFirstChar(propertyName), offset, @@ -2272,6 +2327,79 @@ private void generateArrayProperty( accessOrderListenerCall, noexceptDeclaration); + if (encodingToken.encoding().primitiveType() != PrimitiveType.CHAR) + { + new Formatter(sb).format("\n" + + indent + " #ifdef SBE_USE_SPAN\n" + + indent + " %1$s &put%2$s(std::span src)\n" + + indent + " {\n" + + indent + " const std::size_t srcLength = src.size();\n" + + indent + " if (srcLength > %5$d)\n" + + indent + " {\n" + + indent + " throw std::runtime_error(\"array too large for put%2$s [E106]\");\n" + + indent + " }\n\n" + + + "%6$s" + + indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * srcLength);\n" + + indent + " for (std::size_t start = srcLength; start < %5$d; ++start)\n" + + indent + " {\n" + + indent + " m_buffer[m_offset + %3$d + start] = 0;\n" + + indent + " }\n\n" + + indent + " return *this;\n" + + indent + " }\n" + + indent + " #endif\n", + containingClassName, + toUpperFirstChar(propertyName), + offset, + cppTypeName, + arrayLength, + accessOrderListenerCall); + } + + if (!DISABLE_RAW_ARRAYS) + { + new Formatter(sb).format("\n" + + indent + " #ifdef SBE_USE_SPAN\n" + + indent + " template \n" + + // If std::span is available, redirect string literals to the std::span-accepting overload, + // where we can do compile-time bounds checking. + indent + " %1$s &put%2$s(T&& src) %7$s requires\n" + + indent + " (std::is_pointer_v> &&\n" + + indent + " !std::is_array_v>)\n" + + indent + " #else\n" + + indent + " %1$s &put%2$s(const char *const src)%7$s\n" + + indent + " #endif\n" + + indent + " {\n" + + "%6$s" + + indent + " std::memcpy(m_buffer + m_offset + %3$d, src, sizeof(%4$s) * %5$d);\n" + + indent + " return *this;\n" + + indent + " }\n", + containingClassName, + toUpperFirstChar(propertyName), + offset, + cppTypeName, + arrayLength, + accessOrderListenerCall, + noexceptDeclaration); + + } + if (encodingToken.encoding().primitiveType() == PrimitiveType.CHAR) + { + // Resolve ambiguity of string literal arguments, which match both + // std::span and std::string_view overloads. + new Formatter(sb).format("\n" + + indent + " #ifdef SBE_USE_SPAN\n" + + indent + " template \n" + + indent + " %1$s &put%2$s(const char (&src)[N])%3$s\n" + + indent + " {\n" + + indent + " return put%2$s(std::span(src));\n" + + indent + " }\n" + + indent + " #endif\n", + containingClassName, + toUpperFirstChar(propertyName), + noexceptDeclaration); + } + if (arrayLength > 1 && arrayLength <= 4) { sb.append("\n").append(indent).append(" ") @@ -2332,7 +2460,7 @@ private void generateArrayProperty( generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName); new Formatter(sb).format("\n" + - indent + " #if __cplusplus >= 201703L\n" + + indent + " #ifdef SBE_USE_STRING_VIEW\n" + indent + " SBE_NODISCARD std::string_view get%1$sAsStringView() const%6$s\n" + indent + " {\n" + "%4$s" + @@ -2354,7 +2482,7 @@ private void generateArrayProperty( noexceptDeclaration); new Formatter(sb).format("\n" + - indent + " #if __cplusplus >= 201703L\n" + + indent + " #ifdef SBE_USE_STRING_VIEW\n" + indent + " %1$s &put%2$s(const std::string_view str)\n" + indent + " {\n" + indent + " const std::size_t srcLength = str.length();\n" + diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 1de7412623..b3271dade0 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -103,6 +103,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") sbe_test(DtoTest codecs) target_compile_features(DtoTest PRIVATE cxx_std_17) endif() + + # Check if the GCC version supports C++20 + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11.0") + target_compile_features(CodeGenTest PRIVATE cxx_std_20) + endif() endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "CLang") @@ -111,12 +116,18 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "CLang") sbe_test(DtoTest codecs) target_compile_features(DtoTest PRIVATE cxx_std_17) endif() + + # Check if CLang version supports C++20 + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "10.0") + target_compile_features(CodeGenTest PRIVATE cxx_std_20) + endif() endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - # Check if MSVC version supports C++17 + # Check if MSVC version supports C++17 / C++20 if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "19.14") sbe_test(DtoTest codecs) target_compile_options(DtoTest PRIVATE /std:c++17) + target_compile_options(CodeGenTest PRIVATE /std:c++20) endif() endif() diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index ea00b8120c..039620a6c1 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -1083,3 +1083,65 @@ TEST_F(CodeGenTest, shouldAllowForMultipleIterations) std::string passFive = walkCar(carDecoder); EXPECT_EQ(passOne, passFive); } + +#ifdef SBE_USE_STRING_VIEW +TEST_F(CodeGenTest, shouldBeAbleToUseStdStringViewMethods) +{ + std::string vehicleCode(VEHICLE_CODE, Car::vehicleCodeLength()); + + char buffer[BUFFER_LEN] = {}; + std::uint64_t baseOffset = MessageHeader::encodedLength(); + Car car; + car.wrapForEncode(buffer, baseOffset, sizeof(buffer)); + car.putVehicleCode(std::string_view(vehicleCode)); + + car.sbeRewind(); + EXPECT_EQ(car.getVehicleCodeAsStringView(), vehicleCode); +} +#endif + +#ifdef SBE_USE_SPAN +TEST_F(CodeGenTest, shouldBeAbleToUseStdSpanViewMethods) +{ + char buffer[BUFFER_LEN] = {}; + + std::uint64_t baseOffset = MessageHeader::encodedLength(); + Car car; + car.wrapForEncode(buffer, baseOffset, sizeof(buffer)); + + { + std::array numbers; + for (std::uint64_t i = 0; i < Car::someNumbersLength(); i++) + { + numbers[i] = static_cast(i); + } + car.putSomeNumbers(numbers); + } + + car.sbeRewind(); + + { + std::span numbers = car.getSomeNumbersAsSpan(); + ASSERT_EQ(numbers.size(), Car::someNumbersLength()); + for (std::uint64_t i = 0; i < numbers.size(); i++) + { + EXPECT_EQ(numbers[i], static_cast(i)); + } + } +} +#endif + +#ifdef SBE_USE_SPAN +TEST_F(CodeGenTest, shouldBeAbleToResolveStringLiterals) +{ + char buffer[BUFFER_LEN] = {}; + + std::uint64_t baseOffset = MessageHeader::encodedLength(); + Car car; + car.wrapForEncode(buffer, baseOffset, sizeof(buffer)); + car.putVehicleCode("ABCDE"); + + car.sbeRewind(); + EXPECT_EQ(car.getVehicleCodeAsStringView(), "ABCDE"); +} +#endif \ No newline at end of file From 658838ed3534dd8f53dd513ca54444d3379748b7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 16 Dec 2024 21:11:50 +0100 Subject: [PATCH 500/805] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26efe26f10..b286d72970 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Example for Maven: ```xml     uk.co.real-logic -    sbe-all +    sbe-tool     ${sbe.tool.version} ``` From 633fe63dd569fe0fd5f75e69c16d42c9eed9d265 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:28:10 +0100 Subject: [PATCH 501/805] [Java] Upgrade to JUnit 5.11.4. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ec0df3ab1c..0f911604c5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] agrona = "1.23.1" checkstyle = "10.21.0" -junit = "5.11.3" +junit = "5.11.4" jmh = "1.37" gradle = "8.11.1" From 268fde019391b01b6915cb469bc66ef0de869bc5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:49:31 +0100 Subject: [PATCH 502/805] [Java] Upgrade to Agrona 2.0.0. --- build.gradle | 2 ++ gradle/libs.versions.toml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 6a20ee7201..dbcc35fdaa 100644 --- a/build.gradle +++ b/build.gradle @@ -217,6 +217,7 @@ subprojects { all { testTask.configure { useJUnitPlatform() + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') testLogging { for (def level : LogLevel.values()) @@ -303,6 +304,7 @@ project(':sbe-tool') { minHeapSize = '2g' maxHeapSize = '2g' + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') javaLauncher.set(toolchainLauncher) systemProperty 'sbe.dll', "${rootProject.projectDir}/csharp/sbe-dll/bin/Release/netstandard2.0/SBE.dll" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0f911604c5..b433f94282 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,12 @@ [versions] -agrona = "1.23.1" +agrona = "2.0.0" checkstyle = "10.21.0" junit = "5.11.4" jmh = "1.37" gradle = "8.11.1" [libraries] -agrona = { group = "org.agrona", name = "agrona", version = { strictly = "[1.23.1, 2.0[", require = "1.23.1" } } +agrona = { group = "org.agrona", name = "agrona", version.ref = "agrona" } mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.2" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.2" } From c2e9cb4674f4e18d0d2304321215db34b65a8e69 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:52:53 +0100 Subject: [PATCH 503/805] 1.34.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6214e03b71..2b17ffd504 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.34.0-SNAPSHOT +1.34.0 From 6b37857c77d1a2a775a932a1242b2c13acca91a8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:53:04 +0100 Subject: [PATCH 504/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 2b17ffd504..c9c35c012f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.34.0 +1.35.0-SNAPSHOT From b848b3a670835197afa9d0373794858825e9aab1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:11:39 +0100 Subject: [PATCH 505/805] [Java] Add JVM opts to generator tasks. --- build.gradle | 47 +++++++++++++++++++++++++++++++++++++++-------- version.txt | 2 +- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index dbcc35fdaa..f4c65045ba 100644 --- a/build.gradle +++ b/build.gradle @@ -319,6 +319,7 @@ project(':sbe-tool') { dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': generatedDir, 'sbe.target.language': 'Java', @@ -335,6 +336,7 @@ project(':sbe-tool') { dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': generatedDir, 'sbe.target.language': 'java', @@ -480,7 +482,7 @@ project(':sbe-samples') { sourceSets { generated { java.srcDir generatedDir - compileClasspath += project(':sbe-all').sourceSets.main.runtimeClasspath + compileClasspath += project(':sbe-tool').sourceSets.main.runtimeClasspath } } @@ -489,7 +491,8 @@ project(':sbe-samples') { tasks.register('generateCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') - classpath = project(':sbe-all').sourceSets.main.runtimeClasspath + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': generatedDir, 'sbe.target.language': 'Java', @@ -505,6 +508,7 @@ project(':sbe-samples') { dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.examples.ExampleUsingGeneratedStub') classpath = sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties System.getProperties() } @@ -512,6 +516,7 @@ project(':sbe-samples') { dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.examples.ExampleUsingGeneratedStubExtension') classpath = sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties System.getProperties() } @@ -519,6 +524,7 @@ project(':sbe-samples') { dependsOn 'compileJava' mainClass.set('uk.co.real_logic.sbe.examples.OtfExample') classpath = sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') workingDir = 'src/main/resources' } @@ -596,7 +602,7 @@ project(':sbe-benchmarks') { sourceSets { generated { java.srcDir 'build/generated-src' - compileClasspath += project(':sbe-all').sourceSets.main.runtimeClasspath + compileClasspath += project(':sbe-tool').sourceSets.main.runtimeClasspath } } @@ -605,7 +611,8 @@ project(':sbe-benchmarks') { tasks.register('generateCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') - classpath = project(':sbe-all').sourceSets.main.runtimeClasspath + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'build/generated-src', 'sbe.target.language': 'Java', @@ -629,7 +636,8 @@ project(':sbe-benchmarks') { tasks.register('generateRustExamples', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') - classpath = project(':sbe-all').sourceSets.main.runtimeClasspath + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'generated/rust', 'sbe.xinclude.aware': 'true', @@ -644,7 +652,8 @@ tasks.register('generateRustExamples', JavaExec) { tasks.register('generateRustTestCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') - classpath = project(':sbe-all').sourceSets.main.runtimeClasspath + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'generated/rust', 'sbe.xinclude.aware': 'true', @@ -664,6 +673,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { tasks.register('generateCarExampleDataFile', JavaExec) { mainClass.set('uk.co.real_logic.sbe.examples.ExampleUsingGeneratedStub') classpath = project(':sbe-samples').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties('sbe.encoding.filename': 'rust/car_example_baseline_data.sbe') args = [] standardOutput = new ByteArrayOutputStream() @@ -672,6 +682,7 @@ tasks.register('generateCarExampleDataFile', JavaExec) { tasks.register('generateCarExampleExtensionDataFile', JavaExec) { mainClass.set('uk.co.real_logic.sbe.examples.ExampleUsingGeneratedStubExtension') classpath = project(':sbe-samples').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties('sbe.encoding.filename': 'rust/car_example_extension_data.sbe') args = [] standardOutput = new ByteArrayOutputStream() @@ -702,6 +713,7 @@ tasks.register('runRustTests', Exec) { tasks.register('generateGolangCodecTestComposite', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/struct/src', 'sbe.target.language': 'golang') @@ -711,6 +723,7 @@ tasks.register('generateGolangCodecTestComposite', JavaExec) { tasks.register('generateGolangCodecTestBasic', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/struct/src/basic', 'sbe.target.language': 'golang') @@ -720,6 +733,7 @@ tasks.register('generateGolangCodecTestBasic', JavaExec) { tasks.register('generateGolangCodecTestGroup', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/struct/src/group', 'sbe.target.language': 'golang') @@ -728,6 +742,7 @@ tasks.register('generateGolangCodecTestGroup', JavaExec) { tasks.register('generateGolangCodecTestVarData', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath systemProperties( 'sbe.output.dir': 'gocode/struct/src/vardata', @@ -738,6 +753,7 @@ tasks.register('generateGolangCodecTestVarData', JavaExec) { tasks.register('generateGolangCodecsWithXIncludes', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/struct/src', 'sbe.target.language': 'golang', @@ -750,6 +766,7 @@ tasks.register('generateGolangCodecsWithXIncludes', JavaExec) { tasks.register('generateGolangCodecsWithXSD', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/struct/src', 'sbe.target.language': 'golang', @@ -776,6 +793,7 @@ tasks.register('generateGolangCodecsWithXSD', JavaExec) { tasks.register('generateGolangFlyweightCodecTestComposite', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/flyweight/src', 'sbe.go.generate.generate.flyweights': 'true', @@ -786,6 +804,7 @@ tasks.register('generateGolangFlyweightCodecTestComposite', JavaExec) { tasks.register('generateGolangFlyweightCodecTestBasic', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/flyweight/src/basic', 'sbe.go.generate.generate.flyweights': 'true', @@ -796,6 +815,7 @@ tasks.register('generateGolangFlyweightCodecTestBasic', JavaExec) { tasks.register('generateGolangFlyweightCodecTestGroup', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/flyweight/src/group', 'sbe.go.generate.generate.flyweights': 'true', @@ -806,6 +826,7 @@ tasks.register('generateGolangFlyweightCodecTestGroup', JavaExec) { tasks.register('generateGolangFlyweightCodecTestVarData', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/flyweight/src/vardata', 'sbe.go.generate.generate.flyweights': 'true', @@ -816,6 +837,7 @@ tasks.register('generateGolangFlyweightCodecTestVarData', JavaExec) { tasks.register('generateGolangFlyweightCodecsWithXIncludes', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/flyweight/src', 'sbe.go.generate.generate.flyweights': 'true', @@ -829,6 +851,7 @@ tasks.register('generateGolangFlyweightCodecsWithXIncludes', JavaExec) { tasks.register('generateGolangFlyweightCodecsWithXSD', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'gocode/flyweight/src', 'sbe.go.generate.generate.flyweights': 'true', @@ -880,6 +903,7 @@ tasks.register('generateGolangCodecs') { tasks.register('generateCSharpCodecsWithXIncludes', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'csharp/sbe-generated', 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', @@ -892,6 +916,7 @@ tasks.register('generateCSharpCodecsWithXIncludes', JavaExec) { tasks.register('generateCSharpTestCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'csharp/sbe-generated', 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', @@ -912,6 +937,7 @@ tasks.register('generateCSharpTestCodecs', JavaExec) { tasks.register('generateCSharpTestDtos', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'csharp/sbe-generated', 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharpDtos', @@ -924,6 +950,7 @@ tasks.register('generateCSharpTestDtos', JavaExec) { tasks.register('generateCSharpExplicitPackageOverrideCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'csharp/sbe-generated', 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharp', @@ -936,6 +963,7 @@ tasks.register('generateCSharpExplicitPackageOverrideCodecs', JavaExec) { tasks.register('generateCSharpExplicitPackageOverrideDtos', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'csharp/sbe-generated', 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharpDtos', @@ -956,7 +984,8 @@ tasks.register('generateCSharpCodecs') { tasks.register('generateJavaIrCodecs', JavaExec) { dependsOn 'computeOriginalIrHash' mainClass.set('uk.co.real_logic.sbe.SbeTool') - classpath = project(':sbe-all').sourceSets.main.runtimeClasspath + classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'sbe-tool/src/main/java', 'sbe.target.language': 'Java', @@ -970,6 +999,7 @@ tasks.register('generateJavaIrCodecs', JavaExec) { tasks.register('generateCppIrCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'sbe-tool/src/main/cpp', 'sbe.target.language': 'cpp', @@ -982,6 +1012,7 @@ tasks.register('generateCppIrCodecs', JavaExec) { tasks.register('generateGolangIrCodecs', JavaExec) { mainClass.set('uk.co.real_logic.sbe.SbeTool') classpath = project(':sbe-tool').sourceSets.main.runtimeClasspath + jvmArgs('--add-opens', 'java.base/jdk.internal.misc=ALL-UNNAMED') systemProperties( 'sbe.output.dir': 'sbe-tool/src/main/golang', 'sbe.target.language': 'golang', @@ -999,7 +1030,7 @@ tasks.register('runJavaBenchmarks', Exec) { dependsOn 'sbe-benchmarks:jar' commandLine toolchainLauncher.get().executablePath, '-jar', 'sbe-benchmarks/build/libs/sbe-benchmarks.jar', - '-jvmArgs', '-Dagrona.disable.bounds.checks=true -XX:+UseParallelGC', + '-jvmArgs', '-Dagrona.disable.bounds.checks=true -XX:+UseParallelGC --add-opens java.base/jdk.internal.misc=ALL-UNNAMED', '-w', '1s', '-r', '1s', '-wi', '3', '-i', '5', '-tu', 'ns', '-f', '5' } diff --git a/version.txt b/version.txt index c9c35c012f..6214e03b71 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.0-SNAPSHOT +1.34.0-SNAPSHOT From 949d23481c03099acf6682c64707ea5a034a80b3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:24:42 +0100 Subject: [PATCH 506/805] [C] Add missing JVM options to allow generating codes. --- sbe-benchmarks/src/main/cpp/CMakeLists.txt | 2 +- sbe-samples/src/main/cpp/CMakeLists.txt | 2 +- sbe-tool/src/main/cpp/CMakeLists.txt | 2 +- sbe-tool/src/test/c/CMakeLists.txt | 2 +- sbe-tool/src/test/cpp/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sbe-benchmarks/src/main/cpp/CMakeLists.txt b/sbe-benchmarks/src/main/cpp/CMakeLists.txt index 085e8bf224..055ea4f63a 100644 --- a/sbe-benchmarks/src/main/cpp/CMakeLists.txt +++ b/sbe-benchmarks/src/main/cpp/CMakeLists.txt @@ -39,7 +39,7 @@ set(SBE_MD_SCHEMA ${CODEC_PERF_SCHEMA_DIR}/fix-message-samples.xml) add_custom_command( OUTPUT ${GENERATED_CODECS} DEPENDS ${SBE_CAR_SCHEMA} ${SBE_MD_SCHEMA} sbe-jar ${SBE_JAR} - COMMAND ${Java_JAVA_EXECUTABLE} -Dsbe.output.dir=${CXX_CODEC_TARGET_DIR} -Dsbe.target.language="cpp" -jar ${SBE_JAR} ${SBE_CAR_SCHEMA} ${SBE_MD_SCHEMA} + COMMAND ${Java_JAVA_EXECUTABLE} --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.output.dir=${CXX_CODEC_TARGET_DIR} -Dsbe.target.language="cpp" -jar ${SBE_JAR} ${SBE_CAR_SCHEMA} ${SBE_MD_SCHEMA} ) add_custom_target(perf_codecs DEPENDS ${GENERATED_CODECS}) diff --git a/sbe-samples/src/main/cpp/CMakeLists.txt b/sbe-samples/src/main/cpp/CMakeLists.txt index dd6a5f0b32..2e0a6c8d16 100644 --- a/sbe-samples/src/main/cpp/CMakeLists.txt +++ b/sbe-samples/src/main/cpp/CMakeLists.txt @@ -24,7 +24,7 @@ set(EXAMPLES_SCHEMA ${CODEC_EXAMPLES_SCHEMA_DIR}/example-schema.xml) add_custom_command( OUTPUT ${GENERATED_CODECS} DEPENDS ${EXAMPLES_SCHEMA} sbe-jar ${SBE_JAR} - COMMAND ${Java_JAVA_EXECUTABLE} -Dsbe.output.dir=${CXX_CODEC_TARGET_DIR} -Dsbe.generate.ir=true -Dsbe.target.language=cpp -Dsbe.xinclude.aware=true -jar ${SBE_JAR} ${EXAMPLES_SCHEMA} + COMMAND ${Java_JAVA_EXECUTABLE} --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.output.dir=${CXX_CODEC_TARGET_DIR} -Dsbe.generate.ir=true -Dsbe.target.language=cpp -Dsbe.xinclude.aware=true -jar ${SBE_JAR} ${EXAMPLES_SCHEMA} ) add_custom_target(examples_codecs DEPENDS ${GENERATED_CODECS}) diff --git a/sbe-tool/src/main/cpp/CMakeLists.txt b/sbe-tool/src/main/cpp/CMakeLists.txt index c79be7c58a..abb1f83a49 100644 --- a/sbe-tool/src/main/cpp/CMakeLists.txt +++ b/sbe-tool/src/main/cpp/CMakeLists.txt @@ -28,7 +28,7 @@ find_package(Java REQUIRED) add_custom_command(OUTPUT ${CODECS} COMMAND - ${Java_JAVA_EXECUTABLE} + ${Java_JAVA_EXECUTABLE} --add-opens java.base/jdk.internal.misc=ALL-UNNAMED "-Dsbe.output.dir=${CMAKE_CURRENT_SOURCE_DIR}" "-Dsbe.target.language=CPP" "-jar" "${SBE_JAR}" diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index e8ea222cf7..33169a501d 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -46,7 +46,7 @@ add_custom_command( OUTPUT ${GENERATED_CODECS} DEPENDS sbe-jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${CODE_GENERATION_SCHEMA_WITH_VERSION} ${GROUP_WITH_DATA_SCHEMA} ${ISSUE889_SCHEMA} COMMAND - ${Java_JAVA_EXECUTABLE} + ${Java_JAVA_EXECUTABLE} --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.output.dir=${C_CODEC_TARGET_DIR} -Dsbe.target.language="C" -jar ${SBE_JAR} diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index b3271dade0..ee09f3881e 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -61,7 +61,7 @@ add_custom_command( ${ACCESS_ORDER_SCHEMA} sbe-jar ${SBE_JAR} COMMAND - ${Java_JAVA_EXECUTABLE} + ${Java_JAVA_EXECUTABLE} --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.output.dir=${CXX_CODEC_TARGET_DIR} -Dsbe.generate.ir="true" -Dsbe.target.language="cpp" From 51eeefd317d817515909eac9a7bff8ead4b95136 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:31:03 +0100 Subject: [PATCH 507/805] [Go] Fix Go build. --- gocode/sbe-tool | 1 + 1 file changed, 1 insertion(+) diff --git a/gocode/sbe-tool b/gocode/sbe-tool index 61e4c903e1..811e0b6975 100755 --- a/gocode/sbe-tool +++ b/gocode/sbe-tool @@ -35,6 +35,7 @@ shift $(($OPTIND - 1)) [ -f "$SCHEMA" ] || (echo invalid schema "$SCHEMA"; exit 1) java \ +--add-opens java.base/jdk.internal.misc=ALL-UNNAMED \ -Dsbe.output.dir="$OUTPUTDIR" \ -Dsbe.generate.ir="false" \ -Dsbe.target.language="golang" \ From 658fcbd5fc48178b1bad22aec2dbb3191fef54dc Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:54:01 +0100 Subject: [PATCH 508/805] [Go] Fix Golang build. --- .github/workflows/ci.yml | 4 +--- gocode/flyweight/src/otf/otf_test.go | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23be3be93a..b0364d208e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -416,7 +416,5 @@ jobs: with: distribution: 'zulu' java-version: 17 - - name: Generate codecs - run: ./gradlew generateGolangCodecs - - name: Go + - name: Test run: cd gocode && make diff --git a/gocode/flyweight/src/otf/otf_test.go b/gocode/flyweight/src/otf/otf_test.go index babb370693..10cc0afd0e 100644 --- a/gocode/flyweight/src/otf/otf_test.go +++ b/gocode/flyweight/src/otf/otf_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -//go:generate java -Dsbe.output.dir=. -Dsbe.target.language=golang -Dsbe.go.generate.generate.flyweights=true -Dsbe.generate.ir=true -jar ../../../${SBE_JAR} ../../../../sbe-tool/src/test/resources/code-generation-schema.xml +//go:generate java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.output.dir=. -Dsbe.target.language=golang -Dsbe.go.generate.generate.flyweights=true -Dsbe.generate.ir=true -jar ../../../${SBE_JAR} ../../../../sbe-tool/src/test/resources/code-generation-schema.xml const SchemaFilename = "code-generation-schema.sbeir" const MsgBufferCapacity = 4 * 1024 From f084da2e94a16bbbf185612b3ffc3ebf037fb6e7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:02:14 +0100 Subject: [PATCH 509/805] [Go] Generate Jar for Golang build. --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0364d208e..81f79e5420 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -416,5 +416,7 @@ jobs: with: distribution: 'zulu' java-version: 17 - - name: Test + - name: Generate jar + run: ./gradlew assemble + - name: Run tests run: cd gocode && make From 4ff6344876366b0272c41e492b1d52757a304bb3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:06:08 +0100 Subject: [PATCH 510/805] 1.34.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 6214e03b71..2b17ffd504 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.34.0-SNAPSHOT +1.34.0 From 3ddb76157c30b1a4b3a954bd221992f937dc2067 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 17 Dec 2024 16:06:19 +0100 Subject: [PATCH 511/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 2b17ffd504..c9c35c012f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.34.0 +1.35.0-SNAPSHOT From 34f2c32c861417fb6e7d749e6ad9b401b3147c6c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:12:08 +0100 Subject: [PATCH 512/805] [Doc] Add `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` to the example execution. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b286d72970..3b2d354d45 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Jars for the executable, source, and javadoc for the various modules can be foun An example to execute a Jar from command line using the 'all' jar which includes the Agrona dependency: - java -Dsbe.generate.ir=true -Dsbe.target.language=Cpp -Dsbe.target.namespace=sbe -Dsbe.output.dir=include/gen -Dsbe.errorLog=yes -jar sbe-all/build/libs/sbe-all-${SBE_TOOL_VERSION}.jar my-sbe-messages.xml + java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=true -Dsbe.target.language=Cpp -Dsbe.target.namespace=sbe -Dsbe.output.dir=include/gen -Dsbe.errorLog=yes -jar sbe-all/build/libs/sbe-all-${SBE_TOOL_VERSION}.jar my-sbe-messages.xml C++ Build using CMake --------------------- From a1bc244d8136ee1e39d99cf3666839618dd845a6 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Mon, 30 Dec 2024 06:38:32 -0600 Subject: [PATCH 513/805] [Rust] encoding primitive arrays now supports slice instead of array (issue #1021) (#1040) * [Rust] codegen now implements: "From<&'a mut WriteBuf<'a>> for &'a mut [u8]" * [Rust] refactored codegen of primitive array encoding to accept slice instead of array * [Rust] updated some tests * [Rust] updated codegen to create additional function for primitive arrays that will accept an "impl Iterator". This allows an arbitrary number of items to be passed in, which will guarantee the correct number of items are encoded (defined 'nullValue' will be used where appropriate) * [Rust] generate at_most_*_items_from_slice setter for fixed sized primitive array in message * [Rust] add padded support for slice setter for primitive array field * [Rust] simplify impl of generated slice aware methods * merging in PR * [Rust] updated generator to create "_from_iter" and "_zero_padded" functions for primitive array * [Rust] updated generator to create "_from_iter" and "_zero_padded" functions for primitive array * fixed formatting issues * removed unused format argument --------- Co-authored-by: Michael Ward Co-authored-by: Elvis Wang --- build.gradle | 1 + rust/Cargo.toml | 1 + rust/tests/baseline_enum_from_str.rs | 21 +- rust/tests/extension_test.rs | 4 +- rust/tests/fixed_sized_primitive_array.rs | 1110 +++++++++++++++++ .../sbe/generation/rust/LibRsDef.java | 7 + .../sbe/generation/rust/RustGenerator.java | 218 +++- .../sbe/generation/rust/RustUtil.java | 6 + .../sbe/generation/rust/RustUtilTest.java | 3 +- .../fixed-sized-primitive-array-types.xml | 73 ++ 10 files changed, 1369 insertions(+), 75 deletions(-) create mode 100644 rust/tests/fixed_sized_primitive_array.rs create mode 100644 sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml diff --git a/build.gradle b/build.gradle index f4c65045ba..3e3b3b2ee7 100644 --- a/build.gradle +++ b/build.gradle @@ -665,6 +665,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe-tool/src/test/resources/issue984.xml', 'sbe-tool/src/test/resources/issue987.xml', 'sbe-tool/src/test/resources/issue1028.xml', + 'sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', 'sbe-tool/src/test/resources/nested-composite-name.xml', ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index f15d4d2f6d..2d4f3d4a49 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -19,6 +19,7 @@ issue_987 = { path = "../generated/rust/issue987" } issue_1028 = { path = "../generated/rust/issue1028" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } nested_composite_name = { path = "../generated/rust/nested-composite-name" } +fixed_sized_primitive_array = { path = "../generated/rust/fixed_sized_primitive_array" } [dev-dependencies] criterion = "0.5" diff --git a/rust/tests/baseline_enum_from_str.rs b/rust/tests/baseline_enum_from_str.rs index 4e52fd4bf9..a111d28364 100644 --- a/rust/tests/baseline_enum_from_str.rs +++ b/rust/tests/baseline_enum_from_str.rs @@ -1,21 +1,22 @@ +use BoostType::{NullVal, KERS, NITROUS, SUPERCHARGER, TURBO}; use examples_baseline::{ boost_type::BoostType, }; #[test] fn test_boost_type_from_str() -> Result<(), ()> { - assert_eq!("TURBO".parse::()?, BoostType::TURBO, "Parse \"TURBO\" as BoostType"); - assert_eq!("SUPERCHARGER".parse::()?, BoostType::SUPERCHARGER, "Parse \"SUPERCHARGER\" as BoostType"); - assert_eq!("NITROUS".parse::()?, BoostType::NITROUS, "Parse \"NITROUS\" as BoostType"); - assert_eq!("KERS".parse::()?, BoostType::KERS, "Parse \"KERS\" as BoostType"); + assert_eq!("TURBO".parse::()?, TURBO, "Parse \"TURBO\" as BoostType"); + assert_eq!("SUPERCHARGER".parse::()?, SUPERCHARGER, "Parse \"SUPERCHARGER\" as BoostType"); + assert_eq!("NITROUS".parse::()?, NITROUS, "Parse \"NITROUS\" as BoostType"); + assert_eq!("KERS".parse::()?, KERS, "Parse \"KERS\" as BoostType"); - assert_eq!("Turbo".parse::()?, BoostType::NullVal, "Parse \"Turbo\" as BoostType"); - assert_eq!("Supercharger".parse::()?, BoostType::NullVal, "Parse \"Supercharger\" as BoostType"); - assert_eq!("Nitrous".parse::()?, BoostType::NullVal, "Parse \"Nitrous\" as BoostType"); - assert_eq!("Kers".parse::()?, BoostType::NullVal, "Parse \"Kers\" as BoostType"); + assert_eq!("Turbo".parse::()?, NullVal, "Parse \"Turbo\" as BoostType"); + assert_eq!("Supercharger".parse::()?, NullVal, "Parse \"Supercharger\" as BoostType"); + assert_eq!("Nitrous".parse::()?, NullVal, "Parse \"Nitrous\" as BoostType"); + assert_eq!("Kers".parse::()?, NullVal, "Parse \"Kers\" as BoostType"); - assert_eq!("AA".parse::()?, BoostType::NullVal, "Parse \"AA\" as BoostType"); - assert_eq!("".parse::().unwrap(), BoostType::NullVal, "Parse \"\" as BoostType"); + assert_eq!("AA".parse::()?, NullVal, "Parse \"AA\" as BoostType"); + assert_eq!("".parse::().unwrap(), NullVal, "Parse \"\" as BoostType"); Ok(()) } diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index d7258bc39b..ab62a7715c 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -187,7 +187,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car.available(BooleanType::T); car.code(Model::A); car.some_numbers(&[0, 1, 2, 3]); - car.vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef + car.vehicle_code_from_iter(b"abcdef_extra_is_ignored".into_iter().copied()); // abcdef extras.set_cruise_control(true); extras.set_sports_pack(true); @@ -197,7 +197,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { let mut engine = car.engine_encoder(); engine.capacity(2000); engine.num_cylinders(4); - engine.manufacturer_code(&[49, 50, 51]); // 123 + engine.manufacturer_code(b"123"); engine.efficiency(35); engine.booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); diff --git a/rust/tests/fixed_sized_primitive_array.rs b/rust/tests/fixed_sized_primitive_array.rs new file mode 100644 index 0000000000..8542e3d488 --- /dev/null +++ b/rust/tests/fixed_sized_primitive_array.rs @@ -0,0 +1,1110 @@ +use fixed_sized_primitive_array::{ + demo_codec::{DemoDecoder, DemoEncoder}, + message_header_codec::{MessageHeaderDecoder, ENCODED_LENGTH}, + ReadBuf, WriteBuf, +}; + +fn create_encoder(buffer: &mut [u8]) -> DemoEncoder { + let encoder = DemoEncoder::default().wrap(WriteBuf::new(buffer), ENCODED_LENGTH); + let mut header = encoder.header(0); + header.parent().unwrap() +} + +#[test] +fn test_encode_then_decode_u8_slice() { + let uninit = 1u8; + + let test_data = [ + b"" as &[u8], + b"0" as &[u8], + b"01" as &[u8], + b"012" as &[u8], + b"0123" as &[u8], + b"01234" as &[u8], + b"012345" as &[u8], + b"0123456" as &[u8], + b"01234567" as &[u8], + b"012345678" as &[u8], + b"0123456789" as &[u8], + b"0123456789A" as &[u8], + b"0123456789AB" as &[u8], + b"0123456789ABC" as &[u8], + b"0123456789ABCD" as &[u8], + b"0123456789ABCDE" as &[u8], + b"0123456789ABCDEF" as &[u8], + b"0123456789abcdef" as &[u8], + b"0123456789abcdef0" as &[u8], + b"0123456789abcdef01" as &[u8], + b"0123456789abcdef012" as &[u8], + b"0123456789abcdef0123" as &[u8], + b"0123456789abcdef01234" as &[u8], + b"0123456789abcdef012345" as &[u8], + b"0123456789abcdef0123456" as &[u8], + b"0123456789abcdef01234567" as &[u8], + b"0123456789abcdef012345678" as &[u8], + b"0123456789abcdef0123456789" as &[u8], + b"0123456789abcdef0123456789A" as &[u8], + b"0123456789abcdef0123456789AB" as &[u8], + b"0123456789abcdef0123456789ABC" as &[u8], + b"0123456789abcdef0123456789ABCD" as &[u8], + b"0123456789abcdef0123456789ABCDE" as &[u8], + b"0123456789abcdef0123456789ABCDEF" as &[u8], + ]; + + // + // + // + // + // + // + // + // + macro_rules! run_encode_then_decode_for_array_of_u8_len_16 { + ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr) => { + for each_slice in test_data { + let encode_func = $encode_func; + let decode_func = $decode_func; + let end_encode_func = $end_encode_func; + let end_decode_func = $end_decode_func; + + let cur_len = each_slice.len(); + let effective_len = cur_len.min(16); + + // encode... + let mut buffer = [uninit; 1024]; + let mut encoder = create_encoder(&mut buffer); + + encode_func(&mut encoder, each_slice.into_iter().copied()); + + let end = 1i32; + end_encode_func(&mut encoder, end); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + + let decoder = DemoDecoder::default().header(header, 0); + let decoded = decode_func(&decoder); + for each_idx in 0..effective_len { + assert_eq!( + each_slice[each_idx], decoded[each_idx], + "Item mismatched at {}/{}", + each_idx, cur_len + ); + } + for each_idx in effective_len..16 { + assert_eq!( + decoded[each_idx], uninit, + "Item should not be padded ZERO at {}/{}", + each_idx, cur_len + ); + } + let decoded_end = end_decode_func(&decoder); + assert_eq!(decoded_end, end, "End Item should equal",); + } + }; + } + + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_char_from_iter, + DemoDecoder::fixed_16_char, + DemoEncoder::fixed_16_char_end, + DemoDecoder::fixed_16_char_end + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_ascii_char_from_iter, + DemoDecoder::fixed_16_ascii_char, + DemoEncoder::fixed_16_ascii_char_end, + DemoDecoder::fixed_16_ascii_char_end + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_gb_18030_char_from_iter, + DemoDecoder::fixed_16_gb_18030_char, + DemoEncoder::fixed_16_gb_18030_char_end, + DemoDecoder::fixed_16_gb_18030_char_end + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_utf_8_char_from_iter, + DemoDecoder::fixed_16_utf_8_char, + DemoEncoder::fixed_16_utf_8_char_end, + DemoDecoder::fixed_16_utf_8_char_end + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_u8_from_iter, + DemoDecoder::fixed_16_u8, + DemoEncoder::fixed_16_u8_end, + DemoDecoder::fixed_16_u8_end + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_ascii_u8_from_iter, + DemoDecoder::fixed_16_ascii_u8, + DemoEncoder::fixed_16_ascii_u8_end, + DemoDecoder::fixed_16_ascii_u8_end + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_gb_18030_u8_from_iter, + DemoDecoder::fixed_16_gb_18030_u8, + DemoEncoder::fixed_16_gb_18030_u8_end, + DemoDecoder::fixed_16_gb_18030_u8_end + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_utf_8_u8_from_iter, + DemoDecoder::fixed_16_utf_8_u8, + DemoEncoder::fixed_16_utf_8u_8_end, + DemoDecoder::fixed_16_utf_8u_8_end + ); +} + +#[test] +fn test_encode_then_decode_non_u8_signed_primitive_slice() { + let uninit = 1u8; + + // + // + // + // + macro_rules! run_encode_then_decode_for_array_of_signed_len_16 { + ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr, $i_type:ty, $existed:expr) => { + let test_data = [ + &[] as &[$i_type], + &[1 as $i_type] as &[$i_type], + &[0 as $i_type] as &[$i_type], + &[-1 as $i_type] as &[$i_type], + &[-1, 1 as $i_type] as &[$i_type], + &[-1, 0, 1 as $i_type] as &[$i_type], + &[-2, -1, 1, 2 as $i_type] as &[$i_type], + &[-2, -1, 0, 1, 2 as $i_type] as &[$i_type], + &[-3, -2, -1, 1, 2, 3 as $i_type] as &[$i_type], + &[-3, -2, -1, 0, 1, 2, 3 as $i_type] as &[$i_type], + &[-4, -3, -2, -1, 1, 2, 3, 4 as $i_type] as &[$i_type], + &[-4, -3, -2, -1, 0, 1, 2, 3, 4 as $i_type] as &[$i_type], + &[-5, -4, -3, -2, -1, 1, 2, 3, 4, 5 as $i_type] as &[$i_type], + &[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 as $i_type] as &[$i_type], + &[-6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type], + &[-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type], + &[-7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7 as $i_type] as &[$i_type], + &[ + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7 as $i_type, + ] as &[$i_type], + &[ + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 as $i_type, + ] as &[$i_type], + &[ + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 as $i_type, + ] as &[$i_type], + &[ + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 as $i_type, + ] as &[$i_type], + &[ + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 as $i_type, + ] as &[$i_type], + ]; + + let existed = $existed; + + for each_slice in test_data { + let encode_func = $encode_func; + let decode_func = $decode_func; + let end_encode_func = $end_encode_func; + let end_decode_func = $end_decode_func; + + let cur_len = each_slice.len(); + let effective_len = cur_len.min(16); + + // encode... + let mut buffer = [uninit; 1024]; + let mut encoder = create_encoder(&mut buffer); + + encode_func(&mut encoder, each_slice.into_iter().copied()); + + let end = 1i32; + end_encode_func(&mut encoder, end); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + + let decoder = DemoDecoder::default().header(header, 0); + let decoded = decode_func(&decoder); + for each_idx in 0..effective_len { + assert_eq!( + each_slice[each_idx], + decoded[each_idx], + "Item mismatched at {}/{} for {}", + each_idx, + cur_len, + stringify!($i_type) + ); + } + for each_idx in effective_len..16 { + assert_eq!( + decoded[each_idx], + existed, + "Item should not be padded ZERO at {}/{} for {}", + each_idx, + cur_len, + stringify!($i_type) + ); + } + let decoded_end = end_decode_func(&decoder); + assert_eq!(decoded_end, end, "End Item should equal",); + } + }; + } + + run_encode_then_decode_for_array_of_signed_len_16!( + DemoEncoder::fixed_16_i8_from_iter, + DemoDecoder::fixed_16_i8, + DemoEncoder::fixed_16_i8_end, + DemoDecoder::fixed_16_i8_end, + i8, i8::from_le_bytes([uninit]) + ); + run_encode_then_decode_for_array_of_signed_len_16!( + DemoEncoder::fixed_16_i16_from_iter, + DemoDecoder::fixed_16_i16, + DemoEncoder::fixed_16_i16_end, + DemoDecoder::fixed_16_i16_end, + i16, i16::from_le_bytes([uninit, uninit]) + ); + run_encode_then_decode_for_array_of_signed_len_16!( + DemoEncoder::fixed_16_i32_from_iter, + DemoDecoder::fixed_16_i32, + DemoEncoder::fixed_16_i32_end, + DemoDecoder::fixed_16_i32_end, + i32, i32::from_le_bytes([uninit, uninit, uninit, uninit]) + ); + run_encode_then_decode_for_array_of_signed_len_16!( + DemoEncoder::fixed_16_i64_from_iter, + DemoDecoder::fixed_16_i64, + DemoEncoder::fixed_16_i64_end, + DemoDecoder::fixed_16_i64_end, + i64, i64::from_le_bytes([uninit, uninit, uninit, uninit, uninit, uninit, uninit, uninit]) + ); +} + +#[test] +fn test_encode_then_decode_non_u8_unsigned_primitive_slice() { + let uninit = 1u8; + + // + // + macro_rules! run_encode_then_decode_for_array_of_unsigned_len_16 { + ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr, $i_type:ty, $existed:expr) => { + let test_data = [ + &[] as &[$i_type], + &[1 as $i_type] as &[$i_type], + &[0 as $i_type] as &[$i_type], + &[11 as $i_type] as &[$i_type], + &[11, 1 as $i_type] as &[$i_type], + &[11, 0, 1 as $i_type] as &[$i_type], + &[12, 11, 1, 2 as $i_type] as &[$i_type], + &[12, 11, 0, 1, 2 as $i_type] as &[$i_type], + &[13, 12, 11, 1, 2, 3 as $i_type] as &[$i_type], + &[13, 12, 11, 0, 1, 2, 3 as $i_type] as &[$i_type], + &[14, 13, 12, 11, 1, 2, 3, 4 as $i_type] as &[$i_type], + &[14, 13, 12, 11, 0, 1, 2, 3, 4 as $i_type] as &[$i_type], + &[15, 14, 13, 12, 11, 1, 2, 3, 4, 5 as $i_type] as &[$i_type], + &[15, 14, 13, 12, 11, 0, 1, 2, 3, 4, 5 as $i_type] as &[$i_type], + &[16, 15, 14, 13, 12, 11, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type], + &[16, 15, 14, 13, 12, 11, 0, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type], + &[17, 16, 15, 14, 13, 12, 11, 1, 2, 3, 4, 5, 6, 7 as $i_type] as &[$i_type], + &[ + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7 as $i_type, + ] as &[$i_type], + &[ + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 as $i_type, + ] as &[$i_type], + &[ + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 as $i_type, + ] as &[$i_type], + &[ + 19, + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 as $i_type, + ] as &[$i_type], + &[ + 19, + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 as $i_type, + ] as &[$i_type], + ]; + + let existed = $existed; + + for each_slice in test_data { + let encode_func = $encode_func; + let decode_func = $decode_func; + let end_encode_func = $end_encode_func; + let end_decode_func = $end_decode_func; + + let cur_len = each_slice.len(); + let effective_len = cur_len.min(16); + + // encode... + let mut buffer = [uninit; 1024]; + let mut encoder = create_encoder(&mut buffer); + + encode_func(&mut encoder, each_slice.into_iter().copied()); + + let end = 1i32; + end_encode_func(&mut encoder, end); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + + let decoder = DemoDecoder::default().header(header, 0); + let decoded = decode_func(&decoder); + for each_idx in 0..effective_len { + assert_eq!( + each_slice[each_idx], + decoded[each_idx], + "Item mismatched at {}/{} for {}", + each_idx, + cur_len, + stringify!($i_type) + ); + } + + for each_idx in effective_len..16 { + assert_eq!( + decoded[each_idx], + existed, + "Item should not be padded ZERO at {}/{} for {}", + each_idx, + cur_len, + stringify!($i_type) + ); + } + let decoded_end = end_decode_func(&decoder); + assert_eq!(decoded_end, end, "End Item should equal",); + } + }; + } + + run_encode_then_decode_for_array_of_unsigned_len_16!( + DemoEncoder::fixed_16_u16_from_iter, + DemoDecoder::fixed_16_u16, + DemoEncoder::fixed_16_u16_end, + DemoDecoder::fixed_16_u16_end, + u16, + u16::from_le_bytes([uninit, uninit]) + ); + run_encode_then_decode_for_array_of_unsigned_len_16!( + DemoEncoder::fixed_16_u32_from_iter, + DemoDecoder::fixed_16_u32, + DemoEncoder::fixed_16_u32_end, + DemoDecoder::fixed_16_u32_end, + u32, + u32::from_le_bytes([uninit, uninit, uninit, uninit]) + ); + run_encode_then_decode_for_array_of_unsigned_len_16!( + DemoEncoder::fixed_16_u64_from_iter, + DemoDecoder::fixed_16_u64, + DemoEncoder::fixed_16_u64_end, + DemoDecoder::fixed_16_u64_end, + u64, + u64::from_le_bytes([uninit, uninit, uninit, uninit, uninit, uninit, uninit, uninit]) + ); +} + +#[test] +fn test_encode_then_decode_u8_slice_padded() { + let uninit = 1u8; + + let test_data = [ + b"" as &[u8], + b"0" as &[u8], + b"01" as &[u8], + b"012" as &[u8], + b"0123" as &[u8], + b"01234" as &[u8], + b"012345" as &[u8], + b"0123456" as &[u8], + b"01234567" as &[u8], + b"012345678" as &[u8], + b"0123456789" as &[u8], + b"0123456789A" as &[u8], + b"0123456789AB" as &[u8], + b"0123456789ABC" as &[u8], + b"0123456789ABCD" as &[u8], + b"0123456789ABCDE" as &[u8], + b"0123456789ABCDEF" as &[u8], + b"0123456789abcdef" as &[u8], + b"0123456789abcdef0" as &[u8], + b"0123456789abcdef01" as &[u8], + b"0123456789abcdef012" as &[u8], + b"0123456789abcdef0123" as &[u8], + b"0123456789abcdef01234" as &[u8], + b"0123456789abcdef012345" as &[u8], + b"0123456789abcdef0123456" as &[u8], + b"0123456789abcdef01234567" as &[u8], + b"0123456789abcdef012345678" as &[u8], + b"0123456789abcdef0123456789" as &[u8], + b"0123456789abcdef0123456789A" as &[u8], + b"0123456789abcdef0123456789AB" as &[u8], + b"0123456789abcdef0123456789ABC" as &[u8], + b"0123456789abcdef0123456789ABCD" as &[u8], + b"0123456789abcdef0123456789ABCDE" as &[u8], + b"0123456789abcdef0123456789ABCDEF" as &[u8], + ]; + + // + // + // + // + // + // + // + // + macro_rules! run_encode_then_decode_for_array_of_u8_len_16 { + ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr,) => { + for each_slice in test_data { + let encode_func = $encode_func; + let decode_func = $decode_func; + let end_encode_func = $end_encode_func; + let end_decode_func = $end_decode_func; + + let cur_len = each_slice.len(); + let effective_len = cur_len.min(16); + + // encode... + let mut buffer = [uninit; 1024]; + let mut encoder = create_encoder(&mut buffer); + + encode_func(&mut encoder, each_slice); + + let end = 1i32; + end_encode_func(&mut encoder, end); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + + let decoder = DemoDecoder::default().header(header, 0); + let decoded = decode_func(&decoder); + for each_idx in 0..effective_len { + assert_eq!( + each_slice[each_idx], decoded[each_idx], + "Item mismatched at {}/{}", + each_idx, cur_len + ); + } + for each_idx in effective_len..16 { + assert_eq!( + decoded[each_idx], 0, + "Item should be padded ZERO at {}/{}", + each_idx, cur_len + ); + } + let decoded_end = end_decode_func(&decoder); + assert_eq!(decoded_end, end, "End Item should equal",); + } + }; + } + + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_char_zero_padded, + DemoDecoder::fixed_16_char, + DemoEncoder::fixed_16_char_end, + DemoDecoder::fixed_16_char_end, + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_ascii_char_zero_padded, + DemoDecoder::fixed_16_ascii_char, + DemoEncoder::fixed_16_ascii_char_end, + DemoDecoder::fixed_16_ascii_char_end, + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_gb_18030_char_zero_padded, + DemoDecoder::fixed_16_gb_18030_char, + DemoEncoder::fixed_16_gb_18030_char_end, + DemoDecoder::fixed_16_gb_18030_char_end, + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_utf_8_char_zero_padded, + DemoDecoder::fixed_16_utf_8_char, + DemoEncoder::fixed_16_utf_8_char_end, + DemoDecoder::fixed_16_utf_8_char_end, + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_u8_zero_padded, + DemoDecoder::fixed_16_u8, + DemoEncoder::fixed_16_u8_end, + DemoDecoder::fixed_16_u8_end, + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_ascii_u8_zero_padded, + DemoDecoder::fixed_16_ascii_u8, + DemoEncoder::fixed_16_ascii_u8_end, + DemoDecoder::fixed_16_ascii_u8_end, + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_gb_18030_u8_zero_padded, + DemoDecoder::fixed_16_gb_18030_u8, + DemoEncoder::fixed_16_gb_18030_u8_end, + DemoDecoder::fixed_16_gb_18030_u8_end, + ); + run_encode_then_decode_for_array_of_u8_len_16!( + DemoEncoder::fixed_16_utf_8_u8_zero_padded, + DemoDecoder::fixed_16_utf_8_u8, + DemoEncoder::fixed_16_utf_8u_8_end, + DemoDecoder::fixed_16_utf_8u_8_end, + ); +} + +#[test] +fn test_encode_then_decode_non_u8_signed_primitive_slice_padded() { + let uninit = 1u8; + + // + // + // + // + macro_rules! run_encode_then_decode_for_array_of_signed_len_16 { + ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr, $i_type:ty,) => { + let test_data = [ + &[] as &[$i_type], + &[1 as $i_type] as &[$i_type], + &[0 as $i_type] as &[$i_type], + &[-1 as $i_type] as &[$i_type], + &[-1, 1 as $i_type] as &[$i_type], + &[-1, 0, 1 as $i_type] as &[$i_type], + &[-2, -1, 1, 2 as $i_type] as &[$i_type], + &[-2, -1, 0, 1, 2 as $i_type] as &[$i_type], + &[-3, -2, -1, 1, 2, 3 as $i_type] as &[$i_type], + &[-3, -2, -1, 0, 1, 2, 3 as $i_type] as &[$i_type], + &[-4, -3, -2, -1, 1, 2, 3, 4 as $i_type] as &[$i_type], + &[-4, -3, -2, -1, 0, 1, 2, 3, 4 as $i_type] as &[$i_type], + &[-5, -4, -3, -2, -1, 1, 2, 3, 4, 5 as $i_type] as &[$i_type], + &[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 as $i_type] as &[$i_type], + &[-6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type], + &[-6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type], + &[-7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7 as $i_type] as &[$i_type], + &[ + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7 as $i_type, + ] as &[$i_type], + &[ + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 as $i_type, + ] as &[$i_type], + &[ + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 as $i_type, + ] as &[$i_type], + &[ + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 as $i_type, + ] as &[$i_type], + &[ + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 as $i_type, + ] as &[$i_type], + ]; + for each_slice in test_data { + let encode_func = $encode_func; + let decode_func = $decode_func; + let end_encode_func = $end_encode_func; + let end_decode_func = $end_decode_func; + + let cur_len = each_slice.len(); + let effective_len = cur_len.min(16); + + // encode... + let mut buffer = [uninit; 1024]; + let mut encoder = create_encoder(&mut buffer); + + encode_func(&mut encoder, each_slice); + + let end = 1i32; + end_encode_func(&mut encoder, end); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + + let decoder = DemoDecoder::default().header(header, 0); + let decoded = decode_func(&decoder); + for each_idx in 0..effective_len { + assert_eq!( + each_slice[each_idx], + decoded[each_idx], + "Item mismatched at {}/{} for {}", + each_idx, + cur_len, + stringify!($i_type) + ); + } + for each_idx in effective_len..16 { + assert_eq!( + decoded[each_idx], + 0, + "Item should be padded ZERO at {}/{} for {}", + each_idx, + cur_len, + stringify!($i_type) + ); + } + let decoded_end = end_decode_func(&decoder); + assert_eq!(decoded_end, end, "End Item should equal",); + } + }; + } + + run_encode_then_decode_for_array_of_signed_len_16!( + DemoEncoder::fixed_16_i8_zero_padded, + DemoDecoder::fixed_16_i8, + DemoEncoder::fixed_16_i8_end, + DemoDecoder::fixed_16_i8_end, + i8, + ); + run_encode_then_decode_for_array_of_signed_len_16!( + DemoEncoder::fixed_16_i16_zero_padded, + DemoDecoder::fixed_16_i16, + DemoEncoder::fixed_16_i16_end, + DemoDecoder::fixed_16_i16_end, + i16, + ); + run_encode_then_decode_for_array_of_signed_len_16!( + DemoEncoder::fixed_16_i32_zero_padded, + DemoDecoder::fixed_16_i32, + DemoEncoder::fixed_16_i32_end, + DemoDecoder::fixed_16_i32_end, + i32, + ); + run_encode_then_decode_for_array_of_signed_len_16!( + DemoEncoder::fixed_16_i64_zero_padded, + DemoDecoder::fixed_16_i64, + DemoEncoder::fixed_16_i64_end, + DemoDecoder::fixed_16_i64_end, + i64, + ); +} + +#[test] +fn test_encode_then_decode_non_u8_unsigned_primitive_slice_padded() { + let uninit = 1u8; + + // + // + // + macro_rules! run_encode_then_decode_for_array_of_unsigned_len_16 { + ($encode_func:expr, $decode_func:expr, $end_encode_func:expr, $end_decode_func:expr, $i_type:ty) => { + let test_data = [ + &[] as &[$i_type], + &[1 as $i_type] as &[$i_type], + &[0 as $i_type] as &[$i_type], + &[11 as $i_type] as &[$i_type], + &[11, 1 as $i_type] as &[$i_type], + &[11, 0, 1 as $i_type] as &[$i_type], + &[12, 11, 1, 2 as $i_type] as &[$i_type], + &[12, 11, 0, 1, 2 as $i_type] as &[$i_type], + &[13, 12, 11, 1, 2, 3 as $i_type] as &[$i_type], + &[13, 12, 11, 0, 1, 2, 3 as $i_type] as &[$i_type], + &[14, 13, 12, 11, 1, 2, 3, 4 as $i_type] as &[$i_type], + &[14, 13, 12, 11, 0, 1, 2, 3, 4 as $i_type] as &[$i_type], + &[15, 14, 13, 12, 11, 1, 2, 3, 4, 5 as $i_type] as &[$i_type], + &[15, 14, 13, 12, 11, 0, 1, 2, 3, 4, 5 as $i_type] as &[$i_type], + &[16, 15, 14, 13, 12, 11, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type], + &[16, 15, 14, 13, 12, 11, 0, 1, 2, 3, 4, 5, 6 as $i_type] as &[$i_type], + &[17, 16, 15, 14, 13, 12, 11, 1, 2, 3, 4, 5, 6, 7 as $i_type] as &[$i_type], + &[ + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7 as $i_type, + ] as &[$i_type], + &[ + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 as $i_type, + ] as &[$i_type], + &[ + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 as $i_type, + ] as &[$i_type], + &[ + 19, + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 as $i_type, + ] as &[$i_type], + &[ + 19, + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 as $i_type, + ] as &[$i_type], + ]; + for each_slice in test_data { + let encode_func = $encode_func; + let decode_func = $decode_func; + let end_encode_func = $end_encode_func; + let end_decode_func = $end_decode_func; + + let cur_len = each_slice.len(); + let effective_len = cur_len.min(16); + + // encode... + let mut buffer = [uninit; 1024]; + let mut encoder = create_encoder(&mut buffer); + + encode_func(&mut encoder, each_slice); + + let end = 1i32; + end_encode_func(&mut encoder, end); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + + let decoder = DemoDecoder::default().header(header, 0); + let decoded = decode_func(&decoder); + for each_idx in 0..effective_len { + assert_eq!( + each_slice[each_idx], + decoded[each_idx], + "Item mismatched at {}/{} for {}", + each_idx, + cur_len, + stringify!($i_type) + ); + } + for each_idx in effective_len..16 { + assert_eq!( + decoded[each_idx], + 0, + "Item should be padded ZERO at {}/{} for {}", + each_idx, + cur_len, + stringify!($i_type) + ); + } + let decoded_end = end_decode_func(&decoder); + assert_eq!(decoded_end, end, "End Item should equal",); + } + }; + } + + run_encode_then_decode_for_array_of_unsigned_len_16!( + DemoEncoder::fixed_16_u16_zero_padded, + DemoDecoder::fixed_16_u16, + DemoEncoder::fixed_16_u16_end, + DemoDecoder::fixed_16_u16_end, + u16 + ); + run_encode_then_decode_for_array_of_unsigned_len_16!( + DemoEncoder::fixed_16_u32_zero_padded, + DemoDecoder::fixed_16_u32, + DemoEncoder::fixed_16_u32_end, + DemoDecoder::fixed_16_u32_end, + u32 + ); + run_encode_then_decode_for_array_of_unsigned_len_16!( + DemoEncoder::fixed_16_u64_zero_padded, + DemoDecoder::fixed_16_u64, + DemoEncoder::fixed_16_u64_end, + DemoDecoder::fixed_16_u64_end, + u64 + ); +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index ae50c9bef7..39a5ed633c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -276,7 +276,14 @@ static void generateWriteBuf(final Writer writer, final ByteOrder byteOrder) thr indent(writer, 2, "dest.clone_from_slice(src);\n"); indent(writer, 2, "len\n"); indent(writer, 1, "}\n"); + indent(writer, 0, "}\n"); + // impl From for &[u8] + indent(writer, 0, "impl<%s> From<&%1$s mut %2$s<%1$s>> for &%1$s mut [u8] {\n", BUF_LIFETIME, WRITE_BUF_TYPE); + indent(writer, 1, "#[inline]\n"); + indent(writer, 1, "fn from(buf: &%s mut %2$s<%1$s>) -> &%1$s mut [u8] {\n", BUF_LIFETIME, WRITE_BUF_TYPE); + indent(writer, 2, "buf.data\n"); + indent(writer, 1, "}\n"); indent(writer, 0, "}\n\n"); } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index f78899cb4b..d56c680d28 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -361,7 +361,62 @@ static void generateEncoderVarData( } } - private static void generatePrimitiveEncoder( + private static String rustNullLiteral(final Encoding encoding) + { + return generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue()); + } + + + private static void generateRustDoc( + final StringBuilder sb, + final int level, + final Token typeToken, + final Encoding encoding) throws IOException + { + indent(sb, level, "/// - min value: %s\n", encoding.applicableMinValue()); + indent(sb, level, "/// - max value: %s\n", encoding.applicableMaxValue()); + indent(sb, level, "/// - null value: %s\n", rustNullLiteral(encoding)); + indent(sb, level, "/// - characterEncoding: %s\n", encoding.characterEncoding()); + indent(sb, level, "/// - semanticType: %s\n", encoding.semanticType()); + indent(sb, level, "/// - encodedOffset: %d\n", typeToken.offset()); + indent(sb, level, "/// - encodedLength: %d\n", typeToken.encodedLength()); + indent(sb, level, "/// - version: %d\n", typeToken.version()); + } + + private static void generatePrimitiveArrayFromIterEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name) throws IOException + { + final Encoding encoding = typeToken.encoding(); + final PrimitiveType primitiveType = encoding.primitiveType(); + final String rustPrimitiveType = rustTypeName(primitiveType); + + indent(sb, level, "/// primitive array field '%s' from an Iterator\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s_from_iter(&mut self, iter: impl Iterator) {\n", + formatFunctionName(name), rustPrimitiveType); + + indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); + indent(sb, level + 1, "let buf = self.get_buf_mut();\n"); + indent(sb, level + 1, "for (i, v) in iter.enumerate() {\n"); + + if (primitiveType.size() == 1) + { + indent(sb, level + 2, "buf.put_%s_at(offset + i, v);\n", rustPrimitiveType); + } + else + { + indent(sb, level + 2, "buf.put_%s_at(offset + i * %d, v);\n", + rustPrimitiveType, primitiveType.size()); + } + indent(sb, level + 1, "}\n"); + indent(sb, level, "}\n\n"); + } + + private static void generatePrimitiveArrayZeroPaddedEncoder( final StringBuilder sb, final int level, final Token typeToken, @@ -371,34 +426,66 @@ private static void generatePrimitiveEncoder( final PrimitiveType primitiveType = encoding.primitiveType(); final String rustPrimitiveType = rustTypeName(primitiveType); final int arrayLength = typeToken.arrayLength(); - if (arrayLength > 1) + + indent(sb, level, "/// primitive array field '%s' with zero padding\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s_zero_padded(&mut self, value: &[%s]) {\n", + formatFunctionName(name), rustPrimitiveType); + + indent(sb, level + 1, "let iter = value.iter().copied().chain(std::iter::repeat(0_%s)).take(%d);\n", + rustPrimitiveType, arrayLength); + + indent(sb, level + 1, "self.%s_from_iter(iter);\n", formatFunctionName(name)); + indent(sb, level, "}\n\n"); + } + + private static void generatePrimitiveArrayEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name) throws IOException + { + final Encoding encoding = typeToken.encoding(); + final PrimitiveType primitiveType = encoding.primitiveType(); + final String rustPrimitiveType = rustTypeName(primitiveType); + final int arrayLength = typeToken.arrayLength(); + + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s_at(&mut self, index: usize, value: %s) {\n", + formatFunctionName(name), rustPrimitiveType); + indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); + indent(sb, level + 1, "let buf = self.get_buf_mut();\n"); + + if (primitiveType.size() == 1) { - indent(sb, level, "/// primitive array field '%s'\n", name); - indent(sb, level, "/// - min value: %s\n", encoding.applicableMinValue()); - indent(sb, level, "/// - max value: %s\n", encoding.applicableMaxValue()); - indent(sb, level, "/// - null value: %s\n", encoding.applicableNullValue()); - indent(sb, level, "/// - characterEncoding: %s\n", encoding.characterEncoding()); - indent(sb, level, "/// - semanticType: %s\n", encoding.semanticType()); - indent(sb, level, "/// - encodedOffset: %d\n", typeToken.offset()); - indent(sb, level, "/// - encodedLength: %d\n", typeToken.encodedLength()); - indent(sb, level, "/// - version: %d\n", typeToken.version()); - indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: &[%s; %d]) {\n", - formatFunctionName(name), - rustPrimitiveType, - arrayLength); + indent(sb, level + 1, "buf.put_%s_at(offset + index, value);\n", rustPrimitiveType); + } + else + { + indent(sb, level + 1, "buf.put_%s_at(offset + index * %d, value);\n", + rustPrimitiveType, primitiveType.size()); + } + indent(sb, level, "}\n\n"); - // NB: must create variable 'offset' before calling mutable self.get_buf_mut() - indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); - indent(sb, level + 1, "let buf = self.get_buf_mut();\n"); + indent(sb, level, "/// primitive array field '%s'\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s(&mut self, value: &[%s]) {\n", + formatFunctionName(name), rustPrimitiveType); - if (rustPrimitiveType.equals("u8")) - { - indent(sb, level + 1, "buf.put_bytes_at(offset, value);\n"); - indent(sb, level, "}\n\n"); - return; - } + // NB: must create variable 'offset' before calling mutable self.get_buf_mut() + indent(sb, level + 1, "debug_assert_eq!(%d, value.len());\n", arrayLength); + indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); + indent(sb, level + 1, "let buf = self.get_buf_mut();\n"); + if (rustPrimitiveType.equals("u8")) + { + indent(sb, level + 1, "buf.put_slice_at(offset, value);\n"); + indent(sb, level, "}\n\n"); + } + else + { for (int i = 0; i < arrayLength; i++) { if (i == 0) @@ -416,34 +503,44 @@ private static void generatePrimitiveEncoder( indent(sb, level, "}\n\n"); } - else + + generatePrimitiveArrayFromIterEncoder(sb, level, typeToken, name); + generatePrimitiveArrayZeroPaddedEncoder(sb, level, typeToken, name); + } + + private static void generatePrimitiveEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name) throws IOException + { + final int arrayLength = typeToken.arrayLength(); + if (arrayLength > 1) { - if (encoding.presence() == Encoding.Presence.CONSTANT) - { - indent(sb, level, "// skipping CONSTANT %s\n\n", name); - } - else - { - indent(sb, level, "/// primitive field '%s'\n", name); - indent(sb, level, "/// - min value: %s\n", encoding.applicableMinValue()); - indent(sb, level, "/// - max value: %s\n", encoding.applicableMaxValue()); - indent(sb, level, "/// - null value: %s\n", encoding.applicableNullValue()); - indent(sb, level, "/// - characterEncoding: %s\n", encoding.characterEncoding()); - indent(sb, level, "/// - semanticType: %s\n", encoding.semanticType()); - indent(sb, level, "/// - encodedOffset: %d\n", typeToken.offset()); - indent(sb, level, "/// - encodedLength: %d\n", typeToken.encodedLength()); - indent(sb, level, "/// - version: %d\n", typeToken.version()); - indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", - formatFunctionName(name), - rustPrimitiveType); - - // NB: must create variable 'offset' before calling mutable self.get_buf_mut() - indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); - indent(sb, level + 1, "self.get_buf_mut().put_%s_at(offset, value);\n", rustPrimitiveType); - indent(sb, level, "}\n\n"); - } + generatePrimitiveArrayEncoder(sb, level, typeToken, name); + return; } + + final Encoding encoding = typeToken.encoding(); + if (encoding.presence() == Encoding.Presence.CONSTANT) + { + indent(sb, level, "// skipping CONSTANT %s\n\n", name); + return; + } + + final PrimitiveType primitiveType = encoding.primitiveType(); + final String rustPrimitiveType = rustTypeName(primitiveType); + + indent(sb, level, "/// primitive field '%s'\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", + formatFunctionName(name), rustPrimitiveType); + + // NB: must create variable 'offset' before calling mutable self.get_buf_mut() + indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); + indent(sb, level + 1, "self.get_buf_mut().put_%s_at(offset, value);\n", rustPrimitiveType); + indent(sb, level, "}\n\n"); } private static void generateEnumEncoder( @@ -679,7 +776,7 @@ private static void generatePrimitiveArrayDecoder( if (fieldToken.version() > 0) { indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); - indent(sb, level + 2, "return [%s; %d];\n", encoding.applicableNullValue(), arrayLength); + indent(sb, level + 2, "return [%s; %d];\n", rustNullLiteral(encoding), arrayLength); indent(sb, level + 1, "}\n\n"); } @@ -772,7 +869,7 @@ private static void generatePrimitiveOptionalDecoder( final String rustPrimitiveType = rustTypeName(primitiveType); final String characterEncoding = encoding.characterEncoding(); indent(sb, level, "/// primitive field - '%s' { null_value: '%s' }\n", - encoding.presence(), encoding.applicableNullValue()); + encoding.presence(), rustNullLiteral(encoding)); if (characterEncoding != null) { @@ -789,14 +886,14 @@ private static void generatePrimitiveOptionalDecoder( rustPrimitiveType, getBufOffset(fieldToken)); - final String literal = generateRustLiteral(primitiveType, encoding.applicableNullValue().toString()); - if (literal.endsWith("::NAN")) + final String nullLiteral = rustNullLiteral(encoding); + if (nullLiteral.endsWith("::NAN")) { indent(sb, level + 1, "if value.is_nan() {\n"); } else { - indent(sb, level + 1, "if value == %s {\n", literal); + indent(sb, level + 1, "if value == %s {\n", nullLiteral); } indent(sb, level + 2, "None\n"); @@ -833,8 +930,7 @@ private static void generatePrimitiveRequiredDecoder( if (fieldToken.version() > 0) { indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); - indent(sb, level + 2, "return %s;\n", - generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue().toString())); + indent(sb, level + 2, "return %s;\n", rustNullLiteral(encoding)); indent(sb, level + 1, "}\n\n"); } @@ -1257,8 +1353,7 @@ private static void generateEnum( // null value { final Encoding encoding = messageBody.get(0).encoding(); - final CharSequence nullVal = generateRustLiteral(encoding.primitiveType(), - encoding.applicableNullValue().toString()); + final CharSequence nullVal = rustNullLiteral(encoding); indent(writer, 1, "#[default]\n"); indent(writer, 1, "NullVal = %s, \n", nullVal); } @@ -1322,8 +1417,7 @@ private static void generateFromEnumForPrimitive( { final Encoding encoding = messageBody.get(0).encoding(); - final CharSequence nullVal = generateRustLiteral(encoding.primitiveType(), - encoding.applicableNullValue().toString()); + final CharSequence nullVal = rustNullLiteral(encoding); indent(writer, 3, "%s::NullVal => %s,\n", enumRustName, nullVal); } indent(writer, 2, "}\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index 43b9c8ba8a..ae55de1e9e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -17,6 +17,7 @@ import org.agrona.Verify; import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.PrimitiveValue; import uk.co.real_logic.sbe.generation.Generators; import uk.co.real_logic.sbe.generation.rust.RustGenerator.CodecType; import uk.co.real_logic.sbe.ir.Encoding; @@ -65,6 +66,11 @@ static String rustTypeName(final PrimitiveType primitiveType) return TYPE_NAME_BY_PRIMITIVE_TYPE_MAP.get(primitiveType); } + static String generateRustLiteral(final PrimitiveType type, final PrimitiveValue value) + { + return generateRustLiteral(type, value.toString()); + } + static String generateRustLiteral(final PrimitiveType type, final String value) { Verify.notNull(type, "type"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index d6d7652b83..6092fb5d48 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -88,6 +88,7 @@ void generateRustLiteralsForUnsignedPrimitiveNulls() assertEquals("0xff_u8", generateRustLiteral(UINT8, UINT8.nullValue().toString())); assertEquals("0xffff_u16", generateRustLiteral(UINT16, UINT16.nullValue().toString())); assertEquals("0xffffffff_u32", generateRustLiteral(UINT32, UINT32.nullValue().toString())); + assertEquals("0xffffffffffffffff_u64", generateRustLiteral(UINT64, UINT64.nullValue())); assertEquals("0xffffffffffffffff_u64", generateRustLiteral(UINT64, UINT64.nullValue().toString())); } @@ -100,7 +101,7 @@ void generateRustLiteralNullPrimitiveTypeParam() @Test void generateRustLiteralNullValueParam() { - assertThrows(NullPointerException.class, () -> generateRustLiteral(INT8, null)); + assertThrows(NullPointerException.class, () -> generateRustLiteral(INT8, (String)null)); } @Test diff --git a/sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml b/sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml new file mode 100644 index 0000000000..62f3b9a5b0 --- /dev/null +++ b/sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4caa7f4e5db809fa2a411d949db44181e581b329 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:06:15 +0100 Subject: [PATCH 514/805] Update copyright. --- CMakeLists.txt | 2 +- CONTRIBUTING.md | 2 +- README.md | 2 +- build.gradle | 4 ++-- sbe-benchmarks/src/main/cpp/CMakeLists.txt | 2 +- sbe-benchmarks/src/main/cpp/CarBench.cpp | 2 +- sbe-benchmarks/src/main/cpp/CodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/MarketDataBench.cpp | 2 +- sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h | 2 +- sbe-benchmarks/src/main/cpp/benchlet-main.cpp | 2 +- sbe-benchmarks/src/main/cpp/benchlet.h | 2 +- .../src/main/java/uk/co/real_logic/sbe/CarBenchmark.java | 2 +- .../main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/package-info.java | 2 +- sbe-samples/src/main/cpp/CMakeLists.txt | 2 +- sbe-samples/src/main/cpp/GeneratedStubExample.cpp | 2 +- sbe-samples/src/main/cpp/OtfExample.cpp | 2 +- .../uk/co/real_logic/sbe/examples/ExampleTokenListener.java | 2 +- .../co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java | 2 +- .../sbe/examples/ExampleUsingGeneratedStubExtension.java | 2 +- .../main/java/uk/co/real_logic/sbe/examples/OtfExample.java | 2 +- .../main/java/uk/co/real_logic/sbe/examples/package-info.java | 2 +- sbe-tool/src/main/cpp/CMakeLists.txt | 2 +- sbe-tool/src/main/cpp/otf/Encoding.h | 2 +- sbe-tool/src/main/cpp/otf/IrDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h | 2 +- sbe-tool/src/main/cpp/otf/Token.h | 2 +- sbe-tool/src/main/golang/otf/encoding.go | 2 +- .../src/main/java/uk/co/real_logic/sbe/PrimitiveType.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ValidationUtil.java | 2 +- .../main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java | 2 +- .../java/uk/co/real_logic/sbe/codec/java/MethodSelector.java | 2 +- .../java/uk/co/real_logic/sbe/codec/java/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/CodeGenerator.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/Generators.java | 2 +- .../uk/co/real_logic/sbe/generation/TargetCodeGenerator.java | 2 +- .../real_logic/sbe/generation/TargetCodeGeneratorLoader.java | 2 +- .../java/uk/co/real_logic/sbe/generation/c/CGenerator.java | 2 +- .../uk/co/real_logic/sbe/generation/c/COutputManager.java | 2 +- .../main/java/uk/co/real_logic/sbe/generation/c/CUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/c/package-info.java | 2 +- .../sbe/generation/common/FieldPrecedenceModel.java | 2 +- .../co/real_logic/sbe/generation/common/PrecedenceChecks.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java | 2 +- .../real_logic/sbe/generation/cpp/NamespaceOutputManager.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/csharp/CSharp.java | 2 +- .../real_logic/sbe/generation/csharp/CSharpDtoGenerator.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java | 2 +- .../co/real_logic/sbe/generation/csharp/CSharpGenerator.java | 2 +- .../sbe/generation/csharp/CSharpNamespaceOutputManager.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/csharp/package-info.java | 2 +- .../generation/golang/flyweight/GolangFlyweightGenerator.java | 2 +- .../golang/flyweight/GolangFlyweightOutputManager.java | 2 +- .../sbe/generation/golang/flyweight/GolangFlyweightUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/golang/package-info.java | 2 +- .../sbe/generation/golang/struct/GolangGenerator.java | 2 +- .../sbe/generation/golang/struct/GolangOutputManager.java | 2 +- .../real_logic/sbe/generation/golang/struct/GolangUtil.java | 2 +- .../co/real_logic/sbe/generation/java/JavaDtoGenerator.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/JavaDtos.java | 2 +- .../uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 2 +- .../co/real_logic/sbe/generation/java/JavaOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/JavaUtil.java | 2 +- .../uk/co/real_logic/sbe/generation/java/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 +- .../co/real_logic/sbe/generation/rust/RustOutputManager.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/RustUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/rust/SubGroup.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/package-info.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java | 2 +- .../main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/ir/package-info.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java | 2 +- .../java/uk/co/real_logic/sbe/json/JsonTokenListener.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/json/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java | 2 +- .../main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java | 2 +- .../main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/otf/package-info.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java | 2 +- .../main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java | 2 +- .../uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java | 2 +- .../main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java | 2 +- .../uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java | 2 +- .../co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java | 2 +- sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java | 2 +- .../main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java | 2 +- .../src/main/java/uk/co/real_logic/sbe/xml/package-info.java | 2 +- .../uk/co/real_logic/sbe/properties/DtosPropertyTest.java | 2 +- .../uk/co/real_logic/sbe/properties/JsonPropertyTest.java | 2 +- .../uk/co/real_logic/sbe/properties/ParserPropertyTest.java | 2 +- .../real_logic/sbe/properties/arbitraries/SbeArbitraries.java | 2 +- .../real_logic/sbe/properties/schema/CompositeTypeSchema.java | 2 +- .../sbe/properties/schema/EncodedDataTypeSchema.java | 2 +- .../co/real_logic/sbe/properties/schema/EnumTypeSchema.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/FieldSchema.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/GroupSchema.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/MessageSchema.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/SetSchema.java | 2 +- .../real_logic/sbe/properties/schema/TestXmlSchemaWriter.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/TypeSchema.java | 2 +- .../real_logic/sbe/properties/schema/TypeSchemaVisitor.java | 2 +- .../uk/co/real_logic/sbe/properties/schema/VarDataSchema.java | 2 +- .../sbe/properties/utils/InMemoryOutputManager.java | 2 +- sbe-tool/src/test/c/BoundsCheckTest.cpp | 2 +- sbe-tool/src/test/c/CComplianceTest.c | 2 +- sbe-tool/src/test/c/CComplianceWithVersionTest.c | 2 +- sbe-tool/src/test/c/CMakeLists.txt | 2 +- sbe-tool/src/test/c/CodeGenTest.cpp | 2 +- sbe-tool/src/test/c/GroupWithDataTest.cpp | 2 +- sbe-tool/src/test/c/Issue889Test.cpp | 2 +- sbe-tool/src/test/cpp/BoundsCheckTest.cpp | 2 +- sbe-tool/src/test/cpp/CMakeLists.txt | 2 +- sbe-tool/src/test/cpp/CodeGenTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeElementsTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp | 2 +- sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp | 2 +- sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp | 2 +- sbe-tool/src/test/cpp/GroupWithDataTest.cpp | 2 +- sbe-tool/src/test/cpp/Issue835Test.cpp | 2 +- sbe-tool/src/test/cpp/Issue889Test.cpp | 2 +- sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp | 2 +- sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp | 2 +- .../test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java | 2 +- .../java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java | 2 +- .../java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/TestTargetLanguage.java | 2 +- sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java | 2 +- .../test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java | 2 +- .../java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java | 2 +- .../uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java | 2 +- .../co/real_logic/sbe/generation/csharp/CSharpEnumTest.java | 2 +- .../real_logic/sbe/generation/csharp/CSharpGeneratorTest.java | 2 +- .../sbe/generation/csharp/Issue567GroupSizeTest.java | 2 +- .../sbe/generation/golang/GolangStructGeneratorTest.java | 2 +- .../co/real_logic/sbe/generation/java/CarDecodeTestUtil.java | 2 +- .../real_logic/sbe/generation/java/CharacterEncodingTest.java | 2 +- .../sbe/generation/java/CompositeElementsGenerationTest.java | 2 +- .../real_logic/sbe/generation/java/ConstantCharArrayTest.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/DtoTest.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/EnumTest.java | 2 +- .../sbe/generation/java/FixedSizeDataGeneratorTest.java | 2 +- .../real_logic/sbe/generation/java/GenerateFixBinaryTest.java | 2 +- .../sbe/generation/java/GenerateIlinkBinaryTest.java | 2 +- .../co/real_logic/sbe/generation/java/JavaGeneratorTest.java | 2 +- .../real_logic/sbe/generation/java/JavaOutputManagerTest.java | 2 +- .../co/real_logic/sbe/generation/java/NullEnumTypedTest.java | 2 +- .../sbe/generation/java/PackageOutputManagerTest.java | 2 +- .../co/real_logic/sbe/generation/java/QualifiedYieldTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/ReflectionUtil.java | 2 +- .../java/uk/co/real_logic/sbe/generation/java/RewindTest.java | 2 +- .../real_logic/sbe/generation/java/SchemaExtensionTest.java | 2 +- .../java/SinceVersionTransformedSchemaJavaGenerationTest.java | 2 +- .../sbe/generation/java/SkipAndDecodedLengthTest.java | 2 +- .../uk/co/real_logic/sbe/generation/java/ToStringTest.java | 2 +- .../sbe/generation/java/ValueRefWithLowerCaseEnumTest.java | 2 +- .../real_logic/sbe/generation/java/WarningFormattingTest.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/RustUtilTest.java | 2 +- .../uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java | 2 +- .../java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java | 2 +- .../uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java | 2 +- .../co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java | 2 +- .../test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java | 2 +- .../java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java | 2 +- .../co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java | 2 +- .../src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java | 2 +- .../real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java | 2 +- 212 files changed, 213 insertions(+), 213 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b78278fca..326986a509 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2024 Real Logic Limited. +# Copyright 2013-2025 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 24b6402de5..bac5877c8e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ If you are adding a new file it should have the following header: ``` /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 3b2d354d45..c051584e3b 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ Or run test directly with `Cargo` License (See LICENSE file for full license) ------------------------------------------- -Copyright 2013-2024 Real Logic Limited. +Copyright 2013-2025 Real Logic Limited. Copyright 2017 MarketFactory Inc. Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/build.gradle b/build.gradle index 3e3b3b2ee7..586f2d9c5a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -194,7 +194,7 @@ subprojects { javadoc { failOnError false title = '

    Simple Binary Encoding (SBE)

    ' - options.bottom = 'Copyright © 2013-2024 Real Logic Limited. All Rights Reserved.' + options.bottom = 'Copyright © 2013-2025 Real Logic Limited. All Rights Reserved.' options.encoding = 'UTF-8' options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' diff --git a/sbe-benchmarks/src/main/cpp/CMakeLists.txt b/sbe-benchmarks/src/main/cpp/CMakeLists.txt index 055ea4f63a..38a1f071b4 100644 --- a/sbe-benchmarks/src/main/cpp/CMakeLists.txt +++ b/sbe-benchmarks/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2024 Real Logic Limited. +# Copyright 2013-2025 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/CarBench.cpp b/sbe-benchmarks/src/main/cpp/CarBench.cpp index 42c757efd2..74e174f016 100644 --- a/sbe-benchmarks/src/main/cpp/CarBench.cpp +++ b/sbe-benchmarks/src/main/cpp/CarBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/CodecBench.h b/sbe-benchmarks/src/main/cpp/CodecBench.h index 14cf19547e..005cfa0fc4 100644 --- a/sbe-benchmarks/src/main/cpp/CodecBench.h +++ b/sbe-benchmarks/src/main/cpp/CodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp b/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp index a320b30ab7..04d00a9cf8 100644 --- a/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp +++ b/sbe-benchmarks/src/main/cpp/MarketDataBench.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h index fb044428ae..9f40e6e080 100644 --- a/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeCarCodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h b/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h index fbe11e6de0..38f58d6729 100644 --- a/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h +++ b/sbe-benchmarks/src/main/cpp/SbeMarketDataCodecBench.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/benchlet-main.cpp b/sbe-benchmarks/src/main/cpp/benchlet-main.cpp index f60927438f..c106879458 100644 --- a/sbe-benchmarks/src/main/cpp/benchlet-main.cpp +++ b/sbe-benchmarks/src/main/cpp/benchlet-main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/cpp/benchlet.h b/sbe-benchmarks/src/main/cpp/benchlet.h index c883dd0faf..aa3eb621ac 100644 --- a/sbe-benchmarks/src/main/cpp/benchlet.h +++ b/sbe-benchmarks/src/main/cpp/benchlet.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java index 1531933165..dbc37037ff 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/CarBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java index 1125c6ccc3..c97c0f0144 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/MarketDataBenchmark.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java index 5e8842c2c8..88ae5ee4ba 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/CMakeLists.txt b/sbe-samples/src/main/cpp/CMakeLists.txt index 2e0a6c8d16..dd64470943 100644 --- a/sbe-samples/src/main/cpp/CMakeLists.txt +++ b/sbe-samples/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2024 Real Logic Limited. +# Copyright 2013-2025 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/GeneratedStubExample.cpp b/sbe-samples/src/main/cpp/GeneratedStubExample.cpp index 2ee019f9df..a1e4908678 100644 --- a/sbe-samples/src/main/cpp/GeneratedStubExample.cpp +++ b/sbe-samples/src/main/cpp/GeneratedStubExample.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/cpp/OtfExample.cpp b/sbe-samples/src/main/cpp/OtfExample.cpp index ed24a59a6c..89921520ad 100644 --- a/sbe-samples/src/main/cpp/OtfExample.cpp +++ b/sbe-samples/src/main/cpp/OtfExample.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java index fb03fb954e..51302141d0 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java index 16e4617ce3..00ff187351 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStub.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java index 02daba6701..f053e7fd39 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleUsingGeneratedStubExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java index a45f734aea..2a1c864575 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/OtfExample.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java index a582d13016..1924360927 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/CMakeLists.txt b/sbe-tool/src/main/cpp/CMakeLists.txt index abb1f83a49..bcfdad0e3b 100644 --- a/sbe-tool/src/main/cpp/CMakeLists.txt +++ b/sbe-tool/src/main/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2024 Real Logic Limited. +# Copyright 2013-2025 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/Encoding.h b/sbe-tool/src/main/cpp/otf/Encoding.h index c6464e5ffc..0f265117cc 100644 --- a/sbe-tool/src/main/cpp/otf/Encoding.h +++ b/sbe-tool/src/main/cpp/otf/Encoding.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index b4ed9cefd8..2c497d29ad 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h b/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h index 56249a832b..46440d9233 100644 --- a/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfHeaderDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h index edd65bff17..e84e51db3f 100644 --- a/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h +++ b/sbe-tool/src/main/cpp/otf/OtfMessageDecoder.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/cpp/otf/Token.h b/sbe-tool/src/main/cpp/otf/Token.h index 69e06224cc..2855c2a86c 100644 --- a/sbe-tool/src/main/cpp/otf/Token.h +++ b/sbe-tool/src/main/cpp/otf/Token.h @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/golang/otf/encoding.go b/sbe-tool/src/main/golang/otf/encoding.go index a10fef5b2d..b98f336892 100644 --- a/sbe-tool/src/main/golang/otf/encoding.go +++ b/sbe-tool/src/main/golang/otf/encoding.go @@ -1,4 +1,4 @@ -// Copyright 2013-2024 Real Logic Limited. +// Copyright 2013-2025 Real Logic Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java index 92cb21c32d..ed4a263768 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java index 18b543aef6..db90ae0459 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/PrimitiveValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index 9c0ab8df4b..552a9656ab 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index a7bb7e0d19..426e7c4fd1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java index 93e86eee1e..4d60edc6a5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/GroupOrder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java index 7f17222cdc..687a921a0a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/MethodSelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java index f10999cff9..a97ba65c46 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java index 03dcf30090..2afc91a9c8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/CodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java index a6ba5850ea..c2af0d3738 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/Generators.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java index 461cb2bb22..aa8a41fc21 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index c979bede45..db33966a89 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 68afbb8283..427034515d 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java index 0da63b7c09..4459dc09ac 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/COutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java index 518abd80b2..09067240c0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java index 956b86d379..5cba823b2d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java index 40e5ac7441..cad644fedf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java index cd5e1856aa..882e4dd66e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/PrecedenceChecks.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index b6f337a837..05d214d751 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java index 6e59b6dd06..1dde335d57 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index b8d427241a..df1140ee22 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java index 469faac27a..f076301379 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java index 43c45fa9f7..71f993dc97 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/NamespaceOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java index 4ea7958015..49a0229afc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java index f13b9cfab6..5125f79246 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index b5225caa67..47bef5a349 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java index 118b8e8d45..ab5b591b48 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index af9979879a..b6fd5d7746 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java index 6ec2505238..841c2fbfb1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpNamespaceOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index b4fee26faf..0fd31feed6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java index 54b9fdd77c..53c5a9418d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java index 259c461408..8b2d65ab62 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightOutputManager.java index 3b9e72b716..541fee82b6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java index ba03adbc3b..2b74309d13 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java index c30d9ed062..a11cc42072 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java index 58c357951d..d764a11eca 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangOutputManager.java index a584396a09..faf3178e3d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangUtil.java index 2689da26de..f2a6343387 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2016 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index 8c5bfb8b02..4d8b3d334c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java index 3d4dc61482..852e6bdd04 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright (C) 2017 MarketFactory, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index b47b8839cc..5f28c17a90 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java index 9bbe32bc86..51817dc04c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index 7f885f673c..2290e7f468 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java index cfe10b0723..ee4ebf09fc 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java index 7a6cae1bac..2c9b0501aa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 39a5ed633c..f361397916 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 8faaa9c451..da9060b9a2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index d56c680d28..32f1633178 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java index 49f5f6747d..fe8ca08e63 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index ae55de1e9e..a38bea7a7a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index d0b5abc433..5c1981a874 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java index bfaccf83ee..2c817689c3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java index db4e41a9ff..0a7b332130 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java index 318cc3061f..dfae5acb7d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/GenerationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java index 1ca42e82d1..42fa6b9103 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/HeaderStructure.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java index 87eba20050..09e3f33ead 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Ir.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index 4db9e04a99..98e1a9d409 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java index 82ad99d714..c3bf073e5e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java index b72f8b46a0..13694d0579 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java index db6d2cb849..22c21b7735 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Signal.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java index 6d97572727..7ea00920c0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java index b4533bccb0..f317c5e7f3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java index 3071afb6c9..efff7fdd93 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java index 9ae537b397..4d81dc47b9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java index a7214788a4..476fe58c1c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java index 3f2e518d31..1422092ba1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java index 7bbe1fb11f..41f79bfba8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfHeaderDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java index f9c243555b..1143379c7d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/OtfMessageDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java index df2782b168..a746798965 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/TokenListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java index 0f8916d55b..d9c64a2a2f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java index d3e1aebfb7..04cf0dddd4 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java index 06dfbeb735..fd30d70f78 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java index f7d6052df2..37b8b0e808 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index 78fe6e10a0..0239e864ec 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java index b2566ea787..bedafa57b3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java index 8d3c48ea3f..ceb020e85b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java index d445da2f92..aa91b6ff31 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java index 49cf4ca722..b79e1d6493 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java index 8f507ca366..3575d38413 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IrGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java index 90695b736a..9fbdfc7789 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java index 5203939b4d..c9dfbec5e5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/MessageSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java index 93aa9c8260..b4569347c6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ParserOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java index 2eee8a20c0..f608e572ec 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Presence.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java index 11bdccbe08..8407385f0d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java index c52ae6feed..7b0e678c88 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java index ff5b025ae4..467ac93b80 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java index b96605d860..a5d876baab 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java index 9590c3e756..9b193b6cd9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Type.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java index 008e5a1629..8667d2501c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/XmlSchemaParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright 2017 MarketFactory Inc * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java index c16ea698f3..7c0ead4286 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index a8341e578c..04e1d8fdae 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java index f3d49fbbe7..ebac19703e 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java index 3be05c85ae..451ea8d0e7 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/ParserPropertyTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index b8543b0abd..c1dc232ee3 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java index 264a49219d..f51e23fd90 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/CompositeTypeSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java index ea9d3228bb..443c594934 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EncodedDataTypeSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java index b129e54c71..284791d38b 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/EnumTypeSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java index 1cf9cc2ccf..9a809642dc 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/FieldSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java index c0fafb0dbf..4046d60ecd 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/GroupSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java index edde5e89b6..a071ee2db9 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/MessageSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java index 071f8e7419..502812a672 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/SetSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index faeaab331b..5dc4569db2 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java index 4a359fa6be..e03d2f5bf8 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java index 7dbc69188f..9e4cb435b2 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TypeSchemaVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java index a4298e89e7..eb636a7b80 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/VarDataSchema.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java index dc8482c525..065737c57e 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/BoundsCheckTest.cpp b/sbe-tool/src/test/c/BoundsCheckTest.cpp index 047fab85e6..eda469aed9 100644 --- a/sbe-tool/src/test/c/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/c/BoundsCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CComplianceTest.c b/sbe-tool/src/test/c/CComplianceTest.c index 150edec6e5..33f8070605 100644 --- a/sbe-tool/src/test/c/CComplianceTest.c +++ b/sbe-tool/src/test/c/CComplianceTest.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CComplianceWithVersionTest.c b/sbe-tool/src/test/c/CComplianceWithVersionTest.c index 9156d58ce5..4de06c4b92 100644 --- a/sbe-tool/src/test/c/CComplianceWithVersionTest.c +++ b/sbe-tool/src/test/c/CComplianceWithVersionTest.c @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index 33169a501d..2ed9136bec 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2024 Real Logic Limited. +# Copyright 2013-2025 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/CodeGenTest.cpp b/sbe-tool/src/test/c/CodeGenTest.cpp index cda5433609..6f2a195a11 100644 --- a/sbe-tool/src/test/c/CodeGenTest.cpp +++ b/sbe-tool/src/test/c/CodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/GroupWithDataTest.cpp b/sbe-tool/src/test/c/GroupWithDataTest.cpp index f643b2de43..68e34d8bfd 100644 --- a/sbe-tool/src/test/c/GroupWithDataTest.cpp +++ b/sbe-tool/src/test/c/GroupWithDataTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/c/Issue889Test.cpp b/sbe-tool/src/test/c/Issue889Test.cpp index 800065e7da..2c39ea7d7e 100644 --- a/sbe-tool/src/test/c/Issue889Test.cpp +++ b/sbe-tool/src/test/c/Issue889Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp index aaa6a174a0..9b1763ce0d 100644 --- a/sbe-tool/src/test/cpp/BoundsCheckTest.cpp +++ b/sbe-tool/src/test/cpp/BoundsCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index ee09f3881e..675688cc0c 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2013-2024 Real Logic Limited. +# Copyright 2013-2025 Real Logic Limited. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index 039620a6c1..25c645248f 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeElementsTest.cpp b/sbe-tool/src/test/cpp/CompositeElementsTest.cpp index cede889d68..660333368c 100644 --- a/sbe-tool/src/test/cpp/CompositeElementsTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeElementsTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp index f767072ac6..39383e7659 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsCodeGenTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp b/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp index 22ebe9ecc2..468c2a4594 100644 --- a/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp +++ b/sbe-tool/src/test/cpp/CompositeOffsetsIrTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp index 24ad58c9b8..ef59c81d01 100644 --- a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/GroupWithDataTest.cpp b/sbe-tool/src/test/cpp/GroupWithDataTest.cpp index 03d35c2dee..e984de02e9 100644 --- a/sbe-tool/src/test/cpp/GroupWithDataTest.cpp +++ b/sbe-tool/src/test/cpp/GroupWithDataTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Issue835Test.cpp b/sbe-tool/src/test/cpp/Issue835Test.cpp index 9f59ae3fb0..a1fd46f864 100644 --- a/sbe-tool/src/test/cpp/Issue835Test.cpp +++ b/sbe-tool/src/test/cpp/Issue835Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Issue889Test.cpp b/sbe-tool/src/test/cpp/Issue889Test.cpp index 2acafb021a..3919c2a889 100644 --- a/sbe-tool/src/test/cpp/Issue889Test.cpp +++ b/sbe-tool/src/test/cpp/Issue889Test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp b/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp index 881dd0c020..4d76653fa0 100644 --- a/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp +++ b/sbe-tool/src/test/cpp/MessageBlockLengthTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp b/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp index fe8a58e6b1..fc2dabafda 100644 --- a/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp +++ b/sbe-tool/src/test/cpp/Rc3OtfFullIrTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java index 335e3a59b0..d785c2865b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/EncodedCarTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java index 6ac554b8a7..9afc026648 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/FieldAccessOrderCheckTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java index d0a0bdbdeb..8b943f6275 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TargetCodeGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java index 616aa06603..e47bf3a2bf 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/TestTargetLanguage.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java index be6fad4b98..d7b91086b7 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java index b09495875d..27886bdb2b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/codec/java/TypesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java index db69b1cf83..0091dd16f0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppEnumTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index 79c1651c03..6d4990df3b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpEnumTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpEnumTest.java index fec4a1bcfd..b042fc558d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpEnumTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpEnumTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java index 295ddd293b..e78952d1d2 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java index f96c1ee283..dc60b05010 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/Issue567GroupSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java index b4d6198680..aa578e2de9 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java index 4e063e9b4a..a5d089df1c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CarDecodeTestUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java index 487ce653d3..773ed6e497 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CharacterEncodingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java index ffc38c539f..e44d03263c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/CompositeElementsGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java index e6fe0c252a..e65dda9aa3 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ConstantCharArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java index 68b2fdce83..56d6869199 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java index 11c3424e6c..90eca7fc1c 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/EnumTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java index cd334d9cc1..74d95b309e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/FixedSizeDataGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java index 277404993f..a26048d38d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateFixBinaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java index babefc9391..3f9b7b024e 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/GenerateIlinkBinaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 68679c15a1..4b50d633e6 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java index 1eff4fa662..7d6d315744 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaOutputManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java index d949d6dfe8..97f2ac8c3b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/NullEnumTypedTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java index 36e78d2a28..932da0638b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/PackageOutputManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java index c5f0133783..5f0900a9f8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java index 2db082c6fc..acba97facd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ReflectionUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java index de19ed99ed..01a42a1ce5 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/RewindTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java index ee85bc2abe..bf4ebe746d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SchemaExtensionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java index d69fc82a26..39cee1146b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java index a69c9bfadb..4984038080 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SkipAndDecodedLengthTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java index daec79f9ec..13761019a4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ToStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnumTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnumTest.java index 675f99d05e..3d71f72c31 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnumTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/ValueRefWithLowerCaseEnumTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java index 2871b78d54..abf3b96e91 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/WarningFormattingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java index 6092fb5d48..e86e54c438 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java index f3509f7d97..97faca7848 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java index c888b3f9c5..f5acaa4544 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeElementsIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java index ee2eef15e9..c5c88e9179 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeOffsetsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java index 0d0416dd5a..4e80cd7b53 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/CompositeRefsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index d534863d86..2111fb1038 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java index 5519bcbf15..d4a31725d1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/GroupWithDataIrTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java index a2223ced19..3c8cfaf4a2 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/SinceVersionValidationTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java index b4bdfe9b52..b84abc5b42 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/ValueRefsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java index b5995c4dac..664e45bdee 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/json/JsonPrinterTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java index 3d392e0e95..09ff6834e4 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java index a44ee8d4cd..19066eac25 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeElementsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java index 38d399d1e0..ff63651471 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CompositeTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java index b3b3f7ae4e..052d0aa77f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/CyclicReferencesTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java index 63495cd586..48515d5dc8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EmbeddedLengthAndCountFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java index a0648b730c..f83abce08b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EncodedDataTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java index 70d8159f9b..9acd1b6c3b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/EnumTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java index bfb2965116..94011259e1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/ErrorHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * Copyright 2017 MarketFactory Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java index 265b088c7d..0aadb1715d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/GroupWithDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java index b8c2c130fb..c865dedd33 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/OffsetFileTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java index 7c134861be..c710b46e04 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java index f4ec8c63db..d92183e2d0 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java index 256e832ded..60d09daa15 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java index 32690f6b87..0fd1d90bfd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2024 Real Logic Limited. + * Copyright 2013-2025 Real Logic Limited. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From a209a2f9dd0f0fc69d849a5b75b05f40f5d9b27b Mon Sep 17 00:00:00 2001 From: Nate Bradac <38217740+nbradac@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:03:03 -0600 Subject: [PATCH 515/805] [C++] use m_actingBlockLength in decodeLength() (#1045) --- .../sbe/generation/cpp/CppGenerator.java | 2 +- sbe-tool/src/test/cpp/CMakeLists.txt | 7 +++ .../src/test/cpp/VersionedMessageTest.cpp | 57 +++++++++++++++++++ .../test/resources/versioned-message-v1.xml | 25 ++++++++ .../test/resources/versioned-message-v2.xml | 28 +++++++++ 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 sbe-tool/src/test/cpp/VersionedMessageTest.cpp create mode 100644 sbe-tool/src/test/resources/versioned-message-v1.xml create mode 100644 sbe-tool/src/test/resources/versioned-message-v2.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index df1140ee22..dd5065dbe2 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -3027,7 +3027,7 @@ private CharSequence generateMessageFlyweightCode( " SBE_NODISCARD std::uint64_t decodeLength() const\n" + " {\n" + - " %10$s skipper(m_buffer, m_offset, m_bufferLength, sbeBlockLength(), m_actingVersion);\n" + + " %10$s skipper(m_buffer, m_offset, m_bufferLength, m_actingBlockLength, m_actingVersion);\n" + " skipper.skip();\n" + " return skipper.encodedLength();\n" + " }\n\n" + diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 675688cc0c..53bb18f2ef 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -43,6 +43,8 @@ set(DTO_SCHEMA ${CODEC_SCHEMA_DIR}/dto-test-schema.xml) set(ISSUE835_SCHEMA ${CODEC_SCHEMA_DIR}/issue835.xml) set(ISSUE889_SCHEMA ${CODEC_SCHEMA_DIR}/issue889.xml) set(ACCESS_ORDER_SCHEMA ${CODEC_SCHEMA_DIR}/field-order-check-schema.xml) +set(VERSIONED_MESSAGE_V1_SCHEMA ${CODEC_SCHEMA_DIR}/versioned-message-v1.xml) +set(VERSIONED_MESSAGE_V2_SCHEMA ${CODEC_SCHEMA_DIR}/versioned-message-v2.xml) set(GENERATED_CODECS ${CXX_CODEC_TARGET_DIR} @@ -59,6 +61,8 @@ add_custom_command( ${ISSUE835_SCHEMA} ${ISSUE889_SCHEMA} ${ACCESS_ORDER_SCHEMA} + ${VERSIONED_MESSAGE_V1_SCHEMA} + ${VERSIONED_MESSAGE_V2_SCHEMA} sbe-jar ${SBE_JAR} COMMAND ${Java_JAVA_EXECUTABLE} --add-opens java.base/jdk.internal.misc=ALL-UNNAMED @@ -79,6 +83,8 @@ add_custom_command( ${ISSUE835_SCHEMA} ${ISSUE889_SCHEMA} ${ACCESS_ORDER_SCHEMA} + ${VERSIONED_MESSAGE_V1_SCHEMA} + ${VERSIONED_MESSAGE_V2_SCHEMA} ) add_custom_target(codecs DEPENDS ${GENERATED_CODECS}) @@ -96,6 +102,7 @@ sbe_test(Issue835Test codecs) sbe_test(Issue889Test codecs) sbe_test(FieldAccessOrderCheckTest codecs) target_compile_definitions(FieldAccessOrderCheckTest PRIVATE SBE_ENABLE_PRECEDENCE_CHECKS_IN_TESTS) +sbe_test(VersionedMessageTest codecs) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # Check if the GCC version supports C++17 diff --git a/sbe-tool/src/test/cpp/VersionedMessageTest.cpp b/sbe-tool/src/test/cpp/VersionedMessageTest.cpp new file mode 100644 index 0000000000..af4a90c442 --- /dev/null +++ b/sbe-tool/src/test/cpp/VersionedMessageTest.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2013-2025 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "versmsg/VersionedMessageV1.h" +#include "versmsg/VersionedMessageV2.h" + +using namespace versmsg; + +static const std::size_t BUFFER_LEN = 2048; + +class VersionedMessageTest : public testing::Test +{ +public: + VersionedMessageV2 m_versionedMessageV2 = {}; + VersionedMessageV1 m_versionedMessageV1Decoder = {}; +}; + +TEST_F(VersionedMessageTest, shouldV1DecodeV2Message) +{ + char buffer[BUFFER_LEN] = {}; + + m_versionedMessageV2.wrapForEncode(buffer, 0, sizeof(buffer)); + m_versionedMessageV2.fieldA1(1); + m_versionedMessageV2.fieldB1(2); + m_versionedMessageV2.fieldC2(3); + m_versionedMessageV2.fieldD2(4); + m_versionedMessageV2.fieldE2(5); + m_versionedMessageV2.putString1("asdf", 4); + + m_versionedMessageV1Decoder.wrapForDecode( + buffer, + 0, + VersionedMessageV2::sbeBlockLength(), + VersionedMessageV2::sbeSchemaVersion(), + m_versionedMessageV2.encodedLength()); + + EXPECT_EQ(m_versionedMessageV1Decoder.fieldA1(), (uint32_t)1); + EXPECT_EQ(m_versionedMessageV1Decoder.fieldB1(), (uint32_t)2); + EXPECT_STREQ(m_versionedMessageV1Decoder.string1(), "asdf"); + + EXPECT_EQ(m_versionedMessageV1Decoder.decodeLength(), (uint64_t)26); +} diff --git a/sbe-tool/src/test/resources/versioned-message-v1.xml b/sbe-tool/src/test/resources/versioned-message-v1.xml new file mode 100644 index 0000000000..bd942e82c7 --- /dev/null +++ b/sbe-tool/src/test/resources/versioned-message-v1.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/sbe-tool/src/test/resources/versioned-message-v2.xml b/sbe-tool/src/test/resources/versioned-message-v2.xml new file mode 100644 index 0000000000..3d0de450e5 --- /dev/null +++ b/sbe-tool/src/test/resources/versioned-message-v2.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + From ac0b41a9f7d94ab5e93e7f2d5b70f7c3a04907e2 Mon Sep 17 00:00:00 2001 From: Nate Bradac <38217740+nbradac@users.noreply.github.com> Date: Wed, 8 Jan 2025 14:40:06 -0600 Subject: [PATCH 516/805] [C++] check for not wrapped state in decodeLength() when precedence checks are enabled (#1046) --- .../sbe/generation/cpp/CppGenerator.java | 41 ++++++++++++++++++- .../test/cpp/FieldAccessOrderCheckTest.cpp | 40 ++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index dd5065dbe2..566545df2f 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -536,6 +536,18 @@ private static void generateAccessOrderException( .append(fieldPrecedenceModel.generatedRepresentationClassName()).append(".\");\n"); } + private static void generateAccessOrderException( + final StringBuilder sb, + final String indent, + final String action) + { + sb.append(indent).append("throw AccessOrderError(") + .append("std::string(\"Illegal access. \") + \n") + .append(indent).append(INDENT) + .append("\"Cannot call \\\"").append(action) + .append("()\\\" in state: \" + codecStateName(codecState()));\n"); + } + private static void generateAccessOrderListenerMethodForNextGroupElement( final StringBuilder sb, final FieldPrecedenceModel fieldPrecedenceModel, @@ -3027,6 +3039,7 @@ private CharSequence generateMessageFlyweightCode( " SBE_NODISCARD std::uint64_t decodeLength() const\n" + " {\n" + + "%22$s" + " %10$s skipper(m_buffer, m_offset, m_bufferLength, m_actingBlockLength, m_actingVersion);\n" + " skipper.skip();\n" + " return skipper.encodedLength();\n" + @@ -3071,7 +3084,8 @@ private CharSequence generateMessageFlyweightCode( generateCodecStateTransitionForWrappingLatestVersion(fieldPrecedenceModel), generateOnWrappedListener(fieldPrecedenceModel), generateCodecStateTransitionForWrapping(fieldPrecedenceModel), - generateHiddenCopyConstructor(" ", className)); + generateHiddenCopyConstructor(" ", className), + generateCheckForNotWrappedState("decodeLength", fieldPrecedenceModel)); } private CharSequence generateAccessOrderErrorType(final FieldPrecedenceModel fieldPrecedenceModel) @@ -3311,6 +3325,31 @@ private CharSequence generateCodecStateTransitionForWrapping(final FieldPreceden return generateAccessOrderListenerCall(fieldPrecedenceModel, TWO_INDENT, "onWrapped", "actingVersion"); } + private CharSequence generateCheckForNotWrappedState( + final String action, + final FieldPrecedenceModel fieldPrecedenceModel) + { + if (null == fieldPrecedenceModel) + { + return ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append("#if defined(").append(precedenceChecksFlagName).append(")\n") + .append(TWO_INDENT) + .append("if (codecState() == ") + .append(qualifiedStateCase(fieldPrecedenceModel.notWrappedState())) + .append(")\n") + .append(TWO_INDENT).append("{\n"); + + generateAccessOrderException(sb, THREE_INDENT, action); + + sb.append(TWO_INDENT).append("}\n") + .append("#endif\n"); + + return sb; + } + private CharSequence generateCodecStateTransitionForWrappingLatestVersion( final FieldPrecedenceModel fieldPrecedenceModel ) diff --git a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp index ef59c81d01..2c0e524dc0 100644 --- a/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp +++ b/sbe-tool/src/test/cpp/FieldAccessOrderCheckTest.cpp @@ -5048,3 +5048,43 @@ TEST_F(FieldAccessOrderCheckTest, worksWithInsertionOperator) EXPECT_EQ(decoder.getBAsString(), "abc"); EXPECT_EQ(decoder.getCAsString(), "def"); } + +TEST_F(FieldAccessOrderCheckTest, shouldThrowExceptionWhenNotWrapped) +{ + MultipleVarLength encoder; + encoder.wrapForEncode(m_buffer, OFFSET, BUFFER_LEN); + encoder.a(42); + encoder.putB("abc"); + encoder.putC("def"); + encoder.checkEncodingIsComplete(); + + MultipleVarLength decoder; + + EXPECT_THROW( + { + try + { + decoder.decodeLength(); + } + catch (const std::exception &e) + { + EXPECT_THAT( + e.what(), + HasSubstr("Illegal access. Cannot call \"decodeLength()\" in state: NOT_WRAPPED") + ); + throw; + } + }, + std::logic_error + ); + + decoder.wrapForDecode( + m_buffer, + OFFSET, + MultipleVarLength::sbeBlockLength(), + MultipleVarLength::sbeSchemaVersion(), + BUFFER_LEN + ); + + decoder.decodeLength(); +} From 28fac12c286b0d30400396331740a819ca314ff5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 13 Jan 2025 09:54:11 +0100 Subject: [PATCH 517/805] [Java] Upgrade to Json 20250107. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b433f94282..f918445ba3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ agrona = { group = "org.agrona", name = "agrona", version.ref = "agrona" } mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.2" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.2" } -json = { group = "org.json", name = "json", version = "20240303" } +json = { group = "org.json", name = "json", version = "20250107" } jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "jmh" } jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "jmh" } From d64176dc07e826cd1d7327d9221397d80bcff5c2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 13 Jan 2025 09:57:02 +0100 Subject: [PATCH 518/805] [Java] Upgrade to Mockito 5.15.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f918445ba3..6251b66540 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ gradle = "8.11.1" [libraries] agrona = { group = "org.agrona", name = "agrona", version.ref = "agrona" } -mockito = { group = "org.mockito", name = "mockito-core", version = "5.14.2" } +mockito = { group = "org.mockito", name = "mockito-core", version = "5.15.2" } hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.2" } json = { group = "org.json", name = "json", version = "20250107" } From 59bd78942f4d1d7c6860038a2581639057cdd2a0 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:00:20 +0100 Subject: [PATCH 519/805] 1.34.1 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index c9c35c012f..a95a46d9fa 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.0-SNAPSHOT +1.34.1 From 03dc5e828677670765a975ef5061381dcfb94da3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:00:32 +0100 Subject: [PATCH 520/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index a95a46d9fa..c9c35c012f 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.34.1 +1.35.0-SNAPSHOT From 98b23b6d998e917b1b573db5c0144bc8e854f6ea Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:59:34 +0100 Subject: [PATCH 521/805] [Java] Fix Javadoc location. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 586f2d9c5a..942d14a8f3 100644 --- a/build.gradle +++ b/build.gradle @@ -199,7 +199,7 @@ subprojects { options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' options.links("https://www.javadoc.io/doc/org.agrona/agrona/${libs.versions.agrona.get()}/") - if (buildJavaVersion >= 23) { // early access JavaDoc location is different + if (buildJavaVersion > 23) { // early access JavaDoc location is different options.links("https://download.java.net/java/early_access/jdk${buildJavaVersion}/docs/api/") } else { From 4ec602554226e0795f087270270380090f60ae7a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:18:05 +0100 Subject: [PATCH 522/805] [Java] Use different URI for early access JDK build. --- build.gradle | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 942d14a8f3..ec29dfe5a4 100644 --- a/build.gradle +++ b/build.gradle @@ -27,8 +27,15 @@ plugins { defaultTasks 'clean', 'build' + +static def rawBuildJavaVersion() +{ + return System.getenv('BUILD_JAVA_VERSION') ?: JavaVersion.current().getMajorVersion() +} +boolean isEarlyAccessJavaVersion = rawBuildJavaVersion().endsWith("-ea") + static def getBuildJavaVersion() { - def buildJavaVersion = System.getenv('BUILD_JAVA_VERSION') ?: JavaVersion.current().getMajorVersion() + def buildJavaVersion = rawBuildJavaVersion() if (buildJavaVersion.indexOf('.') > 0) { buildJavaVersion = buildJavaVersion.substring(0, buildJavaVersion.indexOf('.')) } @@ -199,7 +206,7 @@ subprojects { options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' options.links("https://www.javadoc.io/doc/org.agrona/agrona/${libs.versions.agrona.get()}/") - if (buildJavaVersion > 23) { // early access JavaDoc location is different + if (isEarlyAccessJavaVersion) { options.links("https://download.java.net/java/early_access/jdk${buildJavaVersion}/docs/api/") } else { From 4c07009956e59db622d972a0c5ed64f4575a99ac Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:57:50 +0100 Subject: [PATCH 523/805] [Java] Upgrade to Checkstyle 10.21.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6251b66540..259a4f1504 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.0.0" -checkstyle = "10.21.0" +checkstyle = "10.21.1" junit = "5.11.4" jmh = "1.37" gradle = "8.11.1" From 43d4cfa85cdba5625aef2785e457ccf504fe24a4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:58:10 +0100 Subject: [PATCH 524/805] [Java] Upgrade to Agrona 2.0.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 259a4f1504..63dfb168d4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.0.0" +agrona = "2.0.1" checkstyle = "10.21.1" junit = "5.11.4" jmh = "1.37" From 9a9c283e1f943afd389ba283d7ee4d5e70f55652 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Jan 2025 11:36:03 +0100 Subject: [PATCH 525/805] [CI] Upload crash logs for failed Java builds. --- .github/workflows/ci.yml | 39 ++++++++++++++++++++++++++++++++++---- .github/workflows/slow.yml | 14 +++++++++++++- build.gradle | 22 +++++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81f79e5420..a2b568bb73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '17', '21' ] + java: [ '17', '21', '23' ] os: [ 'ubuntu-24.04', 'windows-latest', 'macos-latest' ] steps: - name: Checkout code @@ -52,18 +52,49 @@ jobs: with: distribution: 'zulu' java-version: ${{ matrix.java }} - - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION (Unix) + if: runner.os != 'Windows' run: | java -Xinternalversion echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - - name: Setup java 17 to run the Gradle script + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION (Windows) + if: runner.os == 'Windows' + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "BUILD_JAVA_VERSION=${{ matrix.java }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + - name: Setup java uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 17 - name: Build with Gradle - run: ./gradlew --stacktrace + run: ./gradlew + - name: Copy test logs (Unix) + id: copy_test_logs + if: failure() && runner.os != 'Windows' + run: | + echo "file=build/distributions/test_logs.tbz2" >> $GITHUB_OUTPUT + ./gradlew tarTestLogs + - name: Upload crash logs (Unix) + if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' + uses: actions/upload-artifact@v4 + with: + name: crash-logs-${{ matrix.os }}-java-${{ matrix.java }} + path: ${{ steps.copy_test_logs.outputs.file }} + - name: Copy test logs (Windows) + id: copy_test_logs_windows + if: runner.os == 'Windows' && failure() + run: | + echo "file=build/distributions/test_logs.tbz2" | Out-File $env:GITHUB_OUTPUT -Encoding utf8 -Append + ./gradlew tarTestLogs + - name: Upload crash logs (Windows) + if: runner.os == 'Windows' && always() && steps.copy_test_logs_windows.outputs.file == 'build/distributions/test_logs.tbz2' + uses: actions/upload-artifact@v4 + with: + name: crash-logs-${{ matrix.os }}-java-${{ matrix.java }} + path: ${{ steps.copy_test_logs_windows.outputs.file }} csharp-build: name: C# ${{ matrix.dotnet }} diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index a6700d95b2..915a097ec2 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -55,9 +55,21 @@ jobs: run: ./csharp/build.sh - name: Run property tests run: ./gradlew propertyTest + - name: Copy test logs (Unix) + id: copy_test_logs + if: failure() + run: | + echo "file=build/distributions/test_logs.tbz2" >> $GITHUB_OUTPUT + ./gradlew tarTestLogs + - name: Upload crash logs (Unix) + if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' + uses: actions/upload-artifact@v4 + with: + name: crash-logs-${{ matrix.os }}-property-tests + path: ${{ steps.copy_test_logs.outputs.file }} - name: Upload test results uses: actions/upload-artifact@v4 - if: success() || failure() + if: always() with: name: property-tests path: sbe-tool/build/reports/tests/propertyTest diff --git a/build.gradle b/build.gradle index ec29dfe5a4..03db46371c 100644 --- a/build.gradle +++ b/build.gradle @@ -1079,6 +1079,28 @@ tasks.named('build').configure { dependsOn 'verifyJavaIrCodecsInSync' } +tasks.register('copyTestLogs', Copy) { + from '.' + include '**/build/test-output/**' + include '**/*.hprof' + include '**/*.log' + include '**/*.tlog' + include '**/build/reports/tests/**' + include '**/build/test-results/**/*' + include 'LICENSE' + exclude 'build' + into 'build/test_logs' + + includeEmptyDirs = false +} + +tasks.register('tarTestLogs', Tar) { + dependsOn tasks.named('copyTestLogs') + archiveBaseName.set('test_logs') + from 'build/test_logs' + compression Compression.BZIP2 +} + def isNonStable = { String version -> def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { it -> version.toUpperCase().contains(it) } def regex = /^[0-9,.v-]+(-r)?$/ From fd46e73d76819c2e0d2727edfc9f9ccfeed26f59 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Jan 2025 11:44:29 +0100 Subject: [PATCH 526/805] [CI] Simplify error log upload. --- .github/workflows/ci.yml | 20 ++++---------------- .github/workflows/slow.yml | 8 ++++---- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2b568bb73..83e080689c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,30 +71,18 @@ jobs: java-version: 17 - name: Build with Gradle run: ./gradlew - - name: Copy test logs (Unix) + - name: Copy test logs id: copy_test_logs - if: failure() && runner.os != 'Windows' + if: failure() run: | - echo "file=build/distributions/test_logs.tbz2" >> $GITHUB_OUTPUT + ${{ runner.os == 'Windows' && 'echo "file=build/distributions/test_logs.tbz2" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append' || 'echo "file=build/distributions/test_logs.tbz2" >> $GITHUB_OUTPUT' }} ./gradlew tarTestLogs - - name: Upload crash logs (Unix) + - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' uses: actions/upload-artifact@v4 with: name: crash-logs-${{ matrix.os }}-java-${{ matrix.java }} path: ${{ steps.copy_test_logs.outputs.file }} - - name: Copy test logs (Windows) - id: copy_test_logs_windows - if: runner.os == 'Windows' && failure() - run: | - echo "file=build/distributions/test_logs.tbz2" | Out-File $env:GITHUB_OUTPUT -Encoding utf8 -Append - ./gradlew tarTestLogs - - name: Upload crash logs (Windows) - if: runner.os == 'Windows' && always() && steps.copy_test_logs_windows.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v4 - with: - name: crash-logs-${{ matrix.os }}-java-${{ matrix.java }} - path: ${{ steps.copy_test_logs_windows.outputs.file }} csharp-build: name: C# ${{ matrix.dotnet }} diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 915a097ec2..424e7f3bc8 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -55,17 +55,17 @@ jobs: run: ./csharp/build.sh - name: Run property tests run: ./gradlew propertyTest - - name: Copy test logs (Unix) + - name: Copy test logs id: copy_test_logs if: failure() run: | - echo "file=build/distributions/test_logs.tbz2" >> $GITHUB_OUTPUT + ${{ runner.os == 'Windows' && 'echo "file=build/distributions/test_logs.tbz2" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append' || 'echo "file=build/distributions/test_logs.tbz2" >> $GITHUB_OUTPUT' }} ./gradlew tarTestLogs - - name: Upload crash logs (Unix) + - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' uses: actions/upload-artifact@v4 with: - name: crash-logs-${{ matrix.os }}-property-tests + name: crash-logs-${{ matrix.os }}-property-tests-java-${{matrix.java}}-dotnet-${{matrix.dotnet}} path: ${{ steps.copy_test_logs.outputs.file }} - name: Upload test results uses: actions/upload-artifact@v4 From f54c139ba64277302275f1a7b2ec48f22ee8df01 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Jan 2025 21:01:04 +0100 Subject: [PATCH 527/805] [CI] Use env to setup base Java. --- .github/workflows/ci.yml | 39 ++++++++++++++++++----------------- .github/workflows/release.yml | 3 ++- .github/workflows/slow.yml | 5 +++-- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83e080689c..695135fe35 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ concurrency: env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' + JAVA_VERSION: '17' permissions: contents: read @@ -68,7 +69,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Build with Gradle run: ./gradlew - name: Copy test logs @@ -111,11 +112,11 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Cache NuGet dependencies uses: actions/cache@v4 with: @@ -165,11 +166,11 @@ jobs: run: | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ bionic main universe" sudo apt-get install -y g++-${{ matrix.version }} libsparsehash-dev libidn11 - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Build run: ./cppbuild/cppbuild @@ -205,11 +206,11 @@ jobs: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install -y g++-${{ matrix.version }} - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Build run: ./cppbuild/cppbuild @@ -247,11 +248,11 @@ jobs: echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Build run: ./cppbuild/cppbuild @@ -289,11 +290,11 @@ jobs: echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Build run: ./cppbuild/cppbuild @@ -324,11 +325,11 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -359,11 +360,11 @@ jobs: with: path: ~/.gradle/wrapper key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Build run: cppbuild/cppbuild.cmd @@ -395,11 +396,11 @@ jobs: uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ matrix.rust }} - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - run: ./gradlew runRustTests golang-build: @@ -430,11 +431,11 @@ jobs: uses: actions/setup-go@v4 with: go-version: ${{ matrix.version }} - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Generate jar run: ./gradlew assemble - name: Run tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7d7f62b227..db5f85bba4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,7 @@ concurrency: env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' + JAVA_VERSION: '17' jobs: ci: @@ -47,7 +48,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Publish with Gradle run: ./gradlew publish env: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 424e7f3bc8..c4bfc7aac8 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -14,6 +14,7 @@ concurrency: env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' + JAVA_VERSION: '17' permissions: contents: read @@ -42,11 +43,11 @@ jobs: java -Xinternalversion echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - - name: Setup java 17 to run the Gradle script + - name: Setup java to run Gradle script uses: actions/setup-java@v3 with: distribution: 'zulu' - java-version: 17 + java-version: ${{ env.JAVA_VERSION }} - name: Setup dotnet uses: actions/setup-dotnet@v2 with: From 16f5f874457bcfcf0865394ac3dde0f624181d46 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Jan 2025 22:13:25 +0100 Subject: [PATCH 528/805] [CI] Trigger slow build on PR. --- .github/workflows/ci.yml | 1 + .github/workflows/slow.yml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 695135fe35..e6bcd429c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,7 @@ on: types: [opened, synchronize] branches: - master + - 'release/**' concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index c4bfc7aac8..69e4d9bbe0 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -7,6 +7,11 @@ on: - '**' schedule: - cron: '0 12 * * *' + pull_request: + types: [opened, synchronize] + branches: + - master + - 'release/**' concurrency: group: slow-${{ github.workflow }}-${{ github.ref }} From 1b4fd32e9e474bb6e0cb067fda4242c7df72503a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:37:08 +0100 Subject: [PATCH 529/805] [CI] Trigger slow build on push to master or release branch. --- .github/workflows/ci.yml | 1 + .github/workflows/slow.yml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6bcd429c7..1b3540bce4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: push: branches: - master + - 'release/**' pull_request: types: [opened, synchronize] branches: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 69e4d9bbe0..6f2a234ce0 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -7,6 +7,10 @@ on: - '**' schedule: - cron: '0 12 * * *' + push: + branches: + - master + - 'release/**' pull_request: types: [opened, synchronize] branches: From ad705a9a5159e2e8e8a3b0667e91f5edc3074abf Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:45:32 +0100 Subject: [PATCH 530/805] [CI] Do not automatically trigger build when workflow file changes. --- .github/workflows/ci.yml | 2 ++ .github/workflows/slow.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b3540bce4..866dc53e10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,8 @@ on: branches: - master - 'release/**' + paths-ignore: + - '.github/workflows/**' pull_request: types: [opened, synchronize] branches: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 6f2a234ce0..71ce367082 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -11,6 +11,8 @@ on: branches: - master - 'release/**' + paths-ignore: + - '.github/workflows/**' pull_request: types: [opened, synchronize] branches: From 88b5e8c27f58de36c47051b87e9873d0b31ca014 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:47:59 +0100 Subject: [PATCH 531/805] Revert "[CI] Do not automatically trigger build when workflow file changes." This reverts commit ad705a9a5159e2e8e8a3b0667e91f5edc3074abf. --- .github/workflows/ci.yml | 2 -- .github/workflows/slow.yml | 2 -- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 866dc53e10..1b3540bce4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,8 +7,6 @@ on: branches: - master - 'release/**' - paths-ignore: - - '.github/workflows/**' pull_request: types: [opened, synchronize] branches: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 71ce367082..6f2a234ce0 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -11,8 +11,6 @@ on: branches: - master - 'release/**' - paths-ignore: - - '.github/workflows/**' pull_request: types: [opened, synchronize] branches: From 0db78b363ada40dec160c7a5d26c92c0f1745b7a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 21 Jan 2025 13:49:27 +0100 Subject: [PATCH 532/805] [Java] Tidy up dependency declarations. --- build.gradle | 10 +++++----- gradle/libs.versions.toml | 31 +++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 03db46371c..988f025c19 100644 --- a/build.gradle +++ b/build.gradle @@ -150,10 +150,10 @@ allprojects { resolutionStrategy { failOnVersionConflict() // patching conflicting Checkstyle dependencies - force "org.codehaus.plexus:plexus-utils:3.3.0", - "org.apache.commons:commons-lang3:3.8.1", - "org.apache.httpcomponents:httpcore:4.4.14", - "commons-codec:commons-codec:1.15" + force libs.commons.codec, + libs.commons.lang3, + libs.httpcore, + libs.plexus.utils } } @@ -284,7 +284,7 @@ project(':sbe-tool') { implementation files("${layout.buildDirectory.get()}/classes/java/generated") implementation libs.hamcrest implementation libs.mockito - implementation platform("org.junit:junit-bom:${libs.versions.junit.get()}") + implementation platform(libs.junit.bom) implementation "org.junit.jupiter:junit-jupiter-params" } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 63dfb168d4..a548837ccd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,19 +1,34 @@ [versions] agrona = "2.0.1" checkstyle = "10.21.1" -junit = "5.11.4" -jmh = "1.37" +commons-codec = "1.15" +commons-lang3 = "3.8.1" gradle = "8.11.1" +hamcrest = "3.0" +httpcore = "4.4.14" +jqwik = "1.9.2" +jmh = "1.37" +json = "20250107" +junit = "5.11.4" +mockito = "5.15.2" +plexus = "3.3.0" +shadow = "8.3.5" +versions = "0.51.0" [libraries] agrona = { group = "org.agrona", name = "agrona", version.ref = "agrona" } -mockito = { group = "org.mockito", name = "mockito-core", version = "5.15.2" } -hamcrest = { group = "org.hamcrest", name = "hamcrest", version = "3.0" } -jqwik = { group = "net.jqwik", name = "jqwik", version = "1.9.2" } -json = { group = "org.json", name = "json", version = "20250107" } +commons-codec = { group = "commons-codec", name = "commons-codec", version.ref = "commons-codec" } +commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version.ref = "commons-lang3" } +hamcrest = { group = "org.hamcrest", name = "hamcrest", version.ref = "hamcrest" } +httpcore = { group = "org.apache.httpcomponents", name = "httpcore", version.ref = "httpcore" } +jqwik = { group = "net.jqwik", name = "jqwik", version.ref = "jqwik" } +json = { group = "org.json", name = "json", version.ref = "json" } jmh-core = { group = "org.openjdk.jmh", name = "jmh-core", version.ref = "jmh" } jmh-generator-annprocess = { group = "org.openjdk.jmh", name = "jmh-generator-annprocess", version.ref = "jmh" } +junit-bom = { group = "org.junit", name = "junit-bom", version.ref = "junit" } +mockito = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" } +plexus-utils = { group = "org.codehaus.plexus", name = "plexus-utils", version.ref = "plexus" } [plugins] -versions = { id = "com.github.ben-manes.versions", version = "0.51.0" } -shadow = { id = "com.gradleup.shadow", version = "8.3.5" } +shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } +versions = { id = "com.github.ben-manes.versions", version.ref = "versions" } From 1a3957ca67d0df9a84bbbfba638a3193f5f8870a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 30 Jan 2025 19:29:09 +0100 Subject: [PATCH 533/805] Switch project URL to `aeron-io` organization. --- CONTRIBUTING.md | 2 +- README.md | 28 ++++++++++++++-------------- build.gradle | 8 ++++---- csharp/README.md | 12 ++++++------ csharp/sbe-dll/README.txt | 8 ++++---- csharp/sbe-dll/sbe-dll.csproj | 6 +++--- gocode/README.md | 6 +++--- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bac5877c8e..198011b6f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ When submitting code, please make every effort to follow existing conventions an By contributing your code, you agree to license your contribution under the terms of the APLv2: -https://github.com/real-logic/simple-binary-encoding/blob/master/LICENSE +https://github.com/aeron-io/simple-binary-encoding/blob/master/LICENSE All files are made available under the Apache 2.0 license. diff --git a/README.md b/README.md index c051584e3b..ce55a80bb2 100644 --- a/README.md +++ b/README.md @@ -2,25 +2,25 @@ Simple Binary Encoding (SBE) ============================ [![Javadocs](https://www.javadoc.io/badge/uk.co.real-logic/sbe-tool.svg)](https://www.javadoc.io/doc/uk.co.real-logic/sbe-tool) -[![GitHub](https://img.shields.io/github/license/real-logic/simple-binary-encoding.svg)](https://github.com/real-logic/simple-binary-encoding/blob/master/LICENSE) +[![GitHub](https://img.shields.io/github/license/aeron-io/simple-binary-encoding.svg)](https://github.com/aeron-io/simple-binary-encoding/blob/master/LICENSE) -[![Actions Status](https://github.com/real-logic/simple-binary-encoding/workflows/Continuous%20Integration/badge.svg)](https://github.com/real-logic/simple-binary-encoding/actions) -[![CodeQL Status](https://github.com/real-logic/simple-binary-encoding/workflows/CodeQL/badge.svg)](https://github.com/real-logic/simple-binary-encoding/actions) +[![Actions Status](https://github.com/aeron-io/simple-binary-encoding/workflows/Continuous%20Integration/badge.svg)](https://github.com/aeron-io/simple-binary-encoding/actions) +[![CodeQL Status](https://github.com/aeron-io/simple-binary-encoding/workflows/CodeQL/badge.svg)](https://github.com/aeron-io/simple-binary-encoding/actions) [SBE](https://github.com/FIXTradingCommunity/fix-simple-binary-encoding) is an OSI layer 6 presentation for encoding and decoding binary application messages for low-latency financial applications. This repository contains the reference implementations in Java, C++, Golang, C#, and Rust. -More details on the design and usage of SBE can be found on the [Wiki](https://github.com/real-logic/simple-binary-encoding/wiki). +More details on the design and usage of SBE can be found on the [Wiki](https://github.com/aeron-io/simple-binary-encoding/wiki). An XSD for SBE specs can be found -[here](https://github.com/real-logic/simple-binary-encoding/blob/master/sbe-tool/src/main/resources/fpl/sbe.xsd). Please address questions about the specification to the [SBE FIX community](https://github.com/FIXTradingCommunity/fix-simple-binary-encoding). +[here](https://github.com/aeron-io/simple-binary-encoding/blob/master/sbe-tool/src/main/resources/fpl/sbe.xsd). Please address questions about the specification to the [SBE FIX community](https://github.com/FIXTradingCommunity/fix-simple-binary-encoding). -For the latest version information and changes see the [Change Log](https://github.com/real-logic/simple-binary-encoding/wiki/Change-Log) with **downloads** at [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Csbe). +For the latest version information and changes see the [Change Log](https://github.com/aeron-io/simple-binary-encoding/wiki/Change-Log) with **downloads** at [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Csbe). -The Java and C++ SBE implementations work very efficiently with the [Aeron](https://github.com/real-logic/aeron) +The Java and C++ SBE implementations work very efficiently with the [Aeron](https://github.com/aeron-io/aeron) messaging system for low-latency and high-throughput communications. The Java SBE implementation has a dependency on -[Agrona](https://github.com/real-logic/agrona) for its buffer implementations. Commercial support is available from +[Agrona](https://github.com/aeron-io/agrona) for its buffer implementations. Commercial support is available from [sales@real-logic.co.uk](mailto:sales@real-logic.co.uk?subject=SBE). Binaries @@ -41,7 +41,7 @@ Example for Maven: Build ----- -Build the project with [Gradle](http://gradle.org/) using this [build.gradle](https://github.com/real-logic/simple-binary-encoding/blob/master/build.gradle) file. +Build the project with [Gradle](http://gradle.org/) using this [build.gradle](https://github.com/aeron-io/simple-binary-encoding/blob/master/build.gradle) file. Full clean build: @@ -67,7 +67,7 @@ An example to execute a Jar from command line using the 'all' jar which includes C++ Build using CMake --------------------- NOTE: Linux, Mac OS, and Windows only for the moment. See -[FAQ](https://github.com/real-logic/simple-binary-encoding/wiki/Frequently-Asked-Questions). +[FAQ](https://github.com/aeron-io/simple-binary-encoding/wiki/Frequently-Asked-Questions). Windows builds have been tested with Visual Studio Express 12. For convenience, the `cppbuild` script does a full clean, build, and test of all targets as a Release build. @@ -100,16 +100,16 @@ For convenience on Linux, a gnu Makefile is provided that runs some tests and co Go supports both generating Go structs with encode / decode methods, and flyweights like the other languages. Structs are generated by default for compatibility. Set `sbe.go.generate.generate.flyweights=true` to generate flyweights. Users of golang generated code should see the [user -documentation](https://github.com/real-logic/simple-binary-encoding/wiki/Golang-User-Guide). +documentation](https://github.com/aeron-io/simple-binary-encoding/wiki/Golang-User-Guide). Developers wishing to enhance the golang generator should see the [developer -documentation](https://github.com/real-logic/simple-binary-encoding/blob/master/gocode/README.md) +documentation](https://github.com/aeron-io/simple-binary-encoding/blob/master/gocode/README.md) C# Build -------- -Users of CSharp generated code should see the [user documentation](https://github.com/real-logic/simple-binary-encoding/wiki/Csharp-User-Guide). +Users of CSharp generated code should see the [user documentation](https://github.com/aeron-io/simple-binary-encoding/wiki/Csharp-User-Guide). -Developers wishing to enhance the CSharp generator should see the [developer documentation](https://github.com/real-logic/simple-binary-encoding/blob/master/csharp/README.md) +Developers wishing to enhance the CSharp generator should see the [developer documentation](https://github.com/aeron-io/simple-binary-encoding/blob/master/csharp/README.md) Rust Build ------------ diff --git a/build.gradle b/build.gradle index 988f025c19..d9450544ce 100644 --- a/build.gradle +++ b/build.gradle @@ -79,12 +79,12 @@ def projectPom = { name = 'sbe' description = 'FIX/SBE - OSI layer 6 presentation for encoding and decoding application messages' + ' in binary format for low-latency applications.' - url = 'https://github.com/real-logic/simple-binary-encoding' + url = 'https://github.com/aeron-io/simple-binary-encoding' scm { - connection = 'scm:git:github.com/real-logic/simple-binary-encoding.git' - developerConnection = 'scm:git:github.com/real-logic/simple-binary-encoding.git' - url = 'github.com/real-logic/simple-binary-encoding.git' + connection = 'scm:git:github.com/aeron-io/simple-binary-encoding.git' + developerConnection = 'scm:git:github.com/aeron-io/simple-binary-encoding.git' + url = 'github.com/aeron-io/simple-binary-encoding.git' } licenses { diff --git a/csharp/README.md b/csharp/README.md index 686522e03d..95042ca03a 100644 --- a/csharp/README.md +++ b/csharp/README.md @@ -1,7 +1,7 @@ Overview ======== -There is a [user guide](https://github.com/real-logic/simple-binary-encoding/wiki/Csharp-User-Guide) for people who wish +There is a [user guide](https://github.com/aeron-io/simple-binary-encoding/wiki/Csharp-User-Guide) for people who wish to use the C# generator. This document is to assist developers working on the the SBE C# generator itself. @@ -42,13 +42,13 @@ Code Layout ----------- The Java code that performs the generation of C# code is -[here](https://github.com/real-logic/simple-binary-encoding/tree/master/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp). +[here](https://github.com/aeron-io/simple-binary-encoding/tree/master/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp). $ ./gradlew # Will build sbe-tool jar $ ./gradlew generateCSharpCodecs # will generate the test, benchmark, and example C# code The [Visual Studio 2017 Community -solution](https://github.com/real-logic/simple-binary-encoding/blob/master/csharp/csharp.sln) provides the projects: +solution](https://github.com/aeron-io/simple-binary-encoding/blob/master/csharp/csharp.sln) provides the projects: * sbe-dll (for common marshalling and DirectBuffer functionality) * sbe-generated (containing C# code generated by sbe-tool) @@ -87,6 +87,6 @@ For now you can: * build the SBE csharp generator using `gradlew` * generate the csharp codecs using `gradlew GenerateCSharpCodecs` - * Use the bash script [build.sh](https://github.com/real-logic/simple-binary-encoding/blob/master/csharp/build.sh) to run the tests - * Use the bash script [runtests.sh](https://github.com/real-logic/simple-binary-encoding/blob/master/csharp/runtests.sh) to run the tests - * Use the bash script [pack.sh](https://github.com/real-logic/simple-binary-encoding/blob/master/csharp/pack.sh) to create the nuget package + * Use the bash script [build.sh](https://github.com/aeron-io/simple-binary-encoding/blob/master/csharp/build.sh) to run the tests + * Use the bash script [runtests.sh](https://github.com/aeron-io/simple-binary-encoding/blob/master/csharp/runtests.sh) to run the tests + * Use the bash script [pack.sh](https://github.com/aeron-io/simple-binary-encoding/blob/master/csharp/pack.sh) to create the nuget package diff --git a/csharp/sbe-dll/README.txt b/csharp/sbe-dll/README.txt index 7a1cdf0ced..3c92d4d84d 100644 --- a/csharp/sbe-dll/README.txt +++ b/csharp/sbe-dll/README.txt @@ -58,9 +58,9 @@ Next steps This was just a quick sample but hopefully now you have an idea of the overall process you have to go through to use SBE. -To get all the details please refer to our wiki (https://github.com/real-logic/simple-binary-encoding/wiki/) and especially the following sections: - - schema definition: https://github.com/real-logic/simple-binary-encoding/wiki/FIX-SBE-XML-Primer - - SBE Tool command line: https://github.com/real-logic/simple-binary-encoding/wiki/Sbe-Tool-Guide +To get all the details please refer to our wiki (https://github.com/aeron-io/simple-binary-encoding/wiki/) and especially the following sections: + - schema definition: https://github.com/aeron-io/simple-binary-encoding/wiki/FIX-SBE-XML-Primer + - SBE Tool command line: https://github.com/aeron-io/simple-binary-encoding/wiki/Sbe-Tool-Guide -If you face an issue, a suggestion or a question, please use the issue tracker on the main GitHub repo: https://github.com/real-logic/simple-binary-encoding/issues?state=open +If you face an issue, a suggestion or a question, please use the issue tracker on the main GitHub repo: https://github.com/aeron-io/simple-binary-encoding/issues?state=open diff --git a/csharp/sbe-dll/sbe-dll.csproj b/csharp/sbe-dll/sbe-dll.csproj index 747306310d..6db6d56021 100644 --- a/csharp/sbe-dll/sbe-dll.csproj +++ b/csharp/sbe-dll/sbe-dll.csproj @@ -9,13 +9,13 @@ true Bill Segall, MarketFactory Inc, Adaptive Consulting Apache-2.0 - https://github.com/real-logic/simple-binary-encoding - https://github.com/real-logic/simple-binary-encoding + https://github.com/aeron-io/simple-binary-encoding + https://github.com/aeron-io/simple-binary-encoding SBE;Marshaling;Low;Latency;Simple;Binary;Encoding sbe-tool 1.23.1.1 Simple Binary Encoding for .NET - This package contains all you need to define SBE messages and generate C# encoders and decoders. See https://github.com/real-logic/simple-binary-encoding for more detailed instructions + This package contains all you need to define SBE messages and generate C# encoders and decoders. See https://github.com/aeron-io/simple-binary-encoding for more detailed instructions git diff --git a/gocode/README.md b/gocode/README.md index 5740d9dbca..bbfcf1b6cc 100755 --- a/gocode/README.md +++ b/gocode/README.md @@ -2,7 +2,7 @@ Overview ======== There is now a -[user guide](https://github.com/real-logic/simple-binary-encoding/wiki/Golang-User-Guide) +[user guide](https://github.com/aeron-io/simple-binary-encoding/wiki/Golang-User-Guide) and this document is for development of the SBE golang generator. Go supports both generating Go structs with encode / decode methods, and flyweights like the other languages. @@ -11,10 +11,10 @@ Structs are generated by default for compatibility. Set `sbe.go.generate.generat Code Layout ----------- The Java code that performs the generation of golang code is -[here](https://github.com/real-logic/simple-binary-encoding/tree/master/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang). There is both a struct and a flyweight generator. +[here](https://github.com/aeron-io/simple-binary-encoding/tree/master/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang). There is both a struct and a flyweight generator. Golang code used for testing resides in the top-level -[gocode directory](https://github.com/real-logic/simple-binary-encoding/tree/master/gocode). +[gocode directory](https://github.com/aeron-io/simple-binary-encoding/tree/master/gocode). Building and testing -------------------- From b95c1fe69949be609ab871b3d3cf192a624494bf Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 30 Jan 2025 19:43:10 +0100 Subject: [PATCH 534/805] [Java] Upgrade to Checkstyle 10.21.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a548837ccd..61b6d52032 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.0.1" -checkstyle = "10.21.1" +checkstyle = "10.21.2" commons-codec = "1.15" commons-lang3 = "3.8.1" gradle = "8.11.1" From 3255cbfad7c708fdd4a13be969421f851904b36b Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 30 Jan 2025 19:43:36 +0100 Subject: [PATCH 535/805] [Java] Upgrade to Versions 0.52.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 61b6d52032..72a0148438 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ junit = "5.11.4" mockito = "5.15.2" plexus = "3.3.0" shadow = "8.3.5" -versions = "0.51.0" +versions = "0.52.0" [libraries] agrona = { group = "org.agrona", name = "agrona", version.ref = "agrona" } From 84b8d4a0f90bff84a3433070e48203a7237ceca4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 30 Jan 2025 19:46:24 +0100 Subject: [PATCH 536/805] [Java] Upgrade to Gradle 8.12.1. --- build.gradle | 8 ++++---- gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index d9450544ce..018a53edc1 100644 --- a/build.gradle +++ b/build.gradle @@ -199,7 +199,7 @@ subprojects { } javadoc { - failOnError false + failOnError = false title = '

    Simple Binary Encoding (SBE)

    ' options.bottom = 'Copyright © 2013-2025 Real Logic Limited. All Rights Reserved.' options.encoding = 'UTF-8' @@ -389,7 +389,7 @@ project(':sbe-tool') { repositories { maven { - url(!isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl) + url = !isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl credentials { username = ossrhUsername password = ossrhPassword @@ -459,7 +459,7 @@ project(':sbe-all') { } repositories { maven { - url(!isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl) + url = !isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl credentials { username = ossrhUsername password = ossrhPassword @@ -579,7 +579,7 @@ project(':sbe-samples') { repositories { maven { - url(!isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl) + url = !isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl credentials { username = ossrhUsername password = ossrhPassword diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 72a0148438..73d4e073d7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ agrona = "2.0.1" checkstyle = "10.21.2" commons-codec = "1.15" commons-lang3 = "3.8.1" -gradle = "8.11.1" +gradle = "8.12.1" hamcrest = "3.0" httpcore = "4.4.14" jqwik = "1.9.2" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c1d5e01859..d9fbee2e1d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f5feea6d6b..f3b75f3b0d 100755 --- a/gradlew +++ b/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum From 2fff016a5abe2943fbeebe8cb81d2a9b34087f17 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:54:28 +0100 Subject: [PATCH 537/805] Gradle warning fixes. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 018a53edc1..403c1f8f79 100644 --- a/build.gradle +++ b/build.gradle @@ -1098,7 +1098,7 @@ tasks.register('tarTestLogs', Tar) { dependsOn tasks.named('copyTestLogs') archiveBaseName.set('test_logs') from 'build/test_logs' - compression Compression.BZIP2 + compression = Compression.BZIP2 } def isNonStable = { String version -> From 1942f3d768a963deb71dd1aae2844c41611b00f2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:38:19 +0100 Subject: [PATCH 538/805] Update `Implementation-Vendor`. --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 403c1f8f79..3093d9a74e 100644 --- a/build.gradle +++ b/build.gradle @@ -361,7 +361,7 @@ project(':sbe-tool') { 'Specification-Version': '1.0', 'Implementation-Title': 'SBE', 'Implementation-Version': sbeVersion, - 'Implementation-Vendor': 'Real Logic Limited', + 'Implementation-Vendor': 'Adaptive Financial Consulting', 'Automatic-Module-Name': 'uk.co.real_logic.sbe.tool' ) } @@ -423,7 +423,7 @@ project(':sbe-all') { 'Specification-Version': '1.0', 'Implementation-Title': 'SBE', 'Implementation-Version': sbeVersion, - 'Implementation-Vendor': 'Real Logic Limited', + 'Implementation-Vendor': 'Adaptive Financial Consulting', 'Automatic-Module-Name': 'uk.co.real_logic.sbe.all' ) } @@ -548,7 +548,7 @@ project(':sbe-samples') { 'Specification-Version': '1.0', 'Implementation-Title': 'SBE', 'Implementation-Version': sbeVersion, - 'Implementation-Vendor': 'Real Logic Limited', + 'Implementation-Vendor': 'Adaptive Financial Consulting', 'Automatic-Module-Name': 'uk.co.real_logic.sbe.samples' ) } From 0da03ae96cc87ae211883819098dbc976c340b5d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:48:26 +0100 Subject: [PATCH 539/805] Update `Implementation-Vendor`. --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 3093d9a74e..b0ac62184a 100644 --- a/build.gradle +++ b/build.gradle @@ -361,7 +361,7 @@ project(':sbe-tool') { 'Specification-Version': '1.0', 'Implementation-Title': 'SBE', 'Implementation-Version': sbeVersion, - 'Implementation-Vendor': 'Adaptive Financial Consulting', + 'Implementation-Vendor': 'Adaptive Financial Consulting Limited', 'Automatic-Module-Name': 'uk.co.real_logic.sbe.tool' ) } @@ -423,7 +423,7 @@ project(':sbe-all') { 'Specification-Version': '1.0', 'Implementation-Title': 'SBE', 'Implementation-Version': sbeVersion, - 'Implementation-Vendor': 'Adaptive Financial Consulting', + 'Implementation-Vendor': 'Adaptive Financial Consulting Limited', 'Automatic-Module-Name': 'uk.co.real_logic.sbe.all' ) } @@ -548,7 +548,7 @@ project(':sbe-samples') { 'Specification-Version': '1.0', 'Implementation-Title': 'SBE', 'Implementation-Version': sbeVersion, - 'Implementation-Vendor': 'Adaptive Financial Consulting', + 'Implementation-Vendor': 'Adaptive Financial Consulting Limited', 'Automatic-Module-Name': 'uk.co.real_logic.sbe.samples' ) } From 3a0fbac9d7022db050cac4e39d8049514a18836d Mon Sep 17 00:00:00 2001 From: Kelly Littlepage Date: Tue, 4 Feb 2025 07:52:49 -0500 Subject: [PATCH 540/805] fix: include field 'deprecated' in ir encoding and decoding --- sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java | 1 + sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index 98e1a9d409..63881c0ae7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -240,6 +240,7 @@ private Token decodeToken() .byteOrder(mapByteOrder(tokenDecoder.byteOrder())) .presence(mapPresence(tokenDecoder.presence())); + tokenBuilder.deprecated(tokenDecoder.deprecated()); tokenBuilder.name(tokenDecoder.name()); encBuilder.constValue(get(valBuffer, type, tokenDecoder.getConstValue(valArray, 0, valArray.length))); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java index c3bf073e5e..756f0829ab 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java @@ -192,7 +192,8 @@ private int encodeToken(final Token token) .signal(mapSignal(token.signal())) .primitiveType(mapPrimitiveType(type)) .byteOrder(mapByteOrder(encoding.byteOrder())) - .presence(mapPresence(encoding.presence())); + .presence(mapPresence(encoding.presence())) + .deprecated(token.deprecated()); try { From 127cda953179bc5a7817b3730b9abfe13a68ff78 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:15:46 +0100 Subject: [PATCH 541/805] [Java] Upgrade to Shadow 8.3.6. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 73d4e073d7..c9f95d9791 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ json = "20250107" junit = "5.11.4" mockito = "5.15.2" plexus = "3.3.0" -shadow = "8.3.5" +shadow = "8.3.6" versions = "0.52.0" [libraries] From a4e4997b70c52617a12894ac541e7d7b6a727432 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:43:24 +0100 Subject: [PATCH 542/805] [CI] Set build timeout to 60 minutes for normal tests and 3 hours for slow tests. --- .github/workflows/ci.yml | 10 ++++++++++ .github/workflows/slow.yml | 1 + 2 files changed, 11 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b3540bce4..5b5bd11367 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,7 @@ jobs: java-build: name: Java ${{ matrix.java }} (${{ matrix.os }}) runs-on: ${{ matrix.os }} + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -90,6 +91,7 @@ jobs: csharp-build: name: C# ${{ matrix.dotnet }} runs-on: ubuntu-24.04 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -140,6 +142,7 @@ jobs: cpp-gcc-2004-build: name: C++ GCC ${{ matrix.version }} (Ubuntu 20.04) runs-on: ubuntu-20.04 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -179,6 +182,7 @@ jobs: cpp-gcc-2404-build: name: C++ GCC ${{ matrix.version }} (Ubuntu 24.04) runs-on: ubuntu-24.04 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -219,6 +223,7 @@ jobs: cpp-clang-2004-build: name: C++ Clang ${{ matrix.version }} (Ubuntu 20.04) runs-on: ubuntu-20.04 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -261,6 +266,7 @@ jobs: cpp-clang-2404-build: name: C++ Clang ${{ matrix.version }} (Ubuntu 24.04) runs-on: ubuntu-24.04 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -303,6 +309,7 @@ jobs: cpp-clang-macos-build: name: C++ Xcode ${{ matrix.version }} (macOS) runs-on: ${{ matrix.os }} + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -338,6 +345,7 @@ jobs: cpp-msvc-build: name: C++ MSVC (Windows) runs-on: ${{ matrix.os }} + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -373,6 +381,7 @@ jobs: rust-build: name: Rust ${{ matrix.rust }} runs-on: ubuntu-24.04 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -408,6 +417,7 @@ jobs: golang-build: name: Golang ${{ matrix.version }} runs-on: ubuntu-24.04 + timeout-minutes: 60 strategy: fail-fast: false matrix: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 6f2a234ce0..65510b72f5 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -32,6 +32,7 @@ jobs: property-tests: name: Property tests runs-on: ubuntu-24.04 + timeout-minutes: 180 strategy: matrix: java: [ '21' ] From ee0888f175d0c0b60e7755cf96552e0a1f0fc235 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:46:00 +0100 Subject: [PATCH 543/805] [CI] Set slow build timeout to 2 hours. --- .github/workflows/slow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 65510b72f5..4b07b30367 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -32,7 +32,7 @@ jobs: property-tests: name: Property tests runs-on: ubuntu-24.04 - timeout-minutes: 180 + timeout-minutes: 120 strategy: matrix: java: [ '21' ] From 6079f116121c4a005ba086af2b9c5c91b2d6c756 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:43:39 +0100 Subject: [PATCH 544/805] [Java] Upgrade to Checkstyle 10.21.3. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c9f95d9791..9b419e1f18 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.0.1" -checkstyle = "10.21.2" +checkstyle = "10.21.3" commons-codec = "1.15" commons-lang3 = "3.8.1" gradle = "8.12.1" From 4b216d3b7a7a47c436c56eddb2657eb01d794a7f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:44:02 +0100 Subject: [PATCH 545/805] [Java] Upgrade to JUnit 5.12.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9b419e1f18..91fad866a4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ httpcore = "4.4.14" jqwik = "1.9.2" jmh = "1.37" json = "20250107" -junit = "5.11.4" +junit = "5.12.0" mockito = "5.15.2" plexus = "3.3.0" shadow = "8.3.6" From b1993a8c8e78035427a49bf71fdf129d957f935d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 26 Feb 2025 15:44:35 +0100 Subject: [PATCH 546/805] [Java] Upgrade to Gradle 8.13. --- gradle/libs.versions.toml | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 43705 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 91fad866a4..71c8c1c4b2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ agrona = "2.0.1" checkstyle = "10.21.3" commons-codec = "1.15" commons-lang3 = "3.8.1" -gradle = "8.12.1" +gradle = "8.13" hamcrest = "3.0" httpcore = "4.4.14" jqwik = "1.9.2" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..9bbc975c742b298b441bfb90dbc124400a3751b9 100644 GIT binary patch delta 34744 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 delta 34727 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�{ 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 a%EQ2*fnt2> Date: Wed, 26 Feb 2025 19:23:49 +0100 Subject: [PATCH 547/805] [Java] Bump `Agrona` to 2.1.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 71c8c1c4b2..bfd6ff5d9b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.0.1" +agrona = "2.1.0" checkstyle = "10.21.3" commons-codec = "1.15" commons-lang3 = "3.8.1" From d53dadb9e1568b84a625a6b44f0cebdff793d0e5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:12:19 +0100 Subject: [PATCH 548/805] [CI] Do not cancel an existing build for a scheduled run. --- .github/workflows/slow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 4b07b30367..bdbf452a02 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -19,7 +19,7 @@ on: concurrency: group: slow-${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.event_name != 'schedule' }} env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' From 5bf497fd518734bc4de45d28f585c518f3bb2c3c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 6 Mar 2025 16:16:16 +0100 Subject: [PATCH 549/805] [Java] Bump Checkstyle to 10.21.4. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bfd6ff5d9b..5976cd2c73 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.1.0" -checkstyle = "10.21.3" +checkstyle = "10.21.4" commons-codec = "1.15" commons-lang3 = "3.8.1" gradle = "8.13" From 45f9ee3aff6e468973811bc23b0214641cf92f10 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 6 Mar 2025 16:16:37 +0100 Subject: [PATCH 550/805] [Java] Bump Mockito to 5.16.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5976cd2c73..b9cbe8078a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ jqwik = "1.9.2" jmh = "1.37" json = "20250107" junit = "5.12.0" -mockito = "5.15.2" +mockito = "5.16.0" plexus = "3.3.0" shadow = "8.3.6" versions = "0.52.0" From 6da9841d57159179f07821f00cc94fdea0b24224 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Mar 2025 10:33:50 +0100 Subject: [PATCH 551/805] Bump `Mockito` to 5.16.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b9cbe8078a..9a53023b4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ jqwik = "1.9.2" jmh = "1.37" json = "20250107" junit = "5.12.0" -mockito = "5.16.0" +mockito = "5.16.1" plexus = "3.3.0" shadow = "8.3.6" versions = "0.52.0" From f426ec0ddb2b3b8e65c428bcc29c3c2f088851a7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Mar 2025 10:34:00 +0100 Subject: [PATCH 552/805] Bump `JUnit` to 5.12.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9a53023b4a..fa6ed4f55e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ httpcore = "4.4.14" jqwik = "1.9.2" jmh = "1.37" json = "20250107" -junit = "5.12.0" +junit = "5.12.1" mockito = "5.16.1" plexus = "3.3.0" shadow = "8.3.6" From 048e3876befa8eb834f59eb1d18e615f29ebfda4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 18 Mar 2025 17:52:15 +0100 Subject: [PATCH 553/805] [CI] Enable JDK 24 GA. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b5bd11367..81867c8a7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '17', '21', '23' ] + java: [ '17', '21', '24' ] os: [ 'ubuntu-24.04', 'windows-latest', 'macos-latest' ] steps: - name: Checkout code From 47e4914374197d1d5b064b4bf5af74651879eedf Mon Sep 17 00:00:00 2001 From: Grzegorz Gierlach Date: Fri, 21 Mar 2025 12:15:58 +0100 Subject: [PATCH 554/805] [Rust] Elide explicit ActingVersion lifetime. (#1053) --- .../sbe/generation/rust/MessageCoderDef.java | 10 ++++---- .../sbe/generation/rust/RustGenerator.java | 25 +++++++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index da9060b9a2..e4e19f4c52 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -26,7 +26,7 @@ import static uk.co.real_logic.sbe.generation.rust.RustGenerator.CodecType.Encoder; import static uk.co.real_logic.sbe.generation.rust.RustGenerator.CodecType.Decoder; -import static uk.co.real_logic.sbe.generation.rust.RustGenerator.withLifetime; +import static uk.co.real_logic.sbe.generation.rust.RustGenerator.withBufLifetime; import static uk.co.real_logic.sbe.generation.rust.RustUtil.*; class MessageCoderDef implements RustGenerator.ParentDef @@ -165,8 +165,8 @@ void appendMessageStruct(final Appendable out, final String structName) throws I indent(out, 1, "#[derive(Debug, Default)]\n"); } - indent(out, 1, "pub struct %s {\n", withLifetime(structName)); - indent(out, 2, "buf: %s,\n", withLifetime(this.codecType.bufType())); + indent(out, 1, "pub struct %s {\n", withBufLifetime(structName)); + indent(out, 2, "buf: %s,\n", withBufLifetime(this.codecType.bufType())); indent(out, 2, "initial_offset: usize,\n"); indent(out, 2, "offset: usize,\n"); indent(out, 2, "limit: usize,\n"); @@ -184,7 +184,7 @@ void appendWrapFn(final Appendable out) throws IOException { indent(out, 2, "pub fn wrap(\n"); indent(out, 3, "mut self,\n"); - indent(out, 3, "buf: %s,\n", withLifetime(this.codecType.bufType())); + indent(out, 3, "buf: %s,\n", withBufLifetime(this.codecType.bufType())); indent(out, 3, "offset: usize,\n"); indent(out, 3, "acting_block_length: %s,\n", blockLengthType()); indent(out, 3, "acting_version: %s,\n", schemaVersionType()); @@ -194,7 +194,7 @@ void appendWrapFn(final Appendable out) throws IOException else { indent(out, 2, "pub fn wrap(mut self, buf: %s, offset: usize) -> Self {\n", - withLifetime(this.codecType.bufType())); + withBufLifetime(this.codecType.bufType())); indent(out, 3, "let limit = offset + SBE_BLOCK_LENGTH as usize;\n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 32f1633178..99aad88b46 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -50,6 +50,7 @@ public class RustGenerator implements CodeGenerator { static final String WRITE_BUF_TYPE = "WriteBuf"; static final String READ_BUF_TYPE = "ReadBuf"; + static final String ANONYMOUS_LIFETIME = "'_"; static final String BUF_LIFETIME = "'a"; enum CodecType @@ -187,9 +188,19 @@ String schemaVersionType() return rustTypeName(ir.headerStructure().schemaVersionType()); } - static String withLifetime(final String typeName) + static String withAnonymousLifetime(final String typeName) { - return format("%s<%s>", typeName, BUF_LIFETIME); + return withLifetime(typeName, ANONYMOUS_LIFETIME); + } + + static String withBufLifetime(final String typeName) + { + return withLifetime(typeName, BUF_LIFETIME); + } + + private static String withLifetime(final String typeName, final String lifetime) + { + return format("%s<%s>", typeName, lifetime); } static void appendImplWithLifetimeHeader( @@ -1243,14 +1254,14 @@ static void appendImplEncoderTrait( final Appendable out, final String typeName) throws IOException { - indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withLifetime("Writer"), withLifetime(typeName)); + indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withBufLifetime("Writer"), withBufLifetime(typeName)); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn get_buf_mut(&mut self) -> &mut WriteBuf<'a> {\n"); indent(out, 3, "&mut self.buf\n"); indent(out, 2, "}\n"); indent(out, 1, "}\n\n"); - indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withLifetime("Encoder"), withLifetime(typeName)); + indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withBufLifetime("Encoder"), withBufLifetime(typeName)); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn get_limit(&self) -> usize {\n"); indent(out, 3, "self.limit\n"); @@ -1268,21 +1279,21 @@ static void appendImplDecoderTrait( final Appendable out, final String typeName) throws IOException { - indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, "ActingVersion", withLifetime(typeName)); + indent(out, 1, "impl %s for %s {\n", "ActingVersion", withAnonymousLifetime(typeName)); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn acting_version(&self) -> %s {\n", schemaVersionType); indent(out, 3, "self.acting_version\n"); indent(out, 2, "}\n"); indent(out, 1, "}\n\n"); - indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withLifetime("Reader"), withLifetime(typeName)); + indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withBufLifetime("Reader"), withBufLifetime(typeName)); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn get_buf(&self) -> &ReadBuf<'a> {\n"); indent(out, 3, "&self.buf\n"); indent(out, 2, "}\n"); indent(out, 1, "}\n\n"); - indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withLifetime("Decoder"), withLifetime(typeName)); + indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withBufLifetime("Decoder"), withBufLifetime(typeName)); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn get_limit(&self) -> usize {\n"); indent(out, 3, "self.limit\n"); From bdb32557229fa6cd15a13e92cd3d3810481c2d13 Mon Sep 17 00:00:00 2001 From: marc-adaptive Date: Sun, 6 Apr 2025 12:25:14 -0400 Subject: [PATCH 555/805] [Java] Adjust Java DTO Choice Set Access (#1064) --- .../real_logic/sbe/generation/java/JavaDtoGenerator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index 4d8b3d334c..caf393ef19 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -1771,7 +1771,7 @@ private void generateChoices( fields.add(fieldName); classBuilder.appendField() - .append(indent).append("boolean ").append(fieldName).append(";\n"); + .append(indent).append("private boolean ").append(fieldName).append(";\n"); classBuilder.appendPublic() .append("\n") @@ -1782,7 +1782,7 @@ private void generateChoices( classBuilder.appendPublic() .append("\n") - .append(indent).append(dtoClassName).append(" ") + .append(indent).append("public ").append(dtoClassName).append(" ") .append(formattedPropertyName).append("(boolean value)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") @@ -1792,7 +1792,8 @@ private void generateChoices( } final StringBuilder clearBuilder = classBuilder.appendPublic() - .append(indent).append(dtoClassName).append(" clear()\n") + .append("\n") + .append(indent).append("public ").append(dtoClassName).append(" clear()\n") .append(indent).append("{\n"); for (final String field : fields) From 2a1ee77d792081e0aabb79107aabc1a7ef70161b Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:48:45 +0200 Subject: [PATCH 556/805] Bump `Mockito` to 5.17.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fa6ed4f55e..8a7341c0a2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ jqwik = "1.9.2" jmh = "1.37" json = "20250107" junit = "5.12.1" -mockito = "5.16.1" +mockito = "5.17.0" plexus = "3.3.0" shadow = "8.3.6" versions = "0.52.0" From 14d28c5d1347d6a2e182ab8735dc4c9ef62c2f6e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:49:35 +0200 Subject: [PATCH 557/805] Bump `Checkstyle` to 10.23.0. --- config/checkstyle/checkstyle.xml | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index abb1fc1efe..b97f363689 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -43,7 +43,7 @@ - + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8a7341c0a2..2464c43cc6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.1.0" -checkstyle = "10.21.4" +checkstyle = "10.23.0" commons-codec = "1.15" commons-lang3 = "3.8.1" gradle = "8.13" From d5ba0f6cc3fb761a29cc0b1710aa74734663473e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 7 Apr 2025 15:01:46 +0200 Subject: [PATCH 558/805] Checkstyle fixes. --- .../java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java | 1 + .../java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java | 1 + .../main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java | 1 + .../java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 1 + .../main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java | 1 + 5 files changed, 5 insertions(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java index 0fd31feed6..cfba4755e5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpUtil.java @@ -163,6 +163,7 @@ static String generateDocumentation(final String indent, final Token token) indent + "/// \n"; } + @SuppressWarnings("JavadocVariable") enum Separators { BEGIN_GROUP('['), diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 5f28c17a90..3b6e988750 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -49,6 +49,7 @@ public class JavaGenerator implements CodeGenerator static final String MESSAGE_HEADER_ENCODER_TYPE = "MessageHeaderEncoder"; static final String MESSAGE_HEADER_DECODER_TYPE = "MessageHeaderDecoder"; + @SuppressWarnings("JavadocVariable") enum CodecType { DECODER, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index 2290e7f468..e8e6808c01 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -39,6 +39,7 @@ public class JavaUtil /** * Separator symbols for {@link Object#toString()} implementations on codecs. */ + @SuppressWarnings("JavadocVariable") enum Separator { BEGIN_GROUP('['), diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 99aad88b46..16f6e40cb8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -53,6 +53,7 @@ public class RustGenerator implements CodeGenerator static final String ANONYMOUS_LIFETIME = "'_"; static final String BUF_LIFETIME = "'a"; + @SuppressWarnings("JavadocVariable") enum CodecType { Decoder diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java index a38bea7a7a..836bab1a7b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustUtil.java @@ -301,6 +301,7 @@ static Appendable indent(final Appendable appendable, final int level, final Str return indent(appendable, level).append(format(f, args)); } + @SuppressWarnings("JavadocVariable") enum ReservedKeyword { Abstract, AlignOf, As, Async, Become, Box, Break, Const, Continue, From 05612b41a2c01c3a0e11d89b39a432a8216233f7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 9 Apr 2025 14:18:51 +0200 Subject: [PATCH 559/805] [CI] Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. --- .github/workflows/ci.yml | 187 ++++++++++++---------------------- .github/workflows/codeql.yml | 78 +++++++------- .github/workflows/release.yml | 7 ++ .github/workflows/slow.yml | 4 +- 4 files changed, 118 insertions(+), 158 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81867c8a7c..81b8ea1546 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,18 +39,6 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Setup java uses: actions/setup-java@v4 with: @@ -68,11 +56,13 @@ jobs: java -Xinternalversion echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "BUILD_JAVA_VERSION=${{ matrix.java }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - - name: Setup java + - name: Setup java to run Gradle uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Build with Gradle run: ./gradlew - name: Copy test logs @@ -104,23 +94,18 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Cache NuGet dependencies uses: actions/cache@v4 with: @@ -155,18 +140,6 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ bionic main universe" @@ -176,6 +149,13 @@ jobs: with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Build run: ./cppbuild/cppbuild @@ -195,18 +175,6 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test @@ -217,6 +185,13 @@ jobs: with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Build run: ./cppbuild/cppbuild @@ -236,18 +211,6 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | sudo mkdir -p /etc/apt/keyrings/ @@ -260,6 +223,13 @@ jobs: with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Build run: ./cppbuild/cppbuild @@ -279,18 +249,6 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Install compiler run: | sudo mkdir -p /etc/apt/keyrings/ @@ -303,6 +261,13 @@ jobs: with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Build run: ./cppbuild/cppbuild @@ -322,23 +287,18 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -358,23 +318,18 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Setup java to run Gradle script uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Build run: cppbuild/cppbuild.cmd @@ -391,18 +346,6 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Rust setup uses: dtolnay/rust-toolchain@stable with: @@ -412,6 +355,13 @@ jobs: with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - run: ./gradlew runRustTests golang-build: @@ -427,18 +377,6 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - name: Setup Go uses: actions/setup-go@v4 with: @@ -448,6 +386,13 @@ jobs: with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Generate jar run: ./gradlew assemble - name: Run tests diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5942820cc6..b072c655ad 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -17,6 +17,7 @@ concurrency: env: GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.java.installations.auto-detect=false -Dorg.gradle.warning.mode=fail' JAVA_TOOL_OPTIONS: "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED" + JAVA_VERSION: '17' permissions: contents: read @@ -41,24 +42,22 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Setup java uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.java }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: @@ -93,18 +92,7 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 - with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + - name: Cache NuGet dependencies uses: actions/cache@v4 with: @@ -112,6 +100,22 @@ jobs: key: ${{ runner.os }}-nuget-${{ hashFiles('csharp/**/*.sln') }} restore-keys: | ${{ runner.os }}-nuget- + + - name: Setup java + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: ${{ env.JAVA_VERSION }} + + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - name: Setup dotnet uses: actions/setup-dotnet@v4 with: @@ -151,18 +155,22 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.sha }} - - name: Cache Gradle dependencies - uses: actions/cache@v4 - with: - path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache Gradle wrappers - uses: actions/cache@v4 + + - name: Setup java + uses: actions/setup-java@v4 with: - path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + distribution: 'zulu' + java-version: ${{ env.JAVA_VERSION }} + + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - name: Install compiler run: | sudo apt-get install -y g++-${{ matrix.version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db5f85bba4..7d843cc7f7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,6 +49,13 @@ jobs: with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION + run: | + java -Xinternalversion + echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV + echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Publish with Gradle run: ./gradlew publish env: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index bdbf452a02..feb48c79c8 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -3,8 +3,6 @@ name: Slow checks on: workflow_call: workflow_dispatch: - branches: - - '**' schedule: - cron: '0 12 * * *' push: @@ -58,6 +56,8 @@ jobs: with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Setup dotnet uses: actions/setup-dotnet@v2 with: From 72efb6852c21f185b31f96cf72cc80a296449895 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 14 Apr 2025 10:19:50 +0200 Subject: [PATCH 560/805] [Java] Bump `JUnit` to 5.12.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2464c43cc6..d8f5ab2680 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ httpcore = "4.4.14" jqwik = "1.9.2" jmh = "1.37" json = "20250107" -junit = "5.12.1" +junit = "5.12.2" mockito = "5.17.0" plexus = "3.3.0" shadow = "8.3.6" From 0f0e58d38f7649f9be5d18ab40df5945896208c3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 28 Apr 2025 11:27:19 +0200 Subject: [PATCH 561/805] [Java] Bump `Gradle` to 8.14. --- build.gradle | 1 - gradle/libs.versions.toml | 1 - gradle/wrapper/gradle-wrapper.jar | Bin 43705 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 ++-- gradlew.bat | 4 ++-- 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index b0ac62184a..6859b87b5a 100644 --- a/build.gradle +++ b/build.gradle @@ -1115,7 +1115,6 @@ tasks.named('dependencyUpdates').configure { } wrapper { - gradleVersion = libs.versions.gradle.get() distributionType = 'ALL' } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d8f5ab2680..07a4d2d9dc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,6 @@ agrona = "2.1.0" checkstyle = "10.23.0" commons-codec = "1.15" commons-lang3 = "3.8.1" -gradle = "8.13" hamcrest = "3.0" httpcore = "4.4.14" jqwik = "1.9.2" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9bbc975c742b298b441bfb90dbc124400a3751b9..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 642 zcmdmamFde>rVZJA^}0Q$xegf!xPEW^+5YDM%iT2bEgct9o+jH~+sJas#HZ=szO|** z=Pj=X_vx?W&DSwKck|WWn~hffsvnQ+42*W$b7b0$SCcOoZ`{W{^$^pk;4>8-A*-)$ z?n(Po`1$6Jn_u?t-L+tsPyZ2#X}8T6OS8pAU;kdgd+_Hw4z4TW0p9E!T+=f7-c&O% zFic^X{7^$?^Ho04eona9n#mGMxKhA=~8B%JN`M zMhm5wc-2v)$``sY$!Q`9xiU@DhI73ZxiGEKg>yIPs)NmWwMdF-ngLXpZSqV5ez36n zVkxF2rjrjWR+_xr6e6@_u@s~2uv{9vi*1pj2)BjFD+-%@&pRVP1f{O1glxTOp2-62Ph;v z`N1+vCd)9ea)af*Ol1*JCfnp$%Uu}%OuoN7g2}3C@`L5FlP#(sA=|h@iixuZC?qp^ z=L$=v$ZoI}|87Wh=&h7udff{aieKr*l+zDp?pf)_bbRvUf>kn;HCDMXNlgbbo!QRK I1x7am0No)LiU0rr delta 584 zcmexzm1*ZyrVZJAexH5Moc8h7)w{^+t*dqJ%=yhh23L$9JpFV=_k`zJ-?Q4DI*eSe z+ES)HSrVnWLtJ&)lO%hRkV9zl5qqWRt0e;bb zPPo`)y?HTAyZI&u&X<|2$FDHCf4;!v8}p=?Tm`^F0`u(|1ttf~&t$qP3KUSD>@TJQ zRwJ}Pim6NzEc8KA6)e;S6gs8=7IIL8sQL*MYEuRYO;Uj<%3UbMbV&^&!Zvx+LKmjT z8Zch6rYP7Tw?$Hn(UTJwWiS=$f{lB(C=e*%usDV})0AQIK~sat=ND@+Gg*Pyij!rR z*fa02W|%BsV++>4W{DKDGSIUEHd2$P+8ct!RF+CHDowUuTEZOZ%rJSQv*qOXOSPDN zT|sP-$p*_3ncsWB*qoD7JQcyZ9xan%cJP6Tb4-?AZpr*F6v98hoNaPJm@HV`yya5N z))6pqFXn@}P(3T0nEzM8*c_9KtE9o|_pFd&K35GBXP^9Kg(b6GH-z8S4GDzIl~T+b zdLd#meKKHu$5u))8cu$=GKINkGDPOUD)!0$C(BH(U!}!-e;Q0ok8Sc?V1zRO04>ts AA^-pY diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ed4c299adb..6514f919fd 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index faf93008b7..23d15a9367 100755 --- a/gradlew +++ b/gradlew @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9d21a21834..db3a6ac207 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell From 43d1253ec661cf76e9c9f646f461b10287a421f3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 28 Apr 2025 11:29:29 +0200 Subject: [PATCH 562/805] [Java] Bump `Checkstyle` to 10.23.1. --- build.gradle | 4 ++-- gradle/libs.versions.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 6859b87b5a..b3770aec71 100644 --- a/build.gradle +++ b/build.gradle @@ -172,6 +172,8 @@ subprojects { group = sbeGroup version = sbeVersion + checkstyle.toolVersion = libs.versions.checkstyle.get() + java { toolchain { languageVersion = JavaLanguageVersion.of(buildJavaVersion) @@ -179,8 +181,6 @@ subprojects { sourceCompatibility = JavaVersion.VERSION_17 } - checkstyle.toolVersion = libs.versions.checkstyle.get() - tasks.withType(Sign).configureEach { onlyIf { isReleaseVersion && gradle.taskGraph.hasTask(tasks.publish) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 07a4d2d9dc..3396ceb3b5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.1.0" -checkstyle = "10.23.0" +checkstyle = "10.23.1" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 2f8d61e8dd4417ecbbd1bba6f4fd653e774d1f8f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 28 Apr 2025 11:49:55 +0200 Subject: [PATCH 563/805] [CI] Remove Ubuntu 20.04 based builds as Github no longer supports that image. --- .github/workflows/ci.yml | 73 ---------------------------------------- 1 file changed, 73 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81b8ea1546..b874215b04 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,41 +124,6 @@ jobs: - name: Pack run: ./csharp/pack.sh - cpp-gcc-2004-build: - name: C++ GCC ${{ matrix.version }} (Ubuntu 20.04) - runs-on: ubuntu-20.04 - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - version: [ '6', '7', '8', '9', '10' ] - env: - CC: gcc-${{ matrix.version }} - CXX: g++-${{ matrix.version }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ github.sha }} - - name: Install compiler - run: | - sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ bionic main universe" - sudo apt-get install -y g++-${{ matrix.version }} libsparsehash-dev libidn11 - - name: Setup java to run Gradle script - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: ${{ env.JAVA_VERSION }} - - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION - run: | - java -Xinternalversion - echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV - echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - - name: Build - run: ./cppbuild/cppbuild - cpp-gcc-2404-build: name: C++ GCC ${{ matrix.version }} (Ubuntu 24.04) runs-on: ubuntu-24.04 @@ -195,44 +160,6 @@ jobs: - name: Build run: ./cppbuild/cppbuild - cpp-clang-2004-build: - name: C++ Clang ${{ matrix.version }} (Ubuntu 20.04) - runs-on: ubuntu-20.04 - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - version: [ '9', '10', '11', '12' ] - env: - CC: clang-${{ matrix.version }} - CXX: clang++-${{ matrix.version }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ github.sha }} - - name: Install compiler - run: | - sudo mkdir -p /etc/apt/keyrings/ - curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/llvm-snapshot.gpg - echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list - sudo apt-get update - sudo apt-get install -y clang-${{ matrix.version }} libsparsehash-dev libidn11 - - name: Setup java to run Gradle script - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: ${{ env.JAVA_VERSION }} - - name: Setup BUILD_JAVA_HOME & BUILD_JAVA_VERSION - run: | - java -Xinternalversion - echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV - echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - - name: Build - run: ./cppbuild/cppbuild - cpp-clang-2404-build: name: C++ Clang ${{ matrix.version }} (Ubuntu 24.04) runs-on: ubuntu-24.04 From e04e61b0ae2b4a32615cae67d761356e075b9d8d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 28 Apr 2025 11:52:56 +0200 Subject: [PATCH 564/805] [CI] Add GCC 15 and Clang 19,20 to the build matrix. --- .github/workflows/ci.yml | 4 ++-- .github/workflows/codeql.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b874215b04..98feaa457d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '11', '12', '13', '14' ] + version: [ '11', '12', '13', '14', '15' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} @@ -167,7 +167,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '13', '14', '15', '16', '17', '18' ] + version: [ '13', '14', '15', '16', '17', '18', '19', '20' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b072c655ad..4cdfa3e3aa 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -146,7 +146,7 @@ jobs: fail-fast: false matrix: language: ['cpp'] - version: [ '14' ] + version: [ '15' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} From 4c29cf7ad7a26dfa09a643ebf44fa707da448e72 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 28 Apr 2025 12:04:53 +0200 Subject: [PATCH 565/805] [CI] Remove GCC 15 as it is not yet available. --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98feaa457d..a9dc9e1f9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '11', '12', '13', '14', '15' ] + version: [ '11', '12', '13', '14' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4cdfa3e3aa..b072c655ad 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -146,7 +146,7 @@ jobs: fail-fast: false matrix: language: ['cpp'] - version: [ '15' ] + version: [ '14' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} From 9383d2429a95c579c814a396df9f2f9753d7b587 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 28 Apr 2025 12:10:03 +0200 Subject: [PATCH 566/805] [CI] Bump Go build to use 1.23.x and 1.24.x. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9dc9e1f9f..34d0d20396 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -298,7 +298,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '1.22.x' ] + version: [ '1.23.x', '1.24.x' ] steps: - name: Checkout code uses: actions/checkout@v4 From aab60b04801726ebaea8653e33d4815065f9f81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Andrade?= Date: Tue, 29 Apr 2025 06:43:26 -0300 Subject: [PATCH 567/805] [Rust] get proper version for composite types. (#1058) Co-authored-by: marcio.andrade --- build.gradle | 1 + rust/Cargo.toml | 1 + .../sbe/generation/rust/RustGenerator.java | 4 ++- sbe-tool/src/test/resources/issue1057.xml | 32 +++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 sbe-tool/src/test/resources/issue1057.xml diff --git a/build.gradle b/build.gradle index b3770aec71..8ae1c82751 100644 --- a/build.gradle +++ b/build.gradle @@ -672,6 +672,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe-tool/src/test/resources/issue984.xml', 'sbe-tool/src/test/resources/issue987.xml', 'sbe-tool/src/test/resources/issue1028.xml', + 'sbe-tool/src/test/resources/issue1057.xml', 'sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', 'sbe-tool/src/test/resources/nested-composite-name.xml', diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 2d4f3d4a49..e09cacf21c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -17,6 +17,7 @@ issue_972 = { path = "../generated/rust/issue972" } issue_984 = { path = "../generated/rust/issue984" } issue_987 = { path = "../generated/rust/issue987" } issue_1028 = { path = "../generated/rust/issue1028" } +issue_1057 = { path = "../generated/rust/issue1057" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } nested_composite_name = { path = "../generated/rust/nested-composite-name" } fixed_sized_primitive_array = { path = "../generated/rust/fixed_sized_primitive_array" } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 16f6e40cb8..10d0219b33 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1686,7 +1686,9 @@ private static void generateCompositeDecoder( indent(out, 2, "offset: usize,\n"); indent(out, 1, "}\n\n"); - final int version = tokens.get(1).version(); // skip BEGIN_COMPOSITE + // The version of the composite type is the greatest version of its fields. + final int version = tokens.stream().mapToInt(Token::version).max().orElse(0); + appendImplReaderForComposite(schemaVersionType, version, out, 1, decoderName); // impl<'a, P> start diff --git a/sbe-tool/src/test/resources/issue1057.xml b/sbe-tool/src/test/resources/issue1057.xml new file mode 100644 index 0000000000..8e89fcfade --- /dev/null +++ b/sbe-tool/src/test/resources/issue1057.xml @@ -0,0 +1,32 @@ + + + + 0 + + + + + + + + + + + + + + + + + + \ No newline at end of file From e0512f42b24627961250f69eee9f8ed91800eb99 Mon Sep 17 00:00:00 2001 From: Pierre Irrmann Date: Tue, 29 Apr 2025 11:46:51 +0200 Subject: [PATCH 568/805] [C#] Read NuGet package version from version file (#1061) Co-authored-by: pierre-irrmann --- csharp/sbe-dll/sbe-dll.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/csharp/sbe-dll/sbe-dll.csproj b/csharp/sbe-dll/sbe-dll.csproj index 6db6d56021..e4245e5c1b 100644 --- a/csharp/sbe-dll/sbe-dll.csproj +++ b/csharp/sbe-dll/sbe-dll.csproj @@ -13,7 +13,8 @@ https://github.com/aeron-io/simple-binary-encoding SBE;Marshaling;Low;Latency;Simple;Binary;Encoding sbe-tool - 1.23.1.1 + $(MSBuildProjectDirectory)\..\..\version.txt + $([System.IO.File]::ReadAllText($(VersionFile)).TrimEnd()) Simple Binary Encoding for .NET This package contains all you need to define SBE messages and generate C# encoders and decoders. See https://github.com/aeron-io/simple-binary-encoding for more detailed instructions git @@ -31,7 +32,7 @@ true tools/sbe-tool.sh - + true tools/sbe-tool-all.jar From a79ed83d12002550cd56fce0a58e3b85a14c1313 Mon Sep 17 00:00:00 2001 From: pierre-irrmann Date: Fri, 21 Mar 2025 11:17:47 +0100 Subject: [PATCH 569/805] [C#] Enable dual build for netstandard2.0 & netstandard2.1 --- csharp/sbe-dll/sbe-dll.csproj | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/csharp/sbe-dll/sbe-dll.csproj b/csharp/sbe-dll/sbe-dll.csproj index e4245e5c1b..ac9e4a8414 100644 --- a/csharp/sbe-dll/sbe-dll.csproj +++ b/csharp/sbe-dll/sbe-dll.csproj @@ -1,6 +1,6 @@  - netstandard2.0 + netstandard2.0;netstandard2.1 True SBE Org.SbeTool.Sbe.Dll @@ -38,9 +38,13 @@ - - - - + + + + + + + + From 2ab62bdbb7e0033fa5d7ec6e407cb32a6cfeacd5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 21 May 2025 15:16:58 +0200 Subject: [PATCH 570/805] [Java] Bump `Mockito` to 5.18.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3396ceb3b5..2376329a1c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ jqwik = "1.9.2" jmh = "1.37" json = "20250107" junit = "5.12.2" -mockito = "5.17.0" +mockito = "5.18.0" plexus = "3.3.0" shadow = "8.3.6" versions = "0.52.0" From 7b1c1524d75652921d38322c099087ff26670548 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 21 May 2025 15:17:21 +0200 Subject: [PATCH 571/805] [Java] Bump `Json` to 20250517. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2376329a1c..48b4f4a594 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hamcrest = "3.0" httpcore = "4.4.14" jqwik = "1.9.2" jmh = "1.37" -json = "20250107" +json = "20250517" junit = "5.12.2" mockito = "5.18.0" plexus = "3.3.0" From 08fadc099868e5b8725704c771080a2b7420a7d0 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 26 May 2025 11:52:34 +0200 Subject: [PATCH 572/805] [Java] Bump `Gradle` to 8.14.1. --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6514f919fd..6925085be8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 99cc8c1954402f962407252a5f0f7d7020831239 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 26 May 2025 11:53:02 +0200 Subject: [PATCH 573/805] [Java] Bump `Checkstyle` to 10.24.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 48b4f4a594..30ebe716c7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.1.0" -checkstyle = "10.23.1" +checkstyle = "10.24.0" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 5ee5e5894af127fe5f4cab07b28cd91ee9c5965e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 26 May 2025 14:29:27 +0200 Subject: [PATCH 574/805] [Doc] Add `CHANGELOG.md`. --- CHANGELOG.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..c2e8b2fe38 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,74 @@ +# Changelog + +## [1.35.0] - 2025-05-26 +### Changed +* Update `Implementation-Vendor`. +* **Rust:** Elide explicit ActingVersion lifetime. ([#1053](https://github.com/aeron-io/simple-binary-encoding/pull/1053)) +* **CI:** Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. +* **CI:** Enable JDK 24 GA build. +* **CI:** Simplify error log upload. +* **CI:** Remove Ubuntu 20.04 based builds. +* **CI:** Bump Go build to use 1.23.x and 1.24.x. +* Bump `Agrona` to 2.2.0. +* Bump `Gradle` to 8.14.1. +* Bump `Checkstyle` to 10.24.0. +* Bump `json` to 20250517. +* Bump `JUnit` to 5.12.2. +* Bump `Mockito` to 5.18.0. +* Bump `Shadow` to 8.3.6. +* Bump `Versions` to 0.52. + +### Fixed +* **Java:** include field 'deprecated' in ir encoding and decoding. +* **Java:** Adjust Java DTO Choice Set Access. ([#1064](https://github.com/aeron-io/simple-binary-encoding/issues/1064)) +* **Rust:** get proper version for composite types. ([#1058](https://github.com/aeron-io/simple-binary-encoding/pull/1058)) +* **C#:** Read NuGet package version from version file ([#1061](https://github.com/aeron-io/simple-binary-encoding/pull/1061)) +* **C#:** Enable dual build for netstandard2.0 & netstandard2.1. ([#1062](https://github.com/aeron-io/simple-binary-encoding/pull/1062)) + +## [1.34.1] - 2025-01-13 +### Changed +* Bump `json` to 20250107. +* Bump `Mockito` to 5.15.2. + +### Added +* **Doc:** Add `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` to the example execution. +* **Rust:** encoding primitive arrays now supports slice instead of array (issue [#1021](https://github.com/aeron-io/simple-binary-encoding/issues/)). ([#1040](https://github.com/aeron-io/simple-binary-encoding/pull/1040)) + +### Fixed +* **C++:** check for not wrapped state in `decodeLength()` when precedence checks are enabled. ([#1046](https://github.com/aeron-io/simple-binary-encoding/pull/1046)) +* **C++:** use `m_actingBlockLength` in `decodeLength()`. ([#1045](https://github.com/aeron-io/simple-binary-encoding/pull/1045)) + +## [1.34.0] - 2024-12-17 +### Changed +* **C++:** hide the m_codecStatePtr behind ifdefs to avoid overhead when precedence checking is disabled. ([#1036](https://github.com/aeron-io/simple-binary-encoding/pull/1036)) +* **C++:** use constexpr to define precedence checks lookup tables. +* **Rust:** Enhance enum supporting fromstr and display and into. ([#1020](https://github.com/aeron-io/simple-binary-encoding/pull/1020)) +* **Rust:** codegen of primitive enums now implement 'From' instead of 'Into'. ([#1029](https://github.com/aeron-io/simple-binary-encoding/pull/1029)) +* **Java:** Update Checkstyle rules and apply them. +* **Breaking:** Bump `Agrona` to 2.0.0. + _**Note:** `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` JVM option must be specified in order to generate codecs or use the generated Java classes. For example:_ + ```shell + $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=true -Dsbe.target.language=Cpp -Dsbe.target.namespace=sbe -Dsbe.output.dir=include/gen -Dsbe.errorLog=yes -jar sbe-all/build/libs/sbe-all-${SBE_TOOL_VERSION}.jar my-sbe-messages.xml + ``` +* Bump `Gradle` to 8.11.1. +* Bump `Checkstyle` to 10.21.0. +* Bump `ByteBuddy` to 1.15.11. +* Bump `JUnit` to 5.11.4. +* Bump `jqwik` to 1.9.2. + +### Added +* **C++:** Integrate std::span support for flyweight API. ([#1038](https://github.com/aeron-io/simple-binary-encoding/pull/1038), [#1027](https://github.com/aeron-io/simple-binary-encoding/pull/1027)) +* **Rust:** generate message schema level info in lib.rs. ([#1019](https://github.com/aeron-io/simple-binary-encoding/pull/1019)) + +### Fixed +* **C++:** Fix field precedence check issue [#1031](https://github.com/aeron-io/simple-binary-encoding/issues/1031). ([#1033](https://github.com/aeron-io/simple-binary-encoding/pull/1033)) +* **C++:** respect the package override option for C++ codecs and DTOs. ([#1024](https://github.com/aeron-io/simple-binary-encoding/pull/1024)) +* **C#:** respect the package override option for C# codecs and DTOs. ([#1024](https://github.com/aeron-io/simple-binary-encoding/pull/1024)) +* **Go:** Fix warning about used args in GolangFlyweightGenerator. +* **Rust:** Updated code generator to resolve Issue [#1028](https://github.com/aeron-io/simple-binary-encoding/issues/1028). ([#1037](https://github.com/aeron-io/simple-binary-encoding/pull/1037)) +* **Java:** Prevent collision when field name is 'value'. +* **Java:** Preserve byte order throughout IR transformations. + +[1.35.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.0 +[1.34.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.1 +[1.34.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.0 From 52f3d6f6b7ef1857c156855453e45b054511d1f9 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 26 May 2025 16:35:39 +0200 Subject: [PATCH 575/805] [Java] Bump `Agrona` to 2.2.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 30ebe716c7..20d5d5940a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.1.0" +agrona = "2.2.0" checkstyle = "10.24.0" commons-codec = "1.15" commons-lang3 = "3.8.1" From 29dc5cec8c30135fe19b4121be9d5f5f6ad1ad05 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 26 May 2025 16:36:55 +0200 Subject: [PATCH 576/805] 1.35.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index c9c35c012f..a2d87226ac 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.0-SNAPSHOT +1.35.0 \ No newline at end of file From 3ebb42547fc3b5565e65067eae932f8cb32a3ad6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 26 May 2025 16:37:12 +0200 Subject: [PATCH 577/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index a2d87226ac..aa69911fd7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.0 \ No newline at end of file +1.36.0-SNAPSHOT From ff702747e65c687ac3c194e459447efbc3f5e1f6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 31 May 2025 00:13:09 +0100 Subject: [PATCH 578/805] [Java] Bump `JUnit` to 5.13.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 20d5d5940a..b83f161ba6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.2" jmh = "1.37" json = "20250517" -junit = "5.12.2" +junit = "5.13.0" mockito = "5.18.0" plexus = "3.3.0" shadow = "8.3.6" From 06833056565de381630621adfe6c1339cb2f62fa Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 2 Jun 2025 13:04:48 +0200 Subject: [PATCH 579/805] [Java] Bump `Agrona` to 2.2.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b83f161ba6..b472f9f71e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.2.0" +agrona = "2.2.1" checkstyle = "10.24.0" commons-codec = "1.15" commons-lang3 = "3.8.1" From 2541e9e9b7d372a424a4f4e6a3d72125a00a30d4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 2 Jun 2025 13:04:58 +0200 Subject: [PATCH 580/805] [Doc] Add release notes. --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2e8b2fe38..2ea5b58113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [1.35.1] - 2025-06-02 +### Changed +* Bump `Agrona` to 2.2.1. +* Bump `JUnit` to 5.13.0. + ## [1.35.0] - 2025-05-26 ### Changed * Update `Implementation-Vendor`. @@ -69,6 +74,7 @@ * **Java:** Prevent collision when field name is 'value'. * **Java:** Preserve byte order throughout IR transformations. +[1.35.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.1 [1.35.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.0 [1.34.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.1 [1.34.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.0 From 708e93ce335fbda97342e3633f77c8a698dc59fb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 2 Jun 2025 13:05:15 +0200 Subject: [PATCH 581/805] 1.35.1 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index aa69911fd7..7eee785743 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.0-SNAPSHOT +1.35.1 From 5df8522d348bf46dfe8c5b0345f7263721736a38 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 2 Jun 2025 13:05:25 +0200 Subject: [PATCH 582/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 7eee785743..aa69911fd7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.1 +1.36.0-SNAPSHOT From 95c8fd165905caf5f7ae637fa0cb94bc42b1b6d2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 4 Jun 2025 17:38:34 +0200 Subject: [PATCH 583/805] [Java] Bump `Checkstyle` to 1.25.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b472f9f71e..ed61fb694f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.2.1" -checkstyle = "10.24.0" +checkstyle = "10.25.0" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From cf4ee3ef4ea273cc61865675ec216a0f0e755bac Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 14:38:45 +0200 Subject: [PATCH 584/805] [Java] Bump `Gradle` 8.14.2. --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6925085be8..be2dc79a8a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From e926d3a6b4fde927087a1aa2f6d57dec1642562c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 14:39:20 +0200 Subject: [PATCH 585/805] [Java] Bump `Agrona` to 2.2.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ed61fb694f..4a08456869 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.2.1" +agrona = "2.2.2" checkstyle = "10.25.0" commons-codec = "1.15" commons-lang3 = "3.8.1" From 3c9ee092b9fcd9b6058979e20af9bb8db169be14 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 14:55:25 +0200 Subject: [PATCH 586/805] [Java] Publish artifacts to Central Portal using OSSRH Staging API. --- .github/workflows/release.yml | 10 +- .gitignore | 10 +- CHANGELOG.md | 7 + build.gradle | 61 +++-- buildSrc/build.gradle | 19 ++ buildSrc/settings.gradle | 7 + ...typeCentralPortalUploadRepositoryTask.java | 228 ++++++++++++++++++ 7 files changed, 308 insertions(+), 34 deletions(-) create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/settings.gradle create mode 100644 buildSrc/src/main/java/uk/co/real_logic/sbe/build/SonatypeCentralPortalUploadRepositoryTask.java diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7d843cc7f7..c38dd27632 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -57,9 +57,9 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - name: Publish with Gradle - run: ./gradlew publish + run: ./gradlew publish uploadArtifactsToCentralPortal env: - ORG_GRADLE_PROJECT_ossrhUsername: ${{ secrets.SONATYPE_CENTRAL_USERNAME }} - ORG_GRADLE_PROJECT_ossrhPassword: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }} - ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_RSA_SIGN_KEY }} - ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_RSA_SIGN_KEYPASS }} + SIGNING_GPG_SECRET_KEY: ${{ secrets.GPG_RSA_SIGN_KEY }} + SIGNING_GPG_PASSWORD: ${{ secrets.GPG_RSA_SIGN_KEYPASS }} + SONATYPE_CENTRAL_PORTAL_USERNAME: ${{ secrets.SONATYPE_CENTRAL_PORTAL_USERNAME }} + SONATYPE_CENTRAL_PORTAL_PASSWORD: ${{ secrets.SONATYPE_CENTRAL_PORTAL_PASSWORD }} diff --git a/.gitignore b/.gitignore index fd7d72201b..c34ba580f9 100644 --- a/.gitignore +++ b/.gitignore @@ -19,14 +19,16 @@ build-local.properties deps */bin -build -.gradle -target +build/ +!buildSrc/ +!buildSrc/src/**/build +.gradle/ +target/ GTAGS GRTAGS GPATH prop -out +out/ .vs/ .vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ea5b58113..d0470654a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [1.35.2] - 2025-06-06 +### Changed +* Publish release artifacts to Central Portal using OSSRH Staging API service. +* Bump `Agrona` to 2.2.2. +* Bump `Checkstyle` to 10.25.0. + ## [1.35.1] - 2025-06-02 ### Changed * Bump `Agrona` to 2.2.1. @@ -74,6 +80,7 @@ * **Java:** Prevent collision when field name is 'value'. * **Java:** Preserve byte order throughout IR transformations. +[1.35.2]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.2 [1.35.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.1 [1.35.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.0 [1.34.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.1 diff --git a/build.gradle b/build.gradle index 8ae1c82751..030c4adec8 100644 --- a/build.gradle +++ b/build.gradle @@ -53,26 +53,30 @@ def toolchainLauncher = javaToolchains.launcherFor { def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() -ext { - isReleaseVersion = !sbeVersion.endsWith('-SNAPSHOT') - releasesRepoUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' - snapshotsRepoUrl = 'https://oss.sonatype.org/content/repositories/snapshots/' - - if (!project.hasProperty('ossrhUsername')) { - ossrhUsername = '' +def getConfigProperty(final String projectPropertyName, final String envVarName) { + String value = project.findProperty(projectPropertyName) + if (!value) { + value = System.getenv(envVarName) + if (!value) { + return null + } } - if (!project.hasProperty('ossrhPassword')) { - ossrhPassword = '' - } + value = value.trim() - if (!project.hasProperty('signingKey')) { - signingKey = null - } + return value ? value : null +} - if (!project.hasProperty('signingPassword')) { - signingPassword = null - } +ext { + isReleaseVersion = !sbeVersion.endsWith('-SNAPSHOT') + + sonatypeCentralPortalReleasesRepoUrl = 'https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/' + sonatypeCentralPortalSnapshotsRepoUrl = 'https://central.sonatype.com/repository/maven-snapshots/' + sonatypeCentralPortalUsername = getConfigProperty('sonatypeCentralPortalUsername', 'SONATYPE_CENTRAL_PORTAL_USERNAME') + sonatypeCentralPortalPassword = getConfigProperty('sonatypeCentralPortalPassword', 'SONATYPE_CENTRAL_PORTAL_PASSWORD') + + signingKey = getConfigProperty('signingKey', 'SIGNING_GPG_SECRET_KEY') // NOTE: ASCII armored secret key + signingPassword = getConfigProperty('signingPassword', 'SIGNING_GPG_PASSWORD') // NOTE: Plain text } def projectPom = { @@ -389,10 +393,10 @@ project(':sbe-tool') { repositories { maven { - url = !isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl + url = !isReleaseVersion ? sonatypeCentralPortalSnapshotsRepoUrl : sonatypeCentralPortalReleasesRepoUrl credentials { - username = ossrhUsername - password = ossrhPassword + username = sonatypeCentralPortalUsername + password = sonatypeCentralPortalPassword } } } @@ -459,10 +463,10 @@ project(':sbe-all') { } repositories { maven { - url = !isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl + url = !isReleaseVersion ? sonatypeCentralPortalSnapshotsRepoUrl : sonatypeCentralPortalReleasesRepoUrl credentials { - username = ossrhUsername - password = ossrhPassword + username = sonatypeCentralPortalUsername + password = sonatypeCentralPortalPassword } } } @@ -579,10 +583,10 @@ project(':sbe-samples') { repositories { maven { - url = !isReleaseVersion ? snapshotsRepoUrl : releasesRepoUrl + url = !isReleaseVersion ? sonatypeCentralPortalSnapshotsRepoUrl : sonatypeCentralPortalReleasesRepoUrl credentials { - username = ossrhUsername - password = ossrhPassword + username = sonatypeCentralPortalUsername + password = sonatypeCentralPortalPassword } } } @@ -1115,6 +1119,13 @@ tasks.named('dependencyUpdates').configure { } } +tasks.register('uploadArtifactsToCentralPortal', uk.co.real_logic.sbe.build.SonatypeCentralPortalUploadRepositoryTask) { + portalUsername.set(sonatypeCentralPortalUsername) + portalPassword.set(sonatypeCentralPortalPassword) + groupId.set(aeronGroup) + snapshotRelease.set(!isReleaseVersion) +} + wrapper { distributionType = 'ALL' } diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000000..a4f559284d --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,19 @@ +repositories { + mavenCentral() +} + +configurations.configureEach { + resolutionStrategy { + failOnVersionConflict() + } +} + +dependencies { + implementation libs.json +} + +tasks.withType(JavaCompile).configureEach { + configure(options) { + options.compilerArgs << '-Xlint:deprecation' << '-Xlint:unchecked' // examples + } +} diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 0000000000..b5a0fabf66 --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,7 @@ +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} diff --git a/buildSrc/src/main/java/uk/co/real_logic/sbe/build/SonatypeCentralPortalUploadRepositoryTask.java b/buildSrc/src/main/java/uk/co/real_logic/sbe/build/SonatypeCentralPortalUploadRepositoryTask.java new file mode 100644 index 0000000000..ba806c5ec0 --- /dev/null +++ b/buildSrc/src/main/java/uk/co/real_logic/sbe/build/SonatypeCentralPortalUploadRepositoryTask.java @@ -0,0 +1,228 @@ +/* + * Copyright 2014-2025 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.build; + +import org.gradle.api.DefaultTask; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.TaskAction; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodySubscribers; +import java.net.http.HttpResponse.ResponseInfo; +import java.time.Duration; +import java.util.Base64; + +import static java.nio.charset.StandardCharsets.US_ASCII; + +/** + * This task performs manual steps to publish artifacts to Central Portal via OSSRH Staging API. + */ +public class SonatypeCentralPortalUploadRepositoryTask extends DefaultTask +{ + private static final String CENTRAL_PORTAL_OSSRH_API_URI = "https://ossrh-staging-api.central.sonatype.com"; + private static final Duration CONNECTION_TIMEOUT = Duration.ofSeconds(30); + + private final Property portalUsername; + private final Property portalPassword; + private final Property groupId; + private final Property snapshotRelease; + + /** + * Create new task instance. + */ + public SonatypeCentralPortalUploadRepositoryTask() + { + portalUsername = getProject().getObjects().property(String.class); + portalPassword = getProject().getObjects().property(String.class); + groupId = getProject().getObjects().property(String.class); + snapshotRelease = getProject().getObjects().property(Boolean.class); + } + + /** + * Return property to set Central Portal username. + * + * @return Central Portal username. + */ + @Input + public Property getPortalUsername() + { + return portalUsername; + } + + /** + * Return property to set Central Portal password. + * + * @return Central Portal password. + */ + @Input + public Property getPortalPassword() + { + return portalPassword; + } + + /** + * Return property to set {@code groupId} of the project. + * + * @return {@code groupId} of the project. + */ + @Input + public Property getGroupId() + { + return groupId; + } + + /** + * Return property to set snapshot release. + * + * @return {@code true} if snapshot release. + */ + @Input + public Property getSnapshotRelease() + { + return snapshotRelease; + } + + /** + * Publish staging repository to the Central Portal. + */ + @TaskAction + public void run() throws IOException, InterruptedException + { + if (!portalUsername.isPresent()) + { + return; // release is not configured + } + + if (snapshotRelease.get()) + { + return; // snapshots are published directly + } + + final HttpClient httpClient = HttpClient.newBuilder() + .connectTimeout(CONNECTION_TIMEOUT) + .build(); + + final String userNameAndPassword = portalUsername.get() + ":" + portalPassword.get(); + final String bearer = new String( + Base64.getEncoder().encode(userNameAndPassword.getBytes(US_ASCII)), US_ASCII); + + final HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .header("Authorization", "Bearer " + bearer); + + final URI apiUri = URI.create(CENTRAL_PORTAL_OSSRH_API_URI); + + final String repositoryKey = findOpenRepository(apiUri, httpClient, requestBuilder); + uploadRepositoryToPortal(apiUri, httpClient, requestBuilder, repositoryKey); + dropRepository(apiUri, httpClient, requestBuilder, repositoryKey); + } + + private String findOpenRepository( + final URI apiUri, + final HttpClient httpClient, + final HttpRequest.Builder requestBuilder) throws IOException, InterruptedException + { + final HttpRequest request = requestBuilder + .copy() + .GET() + .uri(apiUri.resolve("/manual/search/repositories?ip=client")) + .build(); + final HttpResponse response = httpClient.send( + request, (ResponseInfo responseInfo) -> BodySubscribers.ofString(US_ASCII)); + + if (200 != response.statusCode()) + { + throw new IllegalStateException("Failed to query repositories: " + + "status=" + response.statusCode() + ", response=" + response.body()); + } + + final JSONArray repositories = new JSONObject(response.body()).getJSONArray("repositories"); + if (repositories.isEmpty()) + { + throw new IllegalStateException("No open repositories found!"); + } + + String repositoryKey = null; + final String group = groupId.get(); + for (int i = 0; i < repositories.length(); i++) + { + final JSONObject repo = (JSONObject)repositories.get(i); + if ("open".equals(repo.getString("state"))) + { + final String key = repo.getString("key"); + if (key.contains(group)) + { + repositoryKey = key; + break; + } + } + } + + if (null == repositoryKey) + { + throw new IllegalStateException("No open repositories found!"); + } + return repositoryKey; + } + + private static void uploadRepositoryToPortal( + final URI apiUri, + final HttpClient httpClient, + final HttpRequest.Builder requestBuilder, + final String repositoryKey) throws IOException, InterruptedException + { + final HttpRequest request = requestBuilder + .copy() + .POST(HttpRequest.BodyPublishers.noBody()) + .uri(apiUri.resolve("/manual/upload/repository/" + repositoryKey + "?publishing_type=automatic")) + .build(); + final HttpResponse response = httpClient.send( + request, (ResponseInfo responseInfo) -> BodySubscribers.ofString(US_ASCII)); + + if (200 != response.statusCode()) + { + throw new IllegalStateException("Failed to upload repository: repository_key=" + repositoryKey + + ", status=" + response.statusCode() + ", response=" + response.body()); + } + } + + private static void dropRepository( + final URI apiUri, + final HttpClient httpClient, + final HttpRequest.Builder requestBuilder, + final String repositoryKey) throws IOException, InterruptedException + { + final HttpRequest request = requestBuilder + .copy() + .DELETE() + .uri(apiUri.resolve("/manual/drop/repository/" + repositoryKey)) + .build(); + final HttpResponse response = httpClient.send( + request, (ResponseInfo responseInfo) -> BodySubscribers.ofString(US_ASCII)); + + if (204 != response.statusCode()) + { + throw new IllegalStateException("Failed to drop repository: repository_key=" + repositoryKey + + ", status=" + response.statusCode() + ", response=" + response.body()); + } + } +} From 0b6f008c766c40d63cc65db7fe6e1fc74e3254e7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 14:55:46 +0200 Subject: [PATCH 587/805] 1.35.2 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index aa69911fd7..0035f2a76b 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.0-SNAPSHOT +1.35.2 From 0ab9fff7e2abdefe7112d261bf648105016adcda Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 14:55:58 +0200 Subject: [PATCH 588/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 0035f2a76b..aa69911fd7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.2 +1.36.0-SNAPSHOT From 605a031cef332773b08463953b8a4c275cf76d6e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 14:57:19 +0200 Subject: [PATCH 589/805] Update doc. --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0470654a6..8c0028add3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ ## [1.35.2] - 2025-06-06 ### Changed -* Publish release artifacts to Central Portal using OSSRH Staging API service. -* Bump `Agrona` to 2.2.2. -* Bump `Checkstyle` to 10.25.0. +* **Java:** Publish release artifacts to Central Portal using OSSRH Staging API service. +* **Java:** Bump `Agrona` to 2.2.2. +* **Java:** Bump `Checkstyle` to 10.25.0. +* **Java:** Bump `Gradle` to 8.14.2. ## [1.35.1] - 2025-06-02 ### Changed From 4a2e3cd11028262acc862b5553411270ab48ca18 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:33:40 +0200 Subject: [PATCH 590/805] [Java] Task invocation bug. --- CHANGELOG.md | 4 ++-- build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c0028add3..da8120cb18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [1.35.2] - 2025-06-06 +## [1.35.3] - 2025-06-06 ### Changed * **Java:** Publish release artifacts to Central Portal using OSSRH Staging API service. * **Java:** Bump `Agrona` to 2.2.2. @@ -81,7 +81,7 @@ * **Java:** Prevent collision when field name is 'value'. * **Java:** Preserve byte order throughout IR transformations. -[1.35.2]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.2 +[1.35.3]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.3 [1.35.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.1 [1.35.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.0 [1.34.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.1 diff --git a/build.gradle b/build.gradle index 030c4adec8..a6f9f542b0 100644 --- a/build.gradle +++ b/build.gradle @@ -1122,7 +1122,7 @@ tasks.named('dependencyUpdates').configure { tasks.register('uploadArtifactsToCentralPortal', uk.co.real_logic.sbe.build.SonatypeCentralPortalUploadRepositoryTask) { portalUsername.set(sonatypeCentralPortalUsername) portalPassword.set(sonatypeCentralPortalPassword) - groupId.set(aeronGroup) + groupId.set(sbeGroup) snapshotRelease.set(!isReleaseVersion) } From 37254bf99c132a38ecf5c7047ad1fd3f1a81c39d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:34:57 +0200 Subject: [PATCH 591/805] 1.35.3 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index aa69911fd7..0c4fe1942d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.0-SNAPSHOT +1.35.3 From 45ff07209827da348766b0f287da8f22cada7ab2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:35:07 +0200 Subject: [PATCH 592/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 0c4fe1942d..aa69911fd7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.3 +1.36.0-SNAPSHOT From f64751b358fab3dacba82d0ee8ed887542554ba9 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 7 Jun 2025 15:39:50 +0200 Subject: [PATCH 593/805] [Java] Bump `JUnit` to 5.13.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4a08456869..5a9fdb63d1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.2" jmh = "1.37" json = "20250517" -junit = "5.13.0" +junit = "5.13.1" mockito = "5.18.0" plexus = "3.3.0" shadow = "8.3.6" From 4e89da2f4c6806fcf0489c1068b96009b06291e2 Mon Sep 17 00:00:00 2001 From: marc-adaptive Date: Mon, 9 Jun 2025 23:24:48 -0400 Subject: [PATCH 594/805] [Java] Adjust Java Dto generateComputeEncodedLength to acount for character encoding (#1072) --- .../sbe/generation/java/JavaDtoGenerator.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index caf393ef19..65d7bbf6a8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -371,14 +371,20 @@ private void generateComputeEncodedLength( .append(formatPropertyName(propertyName)).append("HeaderLength();\n"); final String characterEncoding = varDataToken.encoding().characterEncoding(); - final String lengthAccessor = characterEncoding == null ? ".length" : ".length()"; - lengthBuilder.append(indent).append(INDENT).append("encodedLength += ") - .append("this.").append(fieldName).append(lengthAccessor); + lengthBuilder.append(indent).append(INDENT).append("encodedLength += "); - final int elementByteLength = varDataToken.encoding().primitiveType().size(); - if (elementByteLength != 1) + if (characterEncoding == null) + { + lengthBuilder.append("this.").append(fieldName).append(".length"); + } + else if (JavaUtil.isAsciiEncoding(characterEncoding)) + { + lengthBuilder.append("this.").append(fieldName).append(".length()"); + } + else { - lengthBuilder.append(" * ").append(elementByteLength); + lengthBuilder.append("this.").append(fieldName) + .append(".getBytes(").append(JavaUtil.charset(characterEncoding)).append(").length"); } lengthBuilder.append(";\n\n"); From 1a656cebf40b00b38a745bbb5fe039df453029d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rcio=20Andrade?= Date: Wed, 11 Jun 2025 07:38:40 -0300 Subject: [PATCH 595/805] Return None for optional primite field if its version is less than actingVersion. (#1067) * Fix optional primitive decoder. * Add tests. * Update issue number. --------- Co-authored-by: marcio.andrade Co-authored-by: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> --- build.gradle | 1 + rust/Cargo.toml | 1 + rust/tests/issue_1066_test.rs | 40 +++++++++++++++++++ .../sbe/generation/rust/RustGenerator.java | 7 ++++ sbe-tool/src/test/resources/issue1066.xml | 18 +++++++++ 5 files changed, 67 insertions(+) create mode 100644 rust/tests/issue_1066_test.rs create mode 100644 sbe-tool/src/test/resources/issue1066.xml diff --git a/build.gradle b/build.gradle index a6f9f542b0..b349fe2528 100644 --- a/build.gradle +++ b/build.gradle @@ -677,6 +677,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe-tool/src/test/resources/issue987.xml', 'sbe-tool/src/test/resources/issue1028.xml', 'sbe-tool/src/test/resources/issue1057.xml', + 'sbe-tool/src/test/resources/issue1066.xml', 'sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', 'sbe-tool/src/test/resources/nested-composite-name.xml', diff --git a/rust/Cargo.toml b/rust/Cargo.toml index e09cacf21c..b48fd6ee55 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -18,6 +18,7 @@ issue_984 = { path = "../generated/rust/issue984" } issue_987 = { path = "../generated/rust/issue987" } issue_1028 = { path = "../generated/rust/issue1028" } issue_1057 = { path = "../generated/rust/issue1057" } +issue_1066 = { path = "../generated/rust/issue1066" } baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } nested_composite_name = { path = "../generated/rust/nested-composite-name" } fixed_sized_primitive_array = { path = "../generated/rust/fixed_sized_primitive_array" } diff --git a/rust/tests/issue_1066_test.rs b/rust/tests/issue_1066_test.rs new file mode 100644 index 0000000000..43f7278ebf --- /dev/null +++ b/rust/tests/issue_1066_test.rs @@ -0,0 +1,40 @@ +use issue_1066::{ + issue_1066_codec, + issue_1066_codec::{Issue1066Decoder, Issue1066Encoder}, + *, +}; + +#[test] +fn decode_optional_primitive_field() { + let mut buffer = vec![0u8; 256]; + + // Create a message with `field` set. + let mut encoder = Issue1066Encoder::default().wrap( + WriteBuf::new(&mut buffer), + message_header_codec::ENCODED_LENGTH, + ); + encoder.field(10); + + // Drop encoder to drop the mut reference for the buffer. + drop(encoder); + + // Create a decoder for the message, but stating that the version is 1, instead of 2 + // which is the acting version for `field`. Thus, `field()` must return `None`. + let decoder = Issue1066Decoder::default().wrap( + ReadBuf::new(&mut buffer), + message_header_codec::ENCODED_LENGTH, + issue_1066_codec::SBE_BLOCK_LENGTH, + 1, + ); + assert!(decoder.field().is_none()); + + // Create a decoder for the message, but stating that the version is 1, instead of 2 + // which is the acting version for `field`. Thus, `field()` must return `None`. + let decoder = Issue1066Decoder::default().wrap( + ReadBuf::new(&mut buffer), + message_header_codec::ENCODED_LENGTH, + issue_1066_codec::SBE_BLOCK_LENGTH, + 2, + ); + assert_eq!(decoder.field(), Some(10)); +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 10d0219b33..746f18d022 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -894,6 +894,13 @@ private static void generatePrimitiveOptionalDecoder( formatFunctionName(name), rustPrimitiveType); + if (fieldToken.version() > 0) + { + indent(sb, level + 1, "if self.acting_version() < %d {\n", fieldToken.version()); + indent(sb, level + 2, "return None;\n"); + indent(sb, level + 1, "}\n\n"); + } + indent(sb, level + 1, "let value = self.get_buf().get_%s_at(self.%s);\n", rustPrimitiveType, getBufOffset(fieldToken)); diff --git a/sbe-tool/src/test/resources/issue1066.xml b/sbe-tool/src/test/resources/issue1066.xml new file mode 100644 index 0000000000..a24e45b030 --- /dev/null +++ b/sbe-tool/src/test/resources/issue1066.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + \ No newline at end of file From 777170acde4c2743ebb4641875746441df340fe3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 11 Jun 2025 14:42:02 +0200 Subject: [PATCH 596/805] [CI] Use `macos-15`. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34d0d20396..8d7129e13a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: fail-fast: false matrix: java: [ '17', '21', '24' ] - os: [ 'ubuntu-24.04', 'windows-latest', 'macos-latest' ] + os: [ 'ubuntu-24.04', 'windows-latest', 'macos-15' ] steps: - name: Checkout code uses: actions/checkout@v4 @@ -205,7 +205,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ 'macos-latest' ] + os: [ 'macos-15' ] env: CC: clang CXX: clang++ From cdbc3ec5ef73a6a02d8892dd90767d17b22fbc4d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:57:17 +0200 Subject: [PATCH 597/805] [Java] Bump `jqwik` to 1.9.3. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5a9fdb63d1..710f76675a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" httpcore = "4.4.14" -jqwik = "1.9.2" +jqwik = "1.9.3" jmh = "1.37" json = "20250517" junit = "5.13.1" From c11c331e492d9f5d62da4499124efd240555bde4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:58:53 +0200 Subject: [PATCH 598/805] [Doc] Release notes. --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da8120cb18..b4e3935a1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.35.4] - 2025-06-12 +### Changed +* **Rust:** Return None for optional primite field if its version is less than actingVersion. ([#1067](https://github.com/aeron-io/simple-binary-encoding/pull/1067)) +* **Java:** Adjust Java Dto generateComputeEncodedLength to acount for character encoding. ([#1072](https://github.com/aeron-io/simple-binary-encoding/pull/1072)) +* **Java:** Bump `JUnit` to 5.13.1. +* **Java:** Bump `jqwik` to 1.9.3. + ## [1.35.3] - 2025-06-06 ### Changed * **Java:** Publish release artifacts to Central Portal using OSSRH Staging API service. @@ -81,6 +88,7 @@ * **Java:** Prevent collision when field name is 'value'. * **Java:** Preserve byte order throughout IR transformations. +[1.35.4]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.4 [1.35.3]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.3 [1.35.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.1 [1.35.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.0 From f43b14d75732cb0089bf7abb1273f1cbd201bef7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:59:17 +0200 Subject: [PATCH 599/805] 1.35.4 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index aa69911fd7..f508d5bf03 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.0-SNAPSHOT +1.35.4 From 13f9636fe2b5a63e8c28a0cb367d0f4da6f6a70c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 12 Jun 2025 12:59:34 +0200 Subject: [PATCH 600/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f508d5bf03..aa69911fd7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.4 +1.36.0-SNAPSHOT From 092c1af104c850e1d17ef77b4edc3b3d91ad5475 Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 20 Jun 2025 10:42:40 +0100 Subject: [PATCH 601/805] [Java/C++/C#] Fix a bug in overzealous DTO validation (#1073) * [Java] Cover null values in PBTs. We had a recent bug report where the generated Java DTOs were not correctly handling null values for optional fields. It turns out the property-based tests were not encoding these values. Now, they do, and they fail with messages like this one: ``` java.lang.IllegalArgumentException: member1: value is out of allowed range: 255 at uk.co.real_logic.sbe.properties.TestMessageDto.validateMember1(TestMessageDto.java:33) at uk.co.real_logic.sbe.properties.TestMessageDto.member1(TestMessageDto.java:55) at uk.co.real_logic.sbe.properties.TestMessageDto.decodeWith(TestMessageDto.java:112) at uk.co.real_logic.sbe.properties.TestMessageDto.decodeFrom(TestMessageDto.java:135) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at uk.co.real_logic.sbe.properties.DtosPropertyTest.javaDtoEncodeShouldBeTheInverseOfDtoDecode(DtosPropertyTest.java:114) at java.base/java.lang.reflect.Method.invoke(Method.java:568) ``` * [Java] Support arbitrary char arrays in PBTs without data after null. I spotted a failure in the DTO round-trip test locally where the DTO's (and flyweight codec's) String-typed accessor would return `""` if the first character in an array was the `null` character. Therefore, it would not round-trip the "hidden bytes" after the `null`. In this commit, I've added a generation mode that disables the generation of strings with this format. Given the representation of char[N] in DTOs it would not be sensible to support round-tripping these "hidden bytes". * [Java,C++,C#] Improve DTO value validation. Previously, in Java, the generated validation methods would not permit the null value, even for fields with optional presence. Now, we do allow these correctly. In this commit, I've also attempted to clean up, centralise, and test the logic that decides when validation for a particular side of a range needs to be included. We omit the validation when the native type cannot represent values outside of the range. There are still some gaps around validation, e.g., we do not validate array values. * [Java] Fix JSON escaping of string characters, delimeters, etc. Previously, there were several problems: - (delimeters) single `char` values were output with single quotes, but this is not valid JSON. - (escaping) escaping was not implemented as per the specification in Section 7 of RFC 8259. For example, special-cased control codes, e.g., `\b` were encoded as `\\` followed by `\b` rather than `\\` followed by `b`. Also, the non-special-cased control characters were not encoded using JSON's mechanism for doing so, e.g., `\u0020`. - (numbers) Section 6 of the specification says "Numeric values that cannot be represented in the grammar below (such as Infinity and NaN) are not permitted." However, these were encoded as expressions of numbers with multiple terms, e.g., `-1/0` for positive infinity. While these are quite logical encodings of such "numbers", it is not valid JSON. Therefore, I have kept the expressions, but enclosed them within quotes. Also, in this commit: - Replaced custom compilation logic with Agrona's CompilerUtil. Note that `CompilerUtil#compileOnDisk` is broken. I attempted to use it to see if I could see classes in IntelliJ rather than just stack frames, but it fails with an NPE. --- .../generation/common/DtoValidationUtil.java | 224 +++++++++++++++ .../sbe/generation/cpp/CppDtoGenerator.java | 10 +- .../generation/csharp/CSharpDtoGenerator.java | 11 +- .../sbe/generation/java/JavaDtoGenerator.java | 168 ++++++++--- .../sbe/json/JsonTokenListener.java | 30 +- .../java/uk/co/real_logic/sbe/otf/Types.java | 105 ++++++- .../sbe/properties/DtosPropertyTest.java | 133 +++++---- .../sbe/properties/JsonPropertyTest.java | 18 +- .../sbe/properties/PropertyTestUtil.java | 43 +++ .../arbitraries/SbeArbitraries.java | 263 +++++++++++++++--- .../schema/TestXmlSchemaWriter.java | 16 +- .../utils/InMemoryOutputManager.java | 132 ++------- .../common/DtoValidationUtilTest.java | 105 +++++++ 13 files changed, 959 insertions(+), 299 deletions(-) create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/DtoValidationUtil.java create mode 100644 sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/PropertyTestUtil.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/common/DtoValidationUtilTest.java diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/DtoValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/DtoValidationUtil.java new file mode 100644 index 0000000000..1e522c232b --- /dev/null +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/DtoValidationUtil.java @@ -0,0 +1,224 @@ +/* + * Copyright 2013-2025 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.common; + +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.PrimitiveValue; +import uk.co.real_logic.sbe.ir.Encoding; +import uk.co.real_logic.sbe.ir.Token; + +/** + * Helpers for generating value validation code. + */ +public final class DtoValidationUtil +{ + private DtoValidationUtil() + { + } + + /** + * What support the target language has for native integer types. + */ + public enum NativeIntegerSupport + { + /** + * The target language supports both signed and unsigned integers natively and the generated code uses + * these to represent the SBE types. + */ + SIGNED_AND_UNSIGNED, + + /** + * The target language only supports signed integers natively and the generated code uses the next biggest + * signed integer type to represent the unsigned SBE types, except for UINT64 which is always represented + * as a signed long. + */ + SIGNED_ONLY + } + + /** + * Checks if the native type can represent values less than the valid range of the SBE type. + * + * @param fieldToken the field token to check if it is optional. + * @param encoding the encoding of the field to check the applicable minimum and null values. + * @param integerSupport the support for native integer types in the target language. + * @return true if the native type can represent values less than the valid range of the SBE type, + * false otherwise. + */ + public static boolean nativeTypeRepresentsValuesLessThanValidRange( + final Token fieldToken, + final Encoding encoding, + final NativeIntegerSupport integerSupport) + { + final PrimitiveType primitiveType = encoding.primitiveType(); + final PrimitiveValue minValue = encoding.applicableMinValue(); + + switch (minValue.representation()) + { + case LONG: + final long nativeMinValue = nativeTypeMinValue(primitiveType, integerSupport); + final PrimitiveValue nullValue = encoding.applicableNullValue(); + final boolean gapBefore = minValue.longValue() > nativeMinValue; + final boolean nullFillsGap = fieldToken.isOptionalEncoding() && + nullValue.longValue() == nativeMinValue && + minValue.longValue() == nativeMinValue + 1L; + return gapBefore && !nullFillsGap; + + case DOUBLE: + switch (primitiveType) + { + case FLOAT: + return minValue.doubleValue() > -Float.MAX_VALUE; + case DOUBLE: + return minValue.doubleValue() > -Double.MAX_VALUE; + default: + throw new IllegalArgumentException( + "Type did not have a double representation: " + primitiveType); + } + + default: + throw new IllegalArgumentException( + "Cannot understand the range of a type with representation: " + minValue.representation()); + } + } + + /** + * Checks if the native type can represent values greater than the valid range of the SBE type. + * + * @param fieldToken the field token to check if it is optional. + * @param encoding the encoding of the field to check the applicable maximum and null values. + * @param integerSupport the support for native integer types in the target language. + * @return true if the native type can represent values greater than the valid range of the SBE type, + * false otherwise. + */ + public static boolean nativeTypeRepresentsValuesGreaterThanValidRange( + final Token fieldToken, + final Encoding encoding, + final NativeIntegerSupport integerSupport) + { + final PrimitiveType primitiveType = encoding.primitiveType(); + final PrimitiveValue maxValue = encoding.applicableMaxValue(); + + switch (maxValue.representation()) + { + case LONG: + final long nativeMaxValue = nativeTypeMaxValue(primitiveType, integerSupport); + final PrimitiveValue nullValue = encoding.applicableNullValue(); + final boolean gapAfter = maxValue.longValue() < nativeMaxValue; + final boolean nullFillsGap = fieldToken.isOptionalEncoding() && + nullValue.longValue() == nativeMaxValue && + maxValue.longValue() + 1L == nativeMaxValue; + return gapAfter && !nullFillsGap; + + case DOUBLE: + switch (primitiveType) + { + case FLOAT: + return maxValue.doubleValue() < Float.MAX_VALUE; + case DOUBLE: + return maxValue.doubleValue() < Double.MAX_VALUE; + default: + throw new IllegalArgumentException( + "Type did not have a double representation: " + primitiveType); + } + + default: + throw new IllegalArgumentException( + "Cannot understand the range of a type with representation: " + maxValue.representation()); + } + } + + private static long nativeTypeMinValue( + final PrimitiveType primitiveType, + final NativeIntegerSupport integerSupport) + { + switch (primitiveType) + { + case CHAR: + return Character.MIN_VALUE; + case INT8: + return Byte.MIN_VALUE; + case INT16: + return Short.MIN_VALUE; + case INT32: + return Integer.MIN_VALUE; + case INT64: + return Long.MIN_VALUE; + case UINT8: + if (integerSupport == NativeIntegerSupport.SIGNED_ONLY) + { + return Short.MIN_VALUE; + } + return 0L; + case UINT16: + if (integerSupport == NativeIntegerSupport.SIGNED_ONLY) + { + return Integer.MIN_VALUE; + } + return 0L; + case UINT32: + if (integerSupport == NativeIntegerSupport.SIGNED_ONLY) + { + return Long.MIN_VALUE; + } + return 0L; + case UINT64: + return 0L; + default: + throw new IllegalArgumentException("Type did not have a long representation: " + primitiveType); + } + } + + private static long nativeTypeMaxValue( + final PrimitiveType primitiveType, + final NativeIntegerSupport integerSupport) + { + switch (primitiveType) + { + case CHAR: + return Character.MAX_VALUE; + case INT8: + return Byte.MAX_VALUE; + case INT16: + return Short.MAX_VALUE; + case INT32: + return Integer.MAX_VALUE; + case INT64: + return Long.MAX_VALUE; + case UINT8: + if (integerSupport == NativeIntegerSupport.SIGNED_ONLY) + { + return Short.MAX_VALUE; + } + return 0xFFL; + case UINT16: + if (integerSupport == NativeIntegerSupport.SIGNED_ONLY) + { + return Integer.MAX_VALUE; + } + return 0xFFFFL; + case UINT32: + if (integerSupport == NativeIntegerSupport.SIGNED_ONLY) + { + return Long.MAX_VALUE; + } + return 0xFFFFFFFFL; + case UINT64: + return 0xFFFFFFFFFFFFFFFFL; + default: + throw new IllegalArgumentException("Type did not have a long representation: " + primitiveType); + } + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 05d214d751..baf01b639e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -35,6 +35,9 @@ import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.NativeIntegerSupport.SIGNED_AND_UNSIGNED; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.nativeTypeRepresentsValuesGreaterThanValidRange; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.nativeTypeRepresentsValuesLessThanValidRange; import static uk.co.real_logic.sbe.generation.cpp.CppUtil.*; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; @@ -1591,8 +1594,11 @@ private static void generateSingleValuePropertyValidateMethod( String value = "value"; - final boolean mustPreventLesser = !encoding.applicableMinValue().equals(encoding.primitiveType().minValue()); - final boolean mustPreventGreater = !encoding.applicableMaxValue().equals(encoding.primitiveType().maxValue()); + final boolean mustPreventLesser = + nativeTypeRepresentsValuesLessThanValidRange(fieldToken, encoding, SIGNED_AND_UNSIGNED); + + final boolean mustPreventGreater = + nativeTypeRepresentsValuesGreaterThanValidRange(fieldToken, encoding, SIGNED_AND_UNSIGNED); if (fieldToken.isOptionalEncoding()) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index 47bef5a349..ed55bae37b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -35,6 +35,9 @@ import java.util.Set; import java.util.function.Predicate; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.NativeIntegerSupport.SIGNED_AND_UNSIGNED; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.nativeTypeRepresentsValuesGreaterThanValidRange; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.nativeTypeRepresentsValuesLessThanValidRange; import static uk.co.real_logic.sbe.generation.csharp.CSharpUtil.*; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; @@ -1285,7 +1288,9 @@ private void generateSingleValueProperty( .append("}\n"); } - final boolean mustPreventLesser = !encoding.applicableMinValue().equals(encoding.primitiveType().minValue()); + final boolean mustPreventLesser = + nativeTypeRepresentsValuesLessThanValidRange(fieldToken, typeToken.encoding(), SIGNED_AND_UNSIGNED); + if (mustPreventLesser) { sb.append(indent).append(INDENT) @@ -1299,7 +1304,9 @@ private void generateSingleValueProperty( .append("}\n"); } - final boolean mustPreventGreater = !encoding.applicableMaxValue().equals(encoding.primitiveType().maxValue()); + final boolean mustPreventGreater = + nativeTypeRepresentsValuesGreaterThanValidRange(fieldToken, typeToken.encoding(), SIGNED_AND_UNSIGNED); + if (mustPreventGreater) { sb.append(indent).append(INDENT) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index 65d7bbf6a8..bb7da8df34 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -19,6 +19,7 @@ import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.generation.CodeGenerator; import uk.co.real_logic.sbe.generation.Generators; +import uk.co.real_logic.sbe.ir.Encoding; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.ir.Signal; import uk.co.real_logic.sbe.ir.Token; @@ -36,6 +37,9 @@ import static uk.co.real_logic.sbe.generation.Generators.toLowerFirstChar; import static uk.co.real_logic.sbe.generation.Generators.toUpperFirstChar; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.NativeIntegerSupport.SIGNED_ONLY; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.nativeTypeRepresentsValuesGreaterThanValidRange; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.nativeTypeRepresentsValuesLessThanValidRange; import static uk.co.real_logic.sbe.generation.java.JavaUtil.*; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; @@ -1485,57 +1489,157 @@ private void generateSingleValueProperty( final String typeName = javaTypeName(typeToken.encoding().primitiveType()); final String formattedPropertyName = formatPropertyName(propertyName); final String fieldName = formatFieldName(propertyName); + + final String validateMethod = generateSingleValueValidateMethod( + classBuilder, + decoderClassName, + propertyName, + fieldToken, + typeToken, + indent, + typeName, + formattedPropertyName + ); + + classBuilder.appendField() + .append(indent).append("private ").append(typeName).append(" ").append(fieldName).append(";\n"); + + classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public ").append(typeName).append(" ") + .append(formattedPropertyName).append("()\n") + .append(indent).append("{\n") + .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") + .append(indent).append("}\n"); + + final StringBuilder setterBuilder = classBuilder.appendPublic().append("\n") + .append(generateDocumentation(indent, fieldToken)) + .append(indent).append("public void ").append(formattedPropertyName).append("(") + .append(typeName).append(" value)\n") + .append(indent).append("{\n"); + + if (null != validateMethod) + { + setterBuilder.append(indent).append(INDENT).append(validateMethod).append("(value);\n"); + } + + setterBuilder + .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") + .append(indent).append("}\n"); + } + + private static String generateSingleValueValidateMethod( + final ClassBuilder classBuilder, + final String decoderClassName, + final String propertyName, + final Token fieldToken, + final Token typeToken, + final String indent, + final String typeName, + final String formattedPropertyName) + { + final boolean mustPreventLesser = + nativeTypeRepresentsValuesLessThanValidRange(fieldToken, typeToken.encoding(), SIGNED_ONLY); + + final boolean mustPreventGreater = + nativeTypeRepresentsValuesGreaterThanValidRange(fieldToken, typeToken.encoding(), SIGNED_ONLY); + + if (!mustPreventLesser && !mustPreventGreater) + { + return null; + } + final String validateMethod = "validate" + toUpperFirstChar(propertyName); - final boolean representedWithinJavaType = typeToken.encoding().primitiveType() != PrimitiveType.UINT64; + final StringBuilder validateBuilder = classBuilder.appendPrivate().append("\n") + .append(indent).append("private static void ").append(validateMethod).append("(") + .append(typeName).append(" value)\n") + .append(indent).append("{\n"); - final StringBuilder validationCall = new StringBuilder(); + final boolean allowsNull = fieldToken.isOptionalEncoding(); - if (representedWithinJavaType) + if (allowsNull) { - final StringBuilder validateBuilder = classBuilder.appendPrivate().append("\n") - .append(indent).append("private static void ").append(validateMethod).append("(") - .append(typeName).append(" value)\n") - .append(indent).append("{\n"); + validateBuilder.append(indent).append(INDENT) + .append("if (value == ") + .append(decoderClassName).append(".").append(formattedPropertyName).append("NullValue())\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("return;\n") + .append(indent).append(INDENT) + .append("}\n\n"); + } + if (mustPreventLesser) + { validateBuilder.append(indent).append(INDENT) - .append("if (value < ") - .append(decoderClassName).append(".").append(formattedPropertyName).append("MinValue() || ") - .append("value").append(" > ") - .append(decoderClassName).append(".").append(formattedPropertyName).append("MaxValue())\n") + .append("if ("); + + generateGreaterThanExpression( + validateBuilder, + typeToken.encoding(), + decoderClassName + "." + formattedPropertyName + "MinValue()", + "value" + ); + + validateBuilder + .append(")\n") .append(indent).append(INDENT) .append("{\n") .append(indent).append(INDENT).append(INDENT) .append("throw new IllegalArgumentException(\"") .append(propertyName) - .append(": value is out of allowed range: \" + ") + .append(": value is below allowed minimum: \" + ") .append("value").append(");\n") .append(indent).append(INDENT) - .append("}\n") - .append(indent).append("}\n"); + .append("}\n\n"); + } - validationCall.append(indent).append(INDENT).append(validateMethod).append("(value);\n"); + if (mustPreventGreater) + { + validateBuilder.append(indent).append(INDENT) + .append("if ("); + + generateGreaterThanExpression( + validateBuilder, + typeToken.encoding(), + "value", + decoderClassName + "." + formattedPropertyName + "MaxValue()" + ); + + validateBuilder + .append(")\n") + .append(indent).append(INDENT) + .append("{\n") + .append(indent).append(INDENT).append(INDENT) + .append("throw new IllegalArgumentException(\"") + .append(propertyName) + .append(": value is above allowed maximum: \" + ") + .append("value").append(");\n") + .append(indent).append(INDENT) + .append("}\n\n"); } - classBuilder.appendField() - .append(indent).append("private ").append(typeName).append(" ").append(fieldName).append(";\n"); + validateBuilder.append(indent).append("}\n"); - classBuilder.appendPublic().append("\n") - .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("public ").append(typeName).append(" ") - .append(formattedPropertyName).append("()\n") - .append(indent).append("{\n") - .append(indent).append(INDENT).append("return this.").append(fieldName).append(";\n") - .append(indent).append("}\n"); + return validateMethod; + } - classBuilder.appendPublic().append("\n") - .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("public void ").append(formattedPropertyName).append("(") - .append(typeName).append(" value)\n") - .append(indent).append("{\n") - .append(validationCall) - .append(indent).append(INDENT).append("this.").append(fieldName).append(" = value;\n") - .append(indent).append("}\n"); + private static void generateGreaterThanExpression( + final StringBuilder builder, + final Encoding encoding, + final String lhs, + final String rhs) + { + if (encoding.primitiveType() == PrimitiveType.UINT64) + { + builder.append("Long.compareUnsigned(").append(lhs).append(", ").append(rhs).append(") > 0"); + } + else + { + builder.append(lhs).append(" > ").append(rhs); + } } private void generateConstPropertyMethods( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java index 4d81dc47b9..18001ae9fa 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java @@ -15,13 +15,13 @@ */ package uk.co.real_logic.sbe.json; -import org.agrona.DirectBuffer; -import org.agrona.PrintBufferUtil; import uk.co.real_logic.sbe.PrimitiveValue; import uk.co.real_logic.sbe.ir.Encoding; import uk.co.real_logic.sbe.ir.Token; import uk.co.real_logic.sbe.otf.TokenListener; import uk.co.real_logic.sbe.otf.Types; +import org.agrona.DirectBuffer; +import org.agrona.PrintBufferUtil; import java.io.UnsupportedEncodingException; import java.util.List; @@ -236,7 +236,7 @@ public void onVarData( final String str = charsetName != null ? new String(tempBuffer, 0, length, charsetName) : PrintBufferUtil.hexDump(tempBuffer); - escape(str); + Types.jsonEscape(str, output); doubleQuote(); next(); @@ -290,7 +290,7 @@ private void appendEncodingAsString( final long longValue = constOrNotPresentValue.longValue(); if (PrimitiveValue.NULL_VALUE_CHAR != longValue) { - escape(new String(new byte[]{ (byte)longValue }, characterEncoding)); + Types.jsonEscape(new String(new byte[] {(byte)longValue}, characterEncoding), output); } } catch (final UnsupportedEncodingException ex) @@ -300,7 +300,7 @@ private void appendEncodingAsString( } else { - escape(constOrNotPresentValue.toString()); + Types.jsonEscape(constOrNotPresentValue.toString(), output); } doubleQuote(); @@ -371,7 +371,7 @@ private void escapePrintableChar(final DirectBuffer buffer, final int index, fin final byte c = buffer.getByte(index + (i * elementSize)); if (c > 0) { - escape((char)c); + Types.jsonEscape((char)c, output); } else { @@ -467,22 +467,4 @@ private static long readEncodingAsLong( return Types.getLong(buffer, bufferIndex, typeToken.encoding()); } - - private void escape(final String str) - { - for (int i = 0, length = str.length(); i < length; i++) - { - escape(str.charAt(i)); - } - } - - private void escape(final char c) - { - if ('"' == c || '\\' == c || '\b' == c || '\f' == c || '\n' == c || '\r' == c || '\t' == c) - { - output.append('\\'); - } - - output.append(c); - } } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java index d9c64a2a2f..2d41cf22ba 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/Types.java @@ -15,10 +15,10 @@ */ package uk.co.real_logic.sbe.otf; -import org.agrona.DirectBuffer; import uk.co.real_logic.sbe.PrimitiveType; import uk.co.real_logic.sbe.PrimitiveValue; import uk.co.real_logic.sbe.ir.Encoding; +import org.agrona.DirectBuffer; import java.nio.ByteOrder; @@ -27,6 +27,11 @@ */ public class Types { + private static final char[] HEX_DIGIT = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + /** * Get an integer value from a buffer at a given index for a {@link PrimitiveType}. * @@ -187,7 +192,9 @@ public static void appendAsJsonString( switch (encoding.primitiveType()) { case CHAR: - sb.append('\'').append((char)buffer.getByte(index)).append('\''); + sb.append('\"'); + jsonEscape((char)buffer.getByte(index), sb); + sb.append('\"'); break; case INT8: @@ -227,15 +234,15 @@ public static void appendAsJsonString( final float value = buffer.getFloat(index, encoding.byteOrder()); if (Float.isNaN(value)) { - sb.append("0/0"); + sb.append("\"0/0\""); } else if (value == Float.POSITIVE_INFINITY) { - sb.append("1/0"); + sb.append("\"1/0\""); } else if (value == Float.NEGATIVE_INFINITY) { - sb.append("-1/0"); + sb.append("\"-1/0\""); } else { @@ -249,15 +256,15 @@ else if (value == Float.NEGATIVE_INFINITY) final double value = buffer.getDouble(index, encoding.byteOrder()); if (Double.isNaN(value)) { - sb.append("0/0"); + sb.append("\"0/0\""); } else if (value == Double.POSITIVE_INFINITY) { - sb.append("1/0"); + sb.append("\"1/0\""); } else if (value == Double.NEGATIVE_INFINITY) { - sb.append("-1/0"); + sb.append("\"-1/0\""); } else { @@ -280,7 +287,9 @@ public static void appendAsJsonString(final StringBuilder sb, final PrimitiveVal switch (encoding.primitiveType()) { case CHAR: - sb.append('\'').append((char)value.longValue()).append('\''); + sb.append('\"'); + jsonEscape((char)value.longValue(), sb); + sb.append('\"'); break; case INT8: @@ -299,15 +308,15 @@ public static void appendAsJsonString(final StringBuilder sb, final PrimitiveVal final float floatValue = (float)value.doubleValue(); if (Float.isNaN(floatValue)) { - sb.append("0/0"); + sb.append("\"0/0\""); } else if (floatValue == Float.POSITIVE_INFINITY) { - sb.append("1/0"); + sb.append("\"1/0\""); } else if (floatValue == Float.NEGATIVE_INFINITY) { - sb.append("-1/0"); + sb.append("\"-1/0\""); } else { @@ -321,15 +330,15 @@ else if (floatValue == Float.NEGATIVE_INFINITY) final double doubleValue = value.doubleValue(); if (Double.isNaN(doubleValue)) { - sb.append("0/0"); + sb.append("\"0/0\""); } else if (doubleValue == Double.POSITIVE_INFINITY) { - sb.append("1/0"); + sb.append("\"1/0\""); } else if (doubleValue == Double.NEGATIVE_INFINITY) { - sb.append("-1/0"); + sb.append("\"-1/0\""); } else { @@ -339,4 +348,70 @@ else if (doubleValue == Double.NEGATIVE_INFINITY) } } } + + /** + * Escape a string for use in a JSON string. + * + * @param str the string to escape + * @param output to append the escaped string to + */ + public static void jsonEscape(final String str, final StringBuilder output) + { + for (int i = 0, length = str.length(); i < length; i++) + { + jsonEscape(str.charAt(i), output); + } + } + + /** + * Escape a character for use in a JSON string. + * + * @param c the character to escape + * @param output to append the escaped character to + */ + public static void jsonEscape(final char c, final StringBuilder output) + { + if ('"' == c || '\\' == c) + { + output.append('\\'); + output.append(c); + } + else if ('\b' == c) + { + output.append("\\b"); + } + else if ('\f' == c) + { + output.append("\\f"); + } + else if ('\n' == c) + { + output.append("\\n"); + } + else if ('\r' == c) + { + output.append("\\r"); + } + else if ('\t' == c) + { + output.append("\\t"); + } + else if (c <= 0x1F || Character.isHighSurrogate(c) || Character.isLowSurrogate(c)) + { + jsonUnicodeEncode(c, output); + } + else + { + output.append(c); + } + } + + private static void jsonUnicodeEncode(final char c, final StringBuilder output) + { + output.append('\\').append('u') + .append(HEX_DIGIT[(c >>> 12) & 0x0F]) + .append(HEX_DIGIT[(c >>> 8) & 0x0F]) + .append(HEX_DIGIT[(c >>> 4) & 0x0F]) + .append(HEX_DIGIT[c & 0x0F]); + } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java index 04e1d8fdae..ba37558242 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/DtosPropertyTest.java @@ -31,25 +31,22 @@ import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; import uk.co.real_logic.sbe.properties.utils.InMemoryOutputManager; import org.agrona.*; -import org.agrona.concurrent.UnsafeBuffer; import org.agrona.io.DirectBufferInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.URLClassLoader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; -import java.util.Base64; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.fail; import static uk.co.real_logic.sbe.SbeTool.JAVA_DEFAULT_DECODING_BUFFER_TYPE; import static uk.co.real_logic.sbe.SbeTool.JAVA_DEFAULT_ENCODING_BUFFER_TYPE; +import static uk.co.real_logic.sbe.properties.PropertyTestUtil.addSchemaAndInputMessageFootnotes; @SuppressWarnings("ReadWriteStringCanBeUsed") @EnableFootnotes @@ -65,8 +62,7 @@ public class DtosPropertyTest void javaDtoEncodeShouldBeTheInverseOfDtoDecode( @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage, final Footnotes footnotes) - throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, - IllegalAccessException + throws Exception { final String packageName = encodedMessage.ir().applicableNamespace(); final InMemoryOutputManager outputManager = new InMemoryOutputManager(packageName); @@ -95,39 +91,36 @@ void javaDtoEncodeShouldBeTheInverseOfDtoDecode( fail("Code generation failed.", generationException); } - try (URLClassLoader generatedClassLoader = outputManager.compileGeneratedSources()) - { - final Class dtoClass = - generatedClassLoader.loadClass(packageName + ".TestMessageDto"); - - final Method decodeFrom = - dtoClass.getMethod("decodeFrom", DirectBuffer.class, int.class, int.class, int.class); - - final Method encodeWith = - dtoClass.getMethod("encodeWithHeaderWith", dtoClass, MutableDirectBuffer.class, int.class); - - final int inputLength = encodedMessage.length(); - final ExpandableArrayBuffer inputBuffer = encodedMessage.buffer(); - final MessageHeaderDecoder header = new MessageHeaderDecoder().wrap(inputBuffer, 0); - final int blockLength = header.blockLength(); - final int actingVersion = header.version(); - final Object dto = decodeFrom.invoke(null, - encodedMessage.buffer(), MessageHeaderDecoder.ENCODED_LENGTH, blockLength, actingVersion); - outputBuffer.setMemory(0, outputBuffer.capacity(), (byte)0); - final int outputLength = (int)encodeWith.invoke(null, dto, outputBuffer, 0); - if (!areEqual(inputBuffer, inputLength, outputBuffer, outputLength)) - { - fail("Input and output differ"); - } - } + final Class dtoClass = outputManager.compileAndLoad(packageName + ".TestMessageDto"); + + final Method decodeFrom = + dtoClass.getMethod("decodeFrom", DirectBuffer.class, int.class, int.class, int.class); + + final Method encodeWith = + dtoClass.getMethod("encodeWithHeaderWith", dtoClass, MutableDirectBuffer.class, int.class); + + final int inputLength = encodedMessage.length(); + final DirectBuffer inputBuffer = encodedMessage.buffer(); + final MessageHeaderDecoder header = new MessageHeaderDecoder().wrap(inputBuffer, 0); + final int blockLength = header.blockLength(); + final int actingVersion = header.version(); + final Object dto = decodeFrom.invoke( + null, + encodedMessage.buffer(), MessageHeaderDecoder.ENCODED_LENGTH, blockLength, actingVersion); + outputBuffer.setMemory(0, outputBuffer.capacity(), (byte)0); + final int outputLength = (int)encodeWith.invoke(null, dto, outputBuffer, 0); + assertEqual(inputBuffer, inputLength, outputBuffer, outputLength); } catch (final Throwable throwable) { - addInputFootnotes(footnotes, encodedMessage); + if (null != footnotes) + { + addSchemaAndInputMessageFootnotes(footnotes, encodedMessage); - final StringBuilder generatedSources = new StringBuilder(); - outputManager.dumpSources(generatedSources); - footnotes.addFootnote(generatedSources.toString()); + final StringBuilder generatedSources = new StringBuilder(); + outputManager.dumpSources(generatedSources); + footnotes.addFootnote(generatedSources.toString()); + } throw throwable; } @@ -180,14 +173,12 @@ void csharpDtoEncodeShouldBeTheInverseOfDtoDecode( if (!Arrays.equals(inputBytes, outputBytes)) { throw new AssertionError( - "Input and output files differ\n\n" + - "DIR:" + tempDir + "\n\n" + - "SCHEMA:\n" + encodedMessage.schema()); + "Input and output files differ\n\nDIR:" + tempDir); } } catch (final Throwable throwable) { - addInputFootnotes(footnotes, encodedMessage); + addSchemaAndInputMessageFootnotes(footnotes, encodedMessage); addGeneratedSourcesFootnotes(footnotes, tempDir, ".cs"); throw throwable; @@ -239,14 +230,12 @@ void cppDtoEncodeShouldBeTheInverseOfDtoDecode( final byte[] outputBytes = Files.readAllBytes(tempDir.resolve("output.dat")); if (!Arrays.equals(inputBytes, outputBytes)) { - throw new AssertionError( - "Input and output files differ\n\n" + - "SCHEMA:\n" + encodedMessage.schema()); + throw new AssertionError("Input and output files differ"); } } catch (final Throwable throwable) { - addInputFootnotes(footnotes, encodedMessage); + addSchemaAndInputMessageFootnotes(footnotes, encodedMessage); addGeneratedSourcesFootnotes(footnotes, tempDir, ".cpp"); throw throwable; @@ -319,9 +308,9 @@ private static void execute( @Provide Arbitrary encodedMessage() { - final SbeArbitraries.CharGenerationMode mode = - SbeArbitraries.CharGenerationMode.JSON_PRINTER_COMPATIBLE; - return SbeArbitraries.encodedMessage(mode); + final SbeArbitraries.CharGenerationConfig config = + SbeArbitraries.CharGenerationConfig.firstNullTerminatesCharArray(); + return SbeArbitraries.encodedMessage(config); } private static void copyResourceToFile( @@ -346,13 +335,46 @@ private static void copyResourceToFile( } } - private boolean areEqual( - final ExpandableArrayBuffer inputBuffer, + private static String readResourceFileAsString(final String resourcePath) throws IOException + { + try (InputStream inputStream = DtosPropertyTest.class.getResourceAsStream(resourcePath)) + { + if (inputStream == null) + { + throw new IllegalArgumentException("Resource not found: " + resourcePath); + } + + return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + } + } + + private void assertEqual( + final DirectBuffer inputBuffer, final int inputLength, - final ExpandableArrayBuffer outputBuffer, + final DirectBuffer outputBuffer, final int outputLength) { - return new UnsafeBuffer(inputBuffer, 0, inputLength).equals(new UnsafeBuffer(outputBuffer, 0, outputLength)); + final boolean lengthsDiffer = inputLength != outputLength; + final int minLength = Math.min(inputLength, outputLength); + + for (int i = 0; i < minLength; i++) + { + if (inputBuffer.getByte(i) != outputBuffer.getByte(i)) + { + throw new AssertionError( + "Input and output differ at byte " + i + ".\n" + + "Input length: " + inputLength + ", Output length: " + outputLength + "\n" + + "Input: " + inputBuffer.getByte(i) + ", Output: " + outputBuffer.getByte(i) + + (lengthsDiffer ? "\nLengths differ." : "")); + } + } + + if (lengthsDiffer) + { + throw new AssertionError( + "Input and output differ in length.\n" + + "Input length: " + inputLength + ", Output length: " + outputLength); + } } private void addGeneratedSourcesFootnotes( @@ -383,15 +405,4 @@ private void addGeneratedSourcesFootnotes( LangUtil.rethrowUnchecked(exn); } } - - public void addInputFootnotes(final Footnotes footnotes, final SbeArbitraries.EncodedMessage encodedMessage) - { - final byte[] messageBytes = new byte[encodedMessage.length()]; - encodedMessage.buffer().getBytes(0, messageBytes); - final byte[] base64EncodedMessageBytes = Base64.getEncoder().encode(messageBytes); - - footnotes.addFootnote("Schema:" + System.lineSeparator() + encodedMessage.schema()); - footnotes.addFootnote("Input Message:" + System.lineSeparator() + - new String(base64EncodedMessageBytes, StandardCharsets.UTF_8)); - } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java index ebac19703e..4837d267c7 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/JsonPropertyTest.java @@ -19,16 +19,23 @@ import net.jqwik.api.ForAll; import net.jqwik.api.Property; import net.jqwik.api.Provide; +import net.jqwik.api.footnotes.EnableFootnotes; +import net.jqwik.api.footnotes.Footnotes; import uk.co.real_logic.sbe.json.JsonPrinter; import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; import org.agrona.concurrent.UnsafeBuffer; import org.json.JSONException; import org.json.JSONObject; +import static uk.co.real_logic.sbe.properties.PropertyTestUtil.addSchemaAndInputMessageFootnotes; + public class JsonPropertyTest { @Property - void shouldGenerateValidJson(@ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage) + @EnableFootnotes + void shouldGenerateValidJson( + @ForAll("encodedMessage") final SbeArbitraries.EncodedMessage encodedMessage, + final Footnotes footnotes) { final StringBuilder output = new StringBuilder(); final JsonPrinter printer = new JsonPrinter(encodedMessage.ir()); @@ -39,15 +46,16 @@ void shouldGenerateValidJson(@ForAll("encodedMessage") final SbeArbitraries.Enco } catch (final JSONException e) { - throw new AssertionError("Invalid JSON: " + output + "\n\nSchema:\n" + encodedMessage.schema(), e); + addSchemaAndInputMessageFootnotes(footnotes, encodedMessage); + throw new AssertionError("Invalid JSON: " + output); } } @Provide Arbitrary encodedMessage() { - final SbeArbitraries.CharGenerationMode mode = - SbeArbitraries.CharGenerationMode.JSON_PRINTER_COMPATIBLE; - return SbeArbitraries.encodedMessage(mode); + final SbeArbitraries.CharGenerationConfig config = + SbeArbitraries.CharGenerationConfig.unrestricted(); + return SbeArbitraries.encodedMessage(config); } } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/PropertyTestUtil.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/PropertyTestUtil.java new file mode 100644 index 0000000000..e3c8c4e292 --- /dev/null +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/PropertyTestUtil.java @@ -0,0 +1,43 @@ +/* + * Copyright 2013-2025 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package uk.co.real_logic.sbe.properties; + +import net.jqwik.api.footnotes.Footnotes; +import uk.co.real_logic.sbe.properties.arbitraries.SbeArbitraries; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +final class PropertyTestUtil +{ + private PropertyTestUtil() + { + } + + static void addSchemaAndInputMessageFootnotes( + final Footnotes footnotes, + final SbeArbitraries.EncodedMessage encodedMessage) + { + final byte[] messageBytes = new byte[encodedMessage.length()]; + encodedMessage.buffer().getBytes(0, messageBytes); + final byte[] base64EncodedMessageBytes = Base64.getEncoder().encode(messageBytes); + + footnotes.addFootnote("Schema:" + System.lineSeparator() + encodedMessage.schema()); + footnotes.addFootnote("Input Message:" + System.lineSeparator() + + new String(base64EncodedMessageBytes, StandardCharsets.UTF_8)); + } +} diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java index c1dc232ee3..74bd2cc1da 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/arbitraries/SbeArbitraries.java @@ -29,9 +29,11 @@ import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.ParserOptions; import org.agrona.BitUtil; +import org.agrona.DirectBuffer; import org.agrona.ExpandableArrayBuffer; import org.agrona.MutableDirectBuffer; import org.agrona.collections.MutableInteger; +import org.agrona.concurrent.UnsafeBuffer; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -114,10 +116,30 @@ private static Arbitrary encodedDataTypeSchema() ).as(EncodedDataTypeSchema::new); } - public enum CharGenerationMode + public static class CharGenerationConfig { - UNRESTRICTED, - JSON_PRINTER_COMPATIBLE + private final boolean nullCharTerminatesData; + + public CharGenerationConfig( + final boolean nullCharTerminatesData) + { + this.nullCharTerminatesData = nullCharTerminatesData; + } + + boolean nullCharTerminatesData() + { + return nullCharTerminatesData; + } + + public static CharGenerationConfig unrestricted() + { + return new CharGenerationConfig(false); + } + + public static CharGenerationConfig firstNullTerminatesCharArray() + { + return new CharGenerationConfig(true); + } } private static Arbitrary enumTypeSchema() @@ -343,24 +365,42 @@ private static Arbitrary combineArbitraryEncoders(final List encodedTypeEncoder( + final Encoding encoding, + final boolean isOptional) + { + final Arbitrary inRangeEncoder = encodedTypeEncoder(encoding); - default: - throw new IllegalArgumentException("Unsupported mode: " + mode); + if (isOptional) + { + final Arbitrary nullEncoder = nullEncoder(encoding); + return Arbitraries.oneOf(inRangeEncoder, nullEncoder); + } + else + { + return inRangeEncoder; } } private static Arbitrary encodedTypeEncoder( - final Encoding encoding, - final CharGenerationMode charGenerationMode) + final Encoding encoding) { final PrimitiveValue minValue = encoding.applicableMinValue(); final PrimitiveValue maxValue = encoding.applicableMaxValue(); @@ -369,7 +409,7 @@ private static Arbitrary encodedTypeEncoder( { case CHAR: assert minValue.longValue() <= maxValue.longValue(); - return chars(charGenerationMode).map(c -> + return chars(encoding).map(c -> (builder, buffer, offset, limit) -> { builder.appendLine().append(c).append(" @ ").append(offset) @@ -458,13 +498,95 @@ private static Arbitrary encodedTypeEncoder( } } + private static Arbitrary nullEncoder(final Encoding encoding) + { + final PrimitiveValue nullValue = encoding.applicableNullValue(); + + switch (encoding.primitiveType()) + { + case CHAR: + return Arbitraries.just((char)nullValue.longValue()).map(c -> + (builder, buffer, offset, limit) -> + { + builder.appendLine().append(c).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_BYTE).append("]"); + buffer.putChar(offset, c, encoding.byteOrder()); + }); + + case UINT8: + case INT8: + return Arbitraries.just((short)nullValue.longValue()) + .map(b -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append((byte)(short)b).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_BYTE).append("]"); + buffer.putByte(offset, (byte)(short)b); + }); + + case UINT16: + case INT16: + return Arbitraries.just((int)nullValue.longValue()) + .map(s -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append((short)(int)s).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_SHORT).append("]"); + buffer.putShort(offset, (short)(int)s, encoding.byteOrder()); + }); + + case UINT32: + case INT32: + return Arbitraries.just(nullValue.longValue()) + .map(i -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append((int)(long)i).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_INT).append("]"); + buffer.putInt(offset, (int)(long)i, encoding.byteOrder()); + }); + + case UINT64: + case INT64: + return Arbitraries.just(nullValue.longValue()) + .map(l -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append(l).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_LONG).append("]"); + buffer.putLong(offset, l, encoding.byteOrder()); + }); + + case FLOAT: + return Arbitraries.just((float)nullValue.doubleValue()) + .map(f -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append(f).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_FLOAT).append("]"); + buffer.putFloat(offset, f, encoding.byteOrder()); + }); + + case DOUBLE: + return Arbitraries.just(nullValue.doubleValue()) + .map(d -> (builder, buffer, offset, limit) -> + { + builder.appendLine().append(d).append(" @ ").append(offset) + .append("[").append(BitUtil.SIZE_OF_DOUBLE).append("]"); + buffer.putDouble(offset, d, encoding.byteOrder()); + }); + + default: + throw new IllegalArgumentException("Unsupported type: " + encoding.primitiveType()); + } + } + private static Arbitrary encodedTypeEncoder( final int offset, + final Token memberToken, final Token typeToken, - final CharGenerationMode charGenerationMode) + final CharGenerationConfig charGenerationConfig) { final Encoding encoding = typeToken.encoding(); - final Arbitrary arbEncoder = encodedTypeEncoder(encoding, charGenerationMode); + final Arbitrary arbEncoder = encodedTypeEncoder( + encoding, + memberToken.isOptionalEncoding() + ); if (typeToken.arrayLength() == 1) { @@ -476,11 +598,28 @@ private static Arbitrary encodedTypeEncoder( return arbEncoder.list().ofSize(typeToken.arrayLength()) .map(encoders -> (builder, buffer, bufferOffset, limit) -> { + boolean hasNullTerminated = false; + for (int i = 0; i < typeToken.arrayLength(); i++) { builder.beginScope("[" + i + "]"); final int elementOffset = bufferOffset + offset + i * encoding.primitiveType().size(); - encoders.get(i).encode(builder, buffer, elementOffset, limit); + if (hasNullTerminated) + { + buffer.putByte(elementOffset, (byte)0); + } + else + { + encoders.get(i).encode(builder, buffer, elementOffset, limit); + } + + if (encoding.primitiveType() == PrimitiveType.CHAR && + charGenerationConfig.nullCharTerminatesData() && + buffer.getByte(elementOffset) == 0) + { + hasNullTerminated = true; + } + builder.endScope(); } }); @@ -548,6 +687,7 @@ private static Encoder integerValueEncoder(final Encoding encoding, final long v private static Arbitrary enumEncoder( final int offset, final List tokens, + final Token memberToken, final Token typeToken, final MutableInteger cursor, final int endIdxInclusive) @@ -569,7 +709,7 @@ private static Arbitrary enumEncoder( encoders.add(caseEncoder); } - if (encoders.isEmpty()) + if (memberToken.isOptionalEncoding() || encoders.isEmpty()) { final Encoder nullEncoder = integerValueEncoder( typeToken.encoding(), @@ -684,7 +824,7 @@ private static Arbitrary fieldsEncoder( final MutableInteger cursor, final int endIdxInclusive, final boolean expectFields, - final CharGenerationMode charGenerationMode) + final CharGenerationConfig charGenerationConfig) { final List> encoders = new ArrayList<>(); while (cursor.get() <= endIdxInclusive) @@ -718,7 +858,7 @@ else if (expectFields) final int endCompositeTokenCount = 1; final int lastMemberIdx = nextFieldIdx - endCompositeTokenCount - endFieldTokenCount - 1; final Arbitrary encoder = fieldsEncoder( - tokens, cursor, lastMemberIdx, false, charGenerationMode); + tokens, cursor, lastMemberIdx, false, charGenerationConfig); fieldEncoder = encoder.map(e -> (builder, buffer, bufferOffset, limit) -> e.encode(builder, buffer, bufferOffset + offset, limit)); @@ -727,7 +867,7 @@ else if (expectFields) case BEGIN_ENUM: final int endEnumTokenCount = 1; final int lastValidValueIdx = nextFieldIdx - endFieldTokenCount - endEnumTokenCount - 1; - fieldEncoder = enumEncoder(offset, tokens, typeToken, cursor, lastValidValueIdx); + fieldEncoder = enumEncoder(offset, tokens, memberToken, typeToken, cursor, lastValidValueIdx); break; case BEGIN_SET: @@ -737,7 +877,7 @@ else if (expectFields) break; case ENCODING: - fieldEncoder = encodedTypeEncoder(offset, typeToken, charGenerationMode); + fieldEncoder = encodedTypeEncoder(offset, memberToken, typeToken, charGenerationConfig); break; default: @@ -766,7 +906,7 @@ private static Arbitrary groupsEncoder( final List tokens, final MutableInteger cursor, final int endIdxInclusive, - final CharGenerationMode charGenerationMode) + final CharGenerationConfig charGenerationConfig) { final List> encoders = new ArrayList<>(); @@ -792,9 +932,9 @@ private static Arbitrary groupsEncoder( final Arbitrary groupElement = Combinators.combine( - fieldsEncoder(tokens, cursor, nextFieldIdx - 1, true, charGenerationMode), - groupsEncoder(tokens, cursor, nextFieldIdx - 1, charGenerationMode), - varDataEncoder(tokens, cursor, nextFieldIdx - 1, charGenerationMode) + fieldsEncoder(tokens, cursor, nextFieldIdx - 1, true, charGenerationConfig), + groupsEncoder(tokens, cursor, nextFieldIdx - 1, charGenerationConfig), + varDataEncoder(tokens, cursor, nextFieldIdx - 1) ).as((fieldsEncoder, groupsEncoder, varDataEncoder) -> (builder, buffer, ignored, limit) -> { @@ -843,8 +983,7 @@ private static Arbitrary groupsEncoder( private static Arbitrary varDataEncoder( final List tokens, final MutableInteger cursor, - final int endIdxInclusive, - final CharGenerationMode charGenerationMode) + final int endIdxInclusive) { final List> encoders = new ArrayList<>(); @@ -867,7 +1006,7 @@ private static Arbitrary varDataEncoder( final String characterEncoding = varDataToken.encoding().characterEncoding(); final Arbitrary arbitraryByte = null == characterEncoding ? Arbitraries.bytes() : - chars(charGenerationMode).map(c -> (byte)c.charValue()); + chars(varDataToken.encoding()).map(c -> (byte)c.charValue()); encoders.add(arbitraryByte.list() .ofMaxSize((int)Math.min(lengthToken.encoding().applicableMaxValue().longValue(), 260L)) .map(bytes -> (builder, buffer, ignored, limit) -> @@ -901,7 +1040,7 @@ private static Arbitrary varDataEncoder( private static Arbitrary messageValueEncoder( final Ir ir, final short messageId, - final CharGenerationMode charGenerationMode) + final CharGenerationConfig charGenerationConfig) { final List tokens = ir.getMessage(messageId); final MutableInteger cursor = new MutableInteger(1); @@ -913,11 +1052,11 @@ private static Arbitrary messageValueEncoder( } final Arbitrary fieldsEncoder = fieldsEncoder( - tokens, cursor, tokens.size() - 1, true, charGenerationMode); + tokens, cursor, tokens.size() - 1, true, charGenerationConfig); final Arbitrary groupsEncoder = groupsEncoder( - tokens, cursor, tokens.size() - 1, charGenerationMode); + tokens, cursor, tokens.size() - 1, charGenerationConfig); final Arbitrary varDataEncoder = varDataEncoder( - tokens, cursor, tokens.size() - 1, charGenerationMode); + tokens, cursor, tokens.size() - 1); return Combinators.combine(fieldsEncoder, groupsEncoder, varDataEncoder) .as((fields, groups, varData) -> (builder, buffer, offset, limit) -> { @@ -941,14 +1080,14 @@ public static final class EncodedMessage { private final String schema; private final Ir ir; - private final ExpandableArrayBuffer buffer; + private final DirectBuffer buffer; private final int length; private final String encodingLog; private EncodedMessage( final String schema, final Ir ir, - final ExpandableArrayBuffer buffer, + final DirectBuffer buffer, final int length, final String encodingLog) { @@ -969,7 +1108,7 @@ public Ir ir() return ir; } - public ExpandableArrayBuffer buffer() + public DirectBuffer buffer() { return buffer; } @@ -979,13 +1118,61 @@ public int length() return length; } + /** + * A log of the steps taken to encode the input message. This information is useful for debugging problems in + * the arbitrary message generator. + * + * @return a log of the steps taken to encode the message + */ + @SuppressWarnings("unused") public String encodingLog() { return encodingLog; } + + /** + * Takes the XML schema and Base64 input message from a (possibly shrunken) example and creates an + * {@link EncodedMessage} instance that can be used to drive property-based test logic. This data is output + * when a test fails. + * + * @param schemaXml the schema to use + * @param inputMessage the input message (as a base64 encoded string) + * @return an encoded message for use with property-based tests + */ + @SuppressWarnings("unused") + public static EncodedMessage fromDebugOutput( + final String schemaXml, + final String inputMessage) + { + try (InputStream in = new ByteArrayInputStream(schemaXml.getBytes(StandardCharsets.UTF_8))) + { + final ParserOptions options = ParserOptions.builder() + .suppressOutput(false) + .warningsFatal(true) + .stopOnError(true) + .build(); + final uk.co.real_logic.sbe.xml.MessageSchema parsedSchema = parse(in, options); + final Ir ir = new IrGenerator().generate(parsedSchema); + + final byte[] messageBytes = Base64.getDecoder().decode(inputMessage); + final UnsafeBuffer buffer = new UnsafeBuffer(messageBytes); + + return new EncodedMessage( + schemaXml, + ir, + buffer, + buffer.capacity(), + "" + ); + } + catch (final Exception exception) + { + throw new RuntimeException(exception); + } + } } - public static Arbitrary encodedMessage(final CharGenerationMode mode) + public static Arbitrary encodedMessage(final CharGenerationConfig charGenerationConfig) { return SbeArbitraries.messageSchema().flatMap(testSchema -> { @@ -999,7 +1186,7 @@ public static Arbitrary encodedMessage(final CharGenerationMode .build(); final uk.co.real_logic.sbe.xml.MessageSchema parsedSchema = parse(in, options); final Ir ir = new IrGenerator().generate(parsedSchema); - return SbeArbitraries.messageValueEncoder(ir, testSchema.templateId(), mode) + return SbeArbitraries.messageValueEncoder(ir, testSchema.templateId(), charGenerationConfig) .map(encoder -> { final EncodingLogger logger = new EncodingLogger(); diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java index 5dc4569db2..141e7e469b 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/schema/TestXmlSchemaWriter.java @@ -15,12 +15,17 @@ */ package uk.co.real_logic.sbe.properties.schema; +import uk.co.real_logic.sbe.ir.Encoding; import org.agrona.collections.MutableInteger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; -import uk.co.real_logic.sbe.ir.Encoding; +import java.io.File; +import java.io.StringWriter; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; @@ -28,11 +33,6 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import java.io.File; -import java.io.StringWriter; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; import static java.util.Objects.requireNonNull; @@ -355,7 +355,6 @@ private static void appendTypes( } } - @SuppressWarnings("EnhancedSwitchMigration") private static final class TypeSchemaConverter implements TypeSchemaVisitor { private final Document document; @@ -465,7 +464,8 @@ public Node convert(final VarDataSchema varData) final Element varDataElement = createTypeElement(document, "varData", "uint8"); varDataElement.setAttribute("length", "0"); - if (varData.dataEncoding().equals(VarDataSchema.Encoding.ASCII)) + final VarDataSchema.Encoding encoding = varData.dataEncoding(); + if (encoding.equals(VarDataSchema.Encoding.ASCII)) { varDataElement.setAttribute("characterEncoding", "US-ASCII"); } diff --git a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java index 065737c57e..403c64b068 100644 --- a/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java +++ b/sbe-tool/src/propertyTest/java/uk/co/real_logic/sbe/properties/utils/InMemoryOutputManager.java @@ -15,17 +15,14 @@ */ package uk.co.real_logic.sbe.properties.utils; +import org.agrona.generation.CompilerUtil; import org.agrona.generation.DynamicPackageOutputManager; -import javax.tools.*; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; -import java.net.URI; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.*; +import java.util.HashMap; +import java.util.Map; /** * An implementation of {@link DynamicPackageOutputManager} that stores generated source code in memory and compiles it @@ -34,7 +31,7 @@ public class InMemoryOutputManager implements DynamicPackageOutputManager { private final String packageName; - private final Map sourceFiles = new HashMap<>(); + private final Map sources = new HashMap<>(); private String packageNameOverride; public InMemoryOutputManager(final String packageName) @@ -53,42 +50,32 @@ public void setPackageName(final String packageName) } /** - * Compile the generated sources and return a {@link URLClassLoader} that can be used to load the generated classes. + * Compile the generated sources and return a {@link Class} matching the supplied fully-qualified name. * - * @return a {@link URLClassLoader} that can be used to load the generated classes + * @param fqClassName the fully-qualified class name to compile and load. + * @return a {@link Class} matching the supplied fully-qualified name. */ - public URLClassLoader compileGeneratedSources() + public Class compileAndLoad(final String fqClassName) { - final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - final StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null); - final InMemoryFileManager fileManager = new InMemoryFileManager(standardFileManager); - final JavaCompiler.CompilationTask task = compiler.getTask( - null, - fileManager, - null, - null, - null, - sourceFiles.values()); - - if (!task.call()) + try { - throw new IllegalStateException("Compilation failed"); + return CompilerUtil.compileInMemory(fqClassName, sources); + } + catch (final Exception exception) + { + throw new RuntimeException(exception); } - - final GeneratedCodeLoader classLoader = new GeneratedCodeLoader(getClass().getClassLoader()); - classLoader.defineClasses(fileManager); - return classLoader; } public void dumpSources(final StringBuilder builder) { - builder.append(System.lineSeparator()).append("Generated sources file count: ").append(sourceFiles.size()) + builder.append(System.lineSeparator()).append("Generated sources file count: ").append(sources.size()) .append(System.lineSeparator()); - sourceFiles.forEach((qualifiedName, file) -> + sources.forEach((qualifiedName, source) -> { builder.append(System.lineSeparator()).append("Source file: ").append(qualifiedName) - .append(System.lineSeparator()).append(file.sourceCode) + .append(System.lineSeparator()).append(source) .append(System.lineSeparator()); }); } @@ -109,93 +96,14 @@ public void close() throws IOException packageNameOverride = null; final String qualifiedName = actingPackageName + "." + name; - final InMemoryJavaFileObject sourceFile = - new InMemoryJavaFileObject(qualifiedName, getBuffer().toString()); - final InMemoryJavaFileObject existingFile = sourceFiles.putIfAbsent(qualifiedName, sourceFile); + final String source = getBuffer().toString(); + final CharSequence existingSource = sources.putIfAbsent(qualifiedName, source); - if (existingFile != null && !Objects.equals(existingFile.sourceCode, sourceFile.sourceCode)) + if (null != existingSource && 0 != CharSequence.compare(existingSource, source)) { throw new IllegalStateException("Duplicate (but different) class: " + qualifiedName); } } } - - static class InMemoryFileManager extends ForwardingJavaFileManager - { - private final List outputFiles = new ArrayList<>(); - - InMemoryFileManager(final StandardJavaFileManager fileManager) - { - super(fileManager); - } - - public JavaFileObject getJavaFileForOutput( - final Location location, - final String className, - final JavaFileObject.Kind kind, - final FileObject sibling) - { - final InMemoryJavaFileObject outputFile = new InMemoryJavaFileObject(className, kind); - outputFiles.add(outputFile); - return outputFile; - } - - public Collection outputFiles() - { - return outputFiles; - } - } - - static class InMemoryJavaFileObject extends SimpleJavaFileObject - { - private final String sourceCode; - private final ByteArrayOutputStream outputStream; - - InMemoryJavaFileObject(final String className, final String sourceCode) - { - super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); - this.sourceCode = sourceCode; - this.outputStream = new ByteArrayOutputStream(); - } - - InMemoryJavaFileObject(final String className, final Kind kind) - { - super(URI.create("mem:///" + className.replace('.', '/') + kind.extension), kind); - this.sourceCode = null; - this.outputStream = new ByteArrayOutputStream(); - } - - public CharSequence getCharContent(final boolean ignoreEncodingErrors) - { - return sourceCode; - } - - public ByteArrayOutputStream openOutputStream() - { - return outputStream; - } - - public byte[] getClassBytes() - { - return outputStream.toByteArray(); - } - } - - static class GeneratedCodeLoader extends URLClassLoader - { - GeneratedCodeLoader(final ClassLoader parent) - { - super(new URL[0], parent); - } - - void defineClasses(final InMemoryFileManager fileManager) - { - fileManager.outputFiles().forEach(file -> - { - final byte[] classBytes = file.getClassBytes(); - super.defineClass(null, classBytes, 0, classBytes.length); - }); - } - } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/common/DtoValidationUtilTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/common/DtoValidationUtilTest.java new file mode 100644 index 0000000000..ea6d19e5fa --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/common/DtoValidationUtilTest.java @@ -0,0 +1,105 @@ +/* + * Copyright 2013-2025 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.common; + +import uk.co.real_logic.sbe.PrimitiveType; +import uk.co.real_logic.sbe.PrimitiveValue; +import uk.co.real_logic.sbe.ir.Encoding; +import uk.co.real_logic.sbe.ir.Token; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.nativeTypeRepresentsValuesGreaterThanValidRange; +import static uk.co.real_logic.sbe.generation.common.DtoValidationUtil.nativeTypeRepresentsValuesLessThanValidRange; + +public class DtoValidationUtilTest +{ + @ParameterizedTest + @CsvSource({ + "int8,SIGNED_AND_UNSIGNED,false,-128,-127,127,true,false", + "int8,SIGNED_AND_UNSIGNED,true,-128,-127,127,false,false", + "int8,SIGNED_ONLY,false,-128,-127,127,true,false", + "int8,SIGNED_ONLY,true,-128,-127,127,false,false", + + "int8,SIGNED_AND_UNSIGNED,false,127,-128,126,false,true", + "int8,SIGNED_AND_UNSIGNED,true,127,-128,126,false,false", + "int8,SIGNED_ONLY,false,127,-128,126,false,true", + "int8,SIGNED_ONLY,true,127,-128,126,false,false", + + "int8,SIGNED_ONLY,true,-128,-100,127,true,false", + "int8,SIGNED_ONLY,true,127,-128,100,false,true", + + "int8,SIGNED_ONLY,true,0,-128,127,false,false", + "int8,SIGNED_ONLY,true,0,-127,127,true,false", + "int8,SIGNED_ONLY,true,0,-128,126,false,true", + "int8,SIGNED_ONLY,true,0,-127,126,true,true", + + "uint8,SIGNED_AND_UNSIGNED,false,255,0,254,false,true", + "uint8,SIGNED_AND_UNSIGNED,true,255,0,254,false,false", + "uint8,SIGNED_ONLY,false,255,0,254,true,true", + "uint8,SIGNED_ONLY,true,255,0,254,true,true", + + "float,SIGNED_AND_UNSIGNED,false,-2,-1,1,true,true", + "float,SIGNED_AND_UNSIGNED,true,-2,-1,1,true,true", + "float,SIGNED_ONLY,false,-2,-1,1,true,true", + "float,SIGNED_ONLY,true,-2,-1,1,true,true", + + "uint64,SIGNED_AND_UNSIGNED,true,18446744073709551615,0,18446744073709551614,false,false", + "uint64,SIGNED_AND_UNSIGNED,true,18446744073709551615,1,18446744073709551614,true,false", + "uint64,SIGNED_AND_UNSIGNED,true,18446744073709551615,0,18446744073709551613,false,true", + "uint64,SIGNED_AND_UNSIGNED,true,18446744073709551615,1,18446744073709551613,true,true", + "uint64,SIGNED_ONLY,true,18446744073709551615,0,18446744073709551614,false,false", + "uint64,SIGNED_ONLY,true,18446744073709551615,1,18446744073709551614,true,false", + "uint64,SIGNED_ONLY,true,18446744073709551615,0,18446744073709551613,false,true", + "uint64,SIGNED_ONLY,true,18446744073709551615,1,18446744073709551613,true,true", + }) + void shouldGenerateValidationBasedOnNativeRangeVersusSbeTypeRange( + final String type, + final DtoValidationUtil.NativeIntegerSupport integerSupport, + final boolean isOptional, + final String nullValue, + final String minValue, + final String maxValue, + final boolean shouldValidateBelow, + final boolean shouldValidateAbove) + { + final Token fieldToken = mock(Token.class); + when(fieldToken.isOptionalEncoding()).thenReturn(isOptional); + final Encoding encoding = mock(Encoding.class); + final PrimitiveType primitiveType = PrimitiveType.get(type); + when(encoding.primitiveType()).thenReturn(primitiveType); + when(encoding.applicableNullValue()).thenReturn(PrimitiveValue.parse(nullValue, primitiveType)); + when(encoding.applicableMinValue()).thenReturn(PrimitiveValue.parse(minValue, primitiveType)); + when(encoding.applicableMaxValue()).thenReturn(PrimitiveValue.parse(maxValue, primitiveType)); + + final boolean validatesBelow = + nativeTypeRepresentsValuesLessThanValidRange(fieldToken, encoding, integerSupport); + + final boolean validatesAbove = + nativeTypeRepresentsValuesGreaterThanValidRange(fieldToken, encoding, integerSupport); + + assertEquals( + shouldValidateBelow, validatesBelow, + shouldValidateBelow ? "should" : "should not" + " validate below"); + + assertEquals( + shouldValidateAbove, validatesAbove, + shouldValidateAbove ? "should" : "should not" + " validate above"); + } +} From b69c9a596ff33e301c3f991966f77c503e8537b5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:49:22 +0200 Subject: [PATCH 602/805] [Doc] Release notes. --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4e3935a1f..50bd456c45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [1.35.5] - 2025-06-20 +### Changed +* **Java/C++/C#:** Fix a bug in overzealous DTO validation. ([#1073](https://github.com/aeron-io/simple-binary-encoding/pull/1073)) +* **Java:** Bump `Agrona` to 2.2.3. + ## [1.35.4] - 2025-06-12 ### Changed * **Rust:** Return None for optional primite field if its version is less than actingVersion. ([#1067](https://github.com/aeron-io/simple-binary-encoding/pull/1067)) @@ -88,6 +93,7 @@ * **Java:** Prevent collision when field name is 'value'. * **Java:** Preserve byte order throughout IR transformations. +[1.35.5]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.5 [1.35.4]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.4 [1.35.3]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.3 [1.35.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.1 From 4f62d954c7c9bdbe14e09ed0f38e9da5580679d8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:51:19 +0200 Subject: [PATCH 603/805] [Java] Bump `Aeron` to 2.2.3. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 710f76675a..cfc804dd83 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.2.2" +agrona = "2.2.3" checkstyle = "10.25.0" commons-codec = "1.15" commons-lang3 = "3.8.1" From 6349140e35d5de2e580a10932eab47d818c6da7e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:53:07 +0200 Subject: [PATCH 604/805] 1.35.5 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index aa69911fd7..00bedd1702 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.0-SNAPSHOT +1.35.5 From 0305c5535304cf50588fef3c709d7b354f49a0da Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 11:53:18 +0200 Subject: [PATCH 605/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 00bedd1702..aa69911fd7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.5 +1.36.0-SNAPSHOT From 752febe85ce13360c0f90addf656cd1c99c51ded Mon Sep 17 00:00:00 2001 From: Zach Bray Date: Fri, 20 Jun 2025 15:59:33 +0100 Subject: [PATCH 606/805] [Java] Update CHANGELOG. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50bd456c45..8d8faf7862 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [1.35.5] - 2025-06-20 ### Changed * **Java/C++/C#:** Fix a bug in overzealous DTO validation. ([#1073](https://github.com/aeron-io/simple-binary-encoding/pull/1073)) +* **Java:** Improve JsonPrinter's conformance with the JSON specification (e.g., escaping control characters and using correct delimiters). * **Java:** Bump `Agrona` to 2.2.3. ## [1.35.4] - 2025-06-12 From 13a817f2de93ab5b49e43e8d490a7fcfb8d2038c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:50:04 +0200 Subject: [PATCH 607/805] [Java] Bump `Checkstyle` to 10.25.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cfc804dd83..f756f6bab6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.2.3" -checkstyle = "10.25.0" +checkstyle = "10.25.1" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From ac59f8ef5ab75f8e10f98050bf9aa86dde8478ff Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:50:10 +0200 Subject: [PATCH 608/805] [Java] Bump `Shadow` to 8.3.7. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f756f6bab6..42006b8ffc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20250517" junit = "5.13.1" mockito = "5.18.0" plexus = "3.3.0" -shadow = "8.3.6" +shadow = "8.3.7" versions = "0.52.0" [libraries] From da6a8b46387bb233947ac5740879dbbd2936d820 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:17:01 +0100 Subject: [PATCH 609/805] [Java] Bump `Checkstyle` to 10.26.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 42006b8ffc..df856dc33d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.2.3" -checkstyle = "10.25.1" +checkstyle = "10.26.0" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 3b286f60993e3d8cbddc9857950dcc6c3785d2ec Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:17:08 +0100 Subject: [PATCH 610/805] [Java] Bump `JUnit` to 5.13.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index df856dc33d..4af934928b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" json = "20250517" -junit = "5.13.1" +junit = "5.13.2" mockito = "5.18.0" plexus = "3.3.0" shadow = "8.3.7" From 4cb504c7c9eb1742913be853f3859173d075c5e8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:55:54 +0100 Subject: [PATCH 611/805] [Java] Bump `Agrona` to 2.2.4. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4af934928b..cbfcbd0645 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.2.3" +agrona = "2.2.4" checkstyle = "10.26.0" commons-codec = "1.15" commons-lang3 = "3.8.1" From 041c5bb948676b6d275388d151068f6107f3f658 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:56:16 +0100 Subject: [PATCH 612/805] 1.35.6 released. --- CHANGELOG.md | 8 ++++++++ version.txt | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d8faf7862..b9e90464f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.35.6] - 2025-06-27 +### Changed +* **Java:** Bump `Agrona` to [2.2.4](https://github.com/aeron-io/agrona/releases/tag/2.2.4). +* **Java:** Bump `JUnit` to 5.13.2. +* **Java:** Bump `Checkstyle` to 10.26.0. +* **Java:** Bump `Shadow` to 8.3.7. + ## [1.35.5] - 2025-06-20 ### Changed * **Java/C++/C#:** Fix a bug in overzealous DTO validation. ([#1073](https://github.com/aeron-io/simple-binary-encoding/pull/1073)) @@ -94,6 +101,7 @@ * **Java:** Prevent collision when field name is 'value'. * **Java:** Preserve byte order throughout IR transformations. +[1.35.6]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.6 [1.35.5]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.5 [1.35.4]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.4 [1.35.3]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.3 diff --git a/version.txt b/version.txt index aa69911fd7..21cbe96c2d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.0-SNAPSHOT +1.35.6 From beea0b2cd0ce83e3a24262ba8f37f9d945be5c72 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:56:47 +0100 Subject: [PATCH 613/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 21cbe96c2d..aa69911fd7 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.35.6 +1.36.0-SNAPSHOT From f91958164d86371bf99e3a09d730a4095b58ee45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20L=C3=B6vhall?= Date: Wed, 16 Jul 2025 10:35:34 +0200 Subject: [PATCH 614/805] [C++] add getter for schema id on the IrDecoder (#1077) --- sbe-tool/src/main/cpp/otf/IrDecoder.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index 2c497d29ad..947d5c31e3 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -137,6 +137,10 @@ class IrDecoder return result; } + int schemaId() const { + return m_id; + } + protected: // OS specifics static long long getFileSize(const char *filename) From 84193793c901cd6143ae6f9e6d433b5f421b4299 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:58:09 +0200 Subject: [PATCH 615/805] [Java] Bump `Checkstyle` to 10.26.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cbfcbd0645..66d5b6d2d4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.2.4" -checkstyle = "10.26.0" +checkstyle = "10.26.1" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 761913ce82241a3bb911d0f24cccf90662e0e6c6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:58:19 +0200 Subject: [PATCH 616/805] [Java] Bump `JUnit` to 5.13.3. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 66d5b6d2d4..946d7cd310 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" json = "20250517" -junit = "5.13.2" +junit = "5.13.3" mockito = "5.18.0" plexus = "3.3.0" shadow = "8.3.7" From 7978f394aeffed1e9978cd895747d4b9cc8b77f3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:58:27 +0200 Subject: [PATCH 617/805] [Java] Bump `Shadow` to 8.3.8. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 946d7cd310..fb3d1964ae 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20250517" junit = "5.13.3" mockito = "5.18.0" plexus = "3.3.0" -shadow = "8.3.7" +shadow = "8.3.8" versions = "0.52.0" [libraries] From e93cc1a3205496e64769acdc9658af4373242510 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:59:01 +0200 Subject: [PATCH 618/805] [Java] Bump `Gradle` to 8.14.3. --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index be2dc79a8a..7705927e94 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 66c4dc1153b69e78d284198941848c67b38eb96c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 25 Jul 2025 11:52:55 +0200 Subject: [PATCH 619/805] [Java] Bump `JUnit` to 5.13.4. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fb3d1964ae..d892c475d4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" json = "20250517" -junit = "5.13.3" +junit = "5.13.4" mockito = "5.18.0" plexus = "3.3.0" shadow = "8.3.8" From e3d6d4b20ac03a7719c5d52e7ec217b300f5b120 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 9 Aug 2025 13:24:16 +0300 Subject: [PATCH 620/805] [Java] Bump `Checkstyle` to 11.0.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d892c475d4..3be9f4f5e3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.2.4" -checkstyle = "10.26.1" +checkstyle = "11.0.0" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 547d5330786a08b3eead10459bfb85f257fcf1bb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 9 Aug 2025 13:24:42 +0300 Subject: [PATCH 621/805] [Java] Bump `Shadow` to 9.0.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3be9f4f5e3..0e11ed13a6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20250517" junit = "5.13.4" mockito = "5.18.0" plexus = "3.3.0" -shadow = "8.3.8" +shadow = "9.0.1" versions = "0.52.0" [libraries] From 99db50237bf6cc50a5ab5559818871685def2ed7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 9 Aug 2025 13:25:07 +0300 Subject: [PATCH 622/805] [Java] Bump `Gradle` to 9.0.0. --- gradle/wrapper/gradle-wrapper.jar | Bin 43764 -> 45457 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55baabb587c669f562ae36f953de2481846..8bdaf60c75ab801e22807dde59e12a8735a34077 100644 GIT binary patch delta 37256 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 delta 35551 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7705927e94..48b43d3506 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a9367..ef07e0162b 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From e514ca27f77573401f4fcba8195c0cbc69a61f88 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:47:10 +0200 Subject: [PATCH 623/805] [Java] Bump `Shadow` to 9.0.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0e11ed13a6..90edf96058 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20250517" junit = "5.13.4" mockito = "5.18.0" plexus = "3.3.0" -shadow = "9.0.1" +shadow = "9.0.2" versions = "0.52.0" [libraries] From 3d270481a6a3d011794b652d5c965658520e65a8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 18 Aug 2025 11:47:21 +0200 Subject: [PATCH 624/805] [Java] Bump `Mockito` to 5.19.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90edf96058..e79e4ccdbf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ jqwik = "1.9.3" jmh = "1.37" json = "20250517" junit = "5.13.4" -mockito = "5.18.0" +mockito = "5.19.0" plexus = "3.3.0" shadow = "9.0.2" versions = "0.52.0" From 7816d6bf376d46096b77bd44b177b552af63b521 Mon Sep 17 00:00:00 2001 From: Peter Veentjer Date: Mon, 25 Aug 2025 13:39:35 +0300 Subject: [PATCH 625/805] Replaced empty array creation by Array.Empty (#1080) to prevent creating any objects when not needed. Fixes the following issue: https://github.com/aeron-io/simple-binary-encoding/issues/1079 --- .../co/real_logic/sbe/generation/csharp/CSharpGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index b6fd5d7746..a5dc0b2354 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -1141,7 +1141,7 @@ private CharSequence generateArrayProperty( generateDocumentation(indent, fieldToken), typeName, propName, offset, generateArrayFieldNotPresentCondition(fieldToken.version(), - indent + INDENT + INDENT, "new " + typeName + "[0]"), + indent + INDENT + INDENT, "System.Array.Empty<" + typeName + ">()"), accessOrderListenerCallDoubleIndent)); sb.append(String.format("\n" + @@ -1155,7 +1155,7 @@ private CharSequence generateArrayProperty( generateDocumentation(indent, fieldToken), typeName, propName, offset, generateArrayFieldNotPresentCondition(fieldToken.version(), - indent + INDENT + INDENT, "new " + typeName + "[0]"), + indent + INDENT + INDENT, "System.Array.Empty<" + typeName + ">()"), accessOrderListenerCall)); if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) From 552b4474bee8a226e5f42dd0a0b09682d268967a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 25 Aug 2025 17:49:13 +0200 Subject: [PATCH 626/805] [Java] Add test showing that DTO generator handles constants correctly. --- build.gradle | 3 +- .../sbe/generation/java/DtoTest.java | 35 +++++++++++- .../src/test/resources/dto-test-schema.xml | 57 +++++++++++++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index b349fe2528..13cf19ba9b 100644 --- a/build.gradle +++ b/build.gradle @@ -355,8 +355,9 @@ project(':sbe-tool') { 'sbe.validation.xsd': validationXsdPath, 'sbe.generate.precedence.checks': 'true', 'sbe.java.precedence.checks.property.name': 'sbe.enable.test.precedence.checks', + 'sbe.keyword.append.token': 'KeywordSuffix', 'sbe.java.generate.dtos': 'true') - args = ['src/test/resources/example-extension-schema.xml'] + args = ['src/test/resources/example-extension-schema.xml', 'src/test/resources/dto-test-schema.xml'] } jar { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java index 56d6869199..ecc05a9071 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java @@ -16,13 +16,21 @@ package uk.co.real_logic.sbe.generation.java; -import extension.*; +import dto_test.KeywordsDto; +import dto_test.KeywordsEncoder; +import extension.BooleanType; +import extension.BoostType; +import extension.CarDecoder; +import extension.CarDto; +import extension.CarEncoder; +import extension.Model; import org.agrona.ExpandableArrayBuffer; import org.agrona.MutableDirectBuffer; import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; public class DtoTest { @@ -65,6 +73,31 @@ void shouldRoundTripCar2() assertThat(outputBuffer.byteArray(), equalTo(inputBuffer.byteArray())); } + @Test + void dtoWithKeywords() + { + final KeywordsDto dto = new KeywordsDto(); + dto.assertKeywordSuffix((short)42); + dto.finalKeywordSuffix((short)7); + final ExpandableArrayBuffer input = new ExpandableArrayBuffer(); + final KeywordsEncoder encoder = new KeywordsEncoder(); + encoder.wrap(input, 0); + + KeywordsDto.encodeWith(encoder, dto); + + final byte[] originalBytes = new byte[encoder.encodedLength()]; + input.getBytes(0, originalBytes); + + final KeywordsDto otherDto = + KeywordsDto.decodeFrom(input, 0, KeywordsEncoder.SCHEMA_VERSION, KeywordsEncoder.BLOCK_LENGTH); + KeywordsDto.encodeWith(encoder, otherDto); + + final byte[] otherBytes = new byte[encoder.encodedLength()]; + input.getBytes(0, otherBytes); + + assertArrayEquals(originalBytes, otherBytes); + } + private static int encodeCar(final MutableDirectBuffer buffer, final int offset) { final CarEncoder car = new CarEncoder(); diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml index f6f832e990..fd24bf941d 100644 --- a/sbe-tool/src/test/resources/dto-test-schema.xml +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -107,4 +107,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 46328f70053c11d6360bb6c3b99b67a7635935a6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 26 Aug 2025 10:36:20 +0200 Subject: [PATCH 627/805] [Java] Update the test to use shorter suffix and mixed case characters. --- build.gradle | 2 +- .../sbe/generation/java/DtoTest.java | 7 +- .../src/test/resources/dto-test-schema.xml | 109 +++++++++--------- 3 files changed, 61 insertions(+), 57 deletions(-) diff --git a/build.gradle b/build.gradle index 13cf19ba9b..90102a340e 100644 --- a/build.gradle +++ b/build.gradle @@ -355,7 +355,7 @@ project(':sbe-tool') { 'sbe.validation.xsd': validationXsdPath, 'sbe.generate.precedence.checks': 'true', 'sbe.java.precedence.checks.property.name': 'sbe.enable.test.precedence.checks', - 'sbe.keyword.append.token': 'KeywordSuffix', + 'sbe.keyword.append.token': '$', 'sbe.java.generate.dtos': 'true') args = ['src/test/resources/example-extension-schema.xml', 'src/test/resources/dto-test-schema.xml'] } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java index ecc05a9071..36b32e1b73 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java @@ -77,8 +77,11 @@ void shouldRoundTripCar2() void dtoWithKeywords() { final KeywordsDto dto = new KeywordsDto(); - dto.assertKeywordSuffix((short)42); - dto.finalKeywordSuffix((short)7); + dto.assert$((byte)42); + dto.final$((byte)7); + dto.abstract$((byte)-81); + dto.false$((byte)0); + dto.falsE((byte)1); final ExpandableArrayBuffer input = new ExpandableArrayBuffer(); final KeywordsEncoder encoder = new KeywordsEncoder(); encoder.wrap(input, 0); diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml index fd24bf941d..f3ff272e97 100644 --- a/sbe-tool/src/test/resources/dto-test-schema.xml +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -109,59 +109,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From cb4eb1fd180594153f30fdf01a2c1489ead4259f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 26 Aug 2025 10:43:47 +0200 Subject: [PATCH 628/805] [Java] Fix C++ build by using `X` as a unique suffix for keywords. --- sbe-tool/src/test/cpp/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 53bb18f2ef..06dab75f9b 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -72,6 +72,7 @@ add_custom_command( -Dsbe.generate.precedence.checks="true" -Dsbe.precedence.checks.flag.name="SBE_ENABLE_PRECEDENCE_CHECKS_IN_TESTS" -Dsbe.cpp.disable.implicit.copying="true" + -Dsbe.keyword.append.token="X" -Dsbe.cpp.generate.dtos="true" -jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} From fbd3799dfd5e3235d67f5e522d476e46c6a9c28f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 28 Aug 2025 09:41:33 +0200 Subject: [PATCH 629/805] [Java] Handle primitive arrays correctly in the generated DTO code. --- .../sbe/generation/java/JavaDtoGenerator.java | 11 ++++++++--- .../uk/co/real_logic/sbe/generation/java/DtoTest.java | 2 ++ sbe-tool/src/test/resources/dto-test-schema.xml | 8 +++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index bb7da8df34..335731f290 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -1039,7 +1039,7 @@ private void generateArrayEncodeWith( if (primitiveType == PrimitiveType.CHAR) { - sb.append(indent).append("encoder.").append(toLowerFirstChar(propertyName)).append("(") + sb.append(indent).append("encoder.").append(formattedPropertyName).append("(") .append("dto.").append(formattedPropertyName).append("());\n"); } else @@ -1047,10 +1047,15 @@ private void generateArrayEncodeWith( final String javaTypeName = javaTypeName(primitiveType); sb.append(indent).append(javaTypeName).append("[] ").append(formattedPropertyName).append(" = ") .append("dto.").append(formattedPropertyName).append("();\n") - .append(indent).append("for (int i = 0; i < ").append(formattedPropertyName).append(".length; i++)\n") + .append(indent).append("if (null != ").append(formattedPropertyName).append(")\n") .append(indent).append("{\n") - .append(indent).append(INDENT).append("encoder.").append(formattedPropertyName).append("(") + .append(indent).append(indent).append("for (int i = 0; i < ").append(formattedPropertyName) + .append(".length; i++)\n") + .append(indent).append(indent).append("{\n") + .append(indent).append(indent).append(INDENT).append("encoder.").append(formattedPropertyName) + .append("(") .append("i, ").append(formattedPropertyName).append("[i]);\n") + .append(indent).append(indent).append("}\n") .append(indent).append("}\n"); } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java index 36b32e1b73..24a5093ec8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java @@ -82,6 +82,8 @@ void dtoWithKeywords() dto.abstract$((byte)-81); dto.false$((byte)0); dto.falsE((byte)1); + dto.import$("char nine"); + dto.void$(new int[] {1, 2, 3}); final ExpandableArrayBuffer input = new ExpandableArrayBuffer(); final KeywordsEncoder encoder = new KeywordsEncoder(); encoder.wrap(input, 0); diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml index f3ff272e97..38fb39b6c8 100644 --- a/sbe-tool/src/test/resources/dto-test-schema.xml +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -32,6 +32,8 @@ + + T @@ -133,7 +135,7 @@ - + @@ -147,7 +149,7 @@ - + @@ -156,7 +158,7 @@ - + From d39de50ee4fecdd61f74da0f14dcce6cb1de4b2a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:14:11 +0200 Subject: [PATCH 630/805] [Java] More tests around arrays in DTOs. --- .../sbe/generation/java/DtoTest.java | 36 +++++++++++++++---- .../src/test/resources/dto-test-schema.xml | 16 +++++++-- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java index 24a5093ec8..b16ca3208d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java @@ -18,6 +18,8 @@ import dto_test.KeywordsDto; import dto_test.KeywordsEncoder; +import dto_test.MessageHeaderDecoder; +import dto_test.MessageHeaderEncoder; import extension.BooleanType; import extension.BoostType; import extension.CarDecoder; @@ -28,6 +30,8 @@ import org.agrona.MutableDirectBuffer; import org.junit.jupiter.api.Test; +import java.util.List; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -76,6 +80,10 @@ void shouldRoundTripCar2() @Test void dtoWithKeywords() { + final ExpandableArrayBuffer input = new ExpandableArrayBuffer(); + final KeywordsEncoder encoder = new KeywordsEncoder(); + encoder.wrapAndApplyHeader(input, 0, new MessageHeaderEncoder()); + final KeywordsDto dto = new KeywordsDto(); dto.assert$((byte)42); dto.final$((byte)7); @@ -84,20 +92,34 @@ void dtoWithKeywords() dto.falsE((byte)1); dto.import$("char nine"); dto.void$(new int[] {1, 2, 3}); - final ExpandableArrayBuffer input = new ExpandableArrayBuffer(); - final KeywordsEncoder encoder = new KeywordsEncoder(); - encoder.wrap(input, 0); + + final KeywordsDto.DataDto dto1 = new KeywordsDto.DataDto(); + dto1.this$((byte)90); + final KeywordsDto.DataDto.SuperDto superDto = new KeywordsDto.DataDto.SuperDto(); + superDto.try$(0.5f); + dto1.super$(List.of(superDto)); + final KeywordsDto.DataDto dto2 = new KeywordsDto.DataDto(); + dto2.this$((byte)100); + dto.data(List.of(dto1, dto2)); KeywordsDto.encodeWith(encoder, dto); final byte[] originalBytes = new byte[encoder.encodedLength()]; input.getBytes(0, originalBytes); - final KeywordsDto otherDto = - KeywordsDto.decodeFrom(input, 0, KeywordsEncoder.SCHEMA_VERSION, KeywordsEncoder.BLOCK_LENGTH); - KeywordsDto.encodeWith(encoder, otherDto); + final MessageHeaderDecoder messageHeaderDecoder = new MessageHeaderDecoder(); + messageHeaderDecoder.wrap(input, 0); + + final KeywordsDto otherDto = KeywordsDto.decodeFrom( + input, + MessageHeaderDecoder.ENCODED_LENGTH, + messageHeaderDecoder.blockLength(), + messageHeaderDecoder.version()); + final KeywordsEncoder encoder2 = new KeywordsEncoder(); + encoder2.wrapAndApplyHeader(input, 0, new MessageHeaderEncoder()); + KeywordsDto.encodeWith(encoder2, otherDto); - final byte[] otherBytes = new byte[encoder.encodedLength()]; + final byte[] otherBytes = new byte[encoder2.encodedLength()]; input.getBytes(0, otherBytes); assertArrayEquals(originalBytes, otherBytes); diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml index 38fb39b6c8..12ef9d6ef7 100644 --- a/sbe-tool/src/test/resources/dto-test-schema.xml +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -33,7 +33,7 @@ - + T @@ -71,6 +71,10 @@ + + + +
    @@ -161,10 +165,16 @@ - - + + + + + + + + From ecb43f4312811c2bc7c4c87838be80d795ca65fc Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:14:27 +0200 Subject: [PATCH 631/805] [Java] Bump `Shadow` to 9.1.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e79e4ccdbf..b241820484 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20250517" junit = "5.13.4" mockito = "5.19.0" plexus = "3.3.0" -shadow = "9.0.2" +shadow = "9.1.0" versions = "0.52.0" [libraries] From b13d103d38830793eef5649e80e5041295cf0b37 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 14:59:11 +0200 Subject: [PATCH 632/805] [C++] Fix property name usage in display code generator. --- .../sbe/generation/cpp/CppGenerator.java | 18 +++-- sbe-tool/src/test/c/CMakeLists.txt | 1 + .../test/resources/code-generation-schema.xml | 75 +++++++++++++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 566545df2f..3ee0208cbb 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -290,12 +290,12 @@ private CharSequence generateFullyEncodedCheck(final FieldPrecedenceModel fieldP private static String accessOrderListenerMethodName(final Token token) { - return "on" + Generators.toUpperFirstChar(token.name()) + "Accessed"; + return "on" + Generators.toUpperFirstChar(formatPropertyName(token.name())) + "Accessed"; } private static String accessOrderListenerMethodName(final Token token, final String suffix) { - return "on" + Generators.toUpperFirstChar(token.name()) + suffix + "Accessed"; + return "on" + Generators.toUpperFirstChar(formatPropertyName(token.name())) + suffix + "Accessed"; } private static void generateAccessOrderListenerMethod( @@ -1405,7 +1405,7 @@ private void generateChoiceSet(final List tokens) throws IOException private void generateEnum(final List tokens) throws IOException { final Token enumToken = tokens.get(0); - final String enumName = formatClassName(tokens.get(0).applicableTypeName()); + final String enumName = formatClassName(enumToken.applicableTypeName()); try (Writer out = outputManager.createOutput(enumName)) { @@ -3879,11 +3879,12 @@ private CharSequence appendDisplay( atLeastOne[0] = true; final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); - sb.append(indent).append("builder << R\"(\"").append(varDataToken.name()).append("\": )\";\n"); + final String propertyName = formatPropertyName(varDataToken.name()); + sb.append(indent).append("builder << R\"(\"").append(propertyName).append("\": )\";\n"); if (null == characterEncoding) { - final String skipFunction = "writer.skip" + toUpperFirstChar(varDataToken.name()) + "()"; + final String skipFunction = "writer.skip" + toUpperFirstChar(propertyName) + "()"; sb.append(indent).append("builder << '\"' <<\n").append(indent).append(INDENT).append(skipFunction) .append(" << \" bytes of raw data\\\"\";\n"); @@ -3891,7 +3892,7 @@ private CharSequence appendDisplay( else { final String getAsStringFunction = - "writer.get" + toUpperFirstChar(varDataToken.name()) + "AsJsonEscapedString().c_str()"; + "writer.get" + toUpperFirstChar(propertyName) + "AsJsonEscapedString().c_str()"; sb.append(indent).append("builder << '\"' <<\n").append(indent).append(INDENT) .append(getAsStringFunction).append(" << '\"';\n\n"); @@ -3925,7 +3926,8 @@ private void writeTokenDisplay( } sb.append(indent).append("builder << R\"(\"").append(fieldTokenName).append("\": )\";\n"); - final String fieldName = "writer." + formatPropertyName(fieldTokenName); + final String propertyName = formatPropertyName(fieldTokenName); + final String fieldName = "writer." + propertyName; switch (typeToken.signal()) { @@ -3935,7 +3937,7 @@ private void writeTokenDisplay( if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { final String getAsStringFunction = - "writer.get" + toUpperFirstChar(fieldTokenName) + "AsJsonEscapedString().c_str()"; + "writer.get" + toUpperFirstChar(propertyName) + "AsJsonEscapedString().c_str()"; sb.append(indent).append("builder << '\"' <<\n").append(indent).append(INDENT) .append(getAsStringFunction).append(" << '\"';\n"); diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index 2ed9136bec..fab918f0b3 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -49,6 +49,7 @@ add_custom_command( ${Java_JAVA_EXECUTABLE} --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.output.dir=${C_CODEC_TARGET_DIR} -Dsbe.target.language="C" + -Dsbe.keyword.append.token="X" -jar ${SBE_JAR} ${CODE_GENERATION_SCHEMA} ${CODE_GENERATION_SCHEMA_WITH_VERSION} diff --git a/sbe-tool/src/test/resources/code-generation-schema.xml b/sbe-tool/src/test/resources/code-generation-schema.xml index 7e1634cd1f..be83536199 100644 --- a/sbe-tool/src/test/resources/code-generation-schema.xml +++ b/sbe-tool/src/test/resources/code-generation-schema.xml @@ -7,6 +7,8 @@ description="Example schema" byteOrder="littleEndian"> + + T @@ -34,6 +36,10 @@ + + + + @@ -57,6 +63,12 @@ B C + + 0 + 1 + 222 + 254 + 0 1 @@ -90,4 +102,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8985a966eb7343373460198f17c8d9e8528c8ab9 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 15:26:19 +0200 Subject: [PATCH 633/805] [Java] Increase buffer capacity. --- .../src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index 2111fb1038..122c0ef41d 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -32,7 +32,7 @@ class EncodedIrTest { - private static final int CAPACITY = 1024 * 16; + private static final int CAPACITY = 1024 * 32; @Test void shouldEncodeIr() throws Exception From 61bf426885fa10c30421d34e924348e84cf02cc1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:57:15 +0200 Subject: [PATCH 634/805] [Go] Handle `_` and `String` as keywords + use property name when generating variable data section. --- gocode/flyweight/src/otf/otf_test.go | 2 +- .../uk/co/real_logic/sbe/ValidationUtil.java | 4 +- .../golang/flyweight/GolangFlyweightUtil.java | 21 +-- .../golang/struct/GolangGenerator.java | 2 +- .../test/resources/code-generation-schema.xml | 143 ++++++++++-------- 5 files changed, 88 insertions(+), 84 deletions(-) diff --git a/gocode/flyweight/src/otf/otf_test.go b/gocode/flyweight/src/otf/otf_test.go index 10cc0afd0e..e173da701e 100644 --- a/gocode/flyweight/src/otf/otf_test.go +++ b/gocode/flyweight/src/otf/otf_test.go @@ -7,7 +7,7 @@ import ( "testing" ) -//go:generate java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.output.dir=. -Dsbe.target.language=golang -Dsbe.go.generate.generate.flyweights=true -Dsbe.generate.ir=true -jar ../../../${SBE_JAR} ../../../../sbe-tool/src/test/resources/code-generation-schema.xml +//go:generate java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.output.dir=. -Dsbe.target.language=golang -Dsbe.go.generate.generate.flyweights=true -Dsbe.generate.ir=true -Dsbe.keyword.append.token=X -jar ../../../${SBE_JAR} ../../../../sbe-tool/src/test/resources/code-generation-schema.xml const SchemaFilename = "code-generation-schema.sbeir" const MsgBufferCapacity = 4 * 1024 diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index 426e7c4fd1..92f000cae5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -295,7 +295,7 @@ private static boolean isJavaIdentifier(final String token) "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", - "continue", "for", "import", "return", "var", + "continue", "for", "import", "return", "var", "_", /* https://golang.org/ref/spec#Predeclared_identifiers */ /* types */ @@ -308,7 +308,7 @@ private static boolean isJavaIdentifier(final String token) "nil", /* functions */ "append", "cap", "close", "complex", "copy", "delete", "imag", "len", - "make", "new", "panic", "print", "println", "real", "recover"); + "make", "new", "panic", "print", "println", "real", "recover", "String"); /** * "Check" value for validity of usage as a golang identifier. From: diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java index 2b74309d13..a028aec8dd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightUtil.java @@ -16,8 +16,7 @@ package uk.co.real_logic.sbe.generation.golang.flyweight; import uk.co.real_logic.sbe.PrimitiveType; -import uk.co.real_logic.sbe.SbeTool; -import uk.co.real_logic.sbe.ValidationUtil; +import uk.co.real_logic.sbe.generation.golang.struct.GolangUtil; import java.nio.ByteOrder; import java.util.EnumMap; @@ -105,23 +104,7 @@ public static String golangMarshalType(final PrimitiveType primitiveType) */ public static String formatPropertyName(final String value) { - String formattedValue = toUpperFirstChar(value); - - if (ValidationUtil.isGolangKeyword(formattedValue)) - { - final String keywordAppendToken = System.getProperty(SbeTool.KEYWORD_APPEND_TOKEN); - if (null == keywordAppendToken) - { - throw new IllegalStateException( - "Invalid property name='" + formattedValue + - "' please correct the schema or consider setting system property: " + - SbeTool.KEYWORD_APPEND_TOKEN); - } - - formattedValue += keywordAppendToken; - } - - return formattedValue; + return GolangUtil.formatPropertyName(value); } /** diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java index d764a11eca..d96f4c8e57 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java @@ -1411,7 +1411,7 @@ private void generateVarData( throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + token); } - final String propertyName = toUpperFirstChar(token.name()); + final String propertyName = formatPropertyName(token.name()); final Token lengthToken = Generators.findFirst("length", tokens, i); final int lengthOfLengthField = lengthToken.encodedLength(); final Token varDataToken = Generators.findFirst("varData", tokens, i); diff --git a/sbe-tool/src/test/resources/code-generation-schema.xml b/sbe-tool/src/test/resources/code-generation-schema.xml index be83536199..c6a6633f8b 100644 --- a/sbe-tool/src/test/resources/code-generation-schema.xml +++ b/sbe-tool/src/test/resources/code-generation-schema.xml @@ -4,7 +4,7 @@ id="6" version="0" semanticVersion="5.2" - description="Example schema" + description="Code generation schema" byteOrder="littleEndian"> @@ -102,67 +102,88 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7822307729491594c945a1fe4246bff86a0b88aa Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 18:55:22 +0200 Subject: [PATCH 635/805] [Java] Handle `null` values when encoding enums, i.e. use `Enum.NULL_VAL` if the value was not assigned. --- .../sbe/generation/java/JavaDtoGenerator.java | 18 +++++++++++++++--- .../sbe/generation/java/DtoTest.java | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index 335731f290..d8a4d6f245 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -985,7 +985,7 @@ private void generateFieldEncodeWith( break; case BEGIN_ENUM: - generateEnumEncodeWith(sb, fieldToken, indent); + generateEnumEncodeWith(sb, fieldToken, typeToken, indent); break; case BEGIN_SET: @@ -1081,6 +1081,7 @@ private void generatePrimitiveValueEncodeWith( private void generateEnumEncodeWith( final StringBuilder sb, final Token fieldToken, + final Token typeToken, final String indent) { if (fieldToken.isConstantEncoding()) @@ -1088,11 +1089,22 @@ private void generateEnumEncodeWith( return; } + final String enumName = formatClassName(typeToken.applicableTypeName()); final String propertyName = fieldToken.name(); final String formattedPropertyName = formatPropertyName(propertyName); - sb.append(indent).append("encoder.").append(formattedPropertyName).append("(dto.") - .append(formattedPropertyName).append("());\n"); + sb.append(indent).append(enumName).append(" ").append(formattedPropertyName).append(" = ") + .append("dto.").append(formattedPropertyName).append("();\n"); + sb.append(indent).append("if (null != ").append(formattedPropertyName).append(")\n"); + sb.append(indent).append("{\n"); + sb.append(indent).append(indent).append("encoder.").append(formattedPropertyName) + .append("(").append(formattedPropertyName).append(");\n"); + sb.append(indent).append("}\n"); + sb.append(indent).append("else\n"); + sb.append(indent).append("{\n"); + sb.append(indent).append(indent).append("encoder.").append(formattedPropertyName) + .append("(").append(enumName).append(".NULL_VAL);\n"); + sb.append(indent).append("}\n"); } private void generateComplexPropertyEncodeWith( diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java index b16ca3208d..0f9d58f599 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/DtoTest.java @@ -92,6 +92,7 @@ void dtoWithKeywords() dto.falsE((byte)1); dto.import$("char nine"); dto.void$(new int[] {1, 2, 3}); + dto.continue$(dto_test.Model.B); final KeywordsDto.DataDto dto1 = new KeywordsDto.DataDto(); dto1.this$((byte)90); From d9868d2324123c37b66861ed5a310a4f4ba274f1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 18:58:38 +0200 Subject: [PATCH 636/805] [Java] Fix var data and composite code generation to use property name instead of plain name. Also use property name for access order check methods. --- .../sbe/generation/java/JavaGenerator.java | 78 +++++---- .../test/resources/code-generation-schema.xml | 2 + .../src/test/resources/dto-test-schema.xml | 152 +++++++++++------- 3 files changed, 133 insertions(+), 99 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 3b6e988750..4e48e9bd08 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -471,12 +471,12 @@ private void generateFullyEncodedCheck( private static String accessOrderListenerMethodName(final Token token) { - return "on" + Generators.toUpperFirstChar(token.name()) + "Accessed"; + return "on" + Generators.toUpperFirstChar(formatPropertyName(token.name())) + "Accessed"; } private static String accessOrderListenerMethodName(final Token token, final String suffix) { - return "on" + Generators.toUpperFirstChar(token.name()) + suffix + "Accessed"; + return "on" + Generators.toUpperFirstChar(formatPropertyName(token.name())) + suffix + "Accessed"; } private static void generateAccessOrderListenerMethod( @@ -1428,15 +1428,15 @@ private void generateDecoderVarData( { throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + token); } + final String propertyName = formatPropertyName(token.name()); - generateFieldIdMethod(sb, token, indent); - generateFieldSinceVersionMethod(sb, token, indent); + generateFieldIdMethod(sb, token, propertyName, indent); + generateFieldSinceVersionMethod(sb, token, propertyName, indent); final String characterEncoding = tokens.get(i + 3).encoding().characterEncoding(); - generateCharacterEncodingMethod(sb, token.name(), characterEncoding, indent); - generateFieldMetaAttributeMethod(sb, token, indent); + generateCharacterEncodingMethod(sb, propertyName, characterEncoding, indent); + generateFieldMetaAttributeMethod(sb, token, propertyName, indent); - final String propertyName = Generators.toUpperFirstChar(token.name()); final Token lengthToken = tokens.get(i + 2); final int sizeOfLengthField = lengthToken.encodedLength(); final Encoding lengthEncoding = lengthToken.encoding(); @@ -1492,13 +1492,14 @@ private void generateEncoderVarData( throw new IllegalStateException("tokens must begin with BEGIN_VAR_DATA: token=" + token); } - generateFieldIdMethod(sb, token, indent); + final String propertyName = formatPropertyName(token.name()); + + generateFieldIdMethod(sb, token, propertyName, indent); final Token varDataToken = Generators.findFirst("varData", tokens, i); final String characterEncoding = varDataToken.encoding().characterEncoding(); - generateCharacterEncodingMethod(sb, token.name(), characterEncoding, indent); - generateFieldMetaAttributeMethod(sb, token, indent); + generateCharacterEncodingMethod(sb, propertyName, characterEncoding, indent); + generateFieldMetaAttributeMethod(sb, token, propertyName, indent); - final String propertyName = Generators.toUpperFirstChar(token.name()); final Token lengthToken = Generators.findFirst("length", tokens, i); final int sizeOfLengthField = lengthToken.encodedLength(); final Encoding lengthEncoding = lengthToken.encoding(); @@ -1614,7 +1615,7 @@ private void generateDataDecodeMethods( indent + " buffer.getBytes(limit + headerLength, tmp, 0, dataLength);\n\n" + indent + " return new String(tmp, %6$s);\n" + indent + " }\n", - formatPropertyName(propertyName), + propertyName, generateStringNotPresentCondition(false, token.version(), indent), sizeOfLengthField, PrimitiveType.UINT32 == lengthType ? "(int)" : "", @@ -1668,7 +1669,7 @@ private void generateVarDataWrapDecoder( indent + " parentMessage.limit(limit + headerLength + dataLength);\n" + indent + " wrapBuffer.wrap(buffer, limit + headerLength, dataLength);\n" + indent + " }\n", - propertyName, + Generators.toUpperFirstChar(propertyName), readOnlyBuffer, generateWrapFieldNotPresentCondition(false, token.version(), indent), accessOrderListenerCall, @@ -1845,7 +1846,7 @@ private void generateVarDataTypedDecoder( indent + " buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied);\n\n" + indent + " return bytesCopied;\n" + indent + " }\n", - propertyName, + Generators.toUpperFirstChar(propertyName), exchangeType, generateArrayFieldNotPresentCondition(false, token.version(), indent), accessOrderListenerCall, @@ -1884,7 +1885,7 @@ private void generateDataTypedEncoder( indent + " return this;\n" + indent + " }\n", className, - propertyName, + Generators.toUpperFirstChar(propertyName), exchangeType, maxLengthValue, sizeOfLengthField, @@ -2010,7 +2011,7 @@ private void generateComposite(final List tokens) throws IOException final StringBuilder sb = new StringBuilder(); generateEncodingOffsetMethod(sb, propertyName, encodingToken.offset(), BASE_INDENT); generateEncodingLengthMethod(sb, propertyName, encodingToken.encodedLength(), BASE_INDENT); - generateFieldSinceVersionMethod(sb, encodingToken, BASE_INDENT); + generateFieldSinceVersionMethod(sb, encodingToken, propertyName, BASE_INDENT); final String accessOrderListenerCall = ""; switch (encodingToken.signal()) @@ -3239,9 +3240,8 @@ private static void generateCharacterEncodingMethod( { if (null != characterEncoding) { - final String propName = formatPropertyName(propertyName); sb.append("\n") - .append(indent).append(" public static String ").append(propName).append("CharacterEncoding()\n") + .append(indent).append(" public static String ").append(propertyName).append("CharacterEncoding()\n") .append(indent).append(" {\n") .append(indent).append(" return ").append(charsetName(characterEncoding)).append(";\n") .append(indent).append(" }\n"); @@ -3656,11 +3656,11 @@ private void generateEncoderFields( final String propertyName = formatPropertyName(fieldToken.name()); final String typeName = encoderName(typeToken.name()); - generateFieldIdMethod(sb, fieldToken, indent); - generateFieldSinceVersionMethod(sb, fieldToken, indent); + generateFieldIdMethod(sb, fieldToken, propertyName, indent); + generateFieldSinceVersionMethod(sb, fieldToken, propertyName, indent); generateEncodingOffsetMethod(sb, propertyName, fieldToken.offset(), indent); generateEncodingLengthMethod(sb, propertyName, typeToken.encodedLength(), indent); - generateFieldMetaAttributeMethod(sb, fieldToken, indent); + generateFieldMetaAttributeMethod(sb, fieldToken, propertyName, indent); generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent + " ", fieldToken); final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( fieldPrecedenceModel, indent + " ", fieldToken); @@ -3708,11 +3708,11 @@ private void generateDecoderFields( final String propertyName = formatPropertyName(fieldToken.name()); final String typeName = decoderName(typeToken.name()); - generateFieldIdMethod(sb, fieldToken, indent); - generateFieldSinceVersionMethod(sb, fieldToken, indent); + generateFieldIdMethod(sb, fieldToken, propertyName, indent); + generateFieldSinceVersionMethod(sb, fieldToken, propertyName, indent); generateEncodingOffsetMethod(sb, propertyName, fieldToken.offset(), indent); generateEncodingLengthMethod(sb, propertyName, typeToken.encodedLength(), indent); - generateFieldMetaAttributeMethod(sb, fieldToken, indent); + generateFieldMetaAttributeMethod(sb, fieldToken, propertyName, indent); generateAccessOrderListenerMethod(sb, fieldPrecedenceModel, indent + " ", fieldToken); final CharSequence accessOrderListenerCall = generateAccessOrderListenerCall( @@ -3748,9 +3748,9 @@ private void generateDecoderFields( }); } - private static void generateFieldIdMethod(final StringBuilder sb, final Token token, final String indent) + private static void generateFieldIdMethod( + final StringBuilder sb, final Token token, final String propertyName, final String indent) { - final String propertyName = formatPropertyName(token.name()); sb.append("\n") .append(indent).append(" public static int ").append(propertyName).append("Id()\n") .append(indent).append(" {\n") @@ -3759,9 +3759,8 @@ private static void generateFieldIdMethod(final StringBuilder sb, final Token to } private static void generateEncodingOffsetMethod( - final StringBuilder sb, final String name, final int offset, final String indent) + final StringBuilder sb, final String propertyName, final int offset, final String indent) { - final String propertyName = formatPropertyName(name); sb.append("\n") .append(indent).append(" public static int ").append(propertyName).append("EncodingOffset()\n") .append(indent).append(" {\n") @@ -3770,9 +3769,8 @@ private static void generateEncodingOffsetMethod( } private static void generateEncodingLengthMethod( - final StringBuilder sb, final String name, final int length, final String indent) + final StringBuilder sb, final String propertyName, final int length, final String indent) { - final String propertyName = formatPropertyName(name); sb.append("\n") .append(indent).append(" public static int ").append(propertyName).append("EncodingLength()\n") .append(indent).append(" {\n") @@ -3780,9 +3778,9 @@ private static void generateEncodingLengthMethod( .append(indent).append(" }\n"); } - private static void generateFieldSinceVersionMethod(final StringBuilder sb, final Token token, final String indent) + private static void generateFieldSinceVersionMethod( + final StringBuilder sb, final Token token, final String propertyName, final String indent) { - final String propertyName = formatPropertyName(token.name()); sb.append("\n") .append(indent).append(" public static int ").append(propertyName).append("SinceVersion()\n") .append(indent).append(" {\n") @@ -3790,14 +3788,14 @@ private static void generateFieldSinceVersionMethod(final StringBuilder sb, fina .append(indent).append(" }\n"); } - private static void generateFieldMetaAttributeMethod(final StringBuilder sb, final Token token, final String indent) + private static void generateFieldMetaAttributeMethod( + final StringBuilder sb, final Token token, final String propertyName, final String indent) { final Encoding encoding = token.encoding(); final String epoch = encoding.epoch() == null ? "" : encoding.epoch(); final String timeUnit = encoding.timeUnit() == null ? "" : encoding.timeUnit(); final String semanticType = encoding.semanticType() == null ? "" : encoding.semanticType(); final String presence = encoding.presence().toString().toLowerCase(); - final String propertyName = formatPropertyName(token.name()); sb.append("\n") .append(indent).append(" public static String ") @@ -4429,8 +4427,8 @@ private void appendDecoderDisplay( if (fieldToken.signal() == Signal.BEGIN_FIELD) { final Token encodingToken = fields.get(i + 1); - final String fieldName = formatPropertyName(fieldToken.name()); - lengthBeforeLastGeneratedSeparator = writeTokenDisplay(fieldName, encodingToken, sb, indent); + final String propertyName = formatPropertyName(fieldToken.name()); + lengthBeforeLastGeneratedSeparator = writeTokenDisplay(propertyName, encodingToken, sb, indent); i += fieldToken.componentTokenCount(); } @@ -4486,8 +4484,8 @@ private void appendDecoderDisplay( } final String characterEncoding = varData.get(i + 3).encoding().characterEncoding(); - final String varDataName = formatPropertyName(varDataToken.name()); - append(sb, indent, "builder.append(\"" + varDataName + Separator.KEY_VALUE + "\");"); + final String propertyName = formatPropertyName(varDataToken.name()); + append(sb, indent, "builder.append(\"" + propertyName + Separator.KEY_VALUE + "\");"); if (null == characterEncoding) { final String name = Generators.toUpperFirstChar(varDataToken.name()); @@ -4498,12 +4496,12 @@ private void appendDecoderDisplay( if (isAsciiEncoding(characterEncoding)) { append(sb, indent, "builder.append('\\'');"); - append(sb, indent, formatGetterName(varDataToken.name()) + "(builder);"); + append(sb, indent, formatGetterName(propertyName) + "(builder);"); append(sb, indent, "builder.append('\\'');"); } else { - append(sb, indent, "builder.append('\\'').append(" + varDataName + "()).append('\\'');"); + append(sb, indent, "builder.append('\\'').append(" + propertyName + "()).append('\\'');"); } } diff --git a/sbe-tool/src/test/resources/code-generation-schema.xml b/sbe-tool/src/test/resources/code-generation-schema.xml index c6a6633f8b..2e530a3af5 100644 --- a/sbe-tool/src/test/resources/code-generation-schema.xml +++ b/sbe-tool/src/test/resources/code-generation-schema.xml @@ -180,6 +180,8 @@ + + diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml index 12ef9d6ef7..dd7bae3f8b 100644 --- a/sbe-tool/src/test/resources/dto-test-schema.xml +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -20,6 +20,10 @@
    + + + + @@ -62,6 +66,12 @@ B C + + 0 + 1 + 222 + 254 + 0 1 @@ -115,66 +125,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0d3cd0e322a45c83e2461bc51fb9f69d8c4d2c94 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 19:14:50 +0200 Subject: [PATCH 637/805] [Java] Format property name for C# code. --- build.gradle | 4 +++- .../sbe/generation/csharp/CSharpGenerator.java | 12 ++++++------ .../src/test/resources/code-generation-schema.xml | 3 +++ sbe-tool/src/test/resources/dto-test-schema.xml | 3 +++ 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 90102a340e..72af0e9eb9 100644 --- a/build.gradle +++ b/build.gradle @@ -958,8 +958,10 @@ tasks.register('generateCSharpTestDtos', JavaExec) { 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharpDtos', 'sbe.xinclude.aware': 'true', 'sbe.validation.xsd': validationXsdPath, + 'sbe.keyword.append.token': 'X', 'sbe.types.package.override': 'true') - args = ['sbe-samples/src/main/resources/example-extension-schema.xml'] + args = ['sbe-tool/src/test/resources/dto-test-schema.xml', + 'sbe-samples/src/main/resources/example-extension-schema.xml'] } tasks.register('generateCSharpExplicitPackageOverrideCodecs', JavaExec) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index a5dc0b2354..ee123b7ad7 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -534,7 +534,7 @@ private CharSequence generateVarData( if (token.signal() == Signal.BEGIN_VAR_DATA) { generateFieldIdMethod(sb, token, indent); - generateSinceActingDeprecated(sb, indent, CSharpUtil.formatPropertyName(token.name()), token); + generateSinceActingDeprecated(sb, indent, formatPropertyName(token.name()), token); generateOffsetMethod(sb, token, indent); final Token varDataToken = Generators.findFirst("varData", tokens, i); @@ -1608,12 +1608,12 @@ private CharSequence generateFullyEncodedCheck( private static String accessOrderListenerMethodName(final Token token) { - return "On" + Generators.toUpperFirstChar(token.name()) + "Accessed"; + return "On" + Generators.toUpperFirstChar(formatPropertyName(token.name())) + "Accessed"; } private static String accessOrderListenerMethodName(final Token token, final String suffix) { - return "On" + Generators.toUpperFirstChar(token.name()) + suffix + "Accessed"; + return "On" + Generators.toUpperFirstChar(formatPropertyName(token.name())) + suffix + "Accessed"; } private static void generateAccessOrderListenerMethod( @@ -1956,7 +1956,7 @@ private CharSequence generateFields( generateFieldIdMethod(sb, signalToken, indent + INDENT); generateSinceActingDeprecated( - sb, indent + INDENT, CSharpUtil.formatPropertyName(signalToken.name()), signalToken); + sb, indent + INDENT, formatPropertyName(signalToken.name()), signalToken); generateOffsetMethod(sb, signalToken, indent + INDENT); generateFieldMetaAttributeMethod(sb, signalToken, indent + INDENT); @@ -1997,7 +1997,7 @@ private void generateFieldIdMethod(final StringBuilder sb, final Token token, fi { sb.append(String.format("\n" + indent + "public const int %sId = %d;\n", - CSharpUtil.formatPropertyName(token.name()), + formatPropertyName(token.name()), token.id())); } @@ -2005,7 +2005,7 @@ private void generateOffsetMethod(final StringBuilder sb, final Token token, fin { sb.append(String.format("\n" + indent + "public const int %sOffset = %d;\n", - CSharpUtil.formatPropertyName(token.name()), + formatPropertyName(token.name()), token.offset())); } diff --git a/sbe-tool/src/test/resources/code-generation-schema.xml b/sbe-tool/src/test/resources/code-generation-schema.xml index 2e530a3af5..e9b88942a1 100644 --- a/sbe-tool/src/test/resources/code-generation-schema.xml +++ b/sbe-tool/src/test/resources/code-generation-schema.xml @@ -174,6 +174,9 @@ + + + diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml index dd7bae3f8b..891e4bef91 100644 --- a/sbe-tool/src/test/resources/dto-test-schema.xml +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -196,6 +196,9 @@ + + + From 6200b472a55f8fdfebf420a48f10fe731d785b6e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 19:30:09 +0200 Subject: [PATCH 638/805] [C++] Fix composite encode generation to use formatted property names, i.e. escape keywords. --- .../sbe/generation/cpp/CppDtoGenerator.java | 62 ++++++++----------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index baf01b639e..8aa13494ad 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -1005,8 +1005,7 @@ private void generateArrayEncodeWith( return; } - final String propertyName = fieldToken.name(); - final String formattedPropertyName = formatPropertyName(propertyName); + final String formattedPropertyName = formatPropertyName(fieldToken.name()); if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) { @@ -1014,13 +1013,13 @@ private void generateArrayEncodeWith( final String value = fieldToken.isOptionalEncoding() ? accessor + ".value_or(" + "\"\"" + ")" : accessor; - sb.append(indent).append("codec.put").append(toUpperFirstChar(propertyName)).append("(") + sb.append(indent).append("codec.put").append(toUpperFirstChar(formattedPropertyName)).append("(") .append(value).append(".c_str());\n"); } else { final String typeName = cppTypeName(typeToken.encoding().primitiveType()); - final String vectorVar = toLowerFirstChar(propertyName) + "Vector"; + final String vectorVar = toLowerFirstChar(formattedPropertyName) + "Vector"; final String accessor = "dto." + formattedPropertyName + "()"; final String value = fieldToken.isOptionalEncoding() ? @@ -1034,7 +1033,7 @@ private void generateArrayEncodeWith( .append(typeToken.arrayLength()).append(")\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("throw std::invalid_argument(\"") - .append(propertyName) + .append(formattedPropertyName) .append(": array length != ") .append(typeToken.arrayLength()) .append("\");\n") @@ -1083,8 +1082,7 @@ private void generateEnumEncodeWith( return; } - final String propertyName = fieldToken.name(); - final String formattedPropertyName = formatPropertyName(propertyName); + final String formattedPropertyName = formatPropertyName(fieldToken.name()); sb.append(indent).append("codec.").append(formattedPropertyName).append("(dto.") .append(formattedPropertyName).append("());\n"); @@ -1096,8 +1094,7 @@ private void generateComplexPropertyEncodeWith( final Token typeToken, final String indent) { - final String propertyName = fieldToken.name(); - final String formattedPropertyName = formatPropertyName(propertyName); + final String formattedPropertyName = formatPropertyName(fieldToken.name()); final String typeName = formatDtoClassName(typeToken.applicableTypeName()); sb.append(indent).append(typeName).append("::encodeWith(codec.") @@ -1225,7 +1222,7 @@ private void generateFields( if (signalToken.signal() == Signal.BEGIN_FIELD) { final Token encodingToken = tokens.get(i + 1); - final String propertyName = signalToken.name(); + final String propertyName = formatPropertyName(signalToken.name()); switch (encodingToken.signal()) { @@ -1258,7 +1255,6 @@ private void generateComplexProperty( final String indent) { final String typeName = formatDtoClassName(typeToken.applicableTypeName()); - final String formattedPropertyName = formatPropertyName(propertyName); final String fieldName = "m_" + toLowerFirstChar(propertyName); classBuilder.appendField() @@ -1267,7 +1263,7 @@ private void generateComplexProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("[[nodiscard]] const ").append(typeName).append("& ") - .append(formattedPropertyName).append("() const\n") + .append(propertyName).append("() const\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") .append(indent).append("}\n"); @@ -1275,7 +1271,7 @@ private void generateComplexProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("[[nodiscard]] ").append(typeName).append("& ") - .append(formattedPropertyName).append("()\n") + .append(propertyName).append("()\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") .append(indent).append("}\n"); @@ -1290,8 +1286,6 @@ private void generateEnumProperty( { final String enumName = formatClassName(typeToken.applicableTypeName()) + "::Value"; - final String formattedPropertyName = formatPropertyName(propertyName); - if (fieldToken.isConstantEncoding()) { final String constValue = fieldToken.encoding().constValue().toString(); @@ -1300,7 +1294,7 @@ private void generateEnumProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("[[nodiscard]] static ").append(enumName).append(" ") - .append(formattedPropertyName).append("()\n") + .append(propertyName).append("()\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(enumName).append("::") .append(caseName).append(";\n") @@ -1316,14 +1310,14 @@ private void generateEnumProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("[[nodiscard]] ").append(enumName).append(" ") - .append(formattedPropertyName).append("() const\n") + .append(propertyName).append("() const\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("void ").append(formattedPropertyName) + .append(indent).append("void ").append(propertyName) .append("(").append(enumName).append(" value)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(fieldName).append(" = value;\n") @@ -1378,7 +1372,6 @@ private void generateArrayProperty( final String indent) { final String fieldName = "m_" + toLowerFirstChar(propertyName); - final String formattedPropertyName = formatPropertyName(propertyName); final String validateMethod = "validate" + toUpperFirstChar(propertyName); if (typeToken.encoding().primitiveType() == PrimitiveType.CHAR) @@ -1394,14 +1387,14 @@ private void generateArrayProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("[[nodiscard]] const ").append(typeName).append("& ") - .append(formattedPropertyName).append("() const\n") + .append(propertyName).append("() const\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("void ").append(formattedPropertyName) + .append(indent).append("void ").append(propertyName) .append("(const ").append(typeName).append("& borrowedValue)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(fieldName).append(" = borrowedValue;\n") @@ -1409,7 +1402,7 @@ private void generateArrayProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("void ").append(formattedPropertyName).append("(") + .append(indent).append("void ").append(propertyName).append("(") .append(typeName).append("&& ownedValue)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(fieldName).append(" = std::move(ownedValue);\n") @@ -1423,7 +1416,7 @@ private void generateArrayProperty( validateMethod, typeName, "std::string", - formattedPropertyName); + propertyName); } else { @@ -1440,14 +1433,14 @@ private void generateArrayProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("[[nodiscard]] ").append(typeName).append(" ") - .append(formattedPropertyName).append("() const\n") + .append(propertyName).append("() const\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("void ").append(formattedPropertyName).append("(") + .append(indent).append("void ").append(propertyName).append("(") .append(typeName).append("& borrowedValue").append(")\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(validateMethod).append("(borrowedValue);\n") @@ -1456,7 +1449,7 @@ private void generateArrayProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("void ").append(formattedPropertyName).append("(") + .append(indent).append("void ").append(propertyName).append("(") .append(typeName).append("&& ownedValue").append(")\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(validateMethod).append("(ownedValue);\n") @@ -1471,7 +1464,7 @@ private void generateArrayProperty( validateMethod, typeName, vectorTypeName, - formattedPropertyName); + propertyName); } } @@ -1538,7 +1531,6 @@ private void generateSingleValueProperty( fieldToken, elementTypeName ); - final String formattedPropertyName = formatPropertyName(propertyName); final String fieldName = "m_" + toLowerFirstChar(propertyName); final String validateMethod = "validate" + toUpperFirstChar(propertyName); @@ -1548,14 +1540,14 @@ private void generateSingleValueProperty( classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) .append(indent).append("[[nodiscard]] ").append(typeName).append(" ") - .append(formattedPropertyName).append("() const\n") + .append(propertyName).append("() const\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(fieldName).append(";\n") .append(indent).append("}\n"); classBuilder.appendPublic().append("\n") .append(generateDocumentation(indent, fieldToken)) - .append(indent).append("void ").append(formattedPropertyName).append("(") + .append(indent).append("void ").append(propertyName).append("(") .append(typeName).append(" value)\n") .append(indent).append("{\n") .append(indent).append(INDENT).append(validateMethod).append("(value);\n") @@ -1570,7 +1562,6 @@ private void generateSingleValueProperty( indent, validateMethod, typeName, - formattedPropertyName, elementTypeName, encoding); } @@ -1583,7 +1574,6 @@ private static void generateSingleValuePropertyValidateMethod( final String indent, final String validateMethod, final CharSequence typeName, - final String formattedPropertyName, final String elementTypeName, final Encoding encoding) { @@ -1613,7 +1603,7 @@ private static void generateSingleValuePropertyValidateMethod( validateBuilder.append(indent).append(INDENT) .append("if (value.value() == ").append(codecClassName).append("::") - .append(formattedPropertyName).append("NullValue())\n") + .append(propertyName).append("NullValue())\n") .append(indent).append(INDENT) .append("{\n") .append(indent).append(INDENT).append(INDENT) @@ -1636,7 +1626,7 @@ private static void generateSingleValuePropertyValidateMethod( { validateBuilder.append(indent).append(INDENT) .append("if (").append(value).append(" < ") - .append(codecClassName).append("::").append(formattedPropertyName).append("MinValue())\n") + .append(codecClassName).append("::").append(propertyName).append("MinValue())\n") .append(indent).append(INDENT) .append("{\n") .append(indent).append(INDENT).append(INDENT) @@ -1652,7 +1642,7 @@ private static void generateSingleValuePropertyValidateMethod( { validateBuilder.append(indent).append(INDENT) .append("if (").append(value).append(" > ") - .append(codecClassName).append("::").append(formattedPropertyName).append("MaxValue())\n") + .append(codecClassName).append("::").append(propertyName).append("MaxValue())\n") .append(indent).append(INDENT) .append("{\n") .append(indent).append(INDENT).append(INDENT) @@ -1693,7 +1683,7 @@ private void generateConstPropertyMethods( .append(generateDocumentation(indent, fieldToken)) .append(indent).append("[[nodiscard]] static ") .append(cppTypeName(typeToken.encoding().primitiveType())) - .append(" ").append(formatPropertyName(propertyName)).append("()\n") + .append(" ").append(propertyName).append("()\n") .append(indent).append("{\n") .append(indent).append(INDENT).append("return ").append(literalValue).append(";\n") .append(indent).append("}\n"); From 988a0e88fb6b6eb71597dcc11a128845bc6d868f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 30 Aug 2025 19:32:53 +0200 Subject: [PATCH 639/805] Revert "[Java] Format property name for C# code." This reverts commit 0d3cd0e322a45c83e2461bc51fb9f69d8c4d2c94. --- build.gradle | 4 +--- .../sbe/generation/csharp/CSharpGenerator.java | 12 ++++++------ .../src/test/resources/code-generation-schema.xml | 3 --- sbe-tool/src/test/resources/dto-test-schema.xml | 3 --- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 72af0e9eb9..90102a340e 100644 --- a/build.gradle +++ b/build.gradle @@ -958,10 +958,8 @@ tasks.register('generateCSharpTestDtos', JavaExec) { 'sbe.target.language': 'uk.co.real_logic.sbe.generation.csharp.CSharpDtos', 'sbe.xinclude.aware': 'true', 'sbe.validation.xsd': validationXsdPath, - 'sbe.keyword.append.token': 'X', 'sbe.types.package.override': 'true') - args = ['sbe-tool/src/test/resources/dto-test-schema.xml', - 'sbe-samples/src/main/resources/example-extension-schema.xml'] + args = ['sbe-samples/src/main/resources/example-extension-schema.xml'] } tasks.register('generateCSharpExplicitPackageOverrideCodecs', JavaExec) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index ee123b7ad7..a5dc0b2354 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -534,7 +534,7 @@ private CharSequence generateVarData( if (token.signal() == Signal.BEGIN_VAR_DATA) { generateFieldIdMethod(sb, token, indent); - generateSinceActingDeprecated(sb, indent, formatPropertyName(token.name()), token); + generateSinceActingDeprecated(sb, indent, CSharpUtil.formatPropertyName(token.name()), token); generateOffsetMethod(sb, token, indent); final Token varDataToken = Generators.findFirst("varData", tokens, i); @@ -1608,12 +1608,12 @@ private CharSequence generateFullyEncodedCheck( private static String accessOrderListenerMethodName(final Token token) { - return "On" + Generators.toUpperFirstChar(formatPropertyName(token.name())) + "Accessed"; + return "On" + Generators.toUpperFirstChar(token.name()) + "Accessed"; } private static String accessOrderListenerMethodName(final Token token, final String suffix) { - return "On" + Generators.toUpperFirstChar(formatPropertyName(token.name())) + suffix + "Accessed"; + return "On" + Generators.toUpperFirstChar(token.name()) + suffix + "Accessed"; } private static void generateAccessOrderListenerMethod( @@ -1956,7 +1956,7 @@ private CharSequence generateFields( generateFieldIdMethod(sb, signalToken, indent + INDENT); generateSinceActingDeprecated( - sb, indent + INDENT, formatPropertyName(signalToken.name()), signalToken); + sb, indent + INDENT, CSharpUtil.formatPropertyName(signalToken.name()), signalToken); generateOffsetMethod(sb, signalToken, indent + INDENT); generateFieldMetaAttributeMethod(sb, signalToken, indent + INDENT); @@ -1997,7 +1997,7 @@ private void generateFieldIdMethod(final StringBuilder sb, final Token token, fi { sb.append(String.format("\n" + indent + "public const int %sId = %d;\n", - formatPropertyName(token.name()), + CSharpUtil.formatPropertyName(token.name()), token.id())); } @@ -2005,7 +2005,7 @@ private void generateOffsetMethod(final StringBuilder sb, final Token token, fin { sb.append(String.format("\n" + indent + "public const int %sOffset = %d;\n", - formatPropertyName(token.name()), + CSharpUtil.formatPropertyName(token.name()), token.offset())); } diff --git a/sbe-tool/src/test/resources/code-generation-schema.xml b/sbe-tool/src/test/resources/code-generation-schema.xml index e9b88942a1..2e530a3af5 100644 --- a/sbe-tool/src/test/resources/code-generation-schema.xml +++ b/sbe-tool/src/test/resources/code-generation-schema.xml @@ -174,9 +174,6 @@ - - - diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml index 891e4bef91..dd7bae3f8b 100644 --- a/sbe-tool/src/test/resources/dto-test-schema.xml +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -196,9 +196,6 @@ - - - From 0130951cd2da5c48107444b6a05a5b3afa814f1a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:42:28 +0200 Subject: [PATCH 640/805] [CI] Upgrade `setup-java` and `checkout` actions. --- .github/workflows/ci.yml | 34 +++++++++++++++++----------------- .github/workflows/codeql.yml | 12 ++++++------ .github/workflows/release.yml | 4 ++-- .github/workflows/slow.yml | 2 +- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d7129e13a..ef8d1bc7b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,11 +36,11 @@ jobs: os: [ 'ubuntu-24.04', 'windows-latest', 'macos-15' ] steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Setup java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -57,7 +57,7 @@ jobs: echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "BUILD_JAVA_VERSION=${{ matrix.java }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup java to run Gradle - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -91,11 +91,11 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -137,7 +137,7 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Install compiler @@ -146,7 +146,7 @@ jobs: sudo apt-get update sudo apt-get install -y g++-${{ matrix.version }} - name: Setup java to run Gradle script - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -173,7 +173,7 @@ jobs: CXX: clang++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Install compiler @@ -184,7 +184,7 @@ jobs: sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} - name: Setup java to run Gradle script - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -211,11 +211,11 @@ jobs: CXX: clang++ steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -242,11 +242,11 @@ jobs: CXX: cl steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -270,7 +270,7 @@ jobs: rust: [ stable, beta, nightly ] steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Rust setup @@ -278,7 +278,7 @@ jobs: with: toolchain: ${{ matrix.rust }} - name: Setup java to run Gradle script - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -301,7 +301,7 @@ jobs: version: [ '1.23.x', '1.24.x' ] steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Setup Go @@ -309,7 +309,7 @@ jobs: with: go-version: ${{ matrix.version }} - name: Setup java to run Gradle script - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b072c655ad..4832f66097 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,12 +39,12 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Setup java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -89,7 +89,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} @@ -102,7 +102,7 @@ jobs: ${{ runner.os }}-nuget- - name: Setup java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -152,12 +152,12 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.sha }} - name: Setup java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c38dd27632..acbd160259 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,11 +41,11 @@ jobs: runs-on: ubuntu-24.04 steps: - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ github.ref }} - name: Setup java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index feb48c79c8..29de4d7c2c 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -42,7 +42,7 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - name: Setup java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ matrix.java }} From feea62b27ed064a2203772224693bcba5b8ed7d5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:56:39 +0200 Subject: [PATCH 641/805] [CI] JDK 25 GA. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef8d1bc7b1..5037420eba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '17', '21', '24' ] + java: [ '17', '21', '25' ] os: [ 'ubuntu-24.04', 'windows-latest', 'macos-15' ] steps: - name: Checkout code From 3f3bfcd3b056bde13cb5f2cbbb960db93ea2e185 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:12:34 +0200 Subject: [PATCH 642/805] Revert "[CI] JDK 25 GA." This reverts commit feea62b27ed064a2203772224693bcba5b8ed7d5. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5037420eba..ef8d1bc7b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '17', '21', '25' ] + java: [ '17', '21', '24' ] os: [ 'ubuntu-24.04', 'windows-latest', 'macos-15' ] steps: - name: Checkout code From ef381e4b87485ef522a573fe9f62c990a4afd838 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 11:01:03 +0200 Subject: [PATCH 643/805] [CI] Use JDK 25 Zulu build. --- .github/workflows/ci.yml | 2 +- .github/workflows/slow.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef8d1bc7b1..5037420eba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - java: [ '17', '21', '24' ] + java: [ '17', '21', '25' ] os: [ 'ubuntu-24.04', 'windows-latest', 'macos-15' ] steps: - name: Checkout code diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 29de4d7c2c..0e40379a1d 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -33,7 +33,7 @@ jobs: timeout-minutes: 120 strategy: matrix: - java: [ '21' ] + java: [ '25' ] dotnet: [ '8.0.x' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true From d001777de1e2a6bad409f72a1c481431af3e1fbc Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 12:40:35 +0200 Subject: [PATCH 644/805] [CI] Add `Clang` 21. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5037420eba..b3c08cb75f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -167,7 +167,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '13', '14', '15', '16', '17', '18', '19', '20' ] + version: [ '13', '14', '15', '16', '17', '18', '19', '20', '21' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} From 03852443a6d490c9860b0e62fe52aa1f253cc90f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 12:41:16 +0200 Subject: [PATCH 645/805] [CI] Release without running other builds. --- .github/workflows/release.yml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index acbd160259..e643e54186 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,29 +15,11 @@ env: JAVA_VERSION: '17' jobs: - ci: - uses: ./.github/workflows/ci.yml - permissions: - contents: read - - slow: - uses: ./.github/workflows/slow.yml - permissions: - contents: read - - codeql: - uses: ./.github/workflows/codeql.yml - permissions: - actions: read - contents: read - security-events: write - release: name: Release java artifacts permissions: contents: write packages: write - needs: [ ci , codeql, slow ] runs-on: ubuntu-24.04 steps: - name: checkout From bf97e11f66c8402b6930dd9c8f74ffcf25cff5fd Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 13:00:31 +0200 Subject: [PATCH 646/805] [C] Workaround GoogleTest compilation issue on `Clang` 21. --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 326986a509..22c1dd9205 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,11 @@ find_package(Threads) if (UNIX) add_compile_options(-Wall -Wpedantic -Wextra -Wno-unused-parameter) + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "21.0") + # See gtest: https://github.com/google/googletest/issues/4762 + add_compile_options(-Wno-error=character-conversion) + endif () + if (C_WARNINGS_AS_ERRORS) add_compile_options($<$:-Werror>) endif (C_WARNINGS_AS_ERRORS) From 0bc446c836c9826846d2b8571ba2aba4396c1a8e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 13:05:03 +0200 Subject: [PATCH 647/805] [CI] Add `GCC` 15. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3c08cb75f..3c9896c369 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '11', '12', '13', '14' ] + version: [ '11', '12', '13', '14', '15' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} From ee72467ae754e5fbe19c63f345798d39e7b029e7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 13:16:18 +0200 Subject: [PATCH 648/805] [C] Bump mimium required CMake version to `3.30`. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22c1dd9205..7d4b2c354a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,8 @@ # limitations under the License. # -cmake_minimum_required(VERSION 3.6.1 FATAL_ERROR) -cmake_policy(VERSION 3.6.1) +cmake_minimum_required(VERSION 3.30 FATAL_ERROR) +cmake_policy(VERSION 3.30) file(STRINGS version.txt SBE_VERSION_TXT LIMIT_COUNT 1 REGEX "^[0-9]+(\\.[0-9]+)+") string(REGEX REPLACE "^([0-9]+(\\.[0-9]+)+).*$" "\\1" SBE_VERSION_NUMERIC "${SBE_VERSION_TXT}") From fec7f539b0beb6b456e02c8319be33454937a105 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 13:29:57 +0200 Subject: [PATCH 649/805] Revert "[CI] Add `GCC` 15." This reverts commit 0bc446c836c9826846d2b8571ba2aba4396c1a8e. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c9896c369..b3c08cb75f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,7 +131,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '11', '12', '13', '14', '15' ] + version: [ '11', '12', '13', '14' ] env: CC: gcc-${{ matrix.version }} CXX: g++-${{ matrix.version }} From 76ceb08bcfcb46c433ad508daffcfdefea09a7dc Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:16:48 +0200 Subject: [PATCH 650/805] [C] Bump `GoogleTest` to 1.14.0. --- CMakeLists.txt | 40 +++++++------------------ cppbuild/googletest-1.14.0.zip | Bin 0 -> 1090859 bytes cppbuild/googletest-release-1.12.1.zip | Bin 1081236 -> 0 bytes sbe-tool/src/test/c/CMakeLists.txt | 7 ++--- sbe-tool/src/test/cpp/CMakeLists.txt | 6 ++-- 5 files changed, 15 insertions(+), 38 deletions(-) create mode 100644 cppbuild/googletest-1.14.0.zip delete mode 100644 cppbuild/googletest-release-1.12.1.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d4b2c354a..32f07dd810 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,13 +16,15 @@ cmake_minimum_required(VERSION 3.30 FATAL_ERROR) cmake_policy(VERSION 3.30) +cmake_policy(SET CMP0003 NEW) +cmake_policy(SET CMP0135 NEW) file(STRINGS version.txt SBE_VERSION_TXT LIMIT_COUNT 1 REGEX "^[0-9]+(\\.[0-9]+)+") string(REGEX REPLACE "^([0-9]+(\\.[0-9]+)+).*$" "\\1" SBE_VERSION_NUMERIC "${SBE_VERSION_TXT}") project("sbe" VERSION "${SBE_VERSION_NUMERIC}") -include(ExternalProject) +include(FetchContent) include(CheckLibraryExists) if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) @@ -63,36 +65,12 @@ if (NOT DEFINED CMAKE_C_EXTENSIONS) endif () if (SBE_TESTS) - set(SBE_THIRDPARTY_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/thirdparty") - - ExternalProject_Add( - gtest - URL ${CMAKE_CURRENT_SOURCE_DIR}/cppbuild/googletest-release-1.12.1.zip - URL_MD5 2648d4138129812611cf6b6b4b497a3b - PREFIX "${SBE_THIRDPARTY_BINARY_DIR}/gtest" - CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER};-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - BUILD_BYPRODUCTS "${SBE_THIRDPARTY_BINARY_DIR}/gtest/src/gtest-build/lib/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX};${SBE_THIRDPARTY_BINARY_DIR}/gtest/src/gtest-build/lib/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}" - INSTALL_COMMAND "" - LOG_CONFIGURE ON - LOG_BUILD ON - ) - - ExternalProject_Get_Property(gtest source_dir) - set(GTEST_SOURCE_DIR ${source_dir}) - ExternalProject_Get_Property(gtest binary_dir) - set(GTEST_BINARY_DIR ${binary_dir}) - - if (MSVC AND CMAKE_BUILD_TYPE STREQUAL "Debug") - set(GTEST_POSTFIX "d") - else () - set(GTEST_POSTFIX "") - endif () + FetchContent_Declare( + gmock + URL ${CMAKE_CURRENT_SOURCE_DIR}/cppbuild/googletest-1.14.0.zip + URL_MD5 b4911e882c51cba34bebfb5df500a650) - set(GTEST_LIBS - ${GTEST_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX} - ${GTEST_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX} - ${GTEST_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX} - ) + FetchContent_MakeAvailable(gmock) endif () find_package(Threads) @@ -132,6 +110,8 @@ elseif (MSVC) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd /Od /Zi /MP") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /MP") + set(CMAKE_C_FLAGS_DEBUG "/MTd") + set(CMAKE_C_FLAGS_RELEASE "/MT") if (C_WARNINGS_AS_ERRORS) add_compile_options($<$:/WX>) diff --git a/cppbuild/googletest-1.14.0.zip b/cppbuild/googletest-1.14.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..1b1f7034c68dc3c6f2a6bc3150b8379c4b9ff991 GIT binary patch literal 1090859 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
  18. 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Ξ7|y2X}J0h0r;A;_;Y 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%0D)pf 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%0DPa;%l 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�TC53Gu$dA1Q6F5F2)U82wnx-E6+ks2TWIx=TH z$wP(h4nv>;7eA9v+whgxPIEH;wll4Q*H4T6;i-r$7a!8vyV0P|S!dgrQwDG(B58UF zbAWOLdJAAbNJv>JR)(V;7Yd4Ao}pTQsr00UDCRnT$6&$j+?{92(Ong}MyqZz6+3gi zx9pDeZWPg6(&YD2eoRhtLhI2fYdy@LHET=n!#4bh`Hxc;Ci9l5udIEef{FY#uEuG@ zd!?n&9P>|Nr`E{*;Oo8g-9_1AF#>p?OD8=^6vXZI%u&VYnRDBbbt0{5?Y)W)0CR|L zM%LW0@8)rO(SUQ~?s{Dtf}dPaNSfu3LwQUP?pVF_Ds|>5slwr-4z<^&I>o+C;);}< zvP1%^Rp2ecmX!h z+Zp_%1~mMe_HD$7SU0ds;&KWBA(l?eT!NE_YsxX@>qYwo^pW=y%ZjbzRuv@`$~lz zM{^Za3O2oyjdPpz9&3S}b)QD{`h^s#CXw{3s%M2cUwM?dtINlL?Hr8GMv4c(_mZw?Cn9e0^2 zX0yH55A^3csIKlVj2R3a7wgg7vc`a*oI~Yb4?eHei+U(G5YOE_TmB&~xv{SS?imz(m#hpYw?vJN} zG4c0_pG0|+UkF~9BkRsXfO&{^l0@(2hf!B$=?*1Z7s^TZtshr%?H^akgU5|W?lv|R z$KD46xT{(U^9Ov$o9Xe@6KD}Hkn31{r)~iFs7yjbqF?{t((b7hxm=>p!_GCi)0FX@* z`4R#{M_N%!=>&61(l7@a(Nvm}ORal+Ys$A&oF>ZSg!xR_0`2|0 zGI{nS0OR*6Fd`~ZU6$+^YU$FY@BC;md52pP;H)Y?Eh!}z?LkkW!7Wew!3%~-Y>Yep zn6uFtfdVG7g0G{v-QDZj5FJ?`M z4Q-{jm8(*NYJH!prq`{*n22zFS2KZ5SG?-Nw#;b30Ze_)%Q1Z7W) zD1YYcHwb@Tteo#@eR99@`J{6|iZpApq1q?w&iEA6{Y0dHI^G?GlU+m{ve~on$TlNG z0mqh(zOgHU*As<)GYK|oPiY`vr)*j7lE02{PKLLgVUZCiA|JeueLek>F2TB2H+kb- z58tYL!4E$q_s{=>m{p)sSw-Lj0Hiwpe?jC<_9jNOhAtM?#wL#c10uiTwQ|}RP1t#& z9+pXw9Y-|f&q|PzVh_@crwZbkQmb?Uz^Bj zv9tkX=H=!6y2f+&(|cT45=PV6LD|pK?Rx*$!XdeEp%H1obaQ!m6Qzp-?U@rLbIjC{ z1nnJLH|&UbB#Jh*ESgM4B!gy{BaKK(B)_tzJ)fkR9K06PD%E7NjrOAGKs+D)EwchD zq*)quN|hM~QAFD>6PYrZs;D>`qG58T^Vh!zh1~$~CkcQ&cHx7f4efzNQ-p(ZL=r?2 zO(z8F`!W?_Qq;4AF{=!kGWDX`#o{zH|$poC>wlykT4crnCN!PS6A@huth zM18y_%5WPg4=zTh2*5R7_EgS9_^&RWMEh44Z$Q+$(OtwG9+~Zy%FxO(VQ>b{m^8{? zAE7d83@A_92$kO`15KIE)f)=ki`c55-3J{k{5ZN$wU3t}?vOgF?ilM0`aopd3d2cd zus!b7{QC#)!=D{KcIy7#z>Wv;`Z47GXyDGmfpo*yHxY0eN5>ZvMt)Pa|8@Fk&X60v z{f5ZHn-?2)LswRG2hzvliJZQf@7DDoZ+Lq!*%S4%KJ05^VO!(ZuuU(P6wv#H3rqgBuzhQ7zX*tya@_OX3d(W4X0 z{O-<&ae%jZ73l`t`}gJA*?(frHZJr)&@XbM(eDBn5pZmQ4JcC^=3V%ed)5RX>pX_P z8Fh7R7e0*vPB*e>Tk{6wdDT0c%U+0l^;73tr5b7sKP)0GJ;dO*v56VFG`Uk_Rn z7rB_@yw312W5Dtgnw5a(ifMU$^#zz2ke4h3_k(S?W0AZfNlh%evnLJtr z0U$D=N~5@OSPY~p2MAUuPAhQirpOexl3#

    S> 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 z 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 z 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≠fzdy~y){59F zZTp7gS1}Eh_nq83PL<25F44IaG+x`y6Ck)uXnp+dMmbh!>BbKM}vTT~6U0q}5L`^74 zCdcK|)n2Up>Y6X{UClhBciB6};Bm^NV%>ng{`S6h%laKLaY}xmZBMaNu+fTdsOd}L z!WMb1xDEb(%cz}TSqJOHZfiXkXFG~2C9n;!n0XyXDZrHrzdEeDuSZYV zSx#)XcB<|+xQedoV|rK)F7S)+)`c7F=FcIqT=gGMy(eez1iJPg@R#-T>AA}*1n%qr zx%}p_7-K@rtTyE9+9z`BeWC;jsRo^9TpyCu>N)>zj;6nnz0{5x#ExlR-t>$Ix=(i< z2DuLBag;(g`tCe~=U!6TpgO^8m)zX(9%;_G3`_g0;8Rd0^C_8gU)l>G%j*p-o2+O z+-nvl9vyqR$mk86kDC>ZxlAVcM9Y3W6u&q^6Z15uni%-#diMI>`}_`memh2YIqT|R zPRhfU{i;b1+hLNb;A8Y2J4p1^v%ZBn=QJQ51Z8(drRwpyD0EZ_D=nUp_Y?*q_vL$3?fEK#YP|!gu01B!-SoO_W$?|J3W>BzxGg>GbP98l2iPkX5b#1{a7=OdgY6yUt=#Y-#9`KM zWuPh&UxT0&QME^>0pai^9XH_-ruV)B3yw!3a``-FGiKkWB&59$%q1($fIAw^WOzam(KBk7r*^322LddXN638F950 zsg+cf^t|Qh2`|yr>uZk8gGASh%|nc$*z}?Af#P0hrhN+!K%Gp; zv#Si9pHwc(#z|+uTOtKI94SZ8S#q$>)lijluExF_e0C+NtSvXHXgF?LW(*vxQ%Mo(~FHH2O&?Cks=&Q0rD8w^2{ zv{%Bu_356&N{Jx}9ONpXO>n>0kXxC*PH`8u`w%5u;Zcza+%DuU4J|{q9jHN=dpDhY z%`Bom5tO_;5)N78utOu_f zlZ@4p?+tQ(v;dM))#!6Qo-2DQ5Vf9Hd;#U9fI*-D001BWFol5B?)gfCBR~KEd>{b; zXaOJrOl@sVt&E+F9i3FNH*8#+e^Lpsy{_@-;EZ*D_tXsDtL3IHhLJYiI= zs$jdxis18F%igArh_0#aq|Q(@2%u454HR*dpxgie3L{d0Y`|zPuG~>`?YoO}O=^=- z0I!9M65{&0?Y)~Vn=VUW-wB`H-u`@daXh(-NS)Pb&SIyP8&jebwuu(d9xD6V(YXk_ zohWfO^3=n$8pt*yXpHs819n94Hl$`{|72sW;u8RC)%p`+2g?__2D*2957PJ&vys7B zM8ZsC;?WPfRUZG!2mat?{duu3;xE37y6aewLQ$%5#M%Z=XzT1+vye8ctP;6LPUVr zj_ib~mdFK=TdGc*Ohsn_#vq(NHN3&N_oS zIM{<=mO~Ulu$T~JXY-xWzH)<(Y1C(~9VP7p>_Wh+^TO-jR?px5fWeg{srZrY9Z{gb z+_l2?{YohVS5VO~2?ow2ZwBRh8b%bzNC(`*o7#}PR4N3-{ZWSD{fByyk5qcTH6V#d zP=H@v$@W8oAcQlhri?&2WE$xYUWkAO{5s@7<8K^lXXO#(ML(=a5gb`e@znRTZX--J zHG&fyY8=Ix=!9L(brHb_66wQ0s>SN434r%f?a~ctxs6XKmVI4)wCXkdw1?E68MON- zsT{~d`)RaOe^fDN8AZ>5Hj|)J$P1qBB;|#v86zRYYt#qsqdMq`Q6nqQ0I1eCk-q03 z%)M~w;tt1Sm-|UciuF#Fxg-fE)0MT8Bl-)-7w|ic4g$!ed;F{71lklE|5_4%62iRr*%6NkF#eer)(l?aA%ui;n% zoP$H!GlsSN+8V9stJkpmh+6*u@_>rrk-eQJA4f*Cz~(0gjx@8&0l9B3t{A=UoX4o@ z)kL)VXrCy{Ee6W%LGH@$`|l&FTH0LqCk%OLF1qNU)daD5%7rcyq;=K zxBCEtU)_?~*Ehg7u_7VYU(o+9Zvg+Vy#3R;|9lAl|K#mIl#T8`CGEd2^xt%{RdC`k z_@8WAa{~a-{BJEJs3IXPOlzR;VQlrEYc6a3+8%Hs{d)gGMgA<@0C|gWc9-U;azdGB zl0j)BZB$pN7$E`ogrr5{bZjqv-?F&~LdMm`m3r1vS(|e+<-AX!$Kp7KcvwB-&bR^s6q1#v1~H zev9?{GizwOluH!)PMa*P%_t!ttWDK?G<(W(%x=&atqSJ|sTrc3=LZ3^A=&RXvEo23 z3N-X4Eg#CPpX6}lPfbC{QF(h)4uZ^yTOx(j#I)>pjud9K1R%7Hp!_)p^2X=HA%Tp5 zqIJedrj4Y#7u`tP4-X>>)HD?Zn>mKPttt0cNa)VpDhl_xXGM%{mcA^1$L!1M z%=Hzm0}u8iL%-mr4qh%aC4X1CDqcSzNpuxtCj|2XE;s(g+RCgXToh~pZv+@;$lt4w ztI28FiqLxvOZwyEt|pux1T%&@j$sbZ2^ykWK}p7IEKIcZOn}Mb_0IHF6z^=MG2>pf zHN>H1GoBz3CAu@D_?0xU#(xCakeiW(IQsI^#CC2OugM3C*-s<>r3{wFXvY;i@UND@ z)R}o1#)4l_`I#s%PbV9&jBJVY^<~IPW0B0J91j43GB&e749AKGrx%Dcb6uGwH=AL3 z$;&KcTtEJWD_)1I-kv)F<6h3r&>U{j0YE56I|I#jhB{^kR`dsyy%H1dbB@Um4ynRqKyUm z9_w}zNJj>yAfQP$`CxG;Kht^H<~F_!Wh>z~n)7FDhcYi|C_nu(yA_I4_vfECa#Wi; zxdTAlk32ePqy~J$L+Tsv_ke#)fJXON&^q((+>~OpyxtFgTxPL;Ap~RXJfGpr z&vbP}du#tP9$ufz)y@k?FLz$gn*%u0{YU}$3PJfzoH!25>S8LSTY80-QeAZ&aBzSl zvOfiNmt@J7iw$#qMCf3qrmnV351LDlSZmp53;YdyIBj5y8G|2%&Yzh*7N$Y0;a<@3 za=>P}e<#xzR9^mwz>F9g$w8-BRu0ViQ4aKi1kN<|AKYKxGF%i7_{#TTMm&4Im;Mnp z(8}G6L2k4aLkUVB%-xK%ikWolks|qdcs!l_`*6D%iv_{R4DGFfvk$DJVC-H~lB(y$ zYzhq^L9{Kv5Se$3M2$uxBIR?GIFTIlMm$zpVIpc7Opv6dAg_#nlav>NJEGA9;M|~i z>0o3G2>+-q9}@R=xq_KWn5};?Z3mP==yB2ipqrv8%J)*l%dFR9MLyvm3ml-UHKhg> z0!T608Xky5>!%thBtR|zc|AahV!W5MNX4n6s^0@)$`qS~I0KnPO2S=KfC7F7pvm6| z20B4AC{KIH$V43aZzS1Eijx_nHPS+PFBsKUO4Xnm*`3RR+aaf$e-FMa_d(d>uUFLg zGm#D%=IR-V0;9gsrkd_(rCh*CFZ#Ug*>tcrRD>{_<~NrV6Af01HC6}JCS#42B_pnx zuCIAgI-6LZ%Ars>Gtq3^iK88q2R)vrIR6b~&pM#Mh>%AIqHI zpX*lgWXuRJBs62;>RcFg5Evz60sPn1h? zL@XsGRHRsK-Gd?pJHEkc@oO9ke1R?A>38jj3j*lu_5|Nyy#a%=6^ntRcMH!#z86Pb zsF?VK1bA>SiSX!m6EiC-uY{Gcua`eX#X7X>`Gt+HX=vx~RX4hz52^_jj8C^6lBUz# zEYrEX-Dkb(h^I#SxgF2d^=u9)UJFq3n%@_5+}&nkH8}oK*DaiW01S9D*T83G-X=Wh zv;~bb|_q-fe8S+tx?Iflbe z2JE8oxp3xPdaW*LaTG*g$49Dq%Z~F}R2?OJAx|RXBv5o6Fs4zI zj-hkltK12zwnlT1`PY@+zKn*u4WDpH2|`{)5)pr2H7Gh6;rZtL!6*-)5*4Y4DhL|` zDDLT!=8~!na$nK^y5DsEk*vId;#0R^r&4Mtvn8V}sMdkPE>tSX!gQIn05TQGQsdf4 z!Y12`<)sSAb5Ej%3Y2*9><*^fp|RpoYPUXr>nQ(1@k!Wafz{;uEnuQ zFneR?mN@8vXg3UZf}PZn(X&Sy-UQ*gK-2It$>FkWp(4ZCx;#dONyKFtxB>++_*xZ{ z_?aNb!Lkx*52Lk5*2);ZSXJahUJ!E*lz&MP=h%1AuftKX8s+*i8TN2m1?PD=>C8)G zCrL*ss)aDVi)s2XVrA!P`DTRpk0a{>_}Ef&!%&e%BqYBoMXs3F)E7*C~b@eXwGf&gbePa=Tx?C%}>hIVRyZ* zWzA#zOgVVx48@xBkMG(y{C@@8QaSQctbd1pI4l4FiT^FI{U3$^je&!)z9o&V4ULJu zxs|hnF^#j0xzm4OG_9Tce?o8dzb4}iNhF`u+B0WL&?_MO7k#{}hd`JCRh%ewi8Xs` z>vE$%b*zE~%t-$x)Ar*2Z9kUhl~Ac;PVMp9esqrI{l1nWO{A+8coGrT+PGS1WnbVm z&ox7^b&;s^kUGy@UH!dS@W!qc6fj}FHB^NcQfy2>A`odnjqKSli4?(KBzBu#z>gV= zMN5(p5D;dZNobcRl0PNm(i|DrbUEh{-zAq_+GUp_Fv6h=Fs6Ui5KjFPo)aa$#FrTk zV3p{CMROD1{X*dbG8mxufiFOvJ~TtTBOT9Fj}x~|()hZ)1s{=!NG(=*bR#g!9!I$; z;;l07|FP^kE(d}L3qN2^i=;IHmLM>y4=Y(Qv)4mHnGxbsk1X&X*e6x zg>EU2XQS`PQ91)JSJn|}uVas&>nv33mjDJgK$-_C40r@~sXA1ahl63X1q6o(PR?zI@NV0|Ga^w__kM--`^f(Sx@t;+jVEgVCT5>0Ie-^f( zNntV77tuGneC^KrG2vl13A`DH&W4(&JJT)K;fl1+;a+sgDZC#9M_$XV+2J%;(_01*`o)AeYZM#hOTUBi`XRj+wGK6JgWz6VRWyX%w!9(XIN0AvGBs}KDj(+wC zMm=*gSh?h#Q*L9_DfMDuRY|vVGFuz&HOM_L0sssQ*`qsTl{3)aLrBB86>ZXO3sx9@ zd4?FL73Kew?GE<8y;FDE-d0Gg=#opz=hQa(+ETduuWU1Y2j1?uqueZoFrmQ3VYN*g&q3g?S8k|f{CPEe+)0Ch$!S%eX*~af6EyAQ=3lN% zgqr7Ef_-Y&&j`0<#uwg6S!EO>j>nsB8RB;VY}nhkFy=!i#6=*!G@Pmp2|46Bj0@R_NX(@#jP zRx}tO55fo;vw-k%RXnWVsDt-_q5!u2EalxW|)Yr6hS-oZ@ zhjBg}uZGzU^R1FQrUJqs7a((kr_=C`Mbl_DQ}U)Cchj_rGiHzVt2d!d!RBUuJ9n>x z#t_es)$CnTq;gP8<)Z&EkBRT(a3idu6%iz3+ZONm%&k-VZu>{Ly}Mzyey&NcI~=*L zb1Cfvlk{07EaH62{ux*nuDFEKjaUf}3IT8NKF6N1+BDRLpt5%D{Ut?HVdJ2g7J(0v zrqnO&4uZSK@A;7oHJ_>7?hoT^8n?UL9=;hD&eB8x5rR+X$Gm#4>2|5(;owfGt;Cm4 z)sA;v^{K9hZ`;8jS{`3U@AJ@X``Qr;U#nhTXCV0O8!tUdFvlnwc8xrmv^VWdeZs%Z z0bOEuweM_4*%dEupC116mGBr??+fLT+BjBSPV3Mo-#I=bWo4eZy6+?@#6Z$f*g|-d zjE|$aEJInZvawbZA7OwIU`hf^meQ>9lrqw5+5ZlMN{+3xXf&o%Ks0hQY)tKM zIR7Nb;$U_GW|rfSY_l!b@&Fj(f@h#?kN^z%cGPqgMI1XB}jY)7TTTj#k4k)yV; zV=AdVF*`kUJuz40#_;_07Jkzn4UGTl1n_rs=LL2DoElWyWudF?LM%QEAcOW(_}`~N zTBdjB9lsuM#V1r?Bx~6aW=~LQM*`#Wu1T@8ma$N{7lG9h-C(o*?wc;{`Dn?$E%J{D zbVSK|Hn-~JQAHIf`Ld834ap^vu3h^M&3SS;RoXOe4;X@2xHxeVYCMW+<)g}qI6U%b zguYB44Qv(4f001W7>i!A3x62p2QM=NC{F-HIEG2l%=5$|$(WBP|7u0pl^^W)qkO?L zX{)NMyl3GN!yE9BR3{GVp3E4d43RlZLIJa);CDx``9|{U?u$MtC|uZt%hMPTBimI2wzu(YVxZwU6`6_QI=L$1?F;TTN7WTyYo{Nkp$7=k$ZgY9Lc*l-f}v&ankeHxpdHg-dX&c z^!(i`LnawN+|kp!zE`tzQVzBjilJaNu{aiq9P1w}@ZQJJWs2s&t=XQ!rn~Y`U!W01 zE0tl?jWm{dyJZrhj=KbEyJs4wW)%ZtD;rSK2hLNAyWPG zdywZ+k+T6zhIdn@OS}HW4sX>aeVx8K(1qUBeKw=LwtRi z^GHFXKLFvsh;D| zBs@Hd-sie8$J2l$4Xs9u1y7L~T>y(&X^+Gf=B<8Td0MTIK8llF9trq)W_VtmZMJt3 zY~|#V*YPktUSF6phEJ2AF)64X$RS}ZG^sw=^>A31G@IoX_*(ycfDXenx* zEUjcnOEgkw5P2|9`&%9JT5r-%%%7N;HY72KCaGq~c5r5t%yVQ@ ze(E`RnZua}`eL$+=;O(>mrkX$?@O`hI*50;?GyRHh4bixeUQ*7meN&@PYVn%O`3RF=LX zg6RJ`nKS8celgS75ZI^!yC~PRtj%XPkU;BLWkHK7&#@t@gpQM>4;ND=xS=0tugz`I zX^GqJ_AycLQN&b3wZ)`uhpMK$zO4H975DDhh!(ZnETgJh9ifNr@Jv>AC}`w$4dqB| z@>6~01akUcNUMQ}4tu{v+K@w+WPv)v6qVfm16Av3@GCJdtzkZj2*da=V_aXL{~9zh z#Zs8j8F*zlj42TiSg^tXzQ6Vu2w9@pk+iRGVgUt>@YU@7BGx27>FdmqGATi3rfB`8 zrlyBI;kU}(aFh1%q&TF(FR9|YKN-4#129~j)PZaeWO+L}h;HX3`#dKK!>8RjZ8T__ z$02_m$LY23$bj5hb*e3I07OE6nE#UE8`3T!I$&wno6pi9<^3wuX`KYJ?f&%M;a#s7 zxWt26y*j;XkZ|<~W&AiLB6DOxICLk{efCrE2fsj(_MWOFJ0mjPeU^J3z8$;&?O}2P zZ4jfhFm`Q9c+>#ZkykW?e|hL8GWsRCQEul3qJr1#95#GvG-CBB&?Q6Ys>t-A9l7wV z9BphralkpY=Y6Um1N4z}P|qGPB5-vvlA3sqvKK$+VHrf)UyfZ4^SzS=mhX-%G1^Yz z(j%E0;>X+BLfoXQ$&Tl8{$;-bM5ok2v zpsS}g4{gCz6N=(e-{%jctlxV4XkGVLaIsEj=xw5(UTieEQ-N6Mk&KncjvAwx?FRoWUnP+=e+MC;EawqJ zLNf+dnrWStFD*&rGzsnwr}6DaFq0Z1N@^MK0rU*?&0wU`l&(~p$<%uNJ-Lf;b!p#u z?hjuwi9U&3xi}u_y&$EV`qw@+I*bV>WP@kf3X#mx+205GNHKi$?m2fnXPje7yYP*( z3W$X*TP@;PvW)sYtr?oL8`c|gEBds#4E}Mj_PlhGvq8>Kx>|dVhi@gB4c|-Btsz_{ zYJVKjR^%*}faWs!zK-saiKdruo>-X-JffOU#rEz_OQ=C5NwBi8gx-Lz$b z4sC5^IkZ3Zl--x$fNYp!BM^|D{!NOgL(ofME_&v}%pNYfq1|el2L;isM-o@X`b&wlMa|_Q2UjnJ*0ATHEF^{iw6nRqU zu*Jf)RmlAkt_vmZ)NrnBIy(v|7JbX`YSk8w1JJQ}#XpT!@UvNW7yKG6kyH&Hm(uFV@%NaMuWsK?6`XKgJ zoZNnY_}6wP-6KczlYI}qX0@2Sw}E~Qoo3J|Q*cZf%;)p<2(ArTABC~zwE|3k@JAan zagT940i5-=T!c1Lj8Ue*JVi7>XzVmj0t^wHqQPin2}>D`R7*X~h=%L#Pcaoj_=m0$ z1(ZgldsCPRLHHSe8vRB27Y57)bq- zc7K7d?rWa}LL^Q_dK#0uDPwR@F+l-I|GqN!ocul*%Ag45v^uyL5hTL|A)<4&R}VNO z>dXPXW@C{n3Rp#@yAe1rY_=&xwQ#_t6tyojBorleR-{IY2{){3|3{2H0((Lqr?duA zaD5eb4N!1kTaOLDaoQkZbBgez-86(!HmkO>;l!r`WwHu4Iw?}PM=QOtFeWoUz@ekp zWEftUA&nwfyJ4KWBS_d#AShhkpJONrv~wbc5bRUrzR z!NF!479;joy>IN!l+*q(&`%TYCI##XSJ=^3np)r%LpU<;&Grj`2msTg!l-<2!%y~k zJm;i?Q)qo=KdecX+IzLb1>B9F?gjQb@6aY#QQ8RxJ*&2!e`l2t=)-U>Tz9lMd+$xA z&=7CKXU{Nz<^X3)4qms_5xcb})ZwTb>`4;fi;{ujVD{+Ae36Nya_`M%>0GOd9BC(f zL2MWK7`7H^EWCL#G)<$n*KENG({Im!MLUF#k!bs1u$=D&ra!oj2bydk*xUOuv^={n zWIdp2g$lavTa8;RMS@ohfJdmWiW$aFSHyZ=5wC<|zQ}}9bXB>;QazfE(;tdrI zsMwblX1W?N=JRi1M_cPT%OiE`xH5Ig7DYf7{|ado+F?;ZEM^I9g#%D808u~HGJBEd z;vloMW`)|OI_NRC=9-nu59vckln*IB^CWep7@K8;{wnS*1s;sXm3M$jQ0VWJk0ugL z67>z-VZHR7sTST5lbse4ttbSYPpo+kh26}NJgCUC^oOYuZ7IetiVl`6LDnj_xOKSH zgiFyZqywBO#hKLC@e&!LECnIuVtn|Tw!#SmiscG?b$P>zN||`6=3`3hi(o>BlzrT| zYkd1aPd041wU$DgkHEVRUUYdJ?CQB6uuc_|k~K>#rYLD4wmRS|a*K*boGp?Zgk{+F z_d=^+F9;g$M*V~l^{SU3p4f`vXcZGVN1I-U=X$U@wgqkE59DPTktFO{BTczs`kWd!^RDN8{qaW3vkJ4z*xzsaTI-cSrUFdK#F?MTvGG(8MnO3kuFs zVnAw;W@FEnGM`X51(`}s!x?-+XgpXFMi0lM_ozU}VnG+GF(A*Si{@c2Q~R*7&XlW9 zx%G$F27F9z6P{kd5L1lP%fRYb@{dV>4lcb%aa*i+)i6#Q|2 z-vE8Wg|3z{<3wh}kort#PvaT8G-AIN>7JaYrNO0Xo}z?=P$m-1&gh%tpuGuaix#-* z?QpzyFLf-FpDHVDs5ZXUQOr)=W*Sgf4JL)swHuvAFnujt5|WfeX`3#A{f@imX+=1t zbrvc;t# zh{3R<7xX9*pOCN$JTV%|3a$96s+w)!y|ek9TKeN{Oa3hZHIJ2NHbmj3vFe)&Et+rt?L*2=on`rRhO1MjuIUH0FEG(6ezkPitg4a| z6ytQ7g+_uplYTC@?=snV}U_({qfbk3wW*q(uGZ5Gxoks@3=1-7a%h?ZIuO6A3(D zC(`BrYXT(F^qLxy39E_+N%)#kR9MJ<5Jet}oi1fIJ&@M%Inm&@Sy9yF>eK&=us%cF z4Ou>W5$55pztw|2 z;NatkTBa!M097J2T)E=dP=;>wR5 zRL>n#e~$aip;6hEi|{wuEf;?4-F@E0N7PKE@#B3?W&0XS@6$NEqVyPCrCcai($>mZ zb{U>>>{c^Ws>fR%loxiZQ?+IF;}Ur52?O(C0r_?{B3HG7w@$d*@?z!jnaRW!XMU6P z4st2(oa81Ck3ah4eaX{W{Ued1HUwmZBrCvgRFOX?K%B1d!$@;4HBJ7b7v zq`w!|bwDi*;4B7A*^m-pEh74nYmoDSj$U4EBH?B(-@UH##?{QTE%Hs9djdD{VyvH1b9OA!{nnLVyINdOU>T^U*PY8 z&t=2PT95qG1X_G_eYDc-k>~?$`tfJx-$Bsh4Jd;ero(rA)9V==yudGucJ@r($E_K@%DI)B^@y^RRBO+#3cTS<74DZel`Vip2790EN+8|N5%yt3v4$l? zkb<2vCs`!1(fzd!5WsI4b%efQ&@%!4&|!f*WUO5GZ?Mssjg9}6`aEjh`^LZl0J`u2 z07U<jPU9(*)=t+l;A*8|B2uNdG|v7Xh9 zO!N&fPjx`!sHyPW`Jc>3_rxl}(xb-l5!eOX{)+bEj`9Ub46Cjq=D6dgX%HMrf8C@b zDIm&wMKt14(#01fFvW@rq2rI}PaRUwK;`skhlMisL>Qu>zD5<~Qo=`>dqdTaBqRkR zf|^KmvR3EL9*;r!K@A%C(ISHetCT?#C<%q7I|}RF^71$EipbDKFdu2*N}(8)ML9E4 z9*;n&oBo(8a2__a;y_?py%__7tdo)iXc-WIO0k3M6UeYk3J)Deor*L;Y+#HC?S%zt zDBGorrfYKOfWv@G2qX#xW(_LQ$V@z%jXAmlDruJ9wGxS~NpYEu8uY^W&VH@dn406qOV1m%wUGqMA{iD1cXQ0^*2;kMn ze__ja3T@S+FsE>9xk9n;yluGZt3sQC-e!GFS$zgR=+vW4gFVOE&VbH-hhRlREj85u zreHQ|nLad-Hze9jv)FrbhXW1Od$O5bO+cYje>-w?n(3Ll`WS^a@AUq72(6m(e|@Cb zZiF~bfA9?Xx%h9>lL7eZt-WymT{zs~oFamg>9FfZD7V*VVk}*Mp@~fgoY(xDekKfJ z?kW+_XH*irdWIfS1an)XRr$P*M=&!eaE7%yg6eQ}^#TVr4#VRjvo=rS1MOYX{}kOfccK8z31_n^ic>rF@_cJ~9`q6^>L*&{?eaYhzDK1r z)+Lvttb5mzW(8EOZLN-%290SuuX(ajq84|V1XOL8c)H9=;vV9Ju6M5DdEGDRt~71d z+5Lj{61irEgH|5JvoD!j!k!{F*ZiToMJew@$qRdEaWVOcV*7eJ7jaw89M_a2<@UBh zTyZ}02fPwNlB*^VQIdHY}oX}*LI@>ky;1vF>t=`PHf1a z7{Stl5Es?L>N^OOGP^5l=7%|57OR(_nYex+-;IH??BDPzJIFcAGf6$;LS^MiNCKbS z+{DvfYoLt*&03TMh|@RHVz2I8L8adb&}J6p`=CTGj8zE>K%&7uh|!y8`9= z4Pkk}_0!5HjQn->QEHSV_D`eJWsCVKo!-hTRwQ2*Qiko32 zn*kS(5l5Bhw-7sEHb|Sve>T+$UgIVTq8dcEcxkjZ3!ZxRyg*(BZCHr zjxrUeKW~9mQkDJ&>Ml)Ji*&gZygxPRig+ubqS zmAB(9x}{6u4lkNzE!WaNYauEQj(Frp-waV1@_6?Wo`ni+r^E=38iKjRuMI^@x6X>L z(Xy}UM$x8S@5FFMvMBN`-`6|&&`x&srG_J>Dvrr+(%psQjtlcWq{_9wjE}RSh=%qW zT3b@B<(&=}E&ilh(4~@kZ`gLk;s({Sw5*~GDWvGTB2omgt(I?p(gA7jX-U2Hx`IOQ zjus8M7GO5d-^S9yPL7bGfcN_D0;2C~qVcT?tl%li57In>Zd|pm>To(%2VjGpe0k-c z0+2@+*pX+1RPX?>OiX9GxV&Ij$BHF)F#d@=atFR+)B9c1*5qA5yh`{!1KQNw_zs{W>&w1=9s+!3px!4i5lfW5|Rv<@~g9owO#2XAvQEO*CCyCyk77W`xo*NU9- z*><$V3f{ioR(EI#+*P#T?Umy*ld*NaHFdeu()MJ(j5RsrQ_+RfWy{r(c^Qu@R1P{s z4Pe`u+?m&}(*AAl9*%MCJv8!C>W@$CDfha)Qg>X?FYo11iq#}??NPOzfmPAgEBGF4 zuV?gl+EP#F#Am~lm#q-&mLsHNb;;Ps2*Hl;ZBfy($SidN zNZ)OJCi0&lH|sTOPlQuy%CMKnBx#WMzyn!4&=F-SW1X)A28dJe*26en*4_xzEsG=< zhFWUk6v~c#H|J2pcWA4A`4!-)44AC|UR4)|li;W{33C5%$|(L_94#h1tyrx9))B&1 zhPZ5IEFYA~{84lP9E`c|zooA&>$2NRsNh9VufJ4b$d+zUl;LtuH+~en(8{>$rRufa z0CKR& z1l|0f{u$ZcC&%fgE;77d4k{I27V$=Egr0uWEp4gk_x*1GJnicz;}<=Cv$?$A%l`RE zmC69K1+<#g%%IjPanK|W;E1j)Q>gX@5!@O{B7{s3jejIb@W=Vb8DoQV`t9_4f{UmA z{eoBtdw9mx-^m7kGD{4yNn)sR5%2-+KGCDgB64AvOl@9b240j`eSbWl?V@ro=>}9` z#z#a6RDWNU@v?n8IX=~qj=$hz!hPE zh@LSKCJVG)aY$fM^Rz0F9d9OBm{mQaR4_Em)U*vp(lFnd<5ETeG3Vg=sEOvW2)orP zs;fX@DY(lz1b3toi`h0C6imcjYCYXF8l-5FRgE^ZBqbrXw5OetbvdZw$_YwSMzue# z(9i+}{XoQF)FUbaAAQ^_4G8jxffJDo0w}oD^L{qWsFJjiVv5q$r1DsZ@o5Mtabpe% z3aXHj<&@qapRHTKvlwr#DU$%XWdF$ZA2eigU}8LFjc*+fYT?;rE9AE0s=MH+S??aR zDecsR=e`dMk?77%7UpsoP0XhM;92UkR z;yL26eaMP|`@n*j0vMjW*xXk-4~lK&UWNhRY@%52wJ{ga*K6m#mJm$_k1u7j;{sFG z%y#dL9T=|M8i4&lU5i@hb!%NQb5f`3u)nc7Q3RY;+z-*uS(y$~p#N);+gWw0B=cE{ zixfr?!+AEES%*6+b`+#9lEQVnq{H*_iqe{o__4BvY2aV|YYeuznAu?^9ZrO^^EC3< z&iDK;xUsYr<28-zkmtlZIR4Olp#-;3`5&{K@122g48p$sKb)OYdnQnntYh09+qTV4 z(y?vZ?AW$#Cts3|ZQHhOo}4*1GjpzHZubvZ`>D06-tuO7Y%z^p=XcsX9XO8J95US| z;z=tF-svh?tuNQF{&m#i#cukfkX2keF+ zrf(V5cLxdB%H{8f5zen|-yyWB9l z@Mvqb*B;{F;K0;huSw3C_ZC!ryo~8SAj&)~rd*_j+Zg~s*{>7(T!8IaF83x`!da*D zV1zaLV=3TGPZA=5p}DLOl+$_hTk9xb@c-($CshgQ?c70dIoR;9k3Om4m#(Spoq(BV z^qd-T05zQs_(hGQ7RrDBA;^%~Uo;AXXuLN4F7kq&rCWPKVft)PXA~{G( zd!=>6zb}2cuP8FnY=Bj-9zX$;!Z*>^5u9pvgLH)F4mGdX*o_4=0<@OQe{*6h<|LdG zPN`(a(k+}$wU&q`YSgR+$va}59v&g)XRPsB?85uf6fF!CAJ~<;y8_VbRJ^!sf?eZ!*rpDTTPm|H;og+Owdtl_ z@BSOc=lsfY!^vXrBU-j&jnVSG$8qKr6S~Q&;K|}ry~+~)K3UkZ%V)Wx472j+@KD0# zQz88ZS_?`{gp>5>^|@2jP(WfAhF`=CA023PYfWmgzf#Y^pAtP4e45vu!TYohs`3M&dG_^L~SxjaUp zg@z$7%%7^lcGP>FW&LCSgtPI>A=o@M@C+zi0Uq|3p07i@k6pGI(~v`4o8G}+qo@GO z5syMoY*);eH#y4vuRwP zU*iAcJtVa45%#9yMSMHuUAZC)9AmvHf&zKVMg@CI{ex81PYMf?IB;{uXCKw9y8iOt z43?vNPZD!K3CrQ1a|qA>{(t)~O1M}>)^492sqZ+M z0sBNO-aNC67Mm2Egz~A|EhK@%wRsaiBT&R)gu`yj`{oFO*vFmCvfb(C^y%ps=t$EJ z2fCxWq%ac)Difk(H6UI!15;z3Kb={F<~+*tDr=4|$p$_X>{1ZtThA><{;5qBM|UxY?(0$xqPIqDd(kZl;Qs^(Sa~ zoU{IhNB5x4R=g(7^65r=awC(9iX7E^6}O>A4|bD0^}Q!7DU#Gw)7ELN9T4}F8~SL^-k5U){uUfq@|azq$uDlqUN z4TghuAw66m48Vo4=jh@e$aFsP-VITfQPlpoDr6!W`Y$iSD@rNd3CCVBBCLsd)~AMJ zTCW4-ae;p3$xeH*Dc*EWw0yT%N=n?Ep2w<@*3>wP027UR6kb{Kw0jC=sPqtbo+r&x z=)sL;1Ze=9P$E7*4lpkr)|DA)tr{IEm!mQR%JJ|FS;Q%*S0pA1yWSm_G_g3OB8cZ6 zSEl}*`ya>_w-|JPTUY`fGWgb4=S{s7ryT(72Y%m6JnHu@?~=$==-us|SftSBX<2P< zwsoCa*?Dux#(WkCMRj3)!~C#PAnZn8i1UI9o$Ip$#k)pcdGb5GU0HYNZeX^@$p)Gq zkL3i$`m5z+osGHsF69**LPKmG`!T}DMXznmtPmn^9>mugG=&s{f$e*_tFo%0yg*sA zC3n_ax4Ie)-{z-hvs+W~itWd>vzv=)UCG(M+Szbco7J6ye3rtg1gt5i^9fx7QQ1l!nhTKz6(xgZ3=-u?g9WI5+NGMQ*Bi$^#|8v@_ z^-HSyv24cXwr=GBr1Q}QyZ3_isB-sj^V&EBo2O(*g41)@5r}N>RH&|#Z4#$bDyeP< z=X1R1uBb1F|EdYf<2tgw>3(Kr8xWAd|8!;=n;1Bo|A!{{f5PBD#ndl-tlV(^CG5C; z!UR26iHxB=)+KJn<4)(7r%bS*l#fefWs#Q3MOrKJ*}6Kt8%T{#emqq}&cHte78!dz z9bHi)h`E3U3+Kz1QKP|xh8AGf5Rlk;q=qFH7GAIIF~g;H(Y*Cm0o>dv+qxJ|Txf|o zTnpu{aC7%7<9VL>s|7yk13mDYXXCWsFN*K@100d*qQil%Kk%acQwKHxe!am8aIyjs zT9~hp+{iE-Y5hu=8sPF8!QnJ%+&v*qJ;*Kcv^(H^M4kh?#H|uX@mXYhO*|r90iO8G z+CjMJjCMce?7*tI9oMmg?(R&lGk6*xUE5J10#DP`PPbQP?iS%&H%G?`-*=y)9R#}B zT7~r|2vfVK`pjqDnSVkGnF1`Fhvi#^uG<20gCFN7N3dfD?MdI3In;doAmO9h0;RUG z|B3ybY0t=chD@~qW*pGx6e3jnJpTgw{U^l6vQ1kFj$xpQ?W{9Yp#Azy?Q?W`;Xv#! zbI%cd2uViMUI|aegV%iJmE?wu1V?{8S>4~`PlxM@_3q{=9zW1Vnks_oUeTy+x7wPC zE8?u(P=B^Q{*z7gYucX1_p7nKqq2X;pYe;C`v30i_y~y!Jr>0U_i-whL$3ufVYwIa zJ~vYIhnKcXov?yp>)QQlTI{@`I1Z8;n3kX#8S+&*l&&*jQcq_p57Oov|>Sv?qa zn?+9#EZWNiWya76A9e7YD&7NuLqU@5ytkjW$dO(kk}sLFcBVgs24Y0LLgpdquLZ9i zi=OWSy-#!)!Al5`m={4ti)(qi+x6ZfC#04wi8)63dv=EF!exLNDh}U${q)UxEOs|S z@WH~uApVTVIo~roJ$HfcgQ6&<77e6NDS9;~E8>lCxk; zzX51mJz)*^u677Pb!UcXg^*pR7az}xh@2ePPp@O9E+DSM92*+8a79Y6OZp@Fu;OsG zoR#Z#qxX%oKU?cBX1j;>)_;NM@qMw5N4nCz;&}oQI?zEVoq$=>H+uo5m4)b<69EII z%oQ^;zRLtal~%zWNWU*WC&4$GN^gz4-LKunVPBrtGSBIXfF*ahK!NJJ^BTw+n_#*i zVJ&3P@0vTvW=d~p(^(9M08o?_sc&GcP=)_Y0(2fB=W}5;rSw5H}W8;i(5e%GKfYZ#315hL$^??I^5c93l&-nvV%YT>yO{zaO zqK(X2!|$gY=yx7gizk8uMSV8pA3(?l;gh!H59VZRvN-DtD50h|-7!3@w2L^F(;##M zupZQ`{)&wH#_g`P-+#P@6mTF^t%6cWkqi?QRcaOGu!}c@yoh*}Q1^@I{=3p9STYCp zl*WyGZ%0b@TmN=8EBagGBXK6tDuV)BLKsdB=}+jH=Uw(S`ev9T9`u}jE|w=ir){hd zXTGrz=8riHeuHxUu=H$N>LuKQX!UYL=2DzF2>DKIe{B1K@ zMUC6dtjG<`TqRik4mL&|0}b~gd*BNa%}#FeYq-Uhk&MD6PgAE>kS5w{_!*q&hU(#n z7>wR!XBBbXN)X-0`8l#vBF$uI_T8uXnZoZiky|T=rx??*;M57R1T){~s+B-cBt=+e z&({+M7RYx8%mdgJt@Gek2dF&Ics2;d7OhEa|L;I_Gxc2hsyy@xdV8Jvi-k7@Z1WUU zsnu~I%^vHXRAvie_{~h4;6g9Ev%%CI&CHb<5UOdKgeJt|7tm4~=u>I5od33<>d&r2 z0w*BXuMl0{0%Fp4k*FV0+yVZmr*#0&3@g$mIKB|;E-flS%aqcBM; zH-M}9Vp?OL|6vFh>(BBvp;1dPps%9plx>-^TGLYsUy>y8C??V|5z)U4abf^(OF6F< z{u|q4&l0_ zwqh|OWknZTj4*9VK_$qyp0^qZq}dnEVERj648l2)r^?uGiUJ4LRFmGQao>!Qz@cd} zJYe%1!)!joULw)+s+Ci*0VH}PtxHd76IKI#u#H_gx`G)VG&mU+<2ma%mL}EsnrK%F zu~0BE0H;)S{BkzIj}|TP6u}Vj_c|S3xZ=H~L*Fe#NdMT#hry1(-m@YqoO-?kYzJ*) zGZOB75jLNbyvB#3S+QELd78MG6;hk z5;S`I>LvMnAk+wO0HO-w42wlWQ7z~)4^`X-8hDYqJ- z0fpP2nE_q?Mul>uSPv(}z34Zkq%|cMbTwnVKO<-Kqx)Cx*3snFUh@?tyuJn*ar$mx z8DTbWjSOoiU-O6I1#t;k`wtkZ8ga`txQOSaIF%GQ<`};~oiR0$xZlZ2{3^I@VP$TU1WDos5)fjCO;0ww?ts{9uzc+mT@dQ2&-PRn8{>*ZwXj7{ZN#_Z!}=2Oa0OJM&Gftr{kLg6DvL@yZOiv= zMqXXx)>1E%2sPY>Ddvo@BwLe)_d3e=i^S{UVB@pz#&vTP*EtMqBd1$Tg*u{&*i6cC ziyEjBG7bAJo8=Fqrf^Gt(={JImYJIpbWqSn=khxR{jaJ7pDou=HJJQ$FaAy{Q`3A( zgil$co2|+R#Z`XZ)PW)qd^`N*;L&N1}o^bB5-m%q7dMEq>EZF8>0K zG{L`}?WtnD+{T-~ogZS)mL16H`xIybDJ`hAdEN2P7c0twAQsAEmy@GWjLphDrV+*1 zf9DdY5d+jc^{tQh!I$R1CLtO+i=N4~TrfJG0~amTgTcMCJV%rixemcOG`W0r!3H^1c(q^2H&}X(Jo|y6^XSY6p<`rrTH;QqSG~4TdOCb2;ua!gCsmjH3IdQ zCDY3-dn&eX|D|y}ENfX)9j5U4rQRt}OLF%ik&jBlzeg_{TtAXQw5dP2N$o zC1HM>FUCXsdV+gB`j;#+$1|MtWr@Xe7l2bsB&~s121oy zkY!Sv1nPK;@nC}ZL)|6_9Pl`yOx|c_fSk{quB_{mDLmm5`$zgLk?h;oT3@4Dz<>(?xHUmi(yD`}jQN4sr*L;v+ zzW||deJE{+kJ)eFPQQjZS>RPeH>B)c_4|lCvKe{P`t}L|zBBYnT={X9wlCo-kVjf* zFS|Z88AI{u+7S%_88V&(D}-vy3K1(0o*m?Oj%tM=R+nXKVsa4SrQC2#h&pQ+$$-rP znBZUc4o5sBWHet?vnw9FMvwq*sT-RD2oz2p(ZZ@-I&3a6fIO~u|3v5_Y^VG}*=tQAy*ACCS{HUZW2d!72Ya6TE%0A5 zXR2_y0G_or<$*|!TM~4J8xq@Q_Z90F$%anQ_#rAOoD9^Kduv z&!1_YNDfM~KIPviVkBy_3Zf03j@VoMxnbA9f2jz4*JaL8$8POkqQ%?l8 zJzKsRvTYu#p)Z|cscrAfqmy98_>;BM=<&ccM!#PuODn&d+zrHO6x0XTE2*dL!f;v7 zW?_j_wV6!c z=GNLlhSd>Ck4P}G&90fQTL*P%+%3CK`p(H4`d&BSmqPS}NG2DnlgC?DfkjT4rGas{ zk^4|v9WNWp6h?|7i*lZe`>l*yyO-juEaFpmYs;9c?{HcjYzzt%a>R)@N1@VbDuf&_=naqS7bK}fT7{zTp3gl;yO$bp9^;SWLNSzH^+kMS5 zMvKF;o`yz8$+`)h?e_!mSTt0m(s43->=7&p`XBp9LyR0E;`Q}4&p6>_(CnQ&I6T4I z*5!r$Ay}O{{uUX{Hi91oqQOg?8e-N?-Z{@~MPTin!#$J`meUYgeF*~|Lp?f=bAp_{ z)P$eBMANkry}dP>pIdn(O1XNWj0T5+Oa`_Vh|6iZkV>o4?jRN%lA1l!sbkUFv32c- zqN82JnJSA*d^T6m;DLPhbvNT@Oc(d(*Q#livZp=96T{`#;SLv|hF82@RMC$aRyuwU zIT*^KeL{+nD4$1bi6AgmznRbHwI;Q$*rdZ4JsAQZ3Ij8-HgLx-rtVw#_%?UJX0E`#G$K5m`^R2kz@t~fne`t+C0Rw9 z2q(KN|MXuMA>D4UiO<|_Pv zxn~dKhaC~r&~Dy*d~WoD#Pg50bE=O@wA?{@^#047Wpoy1%YW`wZRXT?ojVG3%!p{O zLA&BuqZ408@nU1uaw=iZW*4Lx5G3*8fWDfc9cJb!&A%@yHsxn)7Sa{KwJ1}#`_YmysHVjwxn zwim8Cl|$OC@F%Q3KM@aNyQkY*xS#S+5{f8BN(Vf}+J!D)xxxz1&tFS3Tdr0A&I66;)A4jd!;&e}Xn@=Q8o{)N+-jKN_FM@&YZsR4fs z#*_!rQ|y()%4Ip>mZybtGYIu_LhCG1)xL4SYYYpVz-Xjs1=GIX9+!`5yPK(1l~^Di zi|BMsTpmv5YLR|xu1^w)wCn_+$!Vk8w+$N5IAqMTLXrOFFDt;&JW`+1)~iq5AR>!KAGspFYy|x`l}yv%Q)qiQgpWy^9~M z*g?FjN1u?j;^RqQqC{jtGN-py8Y{}*+b}K@m?bLRirdFoH{5Q8FATcVf8l5LQFNH` zH|%-fZ;Yze&exw2Vxtl%7Fi?)V;<`&-QkA$+E!aktNBIDM()h^H|ucR0l$*2KQ3Jw zene4^!69x-ksY{9v#UE5(%)_m2OjA;lJ@7|k$fyl)~QRWs4^KUoEJ;oW+R(lH-7w} z5Ndc5?WqRe=$cJo!h9Q>&%&FF91(54l*u1?1}(GI2LHgeG9p%tZwe(bLKTe{NS>tu za!(C*X=f!9GbqS>DOHV7Yk4Gbe>fhBLGM}XvUZTcME&?)wNSu54L((&yIy|}{ftRG zg;(c5=DS$(R7Od=*_L{EEenrLtKHhHTcDc+0XfBozcbqi_W+Q%$_Rz4A{@=hERYbl z@Y8?01yA+qBOZvdp3dU*2;4ijxraJ+M-Hh&`_-`e!Q^53t|5CBAC)1DbEp*q`KH=x z$hP`>c52;>Y}iE2ZSBIr1$T~zVr^y^Vu*{rHzXy#F9+^)tZtJ465Y?%!erC&5MBwe>9DLE>V?<$nVga2uiP3(m9liI(aao>$`S;ql8}t%H@AzUVB4IuL={y1 z9U;3kMVGF5XyyXi_IOj86>s}q9Ap4UsJ**E+ep35!K>Ash_*Y{*;KaA!XB;v(H3)_ z2J)1t1=_g}%aoc69JF)P?(FM0;G$)uS+!xd z%)zYKaFbg<54WvX2%BJP>AZgxctq*}9rtC6&Jz`ZkM*sPJ>zG&%MF$i%i&^B%{Pgv#6l*I;B@2=F z6a{7O`G;L5DnuOoKVYje* zt+MFYtCZM8r&;9giD<-KDwRy$!o3>AC68-ZWzI36xFwxXYf8@>N=>{mx8^GiX2jy| zoPQlRDVR=*f-}v_?9&dQZtkkeo zLmExEl|dkuQs`j$lZ3KSHaQZ>@XnYmHj06V2=w_8gX0J2AjmjyAXd}1Lz)iCVRC!X zQ%NxY#F|{x_;#A2l%6bjk8Qk zufym8U|Ri!W5!(IPN*C_dMiJ9p1Lfarp2zJVPt{Uq3&u2@;n9fBfyU zVuaZ{{h?|bXJ)k4^9!T&5&A~{0*KTQ%_9Gpxz!)f`~*wC=X$*4St|xZ{%l*Vq)|LJ zp}>@iVX;RTWeR1+NKj<}R^zpwUO{H96 z@&OJzYEEb^_Ft_mx~RXkns=8@rVx zo>gpf+HwV&J8C8SCvt$&h{om{i@VaZJght*x~n&GGhKadOY2RHumr?yqe{OAm-rUE z4=N2ba3_p!Bu%6O?O=j7!rivGl2{?hE|;@eN$(?_AcDayT^m(UCkL1&b0ZM!7TDM) z*nO1Q!DXq$q;nHJ-#4st6lKVWc$UVl838o!?fa5CA`~4o^0_D6kV#J8op+O=CCCPE zKE!{!D{vU&lmEJZbXMHZA1D&Cckr#gJS_rFy%O>C+@EeUrU`dK8a#BhZ6@~{p>efI z=AU#z0kIn47q(FQYb6{Hen)f

    U*;Aw`32Zx;Eits#0WA)$op45!!z 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≻lu+CItAZDSv$Kb|%%jmB);sKu|88 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%0D7C-KR+hnQ<kqx$YEK9+ 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 U;MW{mTNc~aj%DNM=+M{Z|LR>lx&QzG literal 0 HcmV?d00001 diff --git a/cppbuild/googletest-release-1.12.1.zip b/cppbuild/googletest-release-1.12.1.zip deleted file mode 100644 index 2eb158e76041f30a3c12a7264af16000cdce65d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1081236 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%0AZqA34YUClF$j zNqbeNW2Cd;yuZ~Jq6K>%yL_GGX=vMAlIfQ`N}6-kf6v(YQONA*GD-CMr2%*Y;x*uE z%sBB7vp5`AR*@};d9X7aezB4W4H{#%gwPE#ps^b$Q+fZjOgxPkf*-O zv&r!rgSjL8Zr=0u-n)P*v@s;r0{-Ub?e|-+_B$m{_=M4}v28}Wd7#J*F`G_@X18XLK8njF_|F~3 zN9g1mDLyKXcO6!=htj!1{-7grM%>Z-xM(=dMvpWsHq(7T4s|htX=+FgGqloYzEv#Q z4&oLSk+cQPEwWf~blOa9+~czHsKlA4;JCI?6weps_3plHP_D{`LGn4BLz?kB%wn&7AG!K14G_MxJ+Wo0bDyxpx>g63-^If!ax{cM=DU z4Z)DoFLeAG8NJb&BjE*>>Z~FsWqgdwaFMwiQKoQia8TRwdsCqYDTjwSe83i#q1sz| z-xvG2+ce^K4tnUsiN8mEVi(6;EUZ7VbClZQLs(C4;GZZwTY{SN^@DLe$+MFGd!g+_ z?w#c1g?r%lB5Xz6_~gX11N@G?%q+zqNuFQuk%|FK$Yy64>789Qp|vk*-1!GZsqV;q z(qfz}1l?M1HkxiBUeFW`{vGC>J&!}NqSh+j%QpDNt$#yUn~T^9<5KdS@t!YR8e6t< zoYyW@53D8XI^f0tV%#Wza=;z!Oh1QN!JgZkV36q~_-Sks;PX9WiGeC32l)#t(>KzwH z#>rS3S^Rt|06q*od8#8DCn!}YM-qI`-@9)}?l?p>rRxz8*Nl3zcJTzM`_t%e;MEm>PJ5aLkdaJgYnPufh=G&fbw+wX*6SS#i_+=njQkUq}mqh3q4%ha} zpOcWc&{QR@k}q)idD}~iQlvn%e8;Bz;bkh3C>RLg!@xP&YL$1hXdsJ~Kf5#}BdGU6=!SFUK5M5B9tnZ^atpamEwrV1mSWHLz~tFoj{T zMcxj?>zWn7v!1QfI(mLC2iZ_YkZ^aHlHtLKt*Ng+6@yv+saOme@Eqj~*Kh%LTHL%a zQBR_s#5$8!MjA8s8@4AvSz055@{_D;R(*Jd)@aT1xKn(lq8CjUmjL%E$BDAVz8pF| z(-pz6XcOI>x&1z26Hxr(^*?8KLH`XVqunv1zTvuw1;nym>j4Pt&<<_O9&TdsPw@yN zJ_k*Le6hv+Gg+(A9su#2NZm~bHo2on8`~8a?aHqLeBv*4$U4ck_z&|1k!t!|VMV=0 zk8I#|fhe2RTi&D}uToxXxRF)*A%q>)_R9#5ArF<$RK&;Pmv zSm+IJfcprDTu2~T@@B8!0kI*KL7-|-Z;e|8#ieRFtC`g-nKSlRV95lv5V`mfw8ypN z{^P}WrKk|(9xGbDck9yFxcdfB`ZMe>SU$_ShhbU<4SLD9tOR>dAbR-^VBiF0XV~)E z_!j}>IGO6qrKmr!5_Tn6*Y=gW$>pvta6H$2gMw@$TQ( z(GW8sztg$bVu350Kp2@bLE<4JV&jy56A*q^4ml^g!b&!(Jbs;bUQ=|0U9{kk&3^+P zUMiN3!sx(`nwCGEd91E`Bsx&WX%~yOm4NN%%|1iUKmS^GaAPW~e%Ic_zfm>3_bgU3 zKUyhxM70N}IUvxQ#fS(@q8TllPz0fsWSP%%wwbcv>?Z4(af_c zD3$T@OANY`b|WqrMss|QvqSJQpg@=67c`O*V04y#1Q9*BZTCdaT8pP9axMgV6`{#7 z$|u=sfU8Nv>WllIFCmm?B#AW@3B@tV10$iLWyBO|HCDz21Vi@IIln~(?dI#>)EcZ!4fmqkBL4if9$L2|N7e2|4t} z0qHDW36BCDTRcH*;KPxhvDOyJrUq6`e0M!>TL>cYuxaeZ`5DW``s$qPI+Ryk)` z(ej%Iy5;)hC=1xZ#?cw~v|Jv>A4&l})^TA=YYyy7^ir-X3 zlY#1K=099?zBh2E>wWj9!>Z&dJj54ad}Rg@L7a`^$0fBur_8Y*RN-%6gN<+#7{lQ% zKGG+3luGo4%FI7BMR-*BRE$|=-mvnzj@4R9$CU{G<~fNNqKlVv^6-XE%uf(87vz0X zlZIKm6Nc;k5%`qXHSW2)w zwKKEh7~|yx%9tHJx*%Y`vmU1Vq4TiyZr)H6g0(Z+W&O3BATWpI>>ll6ICJ0?*?W;e z|L1Qjn{bqg=PtAdiDO=kXHAr2FKq&>q!&$6{+akoq9&4#g6GX*nr^3{nf|Z+Kdnif zRN+2aUzuNS*4_eNo*%EOvN7~)yBE}%rSjo*z*(s8@0DKET#MAjb-3?4U0{yo(4IIT z4+(5=j!;kH+>IH@%}T=O{dvDMz6#m#5%bl41=im@67dxJ(zYh6mF>VAu7B`58)-pz zlw3rtuuy9ekm}dO8oXafZKzlRkI~vQU;G_3`nymkW1k1u(dOGMEKt1i&aQH$(**^$ zS!LVShpB2(X&F;xl>C&l!Tyxgj{&oor>h@ zBIqO+w?i0MqRvca%>e$$aBLN*g{+-fafazcfD&X5MYyLyU%PQ>-4mchRi)xuF{+`d zP1<}Sd7waKi<}Pg;4>C36y8&~-G|T9>Caf#8lQGwhu6pN&dkjlp6+h%U+$7UKnjN{ zuoramJ%PD5!7#k$g;s5?nn1uT5pW)`tHnRD}$I(2>q zudpU9ff=I~V`hw)V6WKSRYYxusfUR(Hpl57?VI7Z>!#cb>5&v+cu=vI_GqLjFpn{k z_-N=wQJB->_PN#EizwMY)V^%e-k~r33{R@bAmeU@Dd24}Gzxnt)1$plmddXj@vB(S zNbfJJR(|&oOcm4*h5xSKIUa92H&{&EZT&Gd+X4CKp^YzV)Sl-FylKFLaBm22lcQ~J z{f{iim*!ZupfNT@Rs0q$=X{*i%M$KJ*~evhy^%_Gvx?UGYOD@$OU$%hO5@7B$s?*u zmf;oZM^Z-1#OQhz6yjf7^6sIkMEL6MD(L3&dd((?uMaxNyU!z3>Cn5JT2#I;AD0GD zs7>C$j$FP4P-tQFfy%5i`SND_O*pk`@kx-J6kYAQD+DY#B1>dEuftGzC;!>Bhlean z0qDrE1!;ZynE?=GO2z(3{8x2}Xa;zd=vbMn8~>g}-d%pOCuD$RNH}~{(kI;*mfDhv zo+J%e+j8ccTyzEYMTvE^(=PfCWL6kNTk?JOlIDv6i6O%Sh-J@acC7Jf>w(Q9V*i=J z2QKKpZj7n+$OD%Nu!@2HD7iCmK5k();=IWh9v)Hm$ie)e=zP)^Zzq}VG2}+3HMWyLo+FWA?KOZ|AM(8 z#E^En&(2`IA}i8Eal8)aA&LvrdQ(F$dY$@YNfQA{YIPXE~ zaP2ixSystbcmqfFTRy&r;j(W>vpBm8gpqGjjVI)2ga4v@)!)CD^%jAM|3|zyEU;(5 z(_75rzCgD3vp0*bZ9NF^XP_m5_}KVUGE^gSh8c#o9foLYkNdoMkC&$oYs>ndz<~v* zkmq2P>tB92eRl6H0f5xkxgCqL z7RKj~#3Z}*2oA>xri^3AwkKi6LiF8Te@}xyRWQ^mQ-Gx1xU~t3`5hFJgdYby!u4XGsjGo-|A7qQ@_d;54x>$$_oR zI(~S(wtu!rIaHsth0q02gd>7o!41P0_1HC+eW=dejPEZu4AqGjRU-S-{#p?sg8+d( zB8=cIvL>6|R7@NzpQe``@7E@t6Lhr48-F_}X)|s;8gH9>~$@4&6dJv~cI|$_t(!1yy zkYE{pNU=Job>IbIKeO69-zPQZiatdL31Rc^5$>ax;Y_h{SXN%}d?q@wbx7+bJ=JWNLQ%SNL>{TJ8=hUi5~t60Bp=4`81oE-(V1_|6po4{<)KM*@uV&>>$boAcq zuXT2pz>6(J_kNegff8Q1t+Oswc?J%;*(m4aOB;@8KF@Wy%*DsZBq{Z)nsPyszJ`t5 z{gT`_! z3NBsoArToums7?3?81giLqO7*1xKgX>-%FlJkpleam$8I7$KUiwEs&ND=s7+jD=Qx zINE1VrFs5p1nE!-uH6MuZep1CJE&O!JB%i>x!VjA%l!RPHnhFC58eaHH>ya$1z~x%x0(Oube%okLa5D z5EDwD65uzVR@W~0p_jO4=qL!eaz!K`#ydZ3#bk{cVi~za*{-nS1j0GL@2P z*CT-n4heC<_hci*6dD9Pm{D`SfZbtuvZ&>-#WNPV1V;ra{!EnP$A{aktRqb_tjO+t zvf9o(d}&+oc>sM2b|l2Hu#OZjVqh@CC2hh=0}si|f(uZREk%q%Sru7iuPkuQObE?y z62ow_{szovoWL0eqYdW*+MzEVE`IaS#=?Hs%D}n@Y(oswzF~i%#dQ+Z3dt9RouSWV zFrXCML@N?40He(Kit|A~Wd%fgv<6}`s{Hlj<#YJ;6t(;PK)fAk6|pcMHEsMAj(z&_n5x~qs7#tN(!f@GLW9C*O@6DMHu^ZWKpRnxnfOH}N8~4M80*I3 zD)B&LxizfqKs5z>$sqQadFg@QDYR(NTPfKTB)T^@#!zviayqAjn1=31N{f}n<`{MKqRBA4vP!xysnq9Ut={-E?7@KQJqQc>1R#=2)Y&J^j9oF&&rTjT znJ6tb4fNUf&*2T~ugLec#U9eyuA_#)OY2UTUW@TcSE({cpKFzg(7w8Vi8_08-q;04 z4Y}b#;-`#q1gB$=S6(?{Gq%wu>?a22wL~%ogcJ^(=qb;Z*L4lXrhoq&NrskL*jK1E z2wb2P8rX8=gtKAIpoe(vneG_HTARyZ1Sm<5dMo{(yW4~^CmQQ*bpfO!kSYH}lq!NB zHYP)i%2;Y!Ts5+D7L;5aUcG@ulGm5?xzJVpXaliJNkU?7Li@-)OU0NYAoJnWf$mVO zQPvP-MV+sbG)FGMjnlv!LrZn*KZ1Azm8NCSiXy&&xF4{guyvydPj7}99fpC|mlJ<&B*XrtUPYJp%N{25 z9hYSneFXEL{4ryzkWj`Sv-lA1`9}3(*9|sOi;5i84Txdi zPHhCZQ19Ii?KLj@M+m^H@98}9MBg8V{rR}H@7bZtuYJ#{W%ft$RiWOMg=7C&lvzw? zq}wYKZ&Wv$+TiWcnJ^TcSy4e-;h1k#4*k84F(r3MSVY&F@A?5t3B+32cNo_gO%=VI z?Y@Qe_cmwkRe297l-X<<6>K`m?^NfVN+;@*U6mDuOV!832xORgGR>g%ix{3R52r}w z1VqE3fx?RrlnvEig-Cx8psjdtgtm=2qnMP~uRIE8a&qRkaoqfUUahL8A58!SEDX{tUofNDIE$R=4W77xI6kw&~&L$Zix^PJX2M} z#l7a7`F%>WrQnQ_r|n@8Q0?E1Nau;ElV819XM_X=ZTX7Ps}Dg7Sjt1dD8XB~t*Ca) zhgq&h7%sO9D4fxPwE0CusB_Y&x3ej;$3dh ztWO(H{w8JKD6&CUr#$j5#Jv{%$_R(-TQZ-%i|Prdk}Mu$6dH;fbRnumRR!@& ze;v4OR!n?v`Ik8%4i#+98J?hcgn1}kJazwS# zQK?^R!$&!PFO0Dmt)KIB*CaAhKoA+<<@`SIGp}xV(eKoQTKHgM%=@?9V^2W1ca()Kh;;-%zXPBt&bOO&;G;4^Nw7O+UN3v#!Uq> zBiV@ZC4-}Tf2vJtWhFy8K|80RK}J#jpqWZ$F%NZ9|51r257d}$F8ZeJV#r^);?{>mRH5|5 z>h(xr4wi)ThRWFd$AwR`HJitI{~}Y}Fo^KfZurk?j_V0JLsf&XLEZTbc5lNO?{?L@ zOGvKA6@@n2<~bh+NQ#F~)Bd8keuw)Ck6;Qk|0kLR2QHAetJM*E7I&e1xm_l-4HM8A z2;EHB_fT}}$3ERz@F{k4c^$kp(B`A@82vi8o*EE$oVJ9;8Z021sC2V~?ApNNo*|!xgT}ff?~qQfHvg+4P=}3NYBsqV8_TQQ+P5 zE`&=3$$WcO({ddCuX6rvdbk!ML;T*^SD@SWIQw!3NCYWTHD*WUs#FU}wwi`>1dJaO z-mUp&ZwKy*cK!C!zE4o+?x_x4r=6e`?Q%#~mTg-$0c|yyHaeWwgVy+}glmvsdKBdu zehn8^yXy;;*t{x47=}2BE;f!YJGY^Zluukv05$ZCIr%u;Mu@;C!5`?*n?~rLkOFce zI0x6fl@o)}j^#8ON1E%-AHe@+V(13%ER@Fowi|f?|1tc3XJR`$D?P*ij{iFmU-w)& zZkeXCe&VSGC|Fu27MM>-c=jq_ml%&pa33uVOPY0RQy>r%K-eJa1Ld2L-qf8E_VRUE z-eqM`ZCq)Dz5NSp%yE9p#oJoJks!XuUF+I)@m?jnI9am%<@8ZksWW^2BmPiokvP-H z&_zBWta2NHSJ6F7dVUb;EGesNWb^Rol4G6@R$vHYAv?Hw=iSMk;VzsGqPU)FlGF3X;zAe>0eijiu z$`4J{SVev^O(gEaElcuf)mF`7%}G|t>XQ;JGJAes)=??{7o)fiTt!-eWJQC&RmS% z$`+l!1db%NdGydyCTS(eSoy%hy^Ai5GqJ3#oN-K`rOXY0E$yUT@@N^i=-~Yz_7O)K zX;<2~GFfHzNFx4T)BcrY!fcJ9w_0qhRNGkW#reW0St^^u`~CV@5;NQ5`!ki)Vy&an ztT<+*`%fI1YZz4#qq3{35@nj0yTJ9hY$EIQNnH~1$E{<=QX?&e<(*Bubm82qOSY}? z={$Ax$s)0qwb7W4M`nTP%<)cO$L8YEs&jVqOyTwzt%+F{wDj4SAx%1TkcRgK`t#|S zGk0_2re`QD5tsmFIwB&F6SH(x6&Oy`)sBy;AK4hvN>ciQRbs)3 zDRZW>(X7M?9Co3^DG>urw+(wKnYRc>dI9&L$0{Nthm6*2ZK2sSan-4=-{ywf8vC5F z{aLBUcA%(@#w_y(|9Kx)*$&>hk6V$&CbF}b?Z!!2^-Z&SJ{r3%v|wBqVbAwFV9N#< zk<~1W3k2`~{DRmVS=(=+=sh7#f9@SGM@yFPZTt0~YF^L=PA-p|<7+8OY>5C?#;Zs4p>nO?!C-a*lzD(%$}ZD#m`&Lj~!~Htj!^ z44&!6p-x!MJO@5&cU~Ry&EdOy4$6y9CwQ7s_HL5Hr_OF~{#>{ayqWkCm)l|*;6@^*SUvrCRrle?{4(5R2D>J*IA4^d(K6{prz zC)ic7Q%`keT(0$oNB|q2#)X;{je*7+8Rj~DQVyQim6(nII7WR!&J2{ zwUegxm#Svo33}14?qe7$I}VxBm|3aOsj^kZ)Ut6eMzH)XARu^zd^}oRmhP<2w>N8bZlS3PM;G1dhVe zQ&n|$va7@0Qkc}CgH&^JiRa(PY$W4_v{5>*XI8>|g4;<6&S$Y#$gh=5AmCyXClyv_ zpK8!uBS?e+F&SLM;H_`Qd{k@l*npNDC8s{$F-*?XfPC&D2y7lfBQQZ8O4avADGqpw z3+!w|tkoX5o5Ti8iundy>My;A;rJ22k?}|MpdnL*zq(n6g8yq(F`KMI!93c^X`-E~ zg+PdMZ{qig2yn^L4MEv#euKP`4h8nvEdNm$6wgRQx}SK;nzX zjr=#k!LPmNxBeRy`UuHYmg-mjx0@!bkCGN z&}14hmujrBM#UU$wC6<3xui8kRBZDczQ zNrQo%i=*K#vlhxeD(0o>sux%^-#O7K5V<@Yyrs~c`UEy>9^nyfwQEkQ5yQX~FSw5> z^iOsut^ekmU5jGqs?%DimgbZ7i=nNr(H*+q%wlU^r5{)F=1{wF8NiTz{@88Z^kJ1K z_4r9xw6#Jv4d#^A9umGVtVc0-v8_lKrRT_%@A%|G+l7{ODmj4-)F&cEHg`bZXXdId zha0^2>n{EFaghbv3;WOmrf`b|y$YL$bql6VGFSOHZ(8Ff@p(n|N#pY&_95HnnMQ0V z>qM*odiPZYN(RhIcb;eR>EqB|s*&X09y+Qw+xC2scY;ak=~2yE!+|3VJ}HxB29^DG zN?9esI37-q}k3|)PU(!|C$s^ z6Fg#)k>HqE^-{U9xMZjCr*|P33U$C9eU3xa%s@yfdwp;l1jH-h7~eEPNS^}Dqg4>( zKxs-^&PWV`#AjuJONC_BkUs%3i&|O;@@ShwR!`ZXCAY)^KGD+BO^%PvAdYNg_LE;_{{M3e#>`b6#HzTUiLaxbDnhQS3PF^L>u zc&^QICNO|)X= zEjxG`KC2~V==?qrnMxl2_}0tIS4)@lqt21KUka|Gq*s8xx( z&#Kis`YKz5&_)EJjfmHX>SvFUm2C!c?6?tlWHS?&9xxKwu~vQ_%Eln1OwW?4oHk~7)vCW zEaz}uS5}=+EUepG4PQCwSM9!puIj2A6lJQRzXwim%Iej2&boG9Y5y#g`2dq}!%%7M zFj?_YV!J$q3bCrVWH=*Vl`hhAWgXy%_xphez!3B!k_ETSSX>zdFI0_<9GMU9)zVbx zWt>Nk7FLhZ3moSDgxLo&jLRVx3^C4sqVX?SwR+4iue);=)6Y~RrpxW^-0z3G-Ezyt z$@^@UB*up+YyLm{Ms?+caSc!Z)Gfab<@qQos_W0n^`TDe@AKpA>D%1(xvuGB8`RJnXIQGwD`z5l{gkKLmbTrph3qmBm0x;YTwa&PvXl;ebI(|+nmA$bhc$>SjJ6#UhLQo z%!~dEmVR-xW}qP+gecN)@3v0D|Dat7Bb|r;!dL786u5%We@!tzw5pY*asQlFrF!)J zicGF_>id9{KJc3T{rm#Ix*p2^1ghS%CgOjo7$K}s;NkL6oKSLgTZ>tmbum3tb#!f) z^!Nsl9&!90V_Rz21vK^-&8V`3zqj-EN+MvYWunix6OldC}_$65G1_r)5< z=@=JjmZWVE5H-PbtWv+m#T6(Kqdqa9%Z6mr6DneCUNLp|!{mP?Sq=I(TbTfTc_&hf zlM_A7gVN35JxA0;6VE$CmliyVBpAPQpBLEdmHJ6$Xf^Eyl({?{G%8D1k9lySPBX6k z@JuUJy_cIWJ#^Gum>TTeftx0wF2U930SA_HmDy3|YZ~mr5P$#8X$=TCVX?YpA*cs` zjk0POzg2klmhG}Sy`G<7h_yA!3~?V}e(JqsKGX7#?kU%^LucO+)u%c2y%xWV3_}t! zlX*dyjOS)V8iCuTT`X(nh6D$6!14!TX&L+TQSEt7y zF#+&{)I5nIgWU|#t;iY%uzZ*-YK-Re{>nmaa#fJ0$GFJuIJ3?n*Whr!0yJsLL8Z5s zwFAJqn)!S(1VUc)TtOPliOg@`h&D@}kKXIqBXfm0u&X#j&spx_!%efe*Vpx&+I8Iq z(T!dVs5s;sbi-{JSIBkTk@_vo0GRDEZ;*WXlnweU5Y^c$RY#HlIuTFqv{T@D!um&V zND{KHMpdg1uJ{aXzWchWj`_W~6-^C~d_HU(Aw>xU*$)=o=|aNxx)9s6H{Go^kqKXH zJT-}p{hC+l5oupmYTL396baM|)Rz*mXu}!4fZzF> zddO!z!V{u*!iW+;8E6?st(>w~Qd*s<4M}`5&LyewbsAGz-^MNcJeC%~Rf`oI<$>i1 zBXM~zVSg&XjF79I8Cni~WSiNY|5{8>vzj-C9FJME=!LSfudx)(c)nkhwPhJgAX`xh zJi9SVczIZwfd$&RQ}v5#+lOMvY1lV4VlyXqP36@*xlDSGL6$w zo?`KSme^j%JWoYX89q8j?YPCt!H>%z^A;j3SZC9?ByNA5$23Mf=yn*xU>ih?jOcQ- z;?-tx%u-i^5ZJF>-^S;MQl^ym2wwD=BRv$_TT|h@o8&r(@0-e$mBgbeAVI9(% z)jd`hf$EGTv(|BTybw&Z`%7u^yY|7(&0k-o|0eCFY8E>t7F zcHaYEPWz_*; zRvFan#ApzhZDq79!b^*Tf=qCmr`SgW;p=D%8|+UrXmUR{Et|^E>JhDyf^6f(igOXF zn^_hIFMn-Iv#>uIc;o_u-I1hxtsM@Qkb!LTFHnN4^UVGsLNqSj+m#IML?o9XNGT2* zcEpOO(xsO?{35;^>GIVx&C8@k%7qSLqNiU)i1>u(n+@TJFBkl!pbw|Sg%Fmw8e0&v z36-m%L#vOZCMJ)-l%(U9QC6L#8H2l=C&F96iaC4_nsofaM&IV-q(6oYyL^-@{Q4JN zdnjERSJGhY+n>7xE7;fTZ7g?_XPP-ui@U}Nw%vU$h;y1}VPo0FEy|WSZTI%eLw4B< zp7>S2>cah6C1j2vS?T4qcnd%F zCgbnPzO_v3Ti*x^P}zzXQko^27JW(?i9WK{Mjq!x4{R{d zic|p{(OscCMQc0=J#qsZ6j(&H%1vYr#?&7v-xV{)V(ggrEsQoDbi>wIggHUqujC77 z@jZlJbKpENNGB*nkDs<`$Y26{amb-ZKw8Dv3{gBrs;7I-Vn#4Hfap%?l%_r;nFht7 zA0$lHm3803aVtiKh;dKr2E!P63s* zBi4&xH$Y_ii0d3)o%sIh7Br77@sN&qS1}C2dN8*_D57S5B~;JY_`bOY)~j^8`tqE>V~F+ zcp+d~JZ`5!kim>DLs|urd6Pg#MFxg=c{-OP2NJ6J+M)|J5)65E>r7*nRD;|(m}>ds zEZ(Ksg=~w4E|5!TSZ-F0;#H_132_Yekmj(=NgEFxQfj-GOPuqskp0AY2PFcfO4<%V zBFYwv!UE@rW@%wKlw0wWbYgye>D->ac++an%>|$ zVJ2*l53MK)7%<5(InRdoW0JD)!^5WGJNTnO^8lAca~5-a#fJbSnH5V3Nv1#eO;%41 z-9V6@bw%fuq##b$=Vok&=*YE2&L9SYEY)rOx40&Y+5VD#xA zr#yiTAcL8S!A(jr7I@z|S&b;?I@^lmDEIa%&q`)JE;JSo3+5Gs0shlCs(ch%P4IwN z7&SG37F)vZF5-=L$56~Cpe(i%IM{=6knGEwz&abxlsmv1Te(jpc?OamPN+E3+yNyD zuj-jBqGN?@MnWr{VRVk&t`^I6m1%jA1M$Lhg>_>SVL#J;#H~O3dS=&u+>EP9TGL$<3+J#iH`I z%o99BTE>d8JJzkU&LjUxZZ-tmZp9%aXHriWGBNe|e!~&0IA*lve`aGnKWrAmCgR|< z_6zp{Ktf!w_KX%(*U_#8<47w@WSf>gkz znLBkDy^9&pCHFJu207eZpwg7I^O9W{ZUw?jw!Q#$Zd#ZqBc&jb6$6&D=(DEzIe(8@ zzH4|TS^o7LcrJF$`#cS17AhRr-G=K$PEJX@J=~tbn(mxz-6$Fh%UZ>3Dzo0q4n1WrYD6{+2gdSiN&h7}sYTee(FWx84&c zG`v5T-1u+V8%YA*lu(z!NxG5;pD32p5;jG`EW%@v=n?b>GnaUrSUqspGV7^x)6+TkKY3c(t^x}d1 zO?&VLP#hO{cb8*@au2J;$sUX84xmbmyOI9-F8B;qA#;X8bT@lr$GVCqvNlRvVeF-L zl&*KPVrT+4L%j6#+Oa)pvdf@MPtv=?^y~EYr?=DN(E34N-Pf-U>8tei-P_JA^Z{e; z^fy{Fu2M~^_@L?J(;zJ-Ok7ndFtlNclpH0lAnUA~aE3GUedr*OXooN%Ru^yTc zhzn#3U_zZ;+QuSWXfRZww|7S3C6#pVK`o$rTEG++RuuHMBkRJM-%l7!&=d!DZwVWAL;<_@Pzn5{oPKCS*INy^Gv ze+pdsx%i*U(9!5omHutRzBd70Faa>}VlFWSqU8ei0PqNi2L|nhKZ1}%1~3Z)Wrh+h zknpHYT2i9etmO=Hn)&30pq+Dz)j6Hb&vMv#|8x6G9FfN{I`lXFoOEeN7W5J81&v?B z3-(jWb;mh^{Md_)DtFGzhbSKe2{jBA%x+y0E$sPcl`V#g)Eu+AqLu=awBqB`4W$Z0 ziN26C-TO7s()l<&*E7o$ZnvL4|L8vkbn%R3A$)^8Rwc9JV~Zt93ugtL*y2eq2j3S5 z>^7D z$=nDy7e9_MUq1C3B+RT7g1qhcv?CmHbEUxua0<14DZrP2V-hf8r^frxX&$)vDp}wd z+n#!@MR2@zinsXA7^lJX7`QVXxHCH%YRBT7;I2;ww>sQlICK%eymOuQcODnzYrvpF zZ4Gn6;j*e;tGtAe9#0kYEg1f+7UT$SKiUtq9y!nrMv`=!%{F>e(@G4rz9>V{!`5RZF%P67vPIwLZ~<{YO%{xqr9d2PBc&|!ke!a@*%#PyGnJ-+ii4WB>7dI#O&bSCB`yAtI}ZEox%b0d*8 zrRMy}W}}H5Z%(&e=E2Zhw2NTWFSic(TMb&dp=m z8Bf}cfY(I>RFY}uD2T~)1zzntK1NY1-#+;x|w#|9}pQIKkxa12|KZV0q7K4 zrv-(+6(ppcAHtXT~ZbEsu*B$Jy=AU^<6>N%@2s&lIPr-xXWXp;^!KoYAAJ7K$- zX@pze&WB-Q45v*erU$E8HcYK=Sy)iXo)N7?l`^Pbvn$SVearDr@`5eCEJeuTFq{+6 z9E%k!y?pFS$(!j>^Cj&ARD}nKddh|3KQM+zt)Xt(wvVKgm^~&oZz}b3;~;f`gz(dV z)V3;`md`y8fM)^rvr!Om?`~e3+uGcPkZ2GA*~FMW6A$ia()DQJcJ#2V4l#sLAV<;m z<|P~FY$Y_p`bwh@*$!%R@zI@bA~+yRd;=avilb|?<34M|IizU~c5S?h zM-6%+S*UA*8z!;2JtPXj{S-LzTqT`w*ujM^Tw#)Y-{rnHC|;-SlRN{i-3J>xEN5is zBeEX2r3{XIA`GZeqB)f3ID9EJ zRA9=I)W>`gfn*ok;Dj<~SY;|h))HzUj${v_iBFRtqe?9!@-#=cjLqKQKliX8iZLsU zn=hv%I`$Y?RyNmpof>=wb?;n5$}n8!rMXm?9|wqlL*?g}T+By21mar4AZ8U}%d2|1 zXl}fqUa)c{p+I!;N<@4V@o%tL-d8nNg*1c*$0=Nc8@fz{$0bjj1Nq{-Or-Ou;-T1H zF|?11lV(UTGzzq@F>Jivlq!a-NFEtRfpQ<|5r|N674o*u_qYS_sd_*RKm*y&4RM+`VZ;ZWbk9IA;ZM_du z_vPL+T#oXZc192?i7qQLdSDW%OxBoFH6U=xeFVWttvjfEkVJ}6FK(v@dEsEPmZ^Cl z`7)~LkdRbe9nv91WDu&>(5ogSJL%K~mMY>d$$RYV_h!$q*CYa{b--25$+>r_SRgOG z5zAA$FzFpLpS?fy2CP@N=$oH=Xg72`!FU%B0MD?o+2RbL0hl!?^t?Fnum_MkT?Y+ci!P*c+TVd_nfs zKte$v6!;ejbErMkv*{kUI8|U;9xe1nl+<7=-h`d8>5p10MPf`9c@cl%<5P=4{bRP= z(D{7yHbYFFr#drXuMw{TpEplqY*YGo*~5acxnSJD+sY^B}alrCMh&o;~D zm%nu>zRR&1Lzmj?LxAePH)HCsr8VK)sy1{0^0>?hZU zvQ_WsSm`{0Vh%L5KjwN1Zfyk7zQAKmid%Ob^!J%|z5g z7HVoqWd1NI@RsIk1?H0gB!k-u8}@)fmrPfK|0D?MT28&papLU4#{@KZ3MYoJ+HILf_ zj;Eb-dCXDx$ggf z-JDZ4i{+PG?A4MfFP4>9I3?3Yt78qV`cY|qXn~qN<3&M-YErlAxBRMxE#z4X@ln!^aBNk!d@S3?bIt z%Cmr*z;I%+wW=jSu^MsPkvamAOwdE*iwAf{Z6{yqXW!6u_J$_u3@7nJA8teLHGgva zn|3iGHJ*RzF=}*-p9o zaR+$P7&V6WB97R~oTI>@gim)Hkb*veGr)L#`0P}JMuMs+xGvCBCnCZaMZgbG*&u3* zXcm4U=HL#9ZMI!=aUQ_n$gARkC8p5v@e`RQ7FbSeV%cPZ_)t6m!23R0b1@|ty z)t9D1c-i3pY;E)nf`~%HO3##V1f(DQ@qS%vnZu3N0#_iKnlu!#r z8U9*yFS|4Y&{J}iFW2JW4iix6TVs5jB_j7t6!PNX<%5^rSMG0YE-@}`(zLAX*j30C zYx!=wS^57VzxXXx|Nfp;`1(&Zy#*t}5t|b3^=i>p&v58e4OMs$z%GNZNA~IHv>XHU zva6@d5>r3Js3Yy+qgub`c*nr+TmZ^Mx0Xl&tc~!SO;FW5sPQYv3kxl1P zVFyMJa5}qVz2`TobliCK9J88+80IV&29Z5_L5|IrJ=^+f%Ho_g!$j$2BfNgX%DfBm z^U@SMIT8al7dZ666w=S)(O=|Mu>u6m!0B_7_FwiWQaYHPZ?v!I;Jm0MaLFAW``|tI z9Y6Ll;okNFN21O9Zbgot)$S#RmjCckv^KQ0{AAleNbCB!zBiziq#q}2?FkimqJ445 z@KfladuTch+4gd4Pg=I6Y1HY*HDsHOH8>Hw8V@aQ2;Yj~LtmfB=i>8>Kl?+^XK2@j zx8k08A%!ZASe4By#p>MrT56T?QOCtxmCzd2T9RN!&sI4O@=85GdR6&FXt8F`&HUW~)8?jDn zURZGx`r>)dxp~rOOp7hA%1=E+ZF8f9b{^ZNgP32lxz27o=iAwpCX>1py!SP)H2R({ z#H?%CIBYVQ1~J(oe5+xah%U1fTM=!_7sRlr9p{=zgze{xFGUZ!M(w64O~yMf?1@Ro zmGD$+*LWJ_s6SGBs%0Mf06FK3p_L?a&?(`ec>vDs1u4#pjfAYlh$ndxIuRWfa=XXK zI18uT?pm|CAWAw#%m7x6m@A9Ol4raL9RYCFyAf6n;LwR|m~nEA8Goont&d)NZMjd{ zy5 zlq3#`nYI-T(JFlBiuJ(E6i)5+ z8{=!UI5&XgnTdn%bh$*$7uK4>5apHguudmBdQpmCm;zI75_IfKmI$t*K5VV>4#;_o zvdV=br@=N&JCSEoynp}okA#I@nlb)113gZ!eN?S!g$(ZLcfPH_qi)D z%8#Sj2g~d#CR1@R@O+8dj!tAj#wmY73vf?A>7nH*THEoj3eR)vF?|d1Y^xFR(_f}W zNN>~o={CKe{4zzgFRL3`XysjRk%ik@V+H2Glu`hJ6nnAG6tg?DqewRTedokk6 zFci!Uxc~Gd^zNuC^AUXTmpG|t(k!@cB$Lpq?0rg2>Lx&v*!P)MTqj;yFt8?OlZCEP z_TD3W67`?`Jmo>KDOl|r_V3eNiB9HqG2?{Oe0lLT^;~Yf=Q3MfR%|`xpz2_>awB^N z!Mh;w!2vMu%d;nRK~L|yW=^K*6_;<+__ZJi26m(?PVm2w#dUN~mo$>>t5)t&QP?Cx zzF5o3J=x4(7ZzRS4O3pNC zCvv{>G?;qu;Tul>KS}m!Y<&#yJG#jed6Bh`^o=k?k_x}4z2qqO+>rW!@50yE34F0% zC!*XJ3~R9|QHPy>o);H`Hey6@y3%=s&zuOOReM|Z5T0Gwh z?h_?GgC8c|FX1W~JKhGzj6;xDA1SWafC2~NZZa!?E}7AskH&XI=Z=R)S`9nGprv{w z@v(vOLaI!|buDIFwrs1#!NLh?nThS($6~8^^G{!;U)=2~7yXxCw8fo|p6q_qA(2Sb z13}p4sh3>@xhL33{6d1=7ueEn9E;;PL^{60V0zj#d9B4%={`tbO#?USG`s~e_ayFt z;Hjbc5rVdUu-784_afphKBT5|uVtLqi%3-S@I;rKQ$js^3Lx9_MItKTfB)D2X>vK( zuiWI_xc1y{LxnpB%!s%9PLjtZD`MV^&H=MFJPa4k&Rx?vq{&&))?iD_oRSW6lDe~w zQDvb|?yy@u+`nsnwM-`KaFQVx+g&T5Ckur#42@cGTb=_ZQ@K?G{ui0NZ_uUrMfT^n z>Eq@RopBcdA7D}Zb9!%>enn>~{W?8LkJGzfrtiE~&4$TtuD(cSrGV?osq7aL>17$c zbUzFf-mt!V&-&kS%Wn~$9!ZHuF78D3o9_58BvF7LldT8~cIfxcJBE`2dNG87WJ;Ie zz`7Z?3n=X%Pi)FrOH6p%~KrI)4KHmUbUxL$E0-+(-n>=ypgi$OX zn~o4jfz^T@K)h9d<+QLW<)ohnj9V|_tqhTNUR7Y4DF!K(rnOcR&pxP`GW=RVi69;& z8VBs8UKbS+@Caj}3fQu-#y!BiFf)(9`~Z`91yr;*;wGpCjM82{+(Ilg6Wo zQ+xi318C;P-G6^gzhRwu-S&SUK1yvJAMXE`-u!j^D77^WH%nw4cyb4y!65io)7oI2 za`vc+Dk`L)d`5)e$2IM&y+FgKFHy^*VPnd{zg1UddT>+Q^bXdX3xFsYrc-^7di!f+ zaY+4YiB0|Zr~@%&ICZ4(FjvHw2fuJ)J|aHZ`hD>;h(;6-Cer)x(H>%)_n(tuRD zW&vx8Xz8id1E-b}$y1cj8m<{rGbF<@2r?_mGIx%3236ZN6gm#OlKPE^eL*dB-svV) zfu1EgxQo6{?ePyE4GJb(KIhRad z;>r%LUQfrR!ikb%K=P1uk~VL(9|YOfYZwSSVj-3>unSI`$5etS^c%u!_F3rnk<45pfMC(5iC@KH0%iI#wPu{c6wftATKM3w_-s` z%(KQMLgTClH{DTVlIi0{vS6UcxRe;xWDKhpQd0qd_MUVm>rw!nu6s@?JL?tAAXgoD zw03hGVUptT(1wDH&ERu2P>;0?Qa5Aj>+~lEV+^e;EV;_+<#2T+o}Gjr2Xck$>p~Ww zluBuE-PuEa62agEmmll0Cr`MS_3q|9$e{K+y0Us;0~h}61p8cd2KL&sp=25b{h8O^ zffKP8#76Dh`In59&kT}v%KR_LNu~!rqeVlcK9}W^*m%{xZ9t+;n~KIoaamMj?(h2b z2CPKuUvikFZJWAK!`%tU;iEa#{$#n%QVWA|2Vk7~5$GLgRlL~p;Bq#0=Eqmtyv~{{ zpBN0k9bM<7V-*W7*948$;qHbDDApt1Dh_F{vul5*MHAliZ zuL%=Y$4%m1wVzK~rslr0xI?KuUnKm63Lri{<1PF^(t+i&N zRLGFYW!-T4%F8oA_kIDwqrIl!65X?7$qG}LR@=c(^%C+rn7cdM;0Tz*6 z9gGOPUD~EF@%3^e-fB~(^Xo(%1ZCuN| zN$IDl{Qe7qufO^#9%%<*Tb=V~)gbP%YT{l-bm;HjPYt;2grM+I}aiRcvrEw?|0`UB8Oc%2$hFE!igS+NUm}~5Ut-Qefb{0 z7!K);ASu+jV>G*z9hX5BPY#B#{A3~&j+oFoaN^ZR?Vq*SL%51X)+lD9u${yQpea^g z7`W(kVHml^PtOHXqfVP3MUZ6wufCcpv|d$@yCN9P(Jhi|Kp<=7wo9hF--l_C!CW=b zauQ{dO1pWLBpbCmQVFBLGW{+~)zfqTCizXpifa&Gi;I#_CO;n9;-e zZ-#W|u*epy9eeB)9m=#Wy%wZKl*>Y}p=tK_l>_(;5aC_CiC-qVo)4>wLr!?snqXoT zPU!k*xcp`pNpAW`dpfOi1GN6JWFV=0(fKaOQUJ_e!dLM}hCc^Q?m-&ZO|+4i|8H@G zl)na1EVqIb%P0$AR|OJOFZP`T6FVBG-?b8}I!?dv3K1g|NcBFQcO0+km!0W{H}dn; zZ=8ZlC~X~$6IG2wvg9BS!JCjh{sLC~wUoSIO4qb3(_Z*gedJ>I0yp&S?muSLd+BQ5 z@;`313era|_<)mBC3KNk(`uvmTZ!L^^dooTRNO{E#X@6sg2LR56^BA_*tA<%cVPoG zsV4~!o5SYVcjDXwN&z>y8#`}>e#XvMKCq+I!4ZEj&L(j!lm3fUcK_(r&m>&^N{jf# zIK4McKj-`AT|a35DXda!kj24^sP3D1e?Cei*R@24g~^pef2}h1K`#Z7 z>}?g^vSnoM4da1*zrTT!82(X+qO&}o(TW3GjGlPKA%Q;|AmRmA$?87Mwh7Il`9K!k zyDguMB?8g!&X4T5$%=ZaCTp=f(gat4S*xse7+r-GDWZIk{q0QW{MUbGd&xh)+ZS}# zb9s4t5Or*;#nLZzdS8$+7$)E(U4b@#J;)Bm>CwA!`s=}re!IuN&FQz#-i1WUAR?=A zczy@yVj%Csz{G!X8}2V|$FB%YC@&W_r_tyvtVdMcpdu1A`UE z!Y@dEah1&C3(rgQC<|dWW*?$5+lCkp9xP7Q(`;nX@Sr7F0SJgXQW@7X z-6kEac)ra@pi?@NbI9Ep*P51KXYNm7j-A*m?senk(ht965g)3`Oo>XaNP}Nbhpz0S z2I{a=7SS3niAwSX5^U(~$184OZ7;Prn~(ndktG7G=v7rMP;V*1)-k&asIzD+mntx7 zaxlpubDMmTbPIo}JqXcq!fPxHwsFzsAaOCJU0f9Ng5yiFhP?x^hoaHIE)7k=cX0j0 zQ4DUUg+Al)Xyi${C`3itEmRgDz0L%axMfq@nFrPn&ATi}bz-zrhp`h@#$rb~BaHBG zR>_coO`M%hV!nwbaJ@x#t7@1Q(Km_{6bfOZT_r9O#7sxrxBIkqsfhpdfvH3vg>v?! zPfKxbN)?(ziKHmcxi|#z`Vgc{!lz@fVE1SglZz-H%U%p_#>T@5J7WQ;%!|Ub$S|27 zO5r@1pMk_`4-)_X^*EhCI)M>)a-G$%UB63yI{o3<<7eL;>zQyy7$1ixHQj4A=5dmM z8YFyjgyw5nft;{L1Jv48G+3bW07MpcU>9LOI#xrnNJN-W!nKp(1kf3|YLLoQHR{P_ z21?3q%JvPB=k>yOxq&*6+l}F=v8PiT6&t4@jLU-yD+~-6!J>|h1wNp^WG;{MixrAe zX(9%PbCpPqR7F>1;{ulet-U{;W8*Tb8m6BPcZxb>&XkQ?NU&TPmbGJJ_AzJ@G{I|W zJ-0TDB*aJMkQAxTmN2qN%MRv8L9INY!hbKTYkVWjs?sNj@<@O>Ajm#qDs@7E4CCbCIkg&M46FoVl2bS=Ja9+I8ihZnV(Vg$J&8xYa&M zR%UvfxS>hxMR4GD@MgYF{ll`ajfCf30cE5VNZn*_k~@q^_w&_>MSzRLM{=cns=KDn z%j<~{qqK1U4!t~yhbUo3rE?rL(R8Ixjst3P*7%ZcRy~i%ci5Y>h_A)yAHa@VPG0B@ zaQNapR8f6K8f7BS@!dc2MOH%fguhGLs)Bn>?2qwWnKP~Aev%bzwV1W&@osm%=IC_+ zUYn$kaL*)hQ=~0v8l<>HT3h#!Qd$G15`zN!VYSpw!uCb~x_S$JDkkmwXqIK!Vno8F z$)t^j7%79p)=JiS60~G2M*~Jh=%^3rs|{Nk*<)uILcVy3g30r^W_i$CvilI+n_s7o zc@6m^4MpV{bH2C;Bv#O;`C5%(f(yTt$|UIs#6O~CWapU*YSP6d9gR-K-^gD|FG8M4 zH>8b=>JVpmd|_>cQL>O?3XhDv%yHG}vR%|9RG_Lz)g$Ok(o+coZnzQy$0Zv>=!isC zK4nHU^V*(q!xZ5(tOdl89cv=>;uoDV_trrA4!R6G8(LP?<90Mx0Gpr?Qp-EQ3Qpww}|e{d5rJtq>g%Jt5< z11*q;+dLkOtf!xiSIvC0NnWJ1kf> zW5L^-GY@_&4Hc5b>nI2Uba!AODGEQdkkqMInz9J0P72yI6tj#{wF=_1VxB{CoF>K` zT7fxbJW3E9b7G5!aaF?tA(7>A_X^9(I#fLDLPo6M2xxi1xCl|s3&#ySo<(%)0>WqWq-7QCNt z)2d#DHLcU2rZucAo^R6ibVDKXn1(JUC5d%ui!Pj z1F{+7Wb*1@v?GHzMV53Du7;wCLqnhYQhbG~v!YM4r6hVbx}xFj6zX&?Zcmyq@rl4?xq&h=DUmXcsyM^(QQho3 zy&+=uyj%V0Zh(6#_Ax736wtF)9)bbThZ6ASDHZC0K?H|ff5ck6Qy(qfh}Ne}Nqe(FhmXaXwXxyYR~i zk0uBh)B}=%;SxJ5H5Ww1z^D?@JX0x-z1YIf6UWbQn6Fz*KUrST5zfmf?aVN-88(=r z9GB7?$;=GaI5~B~h0C*27Xmrn!7?Pf5Y(MD7Xx@94Bl{c<`XU6Y^eyo_m`9Tq@jvv57K zRGYIMl%Y~=xh(L%P`4PK;*O(2hGiPjup0-5`o@ExhDfShG73jo1;!0uGT!7uF{%vs zJi#h^RV=HfT3>BlCIAs0x>Gp)#6m*6W5G9%uv6QKqV+O2pkdh9J=W2UR;Y?MN`UGo zU>6*Fz66FdEBkJ3vJFuS-L70kk3}pZnafIXo}B$E3ns~uaA~507eK|p__D2wc`G06 z_*-AQ0AUG!JwUF+0n)n;8h-CUtUqiCW6Du$?(WtIQ|r(T3^}KCIynUc{m_1y*opcw zyBj>xm1{=qVl7npAf2Rbx8AO9@{@S)adbA+Z8#NM5WOZbzZG9vOxMyi> zWu!le)D=C+>!RIhfo_lLyQPq9?=bH-h{SWyi2@>`8 zghzf}>z{pbFYZf5ahBJgUzc>f9|&;Igp_q(@{$FCe%Q~0CmCQgUXV6);KO)+)JmAH zA28vrDODX|x8esOw!HK4cMXh@F(c-q?<4Vig;j_mo#|K_Ff+bsIJv2DOAiKseADi7 zY_ls8Zg@2!EwgAtiKTPQ%uluP?0J%ov`BkM#LAhIfG`@cuR_udc3Yl|*b;QbJisLa z1<)2f3t%;Z0*gM2tb9U!B~h%$HMRD&fS8z5Dyr!VUb;YmgoC*ukRHUlv#)g4%~W?D zkXoO_$wW1`ydIjd<`sIOyRa&Sy|5M^OYR>?>=7P@uK)Se7#`8bVjlSQ(ink2WvNLT z6o)M?k{t>RN7x}jEw5cUv!ezocO(~_l`kQLiR&@W=G(!hkqaYX zHg{d^80Q+8xT=~6OoAY|G9^)BN8DoD72Qnpe8C_d(7icFX1NelxG*`W>XS}rLETYP z-*Ld&=@S5-Ca(@a@8G8*zR3mcUCqz3%ggNnvaaY6`I0{x-fTz-ut%S5@Fk z$zFsK*CqkWc4lrld6`CaifSNXanH3x!6Iq339bL z3Qpss6re4Ew8wROXfUq~Vo?Pu&FCXimx`42W0&MNOdVP^9?rEmj+KXVPD_jXWBsJ5 zA^?HdSd`ViP7q7x5E{i`u&geNIlx;Ql+(+s{)&bm`T2<}Fl<&#DVx%(85Vf`k{+ca zsRlm2G+s6Kx(1`dn#<^8kqU?9keC0+>L0s{4D~~tRCd7ByW?1D0Sd<{G?${QAZ?}A ze7=W-)UX4{-Z1bj|9FTS4c_y}%A2OoC3@UhLG*9_^Bt0hC0Az0j2s$aT(F8P!VU-K zT@+kZVuN{PFtPpiBBmb=-|V=mii;#BHIGg0 zL-Qi!^&M;~u|9x5Rve}k+<h?)sct_g>l#j4h4@j$BgQ4ID@dadU3O&w2P zFVUb~y0q3CxsY#I8@3J4mTWy|uEEr5b)Y?Vl%$y^)5qmYE|WUXZz>MjmtW%FWX>+h zeg4C=;g4^us{7^61B@YMWmb13!+Sligl+yo+I;6C_G94eYgLGIrra$2Ob>Oxdv@pB$zcB|bkJn=56TUF%8zApW4?wfZg729CGpcQJW{4iZE` zA}J3MK7sYr^M@C(FfkkLati&1KYkbH8;VU2N|IXo;E~>6|)T?TII~J zXe2Wn&}D9M4xO?Iq7!>jXL>r-nW87DSEzOQ9F(g7n># z-tD-b5@+Snu#GyuSaSX~%@5H->NbtA03{-eZ{DppJwcE+kl8q~yx_{LF-+?>r{AT6 zMNuot_k24?shrC?TVD+|5Gi4blhT%oYaEnSqzo z&dh|LAMz4KQEzlxc&n-u_s+zE>JN5Mm|`G|Qc;prsSa6+ByzhDnQQDR(J1Jjue(3< zs@;Qq>9(4eT;it0b@51zF}u(!1$p+aX=bP##ZUTl!LT;Onz{aSku6On5DTDb-s(HI z-I_x&-mK*U^Qw`Ad6;WB+-v)X^x(byuzi0l#lGUalESP3jMGYfPFY%d^s8Gj{dsEpkAszH-ErJ*B}E@$w|I z92+XWN(~>>+zo>gt#gm@Emvo830y56CivNSr!InUJYx~%?xtSn9#*1~_#!R}bexC~ z;PY_Vk}`F)9@lJU0fAGGd#1)7a#@4j_f=s~AUK-FqaK>$183_O?t3IexTua$T1ws@ zCGRhG@g({?{b-yv_jbx<@fCbJ@SekfTgWRrPDj4zAMAUj|M7==9^Y+UWP%$Wm$Dre zWhmNaWxi+T(TYsh90>~DX?l2)KCqG<&As5$hxpGoQ!TI7=5JdQTRuHJ#9Q{~UjY@A z(r14SKM9_EnDUQr0_`+NgY7-vJf4R#tcN`he4_#Rw;SRd?16?AgK+?y{Xh>xYvJ=W-FUG^R3Cg~GFMl-C_hd@{@7zg%I`RR zQe6%-ErU~755DCJ)Tp0Ia%Mg`ufEV{h zr}VDud8ay|`)8E$TWIY|*TTJ?x?Q!e#b@QvE0$Viv7HISg64Wwe_{!bs!7|snnT!_ zfnOSE!PsfnxmPtnAOJd%N}+-$%{*#@>aT}0(Ac4Rq!(@%HMYsDc~*p;GupgOCu?4J zcUe&Td4oMM7Hwjz$8GP&#vA?Pb~FukR8O1o@aN@A89vQ)V22J;Emk~qSZf6KT+sKz zgh9wl&N zvh4RpKeqTPq-WTW6F=mUbv>F4C+tJl8!jRzjvJK^0`x@DO^YU3Z)&Jw#^3Ufrej5g z_YtnX^S4_6fonUMmf;FPNco3!aB%Z6OLT)#k<~@(_|#L$@o8PnjCk(F4%~kt$>p6{ zaZpk?vkd0u!Z0^Cjio}kVnOJvR^u60isk#Dxylr1b5U^;6dTclf)*{rB9PfP&r<|( z^N?NTgyD`ob*JF#Z#vFg`hTh)?ebCNEf>fKxx^ zkEZ6nl-!z-2$QPk^z|};fM<=AX^qAzk+8ssaK?Z&DB_}XEna5`$D%V(Is=uDjOR4v z3+>DXP3>{K+uN<>`*u+U*s1~2uGn5_VDZB!qb`{SbRdxlvOEeoCy0~=9XSZ=sVEQ# z$n(}zRI;RFgh6{83Cg;558+MI5CdM9{w{!-W9F#P3V1$i3{PFMK&s`NTmvvQ`Y$YS z!Nr)uD?_0%BW&%dHb0H_wzI8n^WMV^I*7u5m&0qza_g-fUDamt^p>2rk2u6yP@3z9 zNG8oZ=Y06<;KFy%_g)zLNkJp%o{2LH#mS&5`fkzzVv{(t1-7?II{l_PWw7x?GCS}2wJOggn_L+xI+w1uCKE@KjgZ+&RA4sDdN-<8g=-EDw z|GxYMC#A{S$u!T8_TiN3_xJXFFP+}-X6bl6qt&wuopX&8P$Z0#iTv#Eyw}tKDuZ;z zY{$Ih;K_X~we!ho@`V5s8liC6wMWK&98IfR0!%S zG*m|a&Ki`NxZOIiSbm$;HE{Mmk#fp*{XYg%1 z!1%(fl?ij9e3P8L7n!ltI8g_#NwxRk_qt21z;3_>um*;f2BnZC?h zB9K7c3-ny)2>r;=ji}A&T6zk^Oj<;DHQ5JyuO~qY<;S3oFfR5=|6<@k-rMe-m1?lJ zH$7NKEBUz-x-K7EPXkm~WCPjGnTsZeGxtRZ;n)cXVcA&Qo@mo?sO`00{EATZh06Vj z3Ah?i6N`q9&3F_crs7XqOS4q(#kabnP zvCGFfSpo3i-vMSXwWJvROZKarDMo~bx+R*&cy+Ppn$kU_3 z+#W;S-{H9J!t;tuDD?UmJY%r`sQvasMlIhUKE~(lF3#CLNl_ObXErXJI}X$5d}$Gf zPc1J#|97q^=Mwn5Z^k8MV}CW2)2Vq-(RPT(#R@fRqT(pNy3%lLXI|p03rENuJ}q?* zQoVcKh`B@h$Yk65&rSwx-5xWkL0>WLLX(&tw}Sg8ie^}Yy`j;N-XS<~(^pY5#)bsg zHRe7%kZ03FIwp?!xN+Y=?ECB8bY~S2F@Li|$(=6kt?@O&AnAG~LmNc(@5G5Ee1V^A&loX9w@J*?|}g$Wnz+mn+W zmhhfEw4v1U6OY6#YCIP0;=y-$RbS=@wtFqMfTL#ou?Zqf&4s(X-$<4p5Rh_IZFyAzTcq=fB7uZwDx zCDY!x+-Vs7jhM>-5XcB*sgRowFRf%W;D~6U(ZIt5@SHzKp`{pIW)EoVZbTV?C4b zwcj50Fh-&S%)xEGH}=7zbrH*LePYh1%Y>KFMuZ1NpD7|#(5xgu zM*bY>=%-v$qV|&r95iDKvNzBKemNSHh?N-Hravh&T$6$3?Zdefe;)XET!sYq63k{| zDgR}2(>m>0nup7rI}+Bl1ArA_cJ7jACMypLYlb-7IQ$?Ec}KALYL#pC zE0;cj4A4Adz`{Ro7R4OQ7Y@J(PrQ3@;;OV$#r=|06PeaDz!9n$K}6s=MQdYcwuU1} zjEQ7o-oRqjfu@rW!e!XDeH-Zy)G=~#v<_h)MaIj=qNHTqVhy7*kVTVNbVG%dhzwA& z%6W(hOMuBSYU^B~tVR^~6|htv`z270A#b(%W3rYowQ~mGo4ij%6+2acl_o_hJBc;| zmtFjl`;`ok9L+te+^dehzXp37EXE#H{zLh*zAC@gm37yBTs zH?ZHUb9bwkCyR&~3UZvWHIW3Q4g!VsQ`8CkI^p*5LWDSXQFk9Um^wcD-&#TS zI~wD5hd&_}cIQd9nk_QU@iHd<>nHB{(?&mh=hZk9fGvDMVKp}e$Hv8F$~i!}@W>ae zzYTl=0EyJGzo%noL%opk!Jvro4H=Ka`n)l|A?+~=K<55E5p6FwD~)e>E0(|QuEB5D z0s{2$<*|5R0{Q5;+udpr zs4}$&DKeNyU-#PbEgAecy(N<&dC$Gq^VX}M{j$O;LMys&=&yd(1q?UhgtU8l#a}|S zK3|N}KLqjfbZ^MmnwS{)u}SbAY{UKUF-@rT*u4_0$C2Dn;VZHXorii}r3=6NDp)~L zay?Huq7xsk$m(QRnIv@EiOzfxT_;?^-Pd5@@@OscY)6TQx28*0B;mdY#xdujxj0%e z6#()BXv6NV8c3NFD{D>1OG9hK*T^u7QLLccQnff_1n$^1ra@VN|F!z6lBtKkJEnv8 zc9XR}$P2@kP~WYK3&EmuM1cjOaaOBZB>>bpayc%Yl;>o(=86>*)104++!eV_4;h(g zoL+6Nz7FolTYtpT39uwRDjr{pyUZPc4dWyL zcu~+IT%1k1|CV8{;DXP7;E+_~UiZOlPf%*+yn3B}m2#P7Wh9e{o~;3YJLE5eI7VpB zI*c@Zu#^~=hsz3z-Uyd)uH_Cp-}QB%%W#fGxNmKo4A96h>NwYRYJ3HeiLFGhfFY{Y zqql9HQEwMjAXf-)a1vxy+a<4LzBDw&sSY#5$n#X~k!d1?xZRj$^VJqe=BxX%CNylo zxm1Ii_bh=2Rb@;s%rvdXy!W_O3rp0-q}@AE%WEcXdX5WD;-SlIy=$E^++Ll(5wa{M z1WU;j3s82fihUm*U2O_!&^=^wVV1^K}T4`DcCM>~`i|tun1U^tzBC{dn{b<+~xnw{p5fr4!FmQSo z!C$~1Yr#>xh~pnE4mMGgxB}pIQfmgK!#N(`^vMA0OG9!)#9UZ*6t;mc)gYYPs_n#) zmwn;}aTAsdpyMmrmV<)5t^pWTciGBS4J9};fMegjde{m_2c;MXmlB&^(n=%O!F8QH zqZ^IUNCf>_3wfxBL2JoLPh5Fr*33BuSoWY>X(Osx1{)dOe;bEF7N#Fe(r+ca!&R3C zBLT#oDRtn-zvQre)t61Itfi;EJoQqeQIuSjkco~Pj*XHqU@gQJ(sce72`4{J$%Hen(U6WwETO(KAN_XcxH8-?`83$!lCqs!r$r zfqotCWA!H1fTU~DWcqn$xSzdj6eH#O+_$sa!_d6nRZ{}yDc$yHCHH!syf@IsCq9nr z|CeAtMuLrK`gaSnAw~QSx%T~Szh9(HoW}eia_!@Q9iMib&@8LjW!(uak3>-Q$IkO2 z5;VQPICC=apipCMqO}tk%UGD}fir)(Fl^aT-Ob<5cw)JZe#TpTbYC7r{n(Ks&*9B+ zQ|}BALq+D$HKlj1URZi{d_eHu`JO!Red667>l0AQ13LIg%D{6DoSWU@$q$>73*!pN zPIzeT==0l}`tKqXwCka5c%v*RDsBrG;yYATdUPys*0~1n=g1Rd6#L6;4wLbG+-RB7PnM`MitoNf@> zNcnv=ltt!~=BVq22-6-#(e`UB`qq@YBHqit+?!f&a0_skQ-F+FVcjAYR3%8niGI5W z-D>D6RZZMFm5}Mg_S@{n{~q)GN2X_X2mzt>#4v0DrP*Ob8r?5_0dJ?Ex!q!SyBg;OD?yV? zd~?VvF{dNzy53T2hw3*IiwJ!PcR?|d3Vu+g6$xgyBVI-n^R<*ooyH5}V%kO;s)%`v z%*g96a&#!#R62@QK}^r|PK5H=St_*Ua0NA#Dp(B6SbefcEK<+ta?9*yyC=Lm@%i=K z;)k3F0iLxCtHJ1EI1r*=R3v@mw_ppB4% z!Eiqxdx)!rE{xo0O{P6e&N8OJnn>;Km-v)2?0+SIgiRn-1Sa|axWy&3sWQ;Ow&OaVq~(d z+M0KfV4^+~X@bQ7Yo%y?-kG6Tfyr3X7;hLaxk1`85`flF1GM~bLi~qKVzLN$X^F76 z01kdn7WMDSDhvC(DMT9T#f!Rvs-=wK=@uA%x6%dum(GunZ5jj-Blzw&X*QA%aypw6 zJL>7{1047Nx&38NJmwy@vI{pln+M#4hm$iii6OCtQKC~izfLcPJQ9Hp7?#;M^$%fxi#H*gYw;ApO zaoC%*Cx;DWKN`)mQtoguId;xRRd(4zwnX8TZRe<>au>#jtSBz`t+jeLms8)FcANeZ1i{G~Vn@^hUmXqQY+w0fr8;&`u ze!LpT?1q(ljp(2oUgDoMW={zIyJ`{J9ITE*nI2?|Y)!iELF#dA)qR`zFb?|ENDsuT zl?>2DL~SkrL;{un7PQ8D@O1kD`}5KC75&>sYercoj?`{!W|s_i=`N(5-g&txA<=61 zTWP3&(L7+22bWi2?ZL*1zlwBt{Tf+eUt386E7OCRZ=hVz-9FNNR~i~QYZRx3tu;ix z7Cfs}!BIH^z3-}b(UnNsFC__3Zm2Gp7km4aH0|B!Or6`Z&E9&dg82o^`Tnz`ar(?` zPS0MSC^V58o&*`K>0Tv)6ZU3LqQ!r6$h*}21Za=5Td6izlqK*Mr3*PQDt0$qzFfjE zrZ#BEmz&zFhUV;2C!r#)r`c~kMLSkN8_3En@?D8rJGq%zIXdeyo$l5u^+DjB zFh6?CTq9M8@^$Yne#t5F)M^u8&i&OJNvEe*;l zoi>^wnNI0z#hKgNJTKa)Ds$h*WH*!?*4N?}#FF>;R$cvLwtg|CQxEgB*<5BdqGOV1 z+PVi)_jsb2dp<6`ST}(;O@^$r?^G8@h)k*%bwTI0k@B$6Va&2T6a6&s^d24th*z!_ zA@^osGc|`>MmC(HW5?ifTg8RDV?zzB)=*M@#FaOo#?|v zZ>Nt5bc{OfWFVnAHMD(x*akpey&O+41O%dnt?H}o`7Xt0=~QkxSmNy@eSR`<51WAv zbMBTr^rCiQ0=SP+lR&grjfvogS$UYLkbdZN1BHP*RH)#M0O%VxcS?TVlyq9tqG>AQ9e))mEjJ5(@{p zU~@x-JHW0(3j=9<88EIZ4~{C4EN&tLU{>@;=8wHKJ1}2J*sdPy5yy6f5p?@ve=azI zJJM>B%tw!~tJ`xH!Kzy1^JS*FZgHv2C_ZrdV~K&$p$yXBHT{g{D@H4>Aidn+!q5_Z zQuU|KE}?>>R$l=J+odd_kWDCG$z_`#D7rRe4_bvt-F;xNULNX$3%^B6OJ&)nbB`VE59;2@jL z4-9pGpK!i+{yhKy+%jA|U;LI2y+3MOth(Tiis6xhTv)QgA^t};Oug<9GOgjj&j-)!o2U9h?&q}yDn6q7{9 zc#^){tht6=k2A|^P?MlFmsG2Ve5&gKL>ksxi}}?)8%1F+Nwl!}6yUAnMl{Qar6Y4M z1EYP4Po`r7)wr%4YfzYYpP$MUt@R;IBDOebp70`Z(lPr@8IiR=*Z$Ei{_nmRmc3Bp zJL`0JkHf?Kt{>Y_kOiQ|iXU`YUAB1t*Z0D&(R1hR^e}y}%&v&;7?dINYqU%C^qy@Y z8^9Pdt^Ox6{#O5({Y0k5KgeKQ?)QZ4+LCtoJ7^=g*jKX6F~R)qp+O=GqL&C~FZnroJ9K z4709D76211G%j`9QLna*06cc@bB)g7;awE0bxEdF!Zqs~_R^(LFE6cLJS=&ZDzM5H z3J5^AV}Y_x4kTUEtXM9E*((t+z;xOy^L*W{a9RSHWSzT86*FEJ$>3)Ugx7|I!n@$m z1j?$kLc>UNpHI?Lvp8yzT9q|I39XTu!OyDJ6?69mHjyn>0a=rKi?&-PTFJJv#oE52 ztGg!}xU+TMf8PD#*Z!a$eSn`9&F-^%eO_^-V+}mHNlw8WF6)6+=IpO}cmN`LB2a}nE%jDa{i1^)~vZ5uKEFAKHbr=sBojdEk;)h+c zB*Vp`%c@?{)h)yqmupvaic*XCCiH`?AoRG8)-8GH8d2Lru3T={iukf|88T^1+Q-Me zlW=IatBilC)vbP=Ny4UxLLvEEewhR%(MeNONCckQ$z&Xg+!s)2T}U4%k7XA*v8ViP z0TX&(U^e|%3klewD%zS_;*Qw~s09#Y?W4*t&>R~2tGOshH%;8IBoko6rEtIv#ahcU z54K#YK0(4i#Aw)No)t^kCB+j?7}EuY-MrR{qG_{)_m2bmtOD^OpKUG~O&;38n<8uD zQZi0kNH{8@XK$e4144&JGFUadQNB)G|6WREyQf7nryCPiQfA!Zlw#tG0s9q&M1W9G zPwXiX?jhGc0Wu#6Cl5dU^ymoZxULqPIb92*6&~Tx12(;lz-irQhxp9U?eyBjmm-QL zFw|N_At*+iXd#O$F(P=LagG-gjqTi&1s%-ubz9#*J7HTR){pe1Z6X%!rqz5y8WFoa z;sMf%*laUjb|drP1B*LV?PTuGj@k${G6%CD6_etLV_kaCg zz%SV1cynSlwS{$Inc+ez2@^Y`jq}B%I4TbGu*ME@#3banq$!K_8sBNrmjC{*|9iIi z<(Itq@BjLLSd@^ti1gi}1hH(DS4Z-4vr>lbnXzjLu| z52%wkmW?cYFcDQYeO_P^yzqz=9dKJL;wo;pdN5{+{2 zFWF@JqR3&Q&fn4{u1KZ!K8H)dNF~qrH;0Af$cI0Ce%^{5qb26*8q-+_L{>V*OLoD) zIALdjq*B==NmS+?WGKy0ymbPmWEf0k+M(3SaZYPZS{0F3BDI7R*pJRbK-jBsDq#Iv zQ=nuAvN`R}mg^w4;ttyV(k{%z9N7PFd*9mKwvlc59lrvttd2>BWGp4=%*c*&Wm`_X z+OM{h&h*M;2@nZMXi)^4AT2Rz_ivv%`#h=&044d}zH7~gn-57uf`xjXI*)z!fvOzz z(rz*e%V-y);Rsvd`6e*;JQ0jD;EEecZpC0< zUaOQuBJL{_=evPzCd&SSSZvKRH4T_JFJ_>2HJc$xig5?RHkuf1> zn*<)qNy^^$${J~iQH671|IX~}2Nez2jpQ9f9s3%H1neQJ4MneLR4A4V`@j>${!qL* zaJkVTO0t&E4Th|n`o1yd<AEIvRjCD z;Xw8CK{@*2k29_qfqB>R&F&BP5J;-e1eQH_pREEiRq=&2DqQ_k7aarYieTva`@`1T zxhUL*+>umk!Wb{h^K&XFK}}kT)S#uH;lsc5Xk>0c!)SkvyP9W%bl6`FHkY`h<0o8i!zNiSVo;I7m<=D6Y|up zf(k58p??VaCGA`i32&5jxZ%RRqxBlO&_~cBYw~F1RGCNHWyQ8Frc-cc)19rAjkW9a zgP+hFKAoWwvA=KXNMAGX<<)Nv?_6%}Knrl4$*UP=M68x`IE|6#GO{hdtQN@MVprM} z7L5+u9!xgn(nCg0NsHz zjDnU<`Zy(I3%P#Sc>ht>|DNa)3h5F+3qxO`K+1*F2$CQg;A}tHCsH^?2$4k$k#Jd4 zH+!5iQ?l^L{kBcCeooD39cJt$5G1S5Xna}VXY)#$hl24zXz)j)SPtch>(mHM0KJ|@ z#bx6eo#cZ1rd_+{IrOIw2hZ4TO<8Hw(Zm^*dQkD%|!1IuI*v=9tZUxNIMra9bE^?cNNvhiuM^O zX^3B&bTp;VqlIfo@A?r8VbW(@qt}J!98!+wgtg@Ow`RCvdG$KvT;li+UJ^!{eJ6i@!?V}*ZBUY!>F;bZ|mMSP*XX7*rs^i*58vxKcyvi z9&fV`cv1p-PWm|g!*{717p1q69=tesb+mPqcETRoNqSA2phc0}3xU}o)HWMt&w*he z9I*RJifu6GKtJK=MM+e^?p8o)Rdv>MY-;oAMjoA&WdBkDRx^%CTo)^WF7WrKLcPKy zzLN2AhRm~+Jc?wRpE&_wV`A(pqVZXuGdx$sT^#It#XitU;%ke+sB?0GCjQLMtNDl; z2&B0?;jSYOaNRQygN}(DhT000!LRsP%6_9Xa3(dpS?pH(z2RV@#H&u{R~OH9r~507 z-CtB)ojhR7t=-`Pv)~`A3T7?(o?8ft{9Z}J@8!%TX055z5o`!&r)6Ci4?rX~nXLig zbK?g9m!-s5E1-wY^OcrKu(r(b4G2`^gPvN`2y?jk&B9Lf-8opX&MG)} z_<{Vk^7Z@xu$qUd{Yfp>PSYxndNwr68cZQ-w8yRdAawbW zOO;c&f}Uvqf)@k2wz`naLXPQ_H8XmMX%V{ zWmFClYa52{fARVn;=c0ri1SMYRzHJcz)p!5c}+R}$r0jEC~2-S(yA5es{3PDXAhVubr|kA(eFHl$5I&TW+e@l%FLX+uKD^%g6`K}`o7m@ z-aA!OM$G1Ql$NN#1=6z)h|OY&gkN(?@oA=8y4ej=-Rfa5-QKFfj3)xD7q+9ccJe#M z&(kbXy2}JP!^G+|@q5909blF<@aIzFGx4u`aLZy6x*`TpoK{mNcW_q}Nv>=>nPkaX zX|bVeVv9uPu*^pG8Q&H~)*LA9t2em+^`y!SCsr&9LR44cj-3aCk&55aVsPw=cCs_h zk~18SaF#f_>zcFP_ZksAxIC#bUPMQ)f*~)^`)QTog|TI^9QSj9!oB`e3{DC;VlnUoIwP`s0L@C=hV!s5^)8b7V+Ua zySjNUVu`QmWAF-58;V)x{j7wTMNI4_(=bkCP4@R~aVYp{pZ+WQ*lzI`)pEiY?O%gS zkm#gHZmv*EhQ3Eft4+aa@JmT@RPdLh;!F=Fq-6X;|F>C32rC`Sa@%C5} z&qrzk;k>HO$#|?+386)B!&1^?weqA-zJxn7{u6zLWW4e{O^O?{3ByCSs>m)Qk|3_6 zXSHh9b37Hg_fcc4JPWRl7@wcm6pewB7BpT7xP|)o8oz|l3@|aLg`eo}Q>GSl!tM%W z0N&}On&w53FPQuIdLC*A)53Z#{t?4WCh(g+;Np(wj7owFYFY^Kj$!(R3D$O+bb7I* z%JMTZ!8YXD!6+$FeZAm0&XEs}=>-_bsy#gj&WW1YKM6h>Lz!F@PTgHHt)N@)DPMw2 zm@tnZJ~&4cr_+)DdM8xzr?0VgM}SKtMe11Kz!H zohGBOhHcs-ASLmGZ~7r6Zj<$1QUs~p{e7IY&B1(%0(FPMi4e3OzbK^V1L*Me=BQY@ zE-~a#IBbggJyrBo$YIMbMz0J@9S#IF=tQ2BP>?U0hS30kWb(`ipDYpkI0?)}w4!rN zA~+FhL+W5k#VH9x28=PiTY4_v6V@3Lo&OxmP-GxNT$%{mv1TEU6HS$G8Ll~7p5#`Q@JNkrc)L5vb%M8xZfYcp(+(J9a*V*x^jD$RBYB*>j^<^ z`95t^q^`=v$7C=#E*JZQ0aw_&vlq_h4d^^AOikA*F(Wgt0v!|A9V`|NIkIucy;HAY z=DEF__N4qVstcmNyJw+Dgc8tAe~_yQ{!t|Bx)&cD9UZjt@4Zbpc? z;%vP{hl~Os>J>$xNwhwnWkS>BO-6Z!^mKQ5j+3JtB24qEakRrt7P#vZ%*b)6Z}& zNAyiSDxDQdkM_k6w=CR}k%6lAfG;)jj3gpvkoT7 zSbq*>mr>{ohypfN@&a!bBT|H2IgpHo!m0xa^>RLCo(~bm$%|2!d~xQ{)`A1h|58+@*DV;uW(&Kz&`V~j zT%ZJxQ^FaO)FC91G?J4Ck5eAV9YkF7FU+vfc8U6|C(LZvCMVb@C)7~?34cVrVvp?0 z`H^n8`Vo`4cW1-W^h%I3d;rZ2xobPScR#Y%`AElWK1TZnZH(bfGx0A@kH?bjlogCFnhFyoAZf~E4P zy=`?}$jw5Tdj6MEz1GmC!8b^EA@4SB5D`s5uZ$^<^lJ^eGd5osy~Z)#`?0C+Bxn5BR66w5LxU(f1o+KE$DpZkM9ZZLVAwo_Y_J}NINb6_QZ=yID}z{~E_PtVRMQzelS zHb{4A5-dJ10bN>EEjOrA(<$2XLabWxr&~CqE2`GzkP-q>H{^q<77WxNARSO*{jYY^(+~TkFl$DS4zO7gdFF zu59YikH>w2G7l32%!)s{Bv_kw9nHdQf6Ya-=SWS}?n&^?&TKQL z1skr@dPCreyl3v@2j9AnJR9`Z8_cZ{8yPj3!4-~dS%|DrQ6rf+kS{7;#;u!aa7x@L z2feOai>*owwd-5_@@Y@6GxnU$84CV@&qSmjOQNBB;utwqrX|atACWeer-K1`jh%(X zDWKxmstukhzM8tCHRaRK%JTv^CxXtCl|b5NLe0;L5hroE4IqWV#Cw#}X06jDf$!;p zD=i0-S*QtkAOZ$?mI+dr&Mo?a_X5X7>7^)b{5NRYHC!*}%lt|pHWXX1UT}-vv!UvL zP({;Zak4<@oxN`W%f%(QxlJwBz${w^u8_j>RFvLz?Y#%F5w&fx;3qZfosP8Izq?K| zdj{84ZgAJyoaw8a|J%WV5hZu0EO$+f4uRw0qrxOD9J`77YQb0oG_qf~M8_xfoA*@I*e|rjq zHqCvI#6|lm{cP9p^n%^tpTJQ)WzJ$ew};_=_RTQRvgVbztt9gj)a~T`z*geLPyPF8 zb4yiNdc|j7ag$$bvK{I)6(w3M!!whzU5%qjOQDlK5+@U0qKcp%FwT*io&-lU4yan&|dY?4B>+SlzEsyLe z=O^IzTAo38Hg~gjW7382n>||sz@~}S-K6kAIa05O9NpGsW;uKNi zKn8Ba8H=boSX+*|spT-KDB$28@2ey!obu&8GCV+ug8NZ+j7)Jcn(aJruNg3B5duXK zL@OyH8FgGJg)F$uOtgZ+&5W>PU$p-l= z;ea(aH&4%J)oDIM2|U2-nT5AnaUQ~KljJZ1+`75H1|;tp8f-T&9A^*|qEn31H-uW@ zdk+!{r%?>nQfkn;RdO~SydH4*8yO#y8MzL-eC2i~8dK7x{ns-V*K(8z4(Gv$=3@#Q!l zbCuGN^^m^zFs(${!N~j$t7TAJqJqV*o(Br@<#R)W^#KD|V3eHxe4PshoPdrf^iR|+i(-R+#v30wly%Azo@egYKM z6lFuKVrtXRkt6AOe&)=w`6>v0!tE{J!uuzB@P^ADEfxe(aVI@NIbI)Qmbu`v)_RrG z+lB#?XG@KyJ(-YGhZ#P}A&ogQ7r5eyIs&E|fvztC!k6k4K_9`Su)WF*F1h-wYGMx2 z^)kv+hVh3hl=u}&8!P0*9AZ9n66rD{$GmxE&%mTc71NBkmroK?r_r>DR#A|S%VoiJ z?_{G92Pa(rPn{(H?$zO64_{>orS`jyj8KS!IKi}LPsR_3KZX6HlHf+A5ZrCR#Qi)z zC6%UNMz$Z^LA=3JjvCn!cc;{Ea@qD`8F76HT$MdoKGI<~H3vejE&$T-s$-@;Cx)$9 zuT{i_c_1dkmr=e4d^)vfs8E1N9xe%K1k}V%TMF!0*I6IULH4+cs|TPI(2 zkdKT6gWg$Pm8<3!fjqsvGlq!>auKD6cxhMvq&L94^#~ImOg!CBQDtMxSegQMjc6Xy zuyCpHRebX(2I{`4|Rq)m;S&v=?^(G7$2=kDIp?x z&?LKG<5zIhvb2zLD^NYw-hG0-PjT0Jza=}62o%TloL2W>l^9efpu7?hN@5CD*Y(9_ zKYdw?MvznRr9z7=T*Ses%%0z;&r7MHN{3;MI&?7?d6cQ;e(-jw8{8Y&2^-m>Y?|}K z>1pTRL(`y@w4I|@!h{m7shTIW9>(m<%ZUPhc#5Jm1xSr2rN10_?x2`r^LJ5vr2br|j!A1Y| zlE^~@(cqW(H_(A=12x42zxK(Gd404#b@ycJ8>-EA=k;>-Wsw}vPXvtnk zElW>7MsLxWYKKi4=9RTmfwwXJzM#<9Fx@%bx#bBW7PblL?M!zx0UPtFO;E^#!;jI& zr#n6nDMyeJaZ6e8?$s8k?2AbN-F+MS)0T$1X868sx)Hu^AsK{axxQ_u zNPYAd;qUg{*Z=YG=G(Kgvu`K=Yno5Len_K?KH7aKYkiMt`^2948NFZc@^}UO8WR9$wf5%4Y0K3W)f42=W-_ka92fImJ*P8ad%< z*E177Pe^HVJ3oDK@bcB+^Kj$ih$*2atRsSj2JW`Z_163+?o2JGjY|c_0q%A(H`Pxv z@sQTcO?NgGQgAaAWbi_@l@cX8k z@9FE@1$s)>S-0f#QgMq0`Y_W#J^<8W@FD&x4w?6Iw*tgQ{XBG*QElU3VsJ!4){!Q! zPljgZ>(PzCwMP=<&Qf`0LSY0b=N`{Z%I}gqxBZAS0_nI;3s5igSrF|Dz~ExEXkPw> zQ=q{UNUACLQX@=EDoA25g;3^^L#sLsv`t`CEWa{8t>d)Vk9 zI8pX&bd$lm_xJVHLVrt)72G$Wwj!TO$!Kp0?S(c}GdgaOaZGjguP?_1&2olW;p>co zj!BPQfg@)Qk1m}Kx$}QtkFIvo^g%rT{WN`)UeT!mmzi% z-}Tgb@vCdUCrSIgKDbhgB?}q%m;ZS>qB2&7Z}6Zxo;TN1Oq<)T%M}pew8wgK-z!#z z_M2&IZu49dDn4O)4GZvOCa2xwASKI|lzHrSXeN1sEZgV}y89t`)|4WZ2%*Uaa zK7x1|4LAET0s~HQTD+KiqhN-`7 zUC#i zCP&LV22&=N7n=|BT)E98yrRWjwK=5`!wh=&$u6c~ShMobL8FNt zASAe}sA0DY8(zVsnC0MB;OMnHPBtSB-{~fy?@#EDOjc$POqUoK1HRoe{wova(SYM# zGQcOw8z5JvTJ_kT+=tSqF@;HfsU-8LKH#z8JSAtmbzU+-c#nw->89?7#o;dsLvhI* zTfv8HPI>P{<0}}63nuTTSwkNxagq74SHYSnTHQB8BgxM4SzR!J3Fy({pHO5|9`F1$ z;PzuK*=IRR6J|5cEwbNU4$%gStHo-Q_OhKF5>w?|D<9-Wy^T$*J|!QmJ0mp5)Wo3< z5WAVZ5J~V->0qluhMuvP_486HZ9d(6>ol~TfN7-Xc31kx^xJ;=9T8vZ>B8u04K&0h zbRrOv<>e6)bKZ~jV0IvJyjQzGTmIWlZm~15iW?p7`C7`9ka`QZ%$sWE5mc^^oGPa= z>D-D%G&*C>eGXV~LQ>Gf;~x)>d*o*cgwil=b@EZyFVJN4JJ-qW1JtT5(7dTy=aQ8w z=3R#ODewb(znRZUW#c(b|0+J-{j|~ZB(z#ubCHDR%HFp&n~mn0!-^WETdvn?xgR&Z zD^grigQHXAPTo%I_d61%-PzJSeeVpu7?R`uJz3A<@*mM@%HpNSI*M2l-T0(nDl;H{ zMn2I$>U6IV*@loE*=fx0SeTIMTMX?Kg$m9oyzZ0GgnG%4lF)l4S5HNI5(srk&8HNu zJ5Rltqf9q{v|2vPS3Q${-={mMh`W>S)Blkj*PQ=;RKcntH`ECf!mv=-o};$`Tg)=H_g1(c3Q z8bcCF6jhxh<&Fvt5WbPsc1g2Svq z72mt;4jtVM=*PT1IIXLhGgAM`m=l4XMC!V`y=gaMC*u3q9%iE?)Y>~pMWLOdZWm=v z!NVQBx#z1rYC)q7F*FFC7|1@h0efH%hcAXLrrn4AZFh~mFuG;HW-Tw56Sw;?x@kuL zyGiQ{ct$9J!ewM~gkX2UwF}uvI^319VI?|qg&0Tte%_0(OKS=_W7^N zPdL`^m>qH+l@Sr2RL4OVA1jt-Ma8-DWjY|{J1ToR&?3rLT4%`%4KKF>N|aNs16FCI zp9B1X$1VYf_-qr)$FMmC1;~{~zE-)sLt9_Gl&BaYv>1FSHn#WFzpooO=&)?D_H+bh zMJ%d@+Y^WZ`aG_fX!wy|(7oQv`Lh`%AiQS=r5T}UF3N~j)y$9=(D-^ge?;$=sBZtu zAM0WI$NE=ihHSS`!q%GqL|yB-_xFd5&o0V-Y|xP4eEc10W9jFg<3H}Ni&9JThO+Z3 z%8w34*!z0ubYGL1&^yg{mYe5H7+mHnr;iGCL6>?Sso;J}=pDaCm?}*J#U+*3&6OQ? zyX{H@K+y?^!TWigIO5@>c&%M45;j3~g4G%vXr0?AP4C_)a_5BwW#ZfG-?jpz-fo?K zXB*%ZvIP7RDPtj2X_{t5Clyf%FN;5v#dVjo1NdWMa&D`LjtV`eZunHh0r&HRO!S*G0=&Z`8KCsxJa-FXU0}L_Zr>x7w zA``@|a%a48*9*1aezISjcK&FuB?)N*z->h9EGXxYQhyakRwbT_Qa>S+Qx!+%1VxI`?!*mQoRsA>g>(osJZEu*;x|h7g?x??@=^ zWJP?t zIfKC}%Jj-pxe_HBAP)*6=LuNkWOAM9PA9QWfCj{_H$3fZTI*)?-J;W(*G%^3j}wn2 z&c$UggguPF0Jd(tbNe0cm)F(25(k%wOyXhEnIIce-G~g@IL;bX=Q?%=-Kg{+lHRML zPKfJ)sWA89P6BdB*~#+Y80#w(?iZO#0=bqDXEOas`~Vp7r4xfp?ObJ;V;RS%tSe*Q+xLH*tj?)Hw4Bg<*dX>l=N1?ax)c)8}HZZZTR zxa1Xz6R{Hw6G}j@p@>qcZE4P_S_~s0-Yyvl9RVXDpbMH>!u8CI0NWhgq#0(1|LCa) zsMHj0WZ{dqHS~`Yai%+ffSwv)iQ}*3iXG~^;wN?bZi3>}D^RIC#0g)jDr70*6 z*cc>C;ILDLc@%_C3M2qpo0tk9tc1W@(lbk~Z@x105Us68FKYiN{bSkiS+wROoK9ss zWuZ1_4|+$q%SJ0@6+2jU+MH@yCtMN;LYMz*U)S6x6Wk$T5~)zpJmnNSqHO$dkM||z zASy@En}=fqup+L9)>JM)3kWb7lmoG`=%ZceSb_cla z6K?rqxH*Hj+xCnL?;fKbNfx?(ZiZ-4^Wrsw3FF z*WX4HOC+(-ts=-+R}>r=TdB&6uiwKyecJ?kIHm9sn%87FptU}~_+Y!k&lCHG#-4y1&C#|S%f|V>g0RV_dInFjc zaNXLWzAkexmzpKJ`+I5j8C`322Mi}Q(s#De)@);5iOiIr5){&r*LYQ~xLV=cBD%wZ zEI}ML@|~@?DUPaix1k|@FUU)BEN=s&kgjWsf(|=l;e}!SCG(`RX(|`du6a?*qbe;Y zds8lpdyHTZa?cLoO`JMMjaKauD+HLDberbCXvxAUxe_tuUjL?!)^j-0?dpwf(%r2C zQy$+&SrAutZF8s4r$u70;op7)IX$t~A24eCiJcbq~66zSX|0IV0W zxAXNh;`l|=&AK$i60bxaHMP(PBvCDZH?fS74=Eo20mb9+*-YUkZA_I!WeooQd~{-H zLC-{rMEWupk#>d6x7mM7Do9yA)zr1eA0X#9cQDC;0k9 zkv(L3j?|4Ww%oV4I-lCn+m;{i4afa>e!06C^xs|wymz-~Jv4kM-+Q?vQ?70#>3RB+ zhZ7H^3RrP3n>t#xfOlbpd}ecM#di^L{}Gb71BZp+v+=fb-&c3Acog>cf*j^kYz-tU z26fc@Ds9T+{X>`0UC30Kt;OgAhO3~ zikCsD5*FQ|m4r%IqUcz$NH*oWIe=SJ45QxHfO}we%0mf9k-ZL*^;dSQWC(C2<&pCi z0^+heE?#Ws=sv7AD_N-{OL{@77Lh8+?|iZtXu-z<5C_&f&LZJf?;$#^+-3Kf1@@in z=;-M&_+$+w=}_oXKe+5vw^%`A-}<;L?xl!CRk3*}+KKlD-uofR1iUfmp;ObA(Ig}> zb1w48ZzNlumudm3c9r+2<1kSHCQ_k4ualv>sa9FwI6uuO|MyJmW*+rdL03cC@(=oEcZ2bJe~Igq9tx`E zJB#I5K;^|N>+uLyIoMiQj|><*q|P1x9@ZVP!&^Dsa6<_&h<2fXz||&Q&gQ8x94oQL zUihMHJ|Ew%()J+_5C?#{s(QM?vox=m}H>EN;YU*lq1JC zacj-tUOR3Q(3x&Lry;tI$BI$<}9*_Q<0hdI(ZNPXiklg!km zWjY7x2HmKda;BSe0{5I$iURl8W!j9kZEf9TyB{i-SSjgr5%!Kwj~_{x_-Z<#V^TC8~TSft{KjWrd!$rK)`c!Kj2n6}0@6 zT;#o~cG{+%8umS;C;)`d%)k}pZ1Tgw?5)HHqpz#5F(DYSpdg=EE0=O;)R4qWIN9?! z*#t?)3$15?NlRrIw!tzje`*lG^Qirk0p=r6QiMksAU)SRR!pMqH*{* z#HM17uf6z)Wji;m5e;cz5|7upfSK8^srr9E!{F(K4G@x3!r;jxZCMk&FRps~w5VS& zoOK%|wD`EG$^S)qrXQn?qqX#&B7AW8bdp`}ba?$&MJ19{1P4sDK3c)5*}!za<-Do@ z{S)y!cxDth?7amj=m3(Qyxic2v7s?9L=ptdiyXqpoXJC3hKqd_^U+AD!82(nP&_eIsy68%_O> zbEe z?y_czHhk(iC{<#yOj1W(L`kw7@{u--GDs3hzI0t|uux+<#fL zopRyo-dPr=Mji@dx0lEIwWJeW=$E1@4F=KdH!og${wSaxNALX31gLTT?0P&OF!%rz zjgCMxZ(&R73QMbYRdcV4y0_$d+e=8wpQaQo5k7)qw~o>-A5l`)$w+Lr*0QX zVK`t-K>M#Z!hkiFRKY?c>2>z1+sV-(@aN3o=dF(!0m5n&dzQ1aUrub`U zb(yVVwmPrqKMcGAkIszv4_UQhNYjQFT#js4s$MMARjY>1OP)kpzn(57CI&q3 zvm81Q-c|@mpG!?A9dl&fw%mM?OT^bjYLDozo+**G;;M>!)Ncd6XwQfA1sUTM<L#tcXzJ;5=Emn^>i!LTLv8xt{Xqdil8DEmk zJ|$N-g>PbwYhagrOV75h&9+|JMMV}3HFs2PQ|~_n%nx4&RUyJPjLXy&IlJ2k2aPmS zX)EQ-l-hrO^|^3MpVs+b7=DOy_C}nL$kw~5>Asicz>59fpc7robJf`PQydO9PJ;RnAA-t}ujl5p}k!DAe*aY(^{Y z!^t1oG!t~ftr}_3;emq5sNV-AgRjU+aTHr>yO`@+x0RT}QW^&m+t8Zrgau1+}=r9GhU0$ONPuyfO*K{;H-CS$I+uK1QL zWvN!4$$nznekpo9P`rB&=G=D9vIJl&{~EMkO4)(my6CrsgDytbOc*NTwOBSy(>(X0 zb9Niw${yGirGgi+SZ+%!4wM6oFpERO6Ux-9Nv3UGvF{Ah>)?`gP{b9el@OWQ%oNyE zq}!BtXI4>e-aa~gIghIhJU7QrL3ca{CL}Kd_*7*LbMex3o1dT6`@!1p<~z^bK4d*w zdZpykM!=y!7#Hq3XH|NFz;^3{Pt4C=N+ddpJv#3i31m*ku|S-)CZuPnFdUf#h8`k? zF}p*dLBm>(0;eCZh+4W?U&V!URLDZ|GqJIh>39q;|7p|D+?mj3SeE1XRPmab0uksI z&jo4Vgo)x9A!2Jy5YUl~ju#*$s!Ondok&E2VhMsL1Sh`#JhA9~TGhNfDzxuACw5^w z6itZs;>>>qF=>u*}6wh!<0_^ zru;C4#@B|M4C|3-v5$hzSO0lNQfSY!(~84{p5NR5VtUY(*xI#-bDQ4SfMpn?KxHKv zV6QfLG-crVT|D*@|LNKL0h-3rN#~S}1*vRL7!~UQtQM8HbVE58m4(~Zs=prey6RAa z4T30&Npl$Jm~cy*_Lal!R@dSrojEK$Cw&aoWm0!L>ZL*!Tv8W36wzihYL$&%HI^nH zj@fYQHFLI3PCT|g^=gX8wt@6h;N87w)X3H0iNt{2A-qJAJgu6M7SsyA<>vTG=q~3D z(0z5+{$fC2&~`b!(`E_{;`}JVK+=xbw%QLD7`O21T*SVs&{>!J%$FDTd{O`c|DG)L zXSO!qeM{#l2N7#6f1Go5>{;PgBTr|i(PE98t#1aD&((D%;jE`bW^~jo(#ZF<2<>we z+9RrX6CWVuzqDw=WhP)tH zmA$hXT;x!xT#c&aFFuyQ2U;DE*hLSDryr?WSQ&w5n>_<+>FRQ})bJ;nicz=H5!`fY zzO`$j*KFsAeCq!2L~@S^>js3kf=BU$99k7rDVdJlX%j4$Bh~_bC5>p*EigYX^#;Q$ zZLirrFm}?G8e`q!ZDx=%Ae9b?$bwakTW5~nmUf^yJv7TZjm__qywhqM|4O+1c3&zOxM`1VOhi1e z@HRF4kynU&`Ufd2r(NFEKzQ#=A)LsmAewWIg2$~u4ux8n&!kN+ur2Wx9|4Qkn!jt7 zR1VCEWwiXW!myl^PHG?s+^PFdje%6 z1gkHB{sR%x?HR@{EXM_8j3{c#(W_}*g*e(&(&Wc+xAWR((T>H$zI&Es^k50pvcte` zrhlRe5DTG@nI>=0A7cAvD)|#-p$>?jSI&d(qm9iY>aDrRJM*YK<_-kx5f)SV*2iXM z%u=G|k7+tlrGlVO?@T5D;OMxum7+22wN{%_v0ATE zPK?qpGfGs6H1m=k?C;l?=q5`}8K61;-c^y~I2@<)t^N?h3Q#00)Wy50kjQHxRQ zQMbJ&R+>kWiV=o%{}p}l1q!EWaf+^bs;SkspqNpAqq6>x$h5@2ngoLA;<7@&o^;}q zYi%3OHuD{+Y`f1|Y!gl1W z_VbI14W&YM5|L{#=Nzzn zDEHen#Hf&Wj-5mM#o@NmBX6^SqSqG(cgE5%qr#3UX@(*|iEyyX{I|2I`r6P-*2#br z7C<7yO=@76cu&#J?-Vyf+V!;@acU|XxL%lskq<0z(!0V(1nS=C{|GM8#K`sER-F}miPCw0RBie`$BIqI|f8t@HQ5fwj zxRBP-cb9<)w%C|~Ini|pQD-+kCqd;ZL#{^#IOE}*pzt{LQq}3aS&{jPS2B7hAlSGSZy-*(B>OHoJne7-Vn&R{PCb-wou*Z64NSUpigwQBF--;C zR0e8TmbPFzgoNS02Se|PdRK7lc`;3Usw{PPJam2jegi{Z>eCW(>?-(BtQ@{Q=|zy# z-ZP_%An7g~LODnyT&(0KQ#i^G7zAHcqJdPhmEAV89&wR8j$cVtC%lNCAmIJ;x{)WZ zi;wsB{>llinycm<9A*Lhn1&?NT~0-f)x-D50pVNAmXI~WdB+6K~<#5!I2g57<+D=d}UmyScmA;InT`` z$6Lt?VJ3X0k?D(%A(Lmk@_!Abu~w8OQHGd(zrhcEFaZb@}`$$=P8Yco!D;`Kaby)i15iIH9NoZop3j?B67E%U{2v}KrWZE z0pDQeNLWbG8EgMNerRR(9E&v3J?MX8J+28`p~W|inYHBB^#ln}=u|($HqkfEEdLe*gX&hkTZjm2^97FmZbMzmasUqP(rXsawd?=uNM80B`Mz`8C`~E=U^Yk z$t0NsBQ@g%CMCpWP9RSG2C~R_iT4S}Wd_gNM{hkwE+zPLlp)9-Bh^S2Hqufyq&p*v zVl-haFfzU3P}a-YCkaguhowzo|B3S!E<-SYW$gh*O;NM^U2CMWVeKFzz!a|Y90U5o zJQndZHr=0b1@P+T5aeDuFo!esv@&ebTAN)rN*mUK?sy>zFC0h*A6b}@pX z(m}uFO!S5Cc!A;oc}{7q@1n6V@iCNt#0AVUdv#|o%p2wZL5=Sdwz)zhoU(p07W$S7 zsozQ{01ViA|8;s2kshB=yX4<0${kVJ%mUlth3U|bnVFVIW5x4E$XKK4AviCK&SX)hF&gd7s3FZCW| zDa^_yqT;K^z)LV!C@H=R(SieTB4Tc%w3$4-Uwwv@028r1wSlM!#p+yJ+zhh>r4vjb zBFP*BhYU(%n$5J92;sU=ch>Y+S#0}Bq1G>nn73POFql>>`cOAe!P*9x4>BZ5DaXqr zqBwYEINBUIB|;Ab(YEyXo&6ZI!Kn6BLxt*~4c1swn&m1$O$cf&}#?Ht} z&(y$y&c;~fA1DA|+)0PwjFy$tmRRaftlmOul`2WtfAC^6Q|VoeG}6+>!l&WB

    aP&%S&js%4*AEl1`F0Ww|nQVQN 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 z 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

      qH+f~o$;pW{e9MoD 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

      qGhIl>6Sut+Zra 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≠S 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

      %l{)rihaaG0Z!6$2oVbJWK+oIyd2#Xj++#s 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⪙g8}>o_Eh9(!k5 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

      SwY5tZV^nLW4ARwMF@LjJ5EAq#f9T`%Th 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 JWd7DQ`9Hc?h(rJY diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4eac4a84cc..4f32b203e1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 445395ee3e073d657d92e67c20611c174edc6232 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:29:12 +0100 Subject: [PATCH 720/805] [Java] Upgrade to `Gradle` 9.3.1. --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4f32b203e1..5f38436fc6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 79e460ff56e76d1d0be02a0ce455a7482c97d420 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Wed, 18 Feb 2026 15:02:58 -0600 Subject: [PATCH 721/805] [Rust] updated generator to correctly limit length of var data written (#1096) * [Rust] updated how Cargo.toml package name is cleaned * [Rust] fixed RustGenerator::generateEncoderVarData() to cap slice len to primitive type size * [Rust] updated test imports * [Rust] updated issue1066.xml * [Rust] updated rust tests --------- Co-authored-by: Michael Ward --- build.gradle | 3 +- rust/Cargo.toml | 9 +-- rust/tests/baseline_enum_from_str.rs | 64 +++++++++++++++---- rust/tests/baseline_enum_into.rs | 34 +++++++--- rust/tests/baseline_enum_to_str.rs | 28 ++++++-- rust/tests/baseline_test.rs | 2 +- .../basic_variable_length_schema_test.rs | 43 +++++++++++++ rust/tests/big_endian_test.rs | 6 +- rust/tests/fixed_sized_primitive_array.rs | 12 ++-- rust/tests/issue_1066_test.rs | 2 +- rust/tests/issue_987_test.rs | 7 +- .../sbe/generation/rust/RustGenerator.java | 7 +- .../generation/rust/RustOutputManager.java | 2 +- .../basic-variable-length-schema.xml | 45 +++++++------ sbe-tool/src/test/resources/issue1066.xml | 42 ++++++------ 15 files changed, 219 insertions(+), 87 deletions(-) create mode 100644 rust/tests/basic_variable_length_schema_test.rs diff --git a/build.gradle b/build.gradle index 90102a340e..3d6461d6e7 100644 --- a/build.gradle +++ b/build.gradle @@ -679,8 +679,9 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe-tool/src/test/resources/issue1028.xml', 'sbe-tool/src/test/resources/issue1057.xml', 'sbe-tool/src/test/resources/issue1066.xml', - 'sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml', + 'sbe-tool/src/test/resources/basic-variable-length-schema.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', + 'sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml', 'sbe-tool/src/test/resources/nested-composite-name.xml', ] } diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b48fd6ee55..76119b11b7 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -2,7 +2,7 @@ name = "sbe_rust_example" version = "0.1.0" authors = [] -edition = "2018" +edition = "2021" publish = false [dependencies] @@ -19,12 +19,13 @@ issue_987 = { path = "../generated/rust/issue987" } issue_1028 = { path = "../generated/rust/issue1028" } issue_1057 = { path = "../generated/rust/issue1057" } issue_1066 = { path = "../generated/rust/issue1066" } -baseline_bigendian = { path = "../generated/rust/baseline-bigendian" } -nested_composite_name = { path = "../generated/rust/nested-composite-name" } +baseline_bigendian = { path = "../generated/rust/baseline_bigendian" } +nested_composite_name = { path = "../generated/rust/nested_composite_name" } +sbe_tests = { path = "../generated/rust/sbe_tests" } fixed_sized_primitive_array = { path = "../generated/rust/fixed_sized_primitive_array" } [dev-dependencies] -criterion = "0.5" +criterion = "0.7" [[bench]] name = "car_benchmark" diff --git a/rust/tests/baseline_enum_from_str.rs b/rust/tests/baseline_enum_from_str.rs index a111d28364..26cf7a9102 100644 --- a/rust/tests/baseline_enum_from_str.rs +++ b/rust/tests/baseline_enum_from_str.rs @@ -1,22 +1,60 @@ +use examples_baseline::boost_type::BoostType; use BoostType::{NullVal, KERS, NITROUS, SUPERCHARGER, TURBO}; -use examples_baseline::{ - boost_type::BoostType, -}; #[test] fn test_boost_type_from_str() -> Result<(), ()> { - assert_eq!("TURBO".parse::()?, TURBO, "Parse \"TURBO\" as BoostType"); - assert_eq!("SUPERCHARGER".parse::()?, SUPERCHARGER, "Parse \"SUPERCHARGER\" as BoostType"); - assert_eq!("NITROUS".parse::()?, NITROUS, "Parse \"NITROUS\" as BoostType"); - assert_eq!("KERS".parse::()?, KERS, "Parse \"KERS\" as BoostType"); + assert_eq!( + "TURBO".parse::()?, + TURBO, + "Parse \"TURBO\" as BoostType" + ); + assert_eq!( + "SUPERCHARGER".parse::()?, + SUPERCHARGER, + "Parse \"SUPERCHARGER\" as BoostType" + ); + assert_eq!( + "NITROUS".parse::()?, + NITROUS, + "Parse \"NITROUS\" as BoostType" + ); + assert_eq!( + "KERS".parse::()?, + KERS, + "Parse \"KERS\" as BoostType" + ); - assert_eq!("Turbo".parse::()?, NullVal, "Parse \"Turbo\" as BoostType"); - assert_eq!("Supercharger".parse::()?, NullVal, "Parse \"Supercharger\" as BoostType"); - assert_eq!("Nitrous".parse::()?, NullVal, "Parse \"Nitrous\" as BoostType"); - assert_eq!("Kers".parse::()?, NullVal, "Parse \"Kers\" as BoostType"); + assert_eq!( + "Turbo".parse::()?, + NullVal, + "Parse \"Turbo\" as BoostType" + ); + assert_eq!( + "Supercharger".parse::()?, + NullVal, + "Parse \"Supercharger\" as BoostType" + ); + assert_eq!( + "Nitrous".parse::()?, + NullVal, + "Parse \"Nitrous\" as BoostType" + ); + assert_eq!( + "Kers".parse::()?, + NullVal, + "Parse \"Kers\" as BoostType" + ); - assert_eq!("AA".parse::()?, NullVal, "Parse \"AA\" as BoostType"); - assert_eq!("".parse::().unwrap(), NullVal, "Parse \"\" as BoostType"); + assert_eq!( + "AA".parse::()?, + NullVal, + "Parse \"AA\" as BoostType" + ); + assert_eq!( + "".parse::().unwrap(), + NullVal, + "Parse \"\" as BoostType" + ); Ok(()) } diff --git a/rust/tests/baseline_enum_into.rs b/rust/tests/baseline_enum_into.rs index 9580e51b0d..0af9b0a585 100644 --- a/rust/tests/baseline_enum_into.rs +++ b/rust/tests/baseline_enum_into.rs @@ -1,14 +1,32 @@ -use examples_baseline::{ - boost_type::BoostType, -}; +use examples_baseline::boost_type::BoostType; #[test] fn test_boost_type_from_str() -> Result<(), ()> { - assert_eq!(>::into(BoostType::TURBO), 84_u8, "BoostType::TURBO into value"); - assert_eq!(>::into(BoostType::SUPERCHARGER), 83_u8, "BoostType::SUPERCHARGER into value"); - assert_eq!(>::into(BoostType::NITROUS), 78_u8, "BoostType::NITROUS into value"); - assert_eq!(>::into(BoostType::KERS), 75_u8, "BoostType::KERS into value"); - assert_eq!(>::into(BoostType::NullVal), 0_u8, "BoostType::NullVal into value"); + assert_eq!( + >::into(BoostType::TURBO), + 84_u8, + "BoostType::TURBO into value" + ); + assert_eq!( + >::into(BoostType::SUPERCHARGER), + 83_u8, + "BoostType::SUPERCHARGER into value" + ); + assert_eq!( + >::into(BoostType::NITROUS), + 78_u8, + "BoostType::NITROUS into value" + ); + assert_eq!( + >::into(BoostType::KERS), + 75_u8, + "BoostType::KERS into value" + ); + assert_eq!( + >::into(BoostType::NullVal), + 0_u8, + "BoostType::NullVal into value" + ); Ok(()) } diff --git a/rust/tests/baseline_enum_to_str.rs b/rust/tests/baseline_enum_to_str.rs index 93f5206517..8739d6ec9d 100644 --- a/rust/tests/baseline_enum_to_str.rs +++ b/rust/tests/baseline_enum_to_str.rs @@ -1,14 +1,28 @@ -use examples_baseline::{ - boost_type::BoostType, -}; +use examples_baseline::boost_type::BoostType; #[test] fn test_boost_type_from_str() -> Result<(), ()> { - assert_eq!(format!("{}", BoostType::TURBO), "TURBO", "Display \"TURBO\""); - assert_eq!(format!("{}", BoostType::SUPERCHARGER), "SUPERCHARGER", "Display \"SUPERCHARGER\""); - assert_eq!(format!("{}", BoostType::NITROUS), "NITROUS", "Display \"NITROUS\""); + assert_eq!( + format!("{}", BoostType::TURBO), + "TURBO", + "Display \"TURBO\"" + ); + assert_eq!( + format!("{}", BoostType::SUPERCHARGER), + "SUPERCHARGER", + "Display \"SUPERCHARGER\"" + ); + assert_eq!( + format!("{}", BoostType::NITROUS), + "NITROUS", + "Display \"NITROUS\"" + ); assert_eq!(format!("{}", BoostType::KERS), "KERS", "Display \"KERS\""); - assert_eq!(format!("{}", BoostType::NullVal), "NullVal", "Display \"NullVal\""); + assert_eq!( + format!("{}", BoostType::NullVal), + "NullVal", + "Display \"NullVal\"" + ); Ok(()) } diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index ab711b7c84..49486795a2 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -272,4 +272,4 @@ fn test_issue_1018() { assert_eq!(1, examples_baseline::SBE_SCHEMA_ID); assert_eq!(0, examples_baseline::SBE_SCHEMA_VERSION); assert_eq!("5.2", examples_baseline::SBE_SEMANTIC_VERSION); -} \ No newline at end of file +} diff --git a/rust/tests/basic_variable_length_schema_test.rs b/rust/tests/basic_variable_length_schema_test.rs new file mode 100644 index 0000000000..c8b4eed86f --- /dev/null +++ b/rust/tests/basic_variable_length_schema_test.rs @@ -0,0 +1,43 @@ +use sbe_tests::{ + message_header_codec::MessageHeaderDecoder, + test_message_1_codec::{ + TestMessage1Decoder, SBE_BLOCK_LENGTH, SBE_SCHEMA_ID, SBE_SCHEMA_VERSION, SBE_TEMPLATE_ID, + }, +}; +use sbe_tests::{ + WriteBuf, + {message_header_codec, test_message_1_codec::TestMessage1Encoder, Encoder, ReadBuf}, +}; + +#[test] +fn should_limit_var_data_length() { + // encode... + let mut buffer = vec![0u8; 1024]; + let mut encoder = TestMessage1Encoder::default(); + encoder = encoder.wrap( + WriteBuf::new(buffer.as_mut_slice()), + message_header_codec::ENCODED_LENGTH, + ); + encoder = encoder.header(0).parent().unwrap(); + + let password: String = (0..1024).map(|_| 'x' as char).collect(); + encoder.encrypted_new_password(password.as_bytes()); + assert_eq!(263, encoder.get_limit()); + + // decode... + let buf = ReadBuf::new(buffer.as_slice()); + let header = MessageHeaderDecoder::default().wrap(buf, 0); + assert_eq!(SBE_BLOCK_LENGTH, header.block_length()); + assert_eq!(SBE_SCHEMA_VERSION, header.version()); + assert_eq!(SBE_TEMPLATE_ID, header.template_id()); + assert_eq!(SBE_SCHEMA_ID, header.schema_id()); + + let mut decoder = TestMessage1Decoder::default().header(header, 0); + let coord = decoder.encrypted_new_password_decoder(); + let password = String::from_utf8_lossy(decoder.encrypted_new_password_slice(coord)); + assert_eq!(254, password.len()); + password + .as_bytes() + .iter() + .for_each(|x| assert_eq!(b'x', *x)); +} diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index 1bef7278dd..248a367d52 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -1,10 +1,8 @@ +use baseline_bigendian::car_codec::{CarDecoder, CarEncoder, SBE_TEMPLATE_ID}; use baseline_bigendian::{ boolean_type::BooleanType, boost_type::BoostType, - car_codec::{ - encoder::{AccelerationEncoder, FuelFiguresEncoder, PerformanceFiguresEncoder}, - *, - }, + car_codec::encoder::{AccelerationEncoder, FuelFiguresEncoder, PerformanceFiguresEncoder}, message_header_codec, message_header_codec::MessageHeaderDecoder, model::Model, diff --git a/rust/tests/fixed_sized_primitive_array.rs b/rust/tests/fixed_sized_primitive_array.rs index 8542e3d488..59e6df84d6 100644 --- a/rust/tests/fixed_sized_primitive_array.rs +++ b/rust/tests/fixed_sized_primitive_array.rs @@ -337,28 +337,32 @@ fn test_encode_then_decode_non_u8_signed_primitive_slice() { DemoDecoder::fixed_16_i8, DemoEncoder::fixed_16_i8_end, DemoDecoder::fixed_16_i8_end, - i8, i8::from_le_bytes([uninit]) + i8, + i8::from_le_bytes([uninit]) ); run_encode_then_decode_for_array_of_signed_len_16!( DemoEncoder::fixed_16_i16_from_iter, DemoDecoder::fixed_16_i16, DemoEncoder::fixed_16_i16_end, DemoDecoder::fixed_16_i16_end, - i16, i16::from_le_bytes([uninit, uninit]) + i16, + i16::from_le_bytes([uninit, uninit]) ); run_encode_then_decode_for_array_of_signed_len_16!( DemoEncoder::fixed_16_i32_from_iter, DemoDecoder::fixed_16_i32, DemoEncoder::fixed_16_i32_end, DemoDecoder::fixed_16_i32_end, - i32, i32::from_le_bytes([uninit, uninit, uninit, uninit]) + i32, + i32::from_le_bytes([uninit, uninit, uninit, uninit]) ); run_encode_then_decode_for_array_of_signed_len_16!( DemoEncoder::fixed_16_i64_from_iter, DemoDecoder::fixed_16_i64, DemoEncoder::fixed_16_i64_end, DemoDecoder::fixed_16_i64_end, - i64, i64::from_le_bytes([uninit, uninit, uninit, uninit, uninit, uninit, uninit, uninit]) + i64, + i64::from_le_bytes([uninit, uninit, uninit, uninit, uninit, uninit, uninit, uninit]) ); } diff --git a/rust/tests/issue_1066_test.rs b/rust/tests/issue_1066_test.rs index 43f7278ebf..2c22c0f44b 100644 --- a/rust/tests/issue_1066_test.rs +++ b/rust/tests/issue_1066_test.rs @@ -1,7 +1,7 @@ use issue_1066::{ issue_1066_codec, issue_1066_codec::{Issue1066Decoder, Issue1066Encoder}, - *, + message_header_codec, ReadBuf, WriteBuf, }; #[test] diff --git a/rust/tests/issue_987_test.rs b/rust/tests/issue_987_test.rs index 4462f58b52..bd496ee801 100644 --- a/rust/tests/issue_987_test.rs +++ b/rust/tests/issue_987_test.rs @@ -1,5 +1,10 @@ use issue_987::{ - issue_987_codec::{Issue987Decoder, Issue987Encoder, SBE_BLOCK_LENGTH, SBE_SCHEMA_ID, SBE_SCHEMA_VERSION, SBE_TEMPLATE_ID}, message_header_codec::MessageHeaderDecoder, * + issue_987_codec::{ + Issue987Decoder, Issue987Encoder, SBE_BLOCK_LENGTH, SBE_SCHEMA_ID, SBE_SCHEMA_VERSION, + SBE_TEMPLATE_ID, + }, + message_header_codec::MessageHeaderDecoder, + *, }; fn create_encoder(buffer: &mut Vec, off: usize) -> Issue987Encoder { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 746f18d022..94491b0a15 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -111,7 +111,7 @@ public void generate() throws IOException // create Cargo.toml try (Writer writer = outputManager.createCargoToml()) { - final String packageName = toLowerSnakeCase(ir.packageName()).replaceAll("[.-]", "_"); + final String packageName = toLowerSnakeCase(ir.packageName().replaceAll("[\\s.-]", "_")); final String namespace; if (ir.namespaceName() == null || ir.namespaceName().equalsIgnoreCase(packageName)) { @@ -356,14 +356,15 @@ static void generateEncoderVarData( indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", propertyName, varDataType); indent(sb, level + 1, "let limit = self.get_limit();\n"); - indent(sb, level + 1, "let data_length = value.len();\n"); + indent(sb, level + 1, "let data_length = value.len().min((%s::MAX - 1) as usize);\n", + rustTypeName(lengthType)); indent(sb, level + 1, "self.set_limit(limit + %d + data_length);\n", lengthType.size()); indent(sb, level + 1, "self.get_buf_mut().put_%s_at(limit, data_length as %1$s);\n", rustTypeName(lengthType)); - indent(sb, level + 1, "self.get_buf_mut().put_slice_at(limit + %d, value%s);\n", + indent(sb, level + 1, "self.get_buf_mut().put_slice_at(limit + %d, &value[0..data_length]%s);\n", lengthType.size(), toBytesFn); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java index fe8ca08e63..26ee4ca98f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustOutputManager.java @@ -60,7 +60,7 @@ public RustOutputManager(final String baseDirName, final String packageName) Verify.notNull(packageName, "packageName"); String dirName = baseDirName.endsWith("" + separatorChar) ? baseDirName : baseDirName + separatorChar; - dirName += packageName.replaceAll("\\.", "_").toLowerCase() + separatorChar; + dirName += packageName.replaceAll("[\\s.-]", "_").toLowerCase() + separatorChar; final String libDirName = dirName; rootDir = new File(libDirName); diff --git a/sbe-tool/src/test/resources/basic-variable-length-schema.xml b/sbe-tool/src/test/resources/basic-variable-length-schema.xml index bd5dee2de9..39d681b989 100644 --- a/sbe-tool/src/test/resources/basic-variable-length-schema.xml +++ b/sbe-tool/src/test/resources/basic-variable-length-schema.xml @@ -1,22 +1,25 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/sbe-tool/src/test/resources/issue1066.xml b/sbe-tool/src/test/resources/issue1066.xml index a24e45b030..270926cc70 100644 --- a/sbe-tool/src/test/resources/issue1066.xml +++ b/sbe-tool/src/test/resources/issue1066.xml @@ -1,18 +1,24 @@ - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + \ No newline at end of file From fa33cfc13ddb741a093e0d4bf5bcd4b35620e01f Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Wed, 18 Feb 2026 15:03:20 -0600 Subject: [PATCH 722/805] [Rust] updated some function to "const" (#1098) Co-authored-by: Michael Ward --- .../uk/co/real_logic/sbe/generation/rust/LibRsDef.java | 8 ++++---- .../real_logic/sbe/generation/rust/MessageCoderDef.java | 2 +- .../uk/co/real_logic/sbe/generation/rust/SubGroup.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index f361397916..1de9357f3a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -189,7 +189,7 @@ static void generateReadBuf(final Appendable writer, final ByteOrder byteOrder) indent(writer, 0, "#[allow(dead_code)]\n"); indent(writer, 0, "impl<%s> %s<%s> {\n", BUF_LIFETIME, READ_BUF_TYPE, BUF_LIFETIME); indent(writer, 1, "#[inline]\n"); - indent(writer, 1, "pub fn new(data: &%s [u8]) -> Self {\n", BUF_LIFETIME); + indent(writer, 1, "pub const fn new(data: &%s [u8]) -> Self {\n", BUF_LIFETIME); indent(writer, 2, "Self { data }\n"); indent(writer, 1, "}\n\n"); @@ -205,7 +205,7 @@ static void generateReadBuf(final Appendable writer, final ByteOrder byteOrder) uniquePrimitiveTypes.remove("u8"); indent(writer, 0, "\n"); indent(writer, 1, "#[inline]\n"); - indent(writer, 1, "pub fn get_u8_at(&self, index: usize) -> u8 {\n"); + indent(writer, 1, "pub const fn get_u8_at(&self, index: usize) -> u8 {\n"); indent(writer, 2, "self.data[index]\n"); indent(writer, 1, "}\n"); @@ -238,7 +238,7 @@ static void generateWriteBuf(final Writer writer, final ByteOrder byteOrder) thr indent(writer, 0, "}\n"); indent(writer, 0, "impl<%s> %s<%s> {\n", BUF_LIFETIME, WRITE_BUF_TYPE, BUF_LIFETIME); - indent(writer, 1, "pub fn new(data: &%s mut [u8]) -> Self {\n", BUF_LIFETIME); + indent(writer, 1, "pub const fn new(data: &%s mut [u8]) -> Self {\n", BUF_LIFETIME); indent(writer, 2, "Self { data }\n"); indent(writer, 1, "}\n\n"); @@ -255,7 +255,7 @@ static void generateWriteBuf(final Writer writer, final ByteOrder byteOrder) thr uniquePrimitiveTypes.remove("u8"); indent(writer, 1, "#[inline]\n"); - indent(writer, 1, "pub fn put_u8_at(&mut self, index: usize, value: u8) {\n"); + indent(writer, 1, "pub const fn put_u8_at(&mut self, index: usize, value: u8) {\n"); indent(writer, 2, "self.data[index] = value;\n"); indent(writer, 1, "}\n\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index e4e19f4c52..1979de7b86 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -83,7 +83,7 @@ void generate( appendWrapFn(sb); indent(sb, 2, "#[inline]\n"); - indent(sb, 2, "pub fn encoded_length(&self) -> usize {\n"); + indent(sb, 2, "pub const fn encoded_length(&self) -> usize {\n"); indent(sb, 3, "self.limit - self.offset\n"); indent(sb, 2, "}\n\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 5c1981a874..e96c11c20a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -103,7 +103,7 @@ void generateEncoder( // block_length function indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn block_length() -> %s {\n", rustTypeName(blockLengthPrimitiveType)); + indent(sb, level, "pub const fn block_length() -> %s {\n", rustTypeName(blockLengthPrimitiveType)); indent(sb, level + 1, "%d\n", this.groupToken.encodedLength()); indent(sb, level, "}\n\n"); From 8327dcdf49c3c131094630acafb2ca50dd60c081 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Wed, 18 Feb 2026 15:09:18 -0600 Subject: [PATCH 723/805] [Rust] generated encoders now produce fluent interface (#1097) Co-authored-by: Michael Ward Co-authored-by: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> --- rust/tests/baseline_test.rs | 83 +++++++++---------- rust/tests/big_endian_test.rs | 72 ++++++++-------- rust/tests/extension_test.rs | 80 +++++++++--------- .../sbe/generation/rust/RustGenerator.java | 24 ++++-- 4 files changed, 131 insertions(+), 128 deletions(-) diff --git a/rust/tests/baseline_test.rs b/rust/tests/baseline_test.rs index 49486795a2..5ec352b7d0 100644 --- a/rust/tests/baseline_test.rs +++ b/rust/tests/baseline_test.rs @@ -181,24 +181,26 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { ); car = car.header(0).parent()?; - car.serial_number(1234); - car.model_year(2013); - car.available(BooleanType::T); - car.code(Model::A); - car.some_numbers(&[1, 2, 3, 4]); - car.vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef - - extras.set_cruise_control(true); - extras.set_sports_pack(true); - extras.set_sun_roof(false); + car.serial_number(1234) + .model_year(2013) + .available(BooleanType::T) + .code(Model::A) + .some_numbers(&[1, 2, 3, 4]) + .vehicle_code(&[97, 98, 99, 100, 101, 102]); // abcdef + + extras + .set_cruise_control(true) + .set_sports_pack(true) + .set_sun_roof(false); car.extras(extras); let mut engine = car.engine_encoder(); - engine.capacity(2000); - engine.num_cylinders(4); - engine.manufacturer_code(&[49, 50, 51]); // 123 - engine.efficiency(35); - engine.booster_enabled(BooleanType::T); + engine + .capacity(2000) + .num_cylinders(4) + .manufacturer_code(&[49, 50, 51]) // 123 + .efficiency(35) + .booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); booster.boost_type(BoostType::NITROUS); booster.horse_power(200); @@ -207,19 +209,22 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car = engine.parent()?; fuel_figures = car.fuel_figures_encoder(3, fuel_figures); assert_eq!(Some(0), fuel_figures.advance()?); - fuel_figures.speed(30); - fuel_figures.mpg(35.9); - fuel_figures.usage_description(b"Urban Cycle"); + fuel_figures + .speed(30) + .mpg(35.9) + .usage_description(b"Urban Cycle"); assert_eq!(Some(1), fuel_figures.advance()?); - fuel_figures.speed(55); - fuel_figures.mpg(49.0); - fuel_figures.usage_description(b"Combined Cycle"); + fuel_figures + .speed(55) + .mpg(49.0) + .usage_description(b"Combined Cycle"); assert_eq!(Some(2), fuel_figures.advance()?); - fuel_figures.speed(75); - fuel_figures.mpg(40.0); - fuel_figures.usage_description(b"Highway Cycle"); + fuel_figures + .speed(75) + .mpg(40.0) + .usage_description(b"Highway Cycle"); car = fuel_figures.parent()?; performance_figures = car.performance_figures_encoder(2, performance_figures); @@ -228,16 +233,13 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(4.0); + acceleration.mph(30).seconds(4.0); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.5); + acceleration.mph(60).seconds(7.5); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(12.2); + acceleration.mph(100).seconds(12.2); performance_figures = acceleration.parent()?; assert_eq!(Some(1), performance_figures.advance()?); @@ -245,23 +247,20 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(3.8); + acceleration.mph(30).seconds(3.8); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.1); + acceleration.mph(60).seconds(7.1); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(11.8); + acceleration.mph(100).seconds(11.8); performance_figures = acceleration.parent()?; car = performance_figures.parent()?; - car.manufacturer("Honda"); - car.model("Civic VTi"); - car.activation_code(b"abcdef"); + car.manufacturer("Honda") + .model("Civic VTi") + .activation_code(b"abcdef"); let limit = car.get_limit(); Ok((limit, buffer)) @@ -269,7 +268,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { #[test] fn test_issue_1018() { - assert_eq!(1, examples_baseline::SBE_SCHEMA_ID); - assert_eq!(0, examples_baseline::SBE_SCHEMA_VERSION); - assert_eq!("5.2", examples_baseline::SBE_SEMANTIC_VERSION); + assert_eq!(1, SBE_SCHEMA_ID); + assert_eq!(0, SBE_SCHEMA_VERSION); + assert_eq!("5.2", SBE_SEMANTIC_VERSION); } diff --git a/rust/tests/big_endian_test.rs b/rust/tests/big_endian_test.rs index 248a367d52..a759ff7443 100644 --- a/rust/tests/big_endian_test.rs +++ b/rust/tests/big_endian_test.rs @@ -175,12 +175,12 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { ); car = car.header(0).parent()?; - car.serial_number(1234); - car.model_year(2013); - car.available(BooleanType::T); - car.code(Model::A); - car.some_numbers(&[0, 1, 2, 3, 4]); - car.vehicle_code(b"abcdef"); + car.serial_number(1234) + .model_year(2013) + .available(BooleanType::T) + .code(Model::A) + .some_numbers(&[0, 1, 2, 3, 4]) + .vehicle_code(b"abcdef"); extras.set_cruise_control(true); extras.set_sports_pack(true); @@ -188,32 +188,36 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { car.extras(extras); let mut engine = car.engine_encoder(); - engine.capacity(2000); - engine.num_cylinders(4); - engine.manufacturer_code(b"123"); - engine.efficiency(35); - engine.booster_enabled(BooleanType::T); + engine + .capacity(2000) + .num_cylinders(4) + .manufacturer_code(b"123") + .efficiency(35) + .booster_enabled(BooleanType::T); + let mut booster = engine.booster_encoder(); - booster.boost_type(BoostType::NITROUS); - booster.horse_power(200); + booster.boost_type(BoostType::NITROUS).horse_power(200); engine = booster.parent()?; car = engine.parent()?; fuel_figures = car.fuel_figures_encoder(3, fuel_figures); assert_eq!(Some(0), fuel_figures.advance()?); - fuel_figures.speed(30); - fuel_figures.mpg(35.9); - fuel_figures.usage_description("Urban Cycle"); + fuel_figures + .speed(30) + .mpg(35.9) + .usage_description("Urban Cycle"); assert_eq!(Some(1), fuel_figures.advance()?); - fuel_figures.speed(55); - fuel_figures.mpg(49.0); - fuel_figures.usage_description("Combined Cycle"); + fuel_figures + .speed(55) + .mpg(49.0) + .usage_description("Combined Cycle"); assert_eq!(Some(2), fuel_figures.advance()?); - fuel_figures.speed(75); - fuel_figures.mpg(40.0); - fuel_figures.usage_description("Highway Cycle"); + fuel_figures + .speed(75) + .mpg(40.0) + .usage_description("Highway Cycle"); car = fuel_figures.parent()?; performance_figures = car.performance_figures_encoder(2, performance_figures); @@ -222,16 +226,13 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(4.0); + acceleration.mph(30).seconds(4.0); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.5); + acceleration.mph(60).seconds(7.5); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(12.2); + acceleration.mph(100).seconds(12.2); performance_figures = acceleration.parent()?; assert_eq!(Some(1), performance_figures.advance()?); @@ -239,23 +240,20 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(3.8); + acceleration.mph(30).seconds(3.8); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.1); + acceleration.mph(60).seconds(7.1); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(11.8); + acceleration.mph(100).seconds(11.8); performance_figures = acceleration.parent()?; car = performance_figures.parent()?; - car.manufacturer("Honda"); - car.model("Civic VTi"); - car.activation_code("abcdef"); + car.manufacturer("Honda") + .model("Civic VTi") + .activation_code("abcdef"); let limit = car.get_limit(); Ok((limit, buffer)) diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index ab62a7715c..665d8f92b4 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -182,45 +182,49 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { ); car = car.header(0).parent()?; - car.serial_number(1234); - car.model_year(2013); - car.available(BooleanType::T); - car.code(Model::A); - car.some_numbers(&[0, 1, 2, 3]); - car.vehicle_code_from_iter(b"abcdef_extra_is_ignored".into_iter().copied()); // abcdef - - extras.set_cruise_control(true); - extras.set_sports_pack(true); - extras.set_sun_roof(false); + car.serial_number(1234) + .model_year(2013) + .available(BooleanType::T) + .code(Model::A) + .some_numbers(&[0, 1, 2, 3]) + .vehicle_code_from_iter(b"abcdef_extra_is_ignored".into_iter().copied()); // abcdef + + extras + .set_cruise_control(true) + .set_sports_pack(true) + .set_sun_roof(false); car.extras(extras); let mut engine = car.engine_encoder(); - engine.capacity(2000); - engine.num_cylinders(4); - engine.manufacturer_code(b"123"); - engine.efficiency(35); - engine.booster_enabled(BooleanType::T); + engine + .capacity(2000) + .num_cylinders(4) + .manufacturer_code(b"123") + .efficiency(35) + .booster_enabled(BooleanType::T); let mut booster = engine.booster_encoder(); - booster.boost_type(BoostType::NITROUS); - booster.horse_power(200); + booster.boost_type(BoostType::NITROUS).horse_power(200); engine = booster.parent()?; car = engine.parent()?; fuel_figures = car.fuel_figures_encoder(3, fuel_figures); assert_eq!(Some(0), fuel_figures.advance()?); - fuel_figures.speed(30); - fuel_figures.mpg(35.9); - fuel_figures.usage_description(b"Urban Cycle"); + fuel_figures + .speed(30) + .mpg(35.9) + .usage_description(b"Urban Cycle"); assert_eq!(Some(1), fuel_figures.advance()?); - fuel_figures.speed(55); - fuel_figures.mpg(49.0); - fuel_figures.usage_description(b"Combined Cycle"); + fuel_figures + .speed(55) + .mpg(49.0) + .usage_description(b"Combined Cycle"); assert_eq!(Some(2), fuel_figures.advance()?); - fuel_figures.speed(75); - fuel_figures.mpg(40.0); - fuel_figures.usage_description(b"Highway Cycle"); + fuel_figures + .speed(75) + .mpg(40.0) + .usage_description(b"Highway Cycle"); car = fuel_figures.parent()?; performance_figures = car.performance_figures_encoder(2, performance_figures); @@ -229,16 +233,13 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(4.0); + acceleration.mph(30).seconds(4.0); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.5); + acceleration.mph(60).seconds(7.5); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(12.2); + acceleration.mph(100).seconds(12.2); performance_figures = acceleration.parent()?; assert_eq!(Some(1), performance_figures.advance()?); @@ -246,23 +247,20 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { acceleration = performance_figures.acceleration_encoder(3, acceleration); assert_eq!(Some(0), acceleration.advance()?); - acceleration.mph(30); - acceleration.seconds(3.8); + acceleration.mph(30).seconds(3.8); assert_eq!(Some(1), acceleration.advance()?); - acceleration.mph(60); - acceleration.seconds(7.1); + acceleration.mph(60).seconds(7.1); assert_eq!(Some(2), acceleration.advance()?); - acceleration.mph(100); - acceleration.seconds(11.8); + acceleration.mph(100).seconds(11.8); performance_figures = acceleration.parent()?; car = performance_figures.parent()?; - car.manufacturer("Honda"); - car.model("Civic VTi"); - car.activation_code(b"abcdef"); + car.manufacturer("Honda") + .model("Civic VTi") + .activation_code(b"abcdef"); let limit = car.get_limit(); Ok((limit, buffer)) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 94491b0a15..683d81da44 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -353,7 +353,7 @@ static void generateEncoderVarData( // function to write slice ... todo - handle character encoding ? indent(sb, level, "/// VAR_DATA ENCODER - character encoding: '%s'\n", characterEncoding); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", propertyName, varDataType); + indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\n", propertyName, varDataType); indent(sb, level + 1, "let limit = self.get_limit();\n"); indent(sb, level + 1, "let data_length = value.len().min((%s::MAX - 1) as usize);\n", @@ -368,6 +368,7 @@ static void generateEncoderVarData( lengthType.size(), toBytesFn); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); i += varDataToken.componentTokenCount(); @@ -409,7 +410,7 @@ private static void generatePrimitiveArrayFromIterEncoder( indent(sb, level, "/// primitive array field '%s' from an Iterator\n", name); generateRustDoc(sb, level, typeToken, encoding); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s_from_iter(&mut self, iter: impl Iterator) {\n", + indent(sb, level, "pub fn %s_from_iter(&mut self, iter: impl Iterator) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); @@ -426,6 +427,7 @@ private static void generatePrimitiveArrayFromIterEncoder( rustPrimitiveType, primitiveType.size()); } indent(sb, level + 1, "}\n"); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -443,13 +445,14 @@ private static void generatePrimitiveArrayZeroPaddedEncoder( indent(sb, level, "/// primitive array field '%s' with zero padding\n", name); generateRustDoc(sb, level, typeToken, encoding); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s_zero_padded(&mut self, value: &[%s]) {\n", + indent(sb, level, "pub fn %s_zero_padded(&mut self, value: &[%s]) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); indent(sb, level + 1, "let iter = value.iter().copied().chain(std::iter::repeat(0_%s)).take(%d);\n", rustPrimitiveType, arrayLength); indent(sb, level + 1, "self.%s_from_iter(iter);\n", formatFunctionName(name)); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -465,7 +468,7 @@ private static void generatePrimitiveArrayEncoder( final int arrayLength = typeToken.arrayLength(); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s_at(&mut self, index: usize, value: %s) {\n", + indent(sb, level, "pub fn %s_at(&mut self, index: usize, value: %s) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); indent(sb, level + 1, "let buf = self.get_buf_mut();\n"); @@ -479,12 +482,13 @@ private static void generatePrimitiveArrayEncoder( indent(sb, level + 1, "buf.put_%s_at(offset + index * %d, value);\n", rustPrimitiveType, primitiveType.size()); } + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); indent(sb, level, "/// primitive array field '%s'\n", name); generateRustDoc(sb, level, typeToken, encoding); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: &[%s]) {\n", + indent(sb, level, "pub fn %s(&mut self, value: &[%s]) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); // NB: must create variable 'offset' before calling mutable self.get_buf_mut() @@ -495,6 +499,7 @@ private static void generatePrimitiveArrayEncoder( if (rustPrimitiveType.equals("u8")) { indent(sb, level + 1, "buf.put_slice_at(offset, value);\n"); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } else @@ -514,6 +519,7 @@ private static void generatePrimitiveArrayEncoder( } } + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -547,12 +553,13 @@ private static void generatePrimitiveEncoder( indent(sb, level, "/// primitive field '%s'\n", name); generateRustDoc(sb, level, typeToken, encoding); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", + indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); // NB: must create variable 'offset' before calling mutable self.get_buf_mut() indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); indent(sb, level + 1, "self.get_buf_mut().put_%s_at(offset, value);\n", rustPrimitiveType); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -579,11 +586,12 @@ private static void generateEnumEncoder( indent(sb, level, "/// REQUIRED enum\n"); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", formatFunctionName(name), enumType); + indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\n", formatFunctionName(name), enumType); // NB: must create variable 'offset' before calling mutable self.get_buf_mut() indent(sb, level + 1, "let offset = self.%s;\n", getBufOffset(typeToken)); - indent(sb, level + 1, "self.get_buf_mut().put_%s_at(offset, value as %1$s)\n", rustPrimitiveType); + indent(sb, level + 1, "self.get_buf_mut().put_%s_at(offset, value as %1$s);\n", rustPrimitiveType); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } } From f3b0e79c0a7e4d49e20779823b78ebf9dd876935 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 18 Feb 2026 22:23:57 +0100 Subject: [PATCH 724/805] [Doc] Update release notes. --- CHANGELOG.adoc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 897cda1814..5ae8575833 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,11 @@ = Changelog +== 1.38.0 (unreleased) + +* **[Rust]** Generated encoders now produce fluent interface. (https://github.com/aeron-io/simple-binary-encoding/pull/1097[#1097]) +* **[Rust]** Updated some function to `const`. (https://github.com/aeron-io/simple-binary-encoding/pull/1098[#1098]) +* **[Rust]** Updated generator to correctly limit length of var data written. (https://github.com/aeron-io/simple-binary-encoding/pull/1096[#1096]) + == 1.37.1 (2026-01-13) * **[Java]** Ensure Java code generation for precedence checks always produces the same code without re-orderings. * **[Java]** Upgrade to `Shadow` 9.3.1. From 239829837522a578f918d68d5a5302b188a95a22 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:08:00 +0100 Subject: [PATCH 725/805] [Java] Upgrade to `JUnit` 6.0.3. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5fc18e4e6..4d776a4008 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" json = "20251224" -junit = "6.0.2" +junit = "6.0.3" mockito = "5.21.0" plexus = "3.3.0" shadow = "9.3.1" From 61d6409c2bf3691d9c21b26cba9852586f503e95 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:08:15 +0100 Subject: [PATCH 726/805] [Java] Upgrade to `Checkstyle` 12.3.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4d776a4008..33f839c213 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.4.0" -checkstyle = "12.3.0" +checkstyle = "12.3.1" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 4eaf7f29660835819dd7936cf6286ab50ab3d786 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 2 Mar 2026 11:32:26 +0100 Subject: [PATCH 727/805] [Java] Upgrade to `Mockito` 5.22.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 33f839c213..b14b840259 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ jqwik = "1.9.3" jmh = "1.37" json = "20251224" junit = "6.0.3" -mockito = "5.21.0" +mockito = "5.22.0" plexus = "3.3.0" shadow = "9.3.1" versions = "0.53.0" From b5d28bade3e17bd01f1baa23b265b7bf023b6371 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 2 Mar 2026 12:19:33 +0100 Subject: [PATCH 728/805] [Java] Upgrade to `Shadow` 9.3.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b14b840259..bbe626a7ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20251224" junit = "6.0.3" mockito = "5.22.0" plexus = "3.3.0" -shadow = "9.3.1" +shadow = "9.3.2" versions = "0.53.0" [libraries] From 712779a05b6ea7d2a35d7dc648a933c133747879 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 5 Mar 2026 14:26:26 +0100 Subject: [PATCH 729/805] [Java] Upgrade to `Gradle` 9.4.0. --- gradle/wrapper/gradle-wrapper.jar | Bin 46175 -> 48966 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 61285a659d17295f1de7c53e24fdf13ad755c379..d997cfc60f4cff0e7451d19d49a82fa986695d07 100644 GIT binary patch delta 39855 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

      SdO`o?U^bCPz6Ehh!k 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


      Xdyd*p!l1Y@nCA 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5f38436fc6..5be30bbeb2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index adff685a03..0262dcbd52 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. From ff34cee9d6a1a110aa0283a555a0985535fbe8cd Mon Sep 17 00:00:00 2001 From: Leonardo Arcari Date: Thu, 12 Feb 2026 14:54:33 +0100 Subject: [PATCH 730/805] fix: clippy warnings --- rust/tests/extension_test.rs | 2 +- rust/tests/fixed_sized_primitive_array.rs | 2 +- rust/tests/issue_1066_test.rs | 19 +++++++++---------- rust/tests/issue_435_test.rs | 2 +- rust/tests/issue_895_test.rs | 2 +- rust/tests/issue_972_test.rs | 2 +- rust/tests/issue_984_test.rs | 2 +- rust/tests/issue_987_test.rs | 2 +- 8 files changed, 16 insertions(+), 17 deletions(-) diff --git a/rust/tests/extension_test.rs b/rust/tests/extension_test.rs index 665d8f92b4..984eeb61d8 100644 --- a/rust/tests/extension_test.rs +++ b/rust/tests/extension_test.rs @@ -187,7 +187,7 @@ fn encode_car_from_scratch() -> SbeResult<(usize, Vec)> { .available(BooleanType::T) .code(Model::A) .some_numbers(&[0, 1, 2, 3]) - .vehicle_code_from_iter(b"abcdef_extra_is_ignored".into_iter().copied()); // abcdef + .vehicle_code_from_iter(b"abcdef_extra_is_ignored".iter().copied()); // abcdef extras .set_cruise_control(true) diff --git a/rust/tests/fixed_sized_primitive_array.rs b/rust/tests/fixed_sized_primitive_array.rs index 59e6df84d6..a071e537b3 100644 --- a/rust/tests/fixed_sized_primitive_array.rs +++ b/rust/tests/fixed_sized_primitive_array.rs @@ -4,7 +4,7 @@ use fixed_sized_primitive_array::{ ReadBuf, WriteBuf, }; -fn create_encoder(buffer: &mut [u8]) -> DemoEncoder { +fn create_encoder(buffer: &mut [u8]) -> DemoEncoder<'_> { let encoder = DemoEncoder::default().wrap(WriteBuf::new(buffer), ENCODED_LENGTH); let mut header = encoder.header(0); header.parent().unwrap() diff --git a/rust/tests/issue_1066_test.rs b/rust/tests/issue_1066_test.rs index 2c22c0f44b..95ba97cc1f 100644 --- a/rust/tests/issue_1066_test.rs +++ b/rust/tests/issue_1066_test.rs @@ -9,19 +9,18 @@ fn decode_optional_primitive_field() { let mut buffer = vec![0u8; 256]; // Create a message with `field` set. - let mut encoder = Issue1066Encoder::default().wrap( - WriteBuf::new(&mut buffer), - message_header_codec::ENCODED_LENGTH, - ); - encoder.field(10); - - // Drop encoder to drop the mut reference for the buffer. - drop(encoder); + { + let mut encoder = Issue1066Encoder::default().wrap( + WriteBuf::new(&mut buffer), + message_header_codec::ENCODED_LENGTH, + ); + encoder.field(10); + } // Create a decoder for the message, but stating that the version is 1, instead of 2 // which is the acting version for `field`. Thus, `field()` must return `None`. let decoder = Issue1066Decoder::default().wrap( - ReadBuf::new(&mut buffer), + ReadBuf::new(&buffer), message_header_codec::ENCODED_LENGTH, issue_1066_codec::SBE_BLOCK_LENGTH, 1, @@ -31,7 +30,7 @@ fn decode_optional_primitive_field() { // Create a decoder for the message, but stating that the version is 1, instead of 2 // which is the acting version for `field`. Thus, `field()` must return `None`. let decoder = Issue1066Decoder::default().wrap( - ReadBuf::new(&mut buffer), + ReadBuf::new(&buffer), message_header_codec::ENCODED_LENGTH, issue_1066_codec::SBE_BLOCK_LENGTH, 2, diff --git a/rust/tests/issue_435_test.rs b/rust/tests/issue_435_test.rs index 7b1a9f8ffe..80ca723642 100644 --- a/rust/tests/issue_435_test.rs +++ b/rust/tests/issue_435_test.rs @@ -3,7 +3,7 @@ use issue_435::{ set_ref::SetRef, *, }; -fn create_encoder(buffer: &mut Vec) -> Issue435Encoder { +fn create_encoder(buffer: &mut Vec) -> Issue435Encoder<'_> { let issue_435 = Issue435Encoder::default().wrap( WriteBuf::new(buffer.as_mut_slice()), message_header_codec::ENCODED_LENGTH, diff --git a/rust/tests/issue_895_test.rs b/rust/tests/issue_895_test.rs index cb58e82d85..35db43541c 100644 --- a/rust/tests/issue_895_test.rs +++ b/rust/tests/issue_895_test.rs @@ -1,6 +1,6 @@ use issue_895::{issue_895_codec::*, message_header_codec::*, *}; -fn create_encoder(buffer: &mut Vec) -> Issue895Encoder { +fn create_encoder(buffer: &mut Vec) -> Issue895Encoder<'_> { let issue_895 = Issue895Encoder::default().wrap(WriteBuf::new(buffer.as_mut_slice()), ENCODED_LENGTH); let mut header = issue_895.header(0); diff --git a/rust/tests/issue_972_test.rs b/rust/tests/issue_972_test.rs index bcf4cd77e8..c90fd452df 100644 --- a/rust/tests/issue_972_test.rs +++ b/rust/tests/issue_972_test.rs @@ -1,6 +1,6 @@ use issue_972::{issue_972_codec::*, message_header_codec::MessageHeaderDecoder, *}; -fn create_encoder(buffer: &mut Vec) -> Issue972Encoder { +fn create_encoder(buffer: &mut Vec) -> Issue972Encoder<'_> { let issue_972 = Issue972Encoder::default().wrap( WriteBuf::new(buffer.as_mut_slice()), message_header_codec::ENCODED_LENGTH, diff --git a/rust/tests/issue_984_test.rs b/rust/tests/issue_984_test.rs index 74cae2eb07..a378d39105 100644 --- a/rust/tests/issue_984_test.rs +++ b/rust/tests/issue_984_test.rs @@ -4,7 +4,7 @@ use issue_984::{ *, }; -fn create_encoder(buffer: &mut Vec) -> SimpleMessageEncoder { +fn create_encoder(buffer: &mut Vec) -> SimpleMessageEncoder<'_> { let simple_msg = SimpleMessageEncoder::default().wrap( WriteBuf::new(buffer.as_mut_slice()), message_header_codec::ENCODED_LENGTH, diff --git a/rust/tests/issue_987_test.rs b/rust/tests/issue_987_test.rs index bd496ee801..bca123f2ba 100644 --- a/rust/tests/issue_987_test.rs +++ b/rust/tests/issue_987_test.rs @@ -7,7 +7,7 @@ use issue_987::{ *, }; -fn create_encoder(buffer: &mut Vec, off: usize) -> Issue987Encoder { +fn create_encoder(buffer: &mut Vec, off: usize) -> Issue987Encoder<'_> { let encoder = Issue987Encoder::default().wrap( WriteBuf::new(buffer.as_mut_slice()), off + message_header_codec::ENCODED_LENGTH, From 271699bed8cdd2620cbca3404cdad4ab881ef293 Mon Sep 17 00:00:00 2001 From: Leonardo Arcari Date: Thu, 12 Feb 2026 14:57:29 +0100 Subject: [PATCH 731/805] feat(rust): generate setters for optional primitive fields --- rust/tests/optional_field_nullify_test.rs | 354 ++++++++++++++++++ .../sbe/generation/rust/MessageCoderDef.java | 3 +- .../sbe/generation/rust/RustGenerator.java | 80 +++- .../sbe/generation/rust/SubGroup.java | 3 +- 4 files changed, 437 insertions(+), 3 deletions(-) create mode 100644 rust/tests/optional_field_nullify_test.rs diff --git a/rust/tests/optional_field_nullify_test.rs b/rust/tests/optional_field_nullify_test.rs new file mode 100644 index 0000000000..188eca4cb6 --- /dev/null +++ b/rust/tests/optional_field_nullify_test.rs @@ -0,0 +1,354 @@ +use examples_extension as ext; +use examples_uk_co_real_logic_sbe_benchmarks_fix as mqfix; +use issue_895 as i895; +use issue_972 as i972; + +use ext::{ + boolean_type::BooleanType as ExtBooleanType, + boost_type::BoostType as ExtBoostType, + car_codec::{ + encoder::FuelFiguresEncoder as ExtFuelFiguresEncoder, CarDecoder as ExtCarDecoder, + CarEncoder as ExtCarEncoder, + }, + message_header_codec::{self as ext_header, MessageHeaderDecoder as ExtHeaderDecoder}, + model::Model as ExtModel, + optional_extras::OptionalExtras as ExtOptionalExtras, + ReadBuf as ExtReadBuf, + SbeResult as ExtSbeResult, + WriteBuf as ExtWriteBuf, +}; +use i895::{ + issue_895_codec::{Issue895Decoder, Issue895Encoder}, + message_header_codec::{self as i895_header, MessageHeaderDecoder as I895HeaderDecoder}, + ReadBuf as I895ReadBuf, WriteBuf as I895WriteBuf, +}; +use i972::{ + issue_972_codec::{Issue972Decoder, Issue972Encoder}, + message_header_codec::{self as i972_header, MessageHeaderDecoder as I972HeaderDecoder}, + Either as I972Either, ReadBuf as I972ReadBuf, WriteBuf as I972WriteBuf, +}; +use mqfix::{ + mass_quote_codec::{ + encoder::{QuoteEntriesEncoder, QuoteSetsEncoder}, + MassQuoteDecoder, MassQuoteEncoder, + }, + message_header_codec::{self as mqfix_header, MessageHeaderDecoder as MassQuoteHeaderDecoder}, + ReadBuf as MassQuoteReadBuf, WriteBuf as MassQuoteWriteBuf, +}; + +type TestResult = Result<(), Box>; + +macro_rules! create_encoder_with_header_parent { + ($buffer:expr, $encoder_ty:ty, $write_buf_ty:ty, $encoded_len:expr) => {{ + let encoder = <$encoder_ty>::default().wrap( + <$write_buf_ty>::new($buffer.as_mut_slice()), + $encoded_len, + ); + let mut header = encoder.header(0); + header.parent().unwrap() + }}; +} + +fn create_issue_895_encoder(buffer: &mut Vec) -> Issue895Encoder<'_> { + create_encoder_with_header_parent!( + buffer, + Issue895Encoder<'_>, + I895WriteBuf<'_>, + i895_header::ENCODED_LENGTH + ) +} + +fn create_issue_972_encoder(buffer: &mut Vec) -> Issue972Encoder<'_> { + create_encoder_with_header_parent!( + buffer, + Issue972Encoder<'_>, + I972WriteBuf<'_>, + i972_header::ENCODED_LENGTH + ) +} + +fn create_mass_quote_encoder(buffer: &mut Vec) -> MassQuoteEncoder<'_> { + create_encoder_with_header_parent!( + buffer, + MassQuoteEncoder<'_>, + MassQuoteWriteBuf<'_>, + mqfix_header::ENCODED_LENGTH + ) +} + +fn decode_issue_895(buffer: &[u8]) -> Issue895Decoder<'_> { + let buf = I895ReadBuf::new(buffer); + let header = I895HeaderDecoder::default().wrap(buf, 0); + Issue895Decoder::default().header(header, 0) +} + +fn decode_issue_972(buffer: &[u8]) -> Issue972Decoder<'_> { + let buf = I972ReadBuf::new(buffer); + let header = I972HeaderDecoder::default().wrap(buf, 0); + Issue972Decoder::default().header(header, 0) +} + +fn encode_extension_car_for_optional_field_test( + cup_holder_count: Option, + nullify: bool, +) -> ExtSbeResult> { + let mut buffer = vec![0u8; 256]; + let mut car = ExtCarEncoder::default(); + let mut extras = ExtOptionalExtras::default(); + + car = car.wrap( + ExtWriteBuf::new(buffer.as_mut_slice()), + ext_header::ENCODED_LENGTH, + ); + car = car.header(0).parent()?; + + car.cup_holder_count_opt(cup_holder_count); + if nullify { + // When enabled, tests expect optional message fields to be encoded as "absent". + car.nullify_optional_fields(); + } + car.serial_number(1234); + car.model_year(2013); + car.available(ExtBooleanType::T); + car.code(ExtModel::A); + car.some_numbers(&[0, 1, 2, 3]); + car.vehicle_code(b"abcdef"); + + extras.set_cruise_control(true); + extras.set_sports_pack(true); + extras.set_sun_roof(false); + car.extras(extras); + + let mut engine = car.engine_encoder(); + engine.capacity(2000); + engine.num_cylinders(4); + engine.manufacturer_code(b"123"); + engine.efficiency(35); + engine.booster_enabled(ExtBooleanType::T); + let mut booster = engine.booster_encoder(); + booster.boost_type(ExtBoostType::NITROUS); + booster.horse_power(200); + engine = booster.parent()?; + let _car = engine.parent()?; + + Ok(buffer) +} + +macro_rules! with_decoded_extension_car { + ($buffer:expr, $car:ident, $body:block) => {{ + let buf = ExtReadBuf::new($buffer); + let header = ExtHeaderDecoder::default().wrap(buf, 0); + let $car = ExtCarDecoder::default().header(header, 0); + $body + }}; +} + +#[test] +fn extension_encoder_cup_holder_count_opt_sets_some_and_none() -> TestResult { + let buffer = encode_extension_car_for_optional_field_test(Some(7), false)?; + with_decoded_extension_car!(buffer.as_slice(), car, { + assert_eq!(Some(7), car.cup_holder_count()); + }); + + let buffer = encode_extension_car_for_optional_field_test(None, false)?; + with_decoded_extension_car!(buffer.as_slice(), car, { + assert_eq!(None, car.cup_holder_count()); + }); + + Ok(()) +} + +#[test] +fn extension_encoder_nullify_optional_fields_sets_cup_holder_count_to_none() -> TestResult { + // Control: without nullify, the explicit optional value should remain present. + let buffer = encode_extension_car_for_optional_field_test(Some(7), false)?; + with_decoded_extension_car!(buffer.as_slice(), car, { + assert_eq!(Some(7), car.cup_holder_count()); + }); + + // Contract under test: nullify marks optional fields as absent in the encoded payload. + let buffer = encode_extension_car_for_optional_field_test(Some(7), true)?; + with_decoded_extension_car!(buffer.as_slice(), car, { + assert_eq!(None, car.cup_holder_count()); + }); + + Ok(()) +} + +#[test] +fn nullify_on_composite_and_group_without_optional_fields_has_no_effect() -> TestResult { + let mut buffer = vec![0u8; 256]; + let mut car = ExtCarEncoder::default(); + let mut fuel_figures = ExtFuelFiguresEncoder::default(); + let mut extras = ExtOptionalExtras::default(); + + car = car.wrap( + ExtWriteBuf::new(buffer.as_mut_slice()), + ext_header::ENCODED_LENGTH, + ); + car = car.header(0).parent()?; + + car.serial_number(1234); + car.model_year(2013); + car.available(ExtBooleanType::T); + car.code(ExtModel::A); + car.some_numbers(&[0, 1, 2, 3]); + car.vehicle_code(b"abcdef"); + + extras.set_cruise_control(true); + extras.set_sports_pack(true); + extras.set_sun_roof(false); + car.extras(extras); + + let mut engine = car.engine_encoder(); + engine.capacity(2000); + engine.num_cylinders(4); + engine.manufacturer_code(b"123"); + engine.efficiency(35); + engine.booster_enabled(ExtBooleanType::T); + // Engine has no optional primitive scalar fields, so nullify must be a no-op. + engine.nullify_optional_fields(); + let mut booster = engine.booster_encoder(); + booster.boost_type(ExtBoostType::NITROUS); + booster.horse_power(200); + engine = booster.parent()?; + car = engine.parent()?; + + fuel_figures = car.fuel_figures_encoder(1, fuel_figures); + assert_eq!(Some(0), fuel_figures.advance()?); + fuel_figures.speed(77); + fuel_figures.mpg(12.5); + // FuelFigures group also has no optional primitive scalar fields; expect no change. + fuel_figures.nullify_optional_fields(); + let _car = fuel_figures.parent()?; + + with_decoded_extension_car!(buffer.as_slice(), car, { + let mut engine = car.engine_decoder(); + assert_eq!(2000, engine.capacity()); + assert_eq!(4, engine.num_cylinders()); + assert_eq!(35, engine.efficiency()); + + let mut fuel_figures = engine.parent().unwrap().fuel_figures_decoder(); + assert_eq!(Some(0), fuel_figures.advance().unwrap()); + assert_eq!(77, fuel_figures.speed()); + assert_eq!(12.5, fuel_figures.mpg()); + }); + + Ok(()) +} + +#[test] +fn opt_setters_work_as_expected() -> TestResult { + let mut some_buf = vec![0u8; 256]; + let mut encoder = create_issue_895_encoder(&mut some_buf); + encoder.optional_float_opt(Some(2.07)); + encoder.optional_double_opt(Some(4.12)); + + let decoder = decode_issue_895(some_buf.as_slice()); + assert_eq!(Some(2.07), decoder.optional_float()); + assert_eq!(Some(4.12), decoder.optional_double()); + + let mut none_buf = vec![0u8; 256]; + let mut encoder = create_issue_895_encoder(&mut none_buf); + encoder.optional_float_opt(None); + encoder.optional_double_opt(None); + + let decoder = decode_issue_895(none_buf.as_slice()); + assert_eq!(None, decoder.optional_float()); + assert_eq!(None, decoder.optional_double()); + + Ok(()) +} + +#[test] +fn nullify_optional_fields_sets_all_to_none() -> TestResult { + let mut buf = vec![0u8; 256]; + let mut encoder = create_issue_895_encoder(&mut buf); + encoder.optional_float_opt(Some(2.07)); + encoder.optional_double_opt(Some(4.12)); + // Message-level nullify should clear every optional primitive scalar field. + encoder.nullify_optional_fields(); + + let decoder = decode_issue_895(buf.as_slice()); + // Both optional fields are expected to decode as absent after nullify. + assert_eq!(None, decoder.optional_float()); + assert_eq!(None, decoder.optional_double()); + + Ok(()) +} + +#[test] +fn composite_nullify_optional_fields_sets_fields_to_none() -> TestResult { + let mut buffer = vec![0u8; 256]; + let mut encoder = create_issue_972_encoder(&mut buffer); + encoder.old_field(777); + let mut new_composite_encoder = encoder.new_field_encoder(); + new_composite_encoder.f1(2007); + new_composite_encoder.f2(2012); + // Composite-level nullify should clear composite optional primitive fields. + new_composite_encoder.nullify_optional_fields(); + let _encoder = new_composite_encoder.parent()?; + + let decoder = decode_issue_972(buffer.as_slice()); + match decoder.new_field_decoder() { + I972Either::Right(composite) => { + assert_eq!(None, composite.f1()); + assert_eq!(None, composite.f2()); + } + I972Either::Left(_) => panic!("expected new_field_decoder to return Right(composite)"), + } + + Ok(()) +} + +#[test] +fn message_nullify_without_optional_primitive_fields_has_no_effect() -> TestResult { + let mut buffer = vec![0u8; 256]; + let mut encoder = create_issue_972_encoder(&mut buffer); + encoder.old_field(42); + // Issue972 message has no optional primitive scalar fields; nullify should be a no-op. + encoder.nullify_optional_fields(); + + let decoder = decode_issue_972(buffer.as_slice()); + assert_eq!(42, decoder.old_field()); + + Ok(()) +} + +#[test] +fn group_nullify_optional_fields_sets_optional_fields_to_none() -> TestResult { + let mut buffer = vec![0u8; 1024]; + let mass_quote = create_mass_quote_encoder(&mut buffer); + let mut quote_sets = QuoteSetsEncoder::default(); + let mut quote_entries = QuoteEntriesEncoder::default(); + + quote_sets = mass_quote.quote_sets_encoder(1, quote_sets); + assert_eq!(Some(0), quote_sets.advance()?); + quote_sets.tot_quote_entries(1); + + quote_entries = quote_sets.quote_entries_encoder(1, quote_entries); + assert_eq!(Some(0), quote_entries.advance()?); + quote_entries.security_id_opt(Some(111)); + quote_entries.bid_size_opt(Some(222)); + quote_entries.offer_size_opt(Some(333)); + // Group-level nullify should clear all optional primitive scalar fields in the entry. + quote_entries.nullify_optional_fields(); + + quote_sets = quote_entries.parent()?; + let _mass_quote = quote_sets.parent()?; + + let buf = MassQuoteReadBuf::new(buffer.as_slice()); + let header = MassQuoteHeaderDecoder::default().wrap(buf, 0); + let decoder = MassQuoteDecoder::default().header(header, 0); + + let mut quote_sets = decoder.quote_sets_decoder(); + assert_eq!(Some(0), quote_sets.advance()?); + let mut quote_entries = quote_sets.quote_entries_decoder(); + assert_eq!(Some(0), quote_entries.advance()?); + // Optional fields must decode as absent once group nullify has been applied. + assert_eq!(None, quote_entries.security_id()); + assert_eq!(None, quote_entries.bid_size()); + assert_eq!(None, quote_entries.offer_size()); + + Ok(()) +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 1979de7b86..1fd81d51b2 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -99,7 +99,8 @@ void generate( { appendMessageHeaderEncoderFn(sb); - RustGenerator.generateEncoderFields(sb, fields, 2); + final List optionalPrimitiveFields = RustGenerator.generateEncoderFields(sb, fields, 2); + RustGenerator.generateNullifyOptionalFieldsMethod(sb, 2, optionalPrimitiveFields); RustGenerator.generateEncoderGroups(sb, groups, 2, this); RustGenerator.generateEncoderVarData(sb, varData, 2); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 683d81da44..1e239ee527 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -222,11 +222,13 @@ static String getBufOffset(final Token token) return "offset"; } - static void generateEncoderFields( + static List generateEncoderFields( final StringBuilder sb, final List tokens, final int level) { + final List optionalPrimitiveFields = new ArrayList<>(); + Generators.forEachField( tokens, (fieldToken, typeToken) -> @@ -238,6 +240,11 @@ static void generateEncoderFields( { case ENCODING: generatePrimitiveEncoder(sb, level, typeToken, name); + if (isOptionalPrimitiveScalar(typeToken)) + { + generateOptionalPrimitiveEncoder(sb, level, typeToken, name, typeToken.encoding()); + optionalPrimitiveFields.add(formatFunctionName(name)); + } break; case BEGIN_ENUM: generateEnumEncoder(sb, level, fieldToken, typeToken, name); @@ -257,6 +264,35 @@ static void generateEncoderFields( throw new UncheckedIOException(ex); } }); + + return optionalPrimitiveFields; + } + + static void generateNullifyOptionalFieldsMethod( + final Appendable out, + final int level, + final List optionalPrimitiveFields) throws IOException + { + indent(out, level, "/// Set all optional primitive scalar fields to their null values.\n"); + indent(out, level, "#[inline]\n"); + indent(out, level, "pub fn nullify_optional_fields(&mut self) {\n"); + if (optionalPrimitiveFields.isEmpty()) + { + indent(out, level + 1, "// No optional primitive scalar fields exist; nothing to do.\n"); + } + else + { + for (final String field : optionalPrimitiveFields) + { + indent(out, level + 1, "self.%s_opt(None);\n", field); + } + } + indent(out, level, "}\n\n"); + } + + private static boolean isOptionalPrimitiveScalar(final Token typeToken) + { + return typeToken.arrayLength() == 1 && typeToken.encoding().presence() == Encoding.Presence.OPTIONAL; } static void generateEncoderGroups( @@ -547,6 +583,16 @@ private static void generatePrimitiveEncoder( return; } + generatePrimitiveSetterEncoder(sb, level, typeToken, name, encoding); + } + + private static void generatePrimitiveSetterEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name, + final Encoding encoding) throws IOException + { final PrimitiveType primitiveType = encoding.primitiveType(); final String rustPrimitiveType = rustTypeName(primitiveType); @@ -563,6 +609,30 @@ private static void generatePrimitiveEncoder( indent(sb, level, "}\n\n"); } + private static void generateOptionalPrimitiveEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name, + final Encoding encoding) throws IOException + { + final PrimitiveType primitiveType = encoding.primitiveType(); + final String rustPrimitiveType = rustTypeName(primitiveType); + final String functionName = formatFunctionName(name); + final String nullLiteral = rustNullLiteral(encoding); + + indent(sb, level, "/// optional primitive field '%s'\n", name); + generateRustDoc(sb, level, typeToken, encoding); + indent(sb, level, "/// Set to `None` to encode the field null value.\n"); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s_opt(&mut self, value: Option<%s>) {\n", functionName, rustPrimitiveType); + indent(sb, level + 1, "match value {\n"); + indent(sb, level + 2, "Some(value) => self.%s(value),\n", functionName); + indent(sb, level + 2, "None => self.%s(%s),\n", functionName, nullLiteral); + indent(sb, level + 1, "}\n"); + indent(sb, level, "}\n\n"); + } + private static void generateEnumEncoder( final StringBuilder sb, final int level, @@ -1656,6 +1726,7 @@ private static void generateCompositeEncoder( indent(out, 3, "self.parent.take().ok_or(SbeErr::ParentNotSet)\n"); indent(out, 2, "}\n\n"); + final List optionalPrimitiveFields = new ArrayList<>(); for (int i = 1, end = tokens.size() - 1; i < end; ) { final Token encodingToken = tokens.get(i); @@ -1665,6 +1736,12 @@ private static void generateCompositeEncoder( { case ENCODING: generatePrimitiveEncoder(sb, 2, encodingToken, encodingToken.name()); + if (isOptionalPrimitiveScalar(encodingToken)) + { + generateOptionalPrimitiveEncoder(sb, 2, encodingToken, encodingToken.name(), + encodingToken.encoding()); + optionalPrimitiveFields.add(formatFunctionName(encodingToken.name())); + } break; case BEGIN_ENUM: generateEnumEncoder(sb, 2, encodingToken, encodingToken, encodingToken.name()); @@ -1683,6 +1760,7 @@ private static void generateCompositeEncoder( i += encodingToken.componentTokenCount(); } + generateNullifyOptionalFieldsMethod(out, 2, optionalPrimitiveFields); indent(out, 1, "}\n"); // end impl indent(out, 0, "} // end encoder mod \n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index e96c11c20a..1d9a0e4056 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -132,7 +132,8 @@ void generateEncoder( indent(sb, level + 1, "}\n"); indent(sb, level, "}\n\n"); - RustGenerator.generateEncoderFields(sb, fields, level); + final List optionalPrimitiveFields = RustGenerator.generateEncoderFields(sb, fields, level); + RustGenerator.generateNullifyOptionalFieldsMethod(sb, level, optionalPrimitiveFields); RustGenerator.generateEncoderGroups(sb, groups, level, this); RustGenerator.generateEncoderVarData(sb, varData, level); From bd0ade78b73d94b501c5869fdc6cda777ebaf500 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Sun, 15 Feb 2026 14:26:53 -0600 Subject: [PATCH 732/805] [Rust] updated Encoder trait to include "nullify_optional_fields()" --- rust/tests/optional_field_nullify_test.rs | 6 +- .../sbe/generation/rust/LibRsDef.java | 3 + .../sbe/generation/rust/MessageCoderDef.java | 6 +- .../sbe/generation/rust/RustGenerator.java | 79 ++++++++++++++----- .../sbe/generation/rust/SubGroup.java | 7 +- 5 files changed, 76 insertions(+), 25 deletions(-) diff --git a/rust/tests/optional_field_nullify_test.rs b/rust/tests/optional_field_nullify_test.rs index 188eca4cb6..44318570b1 100644 --- a/rust/tests/optional_field_nullify_test.rs +++ b/rust/tests/optional_field_nullify_test.rs @@ -2,7 +2,6 @@ use examples_extension as ext; use examples_uk_co_real_logic_sbe_benchmarks_fix as mqfix; use issue_895 as i895; use issue_972 as i972; - use ext::{ boolean_type::BooleanType as ExtBooleanType, boost_type::BoostType as ExtBoostType, @@ -92,6 +91,7 @@ fn encode_extension_car_for_optional_field_test( cup_holder_count: Option, nullify: bool, ) -> ExtSbeResult> { + use examples_extension::Encoder; let mut buffer = vec![0u8; 256]; let mut car = ExtCarEncoder::default(); let mut extras = ExtOptionalExtras::default(); @@ -177,6 +177,7 @@ fn extension_encoder_nullify_optional_fields_sets_cup_holder_count_to_none() -> #[test] fn nullify_on_composite_and_group_without_optional_fields_has_no_effect() -> TestResult { + use examples_extension::Encoder; let mut buffer = vec![0u8; 256]; let mut car = ExtCarEncoder::default(); let mut fuel_figures = ExtFuelFiguresEncoder::default(); @@ -262,6 +263,7 @@ fn opt_setters_work_as_expected() -> TestResult { #[test] fn nullify_optional_fields_sets_all_to_none() -> TestResult { + use issue_895::Encoder; let mut buf = vec![0u8; 256]; let mut encoder = create_issue_895_encoder(&mut buf); encoder.optional_float_opt(Some(2.07)); @@ -303,6 +305,7 @@ fn composite_nullify_optional_fields_sets_fields_to_none() -> TestResult { #[test] fn message_nullify_without_optional_primitive_fields_has_no_effect() -> TestResult { + use issue_972::Encoder; let mut buffer = vec![0u8; 256]; let mut encoder = create_issue_972_encoder(&mut buffer); encoder.old_field(42); @@ -317,6 +320,7 @@ fn message_nullify_without_optional_primitive_fields_has_no_effect() -> TestResu #[test] fn group_nullify_optional_fields_sets_optional_fields_to_none() -> TestResult { + use examples_uk_co_real_logic_sbe_benchmarks_fix::Encoder; let mut buffer = vec![0u8; 1024]; let mass_quote = create_mass_quote_encoder(&mut buffer); let mut quote_sets = QuoteSetsEncoder::default(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java index 1de9357f3a..898977b57e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/LibRsDef.java @@ -113,6 +113,9 @@ static void generateEncoderTraits(final Writer writer) throws IOException indent(writer, 0, "pub trait Encoder<'a>: Writer<'a> {\n"); indent(writer, 1, "fn get_limit(&self) -> usize;\n"); indent(writer, 1, "fn set_limit(&mut self, limit: usize);\n"); + indent(writer, 1, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); + indent(writer, 2, "self\n"); + indent(writer, 1, "}\n"); indent(writer, 0, "}\n\n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 1fd81d51b2..cd3e5a8ce0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -72,7 +72,8 @@ void generate( if (codecType == Encoder) { - RustGenerator.appendImplEncoderTrait(sb, msgTypeName); + final List optionalPrimitiveFields = RustGenerator.getOptionalPrimitiveFields(fields); + RustGenerator.appendImplEncoderTrait(sb, msgTypeName, optionalPrimitiveFields); } else { @@ -99,8 +100,7 @@ void generate( { appendMessageHeaderEncoderFn(sb); - final List optionalPrimitiveFields = RustGenerator.generateEncoderFields(sb, fields, 2); - RustGenerator.generateNullifyOptionalFieldsMethod(sb, 2, optionalPrimitiveFields); + RustGenerator.generateEncoderFields(sb, fields, 2); RustGenerator.generateEncoderGroups(sb, groups, 2, this); RustGenerator.generateEncoderVarData(sb, varData, 2); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 1e239ee527..858198902a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -33,9 +33,11 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import static java.lang.String.format; +import static java.lang.System.out; import static uk.co.real_logic.sbe.generation.rust.RustUtil.*; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; @@ -222,13 +224,30 @@ static String getBufOffset(final Token token) return "offset"; } - static List generateEncoderFields( + static List getOptionalPrimitiveFields(final List tokens) + { + final List optionalPrimitiveFields = new ArrayList<>(); + Generators.forEachField( + tokens, + (fieldToken, typeToken) -> + { + final String name = fieldToken.name(); + if (Objects.requireNonNull(typeToken.signal()) == Signal.ENCODING) + { + if (isOptionalPrimitiveScalar(typeToken)) + { + optionalPrimitiveFields.add(formatFunctionName(name)); + } + } + }); + return optionalPrimitiveFields; + } + + static void generateEncoderFields( final StringBuilder sb, final List tokens, final int level) { - final List optionalPrimitiveFields = new ArrayList<>(); - Generators.forEachField( tokens, (fieldToken, typeToken) -> @@ -243,7 +262,6 @@ static List generateEncoderFields( if (isOptionalPrimitiveScalar(typeToken)) { generateOptionalPrimitiveEncoder(sb, level, typeToken, name, typeToken.encoding()); - optionalPrimitiveFields.add(formatFunctionName(name)); } break; case BEGIN_ENUM: @@ -264,8 +282,6 @@ static List generateEncoderFields( throw new UncheckedIOException(ex); } }); - - return optionalPrimitiveFields; } static void generateNullifyOptionalFieldsMethod( @@ -275,18 +291,12 @@ static void generateNullifyOptionalFieldsMethod( { indent(out, level, "/// Set all optional primitive scalar fields to their null values.\n"); indent(out, level, "#[inline]\n"); - indent(out, level, "pub fn nullify_optional_fields(&mut self) {\n"); - if (optionalPrimitiveFields.isEmpty()) + indent(out, level, "pub fn nullify_optional_fields(&mut self) -> &mut Self {\n"); + for (final String field : optionalPrimitiveFields) { - indent(out, level + 1, "// No optional primitive scalar fields exist; nothing to do.\n"); - } - else - { - for (final String field : optionalPrimitiveFields) - { - indent(out, level + 1, "self.%s_opt(None);\n", field); - } + indent(out, level + 1, "self.%s_opt(None);\n", field); } + indent(out, level + 1, "self\n"); indent(out, level, "}\n\n"); } @@ -1339,7 +1349,8 @@ private static void generateSingleBitSet( static void appendImplEncoderTrait( final Appendable out, - final String typeName) throws IOException + final String typeName, + final List optionalPrimitiveFields) throws IOException { indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withBufLifetime("Writer"), withBufLifetime(typeName)); indent(out, 2, "#[inline]\n"); @@ -1358,6 +1369,21 @@ static void appendImplEncoderTrait( indent(out, 2, "fn set_limit(&mut self, limit: usize) {\n"); indent(out, 3, "self.limit = limit;\n"); indent(out, 2, "}\n"); + + if (!optionalPrimitiveFields.isEmpty()) + { + indent(out, 0, "\n"); + indent(out, 2, "/// xxx Set all optional primitive scalar fields to their 'null' values.\n"); + indent(out, 2, "#[inline]\n"); + indent(out, 2, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); + for (final String field : optionalPrimitiveFields) + { + indent(out, 3, "self.%s_opt(None);\n", field); + } + indent(out, 3, "self\n"); + indent(out, 2, "}\n"); + } + indent(out, 1, "}\n\n"); } @@ -1628,7 +1654,8 @@ static void appendImplWriterForComposite( static void appendImplEncoderForComposite( final Appendable out, final int level, - final String name) throws IOException + final String name, + final List optionalPrimitiveFields) throws IOException { appendImplWriterForComposite(out, level, name); @@ -1643,6 +1670,21 @@ static void appendImplEncoderForComposite( indent(out, level + 1, "fn set_limit(&mut self, limit: usize) {\n"); indent(out, level + 2, "self.parent.as_mut().expect(\"parent missing\").set_limit(limit);\n"); indent(out, level + 1, "}\n"); + + if (!optionalPrimitiveFields.isEmpty()) + { + indent(out, 0, "\n"); + indent(out, 2, "/// Set all optional primitive scalar fields to their 'null' values.\n"); + indent(out, 2, "#[inline]\n"); + indent(out, 2, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); + for (final String field : optionalPrimitiveFields) + { + indent(out, 3, "self.%s_opt(None);\n", field); + } + indent(out, 3, "self\n"); + indent(out, 2, "}\n"); + } + indent(out, level, "}\n\n"); } @@ -1721,6 +1763,7 @@ private static void generateCompositeEncoder( indent(out, 2, "}\n\n"); // parent fn... + indent(out, 2, "/// parent fns\n"); indent(out, 2, "#[inline]\n"); indent(out, 2, "pub fn parent(&mut self) -> SbeResult

      {\n"); indent(out, 3, "self.parent.take().ok_or(SbeErr::ParentNotSet)\n"); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 1d9a0e4056..96d2b07d2e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -72,7 +72,8 @@ void generateEncoder( indent(sb, level, "initial_limit: usize,\n"); indent(sb, level - 1, "}\n\n"); - RustGenerator.appendImplEncoderForComposite(sb, level - 1, name); + final List optionalPrimitiveFields = RustGenerator.getOptionalPrimitiveFields(fields); + RustGenerator.appendImplEncoderForComposite(sb, level - 1, name, optionalPrimitiveFields); // define impl... indent(sb, level - 1, "impl<'a, P> %s

      where P: Encoder<'a> + Default {\n", name); @@ -132,8 +133,8 @@ void generateEncoder( indent(sb, level + 1, "}\n"); indent(sb, level, "}\n\n"); - final List optionalPrimitiveFields = RustGenerator.generateEncoderFields(sb, fields, level); - RustGenerator.generateNullifyOptionalFieldsMethod(sb, level, optionalPrimitiveFields); + RustGenerator.generateEncoderFields(sb, fields, level); +// RustGenerator.generateNullifyOptionalFieldsMethod(sb, level, optionalPrimitiveFields); RustGenerator.generateEncoderGroups(sb, groups, level, this); RustGenerator.generateEncoderVarData(sb, varData, level); From ccc8fcc58c275eaacce4ee31e45b942076bfff37 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Sun, 15 Feb 2026 14:35:11 -0600 Subject: [PATCH 733/805] [Rust] minor edit --- .../uk/co/real_logic/sbe/generation/rust/RustGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 858198902a..15f383a0a6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1373,7 +1373,7 @@ static void appendImplEncoderTrait( if (!optionalPrimitiveFields.isEmpty()) { indent(out, 0, "\n"); - indent(out, 2, "/// xxx Set all optional primitive scalar fields to their 'null' values.\n"); + indent(out, 2, "/// Set all optional primitive scalar fields to their 'null' values.\n"); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); for (final String field : optionalPrimitiveFields) From 1ccfd4a0f791a35cb8db94c17dedc029b7453d04 Mon Sep 17 00:00:00 2001 From: Michael Ward Date: Sun, 15 Feb 2026 15:06:45 -0600 Subject: [PATCH 734/805] Update sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java Co-authored-by: Leonardo Arcari --- .../main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 96d2b07d2e..5012cda52c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -134,7 +134,6 @@ void generateEncoder( indent(sb, level, "}\n\n"); RustGenerator.generateEncoderFields(sb, fields, level); -// RustGenerator.generateNullifyOptionalFieldsMethod(sb, level, optionalPrimitiveFields); RustGenerator.generateEncoderGroups(sb, groups, level, this); RustGenerator.generateEncoderVarData(sb, varData, level); From 0388477e97680d18fa271bba21d18e825d9c29dc Mon Sep 17 00:00:00 2001 From: Leonardo Arcari Date: Wed, 18 Feb 2026 17:22:14 +0100 Subject: [PATCH 735/805] feat(rust): generate setters for optional enum fields too --- build.gradle | 1 + rust/Cargo.toml | 1 + rust/tests/optional_field_nullify_test.rs | 87 +++++++++++++++-- .../sbe/generation/rust/MessageCoderDef.java | 4 +- .../sbe/generation/rust/RustGenerator.java | 93 ++++++++++++++----- .../sbe/generation/rust/SubGroup.java | 4 +- .../test/resources/optional_enum_nullify.xml | 31 +++++++ 7 files changed, 184 insertions(+), 37 deletions(-) create mode 100644 sbe-tool/src/test/resources/optional_enum_nullify.xml diff --git a/build.gradle b/build.gradle index 3d6461d6e7..df2554c746 100644 --- a/build.gradle +++ b/build.gradle @@ -679,6 +679,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe-tool/src/test/resources/issue1028.xml', 'sbe-tool/src/test/resources/issue1057.xml', 'sbe-tool/src/test/resources/issue1066.xml', + 'sbe-tool/src/test/resources/optional_enum_nullify.xml', 'sbe-tool/src/test/resources/basic-variable-length-schema.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', 'sbe-tool/src/test/resources/fixed-sized-primitive-array-types.xml', diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 76119b11b7..df19774eb3 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -22,6 +22,7 @@ issue_1066 = { path = "../generated/rust/issue1066" } baseline_bigendian = { path = "../generated/rust/baseline_bigendian" } nested_composite_name = { path = "../generated/rust/nested_composite_name" } sbe_tests = { path = "../generated/rust/sbe_tests" } +optional_enum_nullify = { path = "../generated/rust/optional_enum_nullify" } fixed_sized_primitive_array = { path = "../generated/rust/fixed_sized_primitive_array" } [dev-dependencies] diff --git a/rust/tests/optional_field_nullify_test.rs b/rust/tests/optional_field_nullify_test.rs index 44318570b1..2f9555a413 100644 --- a/rust/tests/optional_field_nullify_test.rs +++ b/rust/tests/optional_field_nullify_test.rs @@ -1,7 +1,5 @@ use examples_extension as ext; use examples_uk_co_real_logic_sbe_benchmarks_fix as mqfix; -use issue_895 as i895; -use issue_972 as i972; use ext::{ boolean_type::BooleanType as ExtBooleanType, boost_type::BoostType as ExtBoostType, @@ -12,9 +10,7 @@ use ext::{ message_header_codec::{self as ext_header, MessageHeaderDecoder as ExtHeaderDecoder}, model::Model as ExtModel, optional_extras::OptionalExtras as ExtOptionalExtras, - ReadBuf as ExtReadBuf, - SbeResult as ExtSbeResult, - WriteBuf as ExtWriteBuf, + ReadBuf as ExtReadBuf, SbeResult as ExtSbeResult, WriteBuf as ExtWriteBuf, }; use i895::{ issue_895_codec::{Issue895Decoder, Issue895Encoder}, @@ -26,6 +22,8 @@ use i972::{ message_header_codec::{self as i972_header, MessageHeaderDecoder as I972HeaderDecoder}, Either as I972Either, ReadBuf as I972ReadBuf, WriteBuf as I972WriteBuf, }; +use issue_895 as i895; +use issue_972 as i972; use mqfix::{ mass_quote_codec::{ encoder::{QuoteEntriesEncoder, QuoteSetsEncoder}, @@ -34,15 +32,23 @@ use mqfix::{ message_header_codec::{self as mqfix_header, MessageHeaderDecoder as MassQuoteHeaderDecoder}, ReadBuf as MassQuoteReadBuf, WriteBuf as MassQuoteWriteBuf, }; +use oen::{ + enum_type::EnumType as OenEnumType, + message_header_codec::{ + self as oen_header, MessageHeaderDecoder as OptionalEnumNullifyHeaderDecoder, + }, + optional_encoding_enum_type::OptionalEncodingEnumType as OenOptionalEncodingEnumType, + optional_enum_nullify_codec::{OptionalEnumNullifyDecoder, OptionalEnumNullifyEncoder}, + ReadBuf as OenReadBuf, WriteBuf as OenWriteBuf, +}; +use optional_enum_nullify as oen; type TestResult = Result<(), Box>; macro_rules! create_encoder_with_header_parent { ($buffer:expr, $encoder_ty:ty, $write_buf_ty:ty, $encoded_len:expr) => {{ - let encoder = <$encoder_ty>::default().wrap( - <$write_buf_ty>::new($buffer.as_mut_slice()), - $encoded_len, - ); + let encoder = <$encoder_ty>::default() + .wrap(<$write_buf_ty>::new($buffer.as_mut_slice()), $encoded_len); let mut header = encoder.header(0); header.parent().unwrap() }}; @@ -66,6 +72,15 @@ fn create_issue_972_encoder(buffer: &mut Vec) -> Issue972Encoder<'_> { ) } +fn create_optional_enum_nullify_encoder(buffer: &mut Vec) -> OptionalEnumNullifyEncoder<'_> { + create_encoder_with_header_parent!( + buffer, + OptionalEnumNullifyEncoder<'_>, + OenWriteBuf<'_>, + oen_header::ENCODED_LENGTH + ) +} + fn create_mass_quote_encoder(buffer: &mut Vec) -> MassQuoteEncoder<'_> { create_encoder_with_header_parent!( buffer, @@ -87,6 +102,12 @@ fn decode_issue_972(buffer: &[u8]) -> Issue972Decoder<'_> { Issue972Decoder::default().header(header, 0) } +fn decode_optional_enum_nullify(buffer: &[u8]) -> OptionalEnumNullifyDecoder<'_> { + let buf = OenReadBuf::new(buffer); + let header = OptionalEnumNullifyHeaderDecoder::default().wrap(buf, 0); + OptionalEnumNullifyDecoder::default().header(header, 0) +} + fn encode_extension_car_for_optional_field_test( cup_holder_count: Option, nullify: bool, @@ -356,3 +377,51 @@ fn group_nullify_optional_fields_sets_optional_fields_to_none() -> TestResult { Ok(()) } + +#[test] +fn nullify_optional_fields_sets_optional_enum_field_to_null_value() -> TestResult { + use oen::Encoder; + let mut control_buffer = vec![0u8; 256]; + let mut control_encoder = create_optional_enum_nullify_encoder(&mut control_buffer); + // Optionality is declared on the field, matching IR optional enum semantics. + control_encoder.optional_enum_opt(Some(OenEnumType::One)); + // This field is required, even if its enum type encoding is optional. + control_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Alpha); + + let control_decoder = decode_optional_enum_nullify(control_buffer.as_slice()); + assert_eq!(OenEnumType::One, control_decoder.optional_enum()); + assert_eq!( + OenOptionalEncodingEnumType::Alpha, + control_decoder.required_enum_from_optional_type() + ); + + let mut none_buffer = vec![0u8; 256]; + let mut none_encoder = create_optional_enum_nullify_encoder(&mut none_buffer); + none_encoder.optional_enum_opt(None); + none_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Beta); + + let none_decoder = decode_optional_enum_nullify(none_buffer.as_slice()); + assert_eq!(OenEnumType::NullVal, none_decoder.optional_enum()); + assert_eq!( + OenOptionalEncodingEnumType::Beta, + none_decoder.required_enum_from_optional_type() + ); + + let mut nullified_buffer = vec![0u8; 256]; + let mut nullified_encoder = create_optional_enum_nullify_encoder(&mut nullified_buffer); + nullified_encoder.optional_enum_opt(Some(OenEnumType::Two)); + nullified_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Beta); + // This is the behavior under test: nullify should route through *_opt(None) + // only for field-optional members, so `optional_enum` becomes NullVal while + // the required field remains unchanged even if its enum type encoding is optional. + nullified_encoder.nullify_optional_fields(); + + let nullified_decoder = decode_optional_enum_nullify(nullified_buffer.as_slice()); + assert_eq!(OenEnumType::NullVal, nullified_decoder.optional_enum()); + assert_eq!( + OenOptionalEncodingEnumType::Beta, + nullified_decoder.required_enum_from_optional_type() + ); + + Ok(()) +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index cd3e5a8ce0..0f51975b7a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -72,8 +72,8 @@ void generate( if (codecType == Encoder) { - final List optionalPrimitiveFields = RustGenerator.getOptionalPrimitiveFields(fields); - RustGenerator.appendImplEncoderTrait(sb, msgTypeName, optionalPrimitiveFields); + final List optionalFields = RustGenerator.getNullifyOptionalFields(fields); + RustGenerator.appendImplEncoderTrait(sb, msgTypeName, optionalFields); } else { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 15f383a0a6..b19cba2762 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -224,23 +224,29 @@ static String getBufOffset(final Token token) return "offset"; } - static List getOptionalPrimitiveFields(final List tokens) + static List getNullifyOptionalFields(final List tokens) { - final List optionalPrimitiveFields = new ArrayList<>(); + final List optionalFields = new ArrayList<>(); Generators.forEachField( tokens, (fieldToken, typeToken) -> { - final String name = fieldToken.name(); - if (Objects.requireNonNull(typeToken.signal()) == Signal.ENCODING) + final String fieldName = formatFunctionName(fieldToken.name()); + final Signal signal = Objects.requireNonNull(typeToken.signal()); + if (signal == Signal.ENCODING) { if (isOptionalPrimitiveScalar(typeToken)) { - optionalPrimitiveFields.add(formatFunctionName(name)); + optionalFields.add(fieldName); } } + else if (signal == BEGIN_ENUM && + isOptionalEnum(typeToken, fieldToken)) + { + optionalFields.add(fieldName); + } }); - return optionalPrimitiveFields; + return optionalFields; } static void generateEncoderFields( @@ -266,6 +272,10 @@ static void generateEncoderFields( break; case BEGIN_ENUM: generateEnumEncoder(sb, level, fieldToken, typeToken, name); + if (isOptionalEnum(typeToken, fieldToken)) + { + generateOptionalEnumEncoder(sb, level, typeToken, name); + } break; case BEGIN_SET: generateBitSetEncoder(sb, level, typeToken, name); @@ -287,12 +297,12 @@ static void generateEncoderFields( static void generateNullifyOptionalFieldsMethod( final Appendable out, final int level, - final List optionalPrimitiveFields) throws IOException + final List optionalFields) throws IOException { - indent(out, level, "/// Set all optional primitive scalar fields to their null values.\n"); + indent(out, level, "/// Set all optional fields to their null values.\n"); indent(out, level, "#[inline]\n"); indent(out, level, "pub fn nullify_optional_fields(&mut self) -> &mut Self {\n"); - for (final String field : optionalPrimitiveFields) + for (final String field : optionalFields) { indent(out, level + 1, "self.%s_opt(None);\n", field); } @@ -305,6 +315,18 @@ private static boolean isOptionalPrimitiveScalar(final Token typeToken) return typeToken.arrayLength() == 1 && typeToken.encoding().presence() == Encoding.Presence.OPTIONAL; } + private static boolean isOptionalEnum(final Token typeToken, final Token fieldToken) + { + return typeToken.signal() == BEGIN_ENUM && fieldToken.isOptionalEncoding(); + } + + private static String rustEnumType(final Token typeToken) + { + final String referencedName = typeToken.referencedName(); + final String enumTypeName = referencedName == null ? typeToken.name() : referencedName; + return format("%s::%s", toLowerSnakeCase(enumTypeName), formatStructName(enumTypeName)); + } + static void generateEncoderGroups( final StringBuilder sb, final List tokens, @@ -650,10 +672,7 @@ private static void generateEnumEncoder( final Token typeToken, final String name) throws IOException { - final String referencedName = typeToken.referencedName(); - final String enumType = format("%s::%s", - toLowerSnakeCase(referencedName == null ? typeToken.name() : referencedName), - formatStructName(referencedName == null ? typeToken.name() : referencedName)); + final String enumType = rustEnumType(typeToken); if (fieldToken.isConstantEncoding()) { @@ -676,6 +695,27 @@ private static void generateEnumEncoder( } } + private static void generateOptionalEnumEncoder( + final StringBuilder sb, + final int level, + final Token typeToken, + final String name) throws IOException + { + final String functionName = formatFunctionName(name); + final String enumType = rustEnumType(typeToken); + + indent(sb, level, "/// optional enum field '%s'\n", name); + generateRustDoc(sb, level, typeToken, typeToken.encoding()); + indent(sb, level, "/// Set to `None` to encode the field null value.\n"); + indent(sb, level, "#[inline]\n"); + indent(sb, level, "pub fn %s_opt(&mut self, value: Option<%s>) {\n", functionName, enumType); + indent(sb, level + 1, "match value {\n"); + indent(sb, level + 2, "Some(value) => self.%s(value),\n", functionName); + indent(sb, level + 2, "None => self.%s(%s::NullVal),\n", functionName, enumType); + indent(sb, level + 1, "}\n"); + indent(sb, level, "}\n\n"); + } + private static void generateBitSetEncoder( final StringBuilder sb, final int level, @@ -1350,7 +1390,7 @@ private static void generateSingleBitSet( static void appendImplEncoderTrait( final Appendable out, final String typeName, - final List optionalPrimitiveFields) throws IOException + final List optionalFields) throws IOException { indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withBufLifetime("Writer"), withBufLifetime(typeName)); indent(out, 2, "#[inline]\n"); @@ -1370,13 +1410,13 @@ static void appendImplEncoderTrait( indent(out, 3, "self.limit = limit;\n"); indent(out, 2, "}\n"); - if (!optionalPrimitiveFields.isEmpty()) + if (!optionalFields.isEmpty()) { indent(out, 0, "\n"); - indent(out, 2, "/// Set all optional primitive scalar fields to their 'null' values.\n"); + indent(out, 2, "/// Set all optional fields to their 'null' values.\n"); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); - for (final String field : optionalPrimitiveFields) + for (final String field : optionalFields) { indent(out, 3, "self.%s_opt(None);\n", field); } @@ -1655,7 +1695,7 @@ static void appendImplEncoderForComposite( final Appendable out, final int level, final String name, - final List optionalPrimitiveFields) throws IOException + final List optionalFields) throws IOException { appendImplWriterForComposite(out, level, name); @@ -1671,13 +1711,13 @@ static void appendImplEncoderForComposite( indent(out, level + 2, "self.parent.as_mut().expect(\"parent missing\").set_limit(limit);\n"); indent(out, level + 1, "}\n"); - if (!optionalPrimitiveFields.isEmpty()) + if (!optionalFields.isEmpty()) { indent(out, 0, "\n"); - indent(out, 2, "/// Set all optional primitive scalar fields to their 'null' values.\n"); + indent(out, 2, "/// Set all optional fields to their 'null' values.\n"); indent(out, 2, "#[inline]\n"); indent(out, 2, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); - for (final String field : optionalPrimitiveFields) + for (final String field : optionalFields) { indent(out, 3, "self.%s_opt(None);\n", field); } @@ -1769,7 +1809,7 @@ private static void generateCompositeEncoder( indent(out, 3, "self.parent.take().ok_or(SbeErr::ParentNotSet)\n"); indent(out, 2, "}\n\n"); - final List optionalPrimitiveFields = new ArrayList<>(); + final List optionalFields = new ArrayList<>(); for (int i = 1, end = tokens.size() - 1; i < end; ) { final Token encodingToken = tokens.get(i); @@ -1783,11 +1823,16 @@ private static void generateCompositeEncoder( { generateOptionalPrimitiveEncoder(sb, 2, encodingToken, encodingToken.name(), encodingToken.encoding()); - optionalPrimitiveFields.add(formatFunctionName(encodingToken.name())); + optionalFields.add(formatFunctionName(encodingToken.name())); } break; case BEGIN_ENUM: generateEnumEncoder(sb, 2, encodingToken, encodingToken, encodingToken.name()); + if (isOptionalEnum(encodingToken, encodingToken)) + { + generateOptionalEnumEncoder(sb, 2, encodingToken, encodingToken.name()); + optionalFields.add(formatFunctionName(encodingToken.name())); + } break; case BEGIN_SET: generateBitSetEncoder(sb, 2, encodingToken, encodingToken.name()); @@ -1803,7 +1848,7 @@ private static void generateCompositeEncoder( i += encodingToken.componentTokenCount(); } - generateNullifyOptionalFieldsMethod(out, 2, optionalPrimitiveFields); + generateNullifyOptionalFieldsMethod(out, 2, optionalFields); indent(out, 1, "}\n"); // end impl indent(out, 0, "} // end encoder mod \n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index 5012cda52c..b465cee680 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -72,8 +72,8 @@ void generateEncoder( indent(sb, level, "initial_limit: usize,\n"); indent(sb, level - 1, "}\n\n"); - final List optionalPrimitiveFields = RustGenerator.getOptionalPrimitiveFields(fields); - RustGenerator.appendImplEncoderForComposite(sb, level - 1, name, optionalPrimitiveFields); + final List optionalFields = RustGenerator.getNullifyOptionalFields(fields); + RustGenerator.appendImplEncoderForComposite(sb, level - 1, name, optionalFields); // define impl... indent(sb, level - 1, "impl<'a, P> %s

      where P: Encoder<'a> + Default {\n", name); diff --git a/sbe-tool/src/test/resources/optional_enum_nullify.xml b/sbe-tool/src/test/resources/optional_enum_nullify.xml new file mode 100644 index 0000000000..22478f92e3 --- /dev/null +++ b/sbe-tool/src/test/resources/optional_enum_nullify.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + 1 + 2 + + + + 3 + 4 + + + + + + + From f6b2b7a9460824ec7a3e9432f47ddc55421b0d0f Mon Sep 17 00:00:00 2001 From: Leonardo Arcari Date: Thu, 19 Feb 2026 18:24:24 +0100 Subject: [PATCH 736/805] feat(rust): recursively call nullify_optional_fields on composites --- rust/tests/optional_field_nullify_test.rs | 19 ++- .../sbe/generation/rust/MessageCoderDef.java | 4 +- .../sbe/generation/rust/RustGenerator.java | 117 +++++++++++------- .../sbe/generation/rust/SubGroup.java | 4 +- .../test/resources/optional_enum_nullify.xml | 4 + 5 files changed, 100 insertions(+), 48 deletions(-) diff --git a/rust/tests/optional_field_nullify_test.rs b/rust/tests/optional_field_nullify_test.rs index 2f9555a413..fe2f5fc0d6 100644 --- a/rust/tests/optional_field_nullify_test.rs +++ b/rust/tests/optional_field_nullify_test.rs @@ -387,6 +387,9 @@ fn nullify_optional_fields_sets_optional_enum_field_to_null_value() -> TestResul control_encoder.optional_enum_opt(Some(OenEnumType::One)); // This field is required, even if its enum type encoding is optional. control_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Alpha); + let mut control_composite = control_encoder.optional_composite_encoder(); + control_composite.optional_counter_opt(Some(77)); + let _control_encoder = control_composite.parent()?; let control_decoder = decode_optional_enum_nullify(control_buffer.as_slice()); assert_eq!(OenEnumType::One, control_decoder.optional_enum()); @@ -394,11 +397,16 @@ fn nullify_optional_fields_sets_optional_enum_field_to_null_value() -> TestResul OenOptionalEncodingEnumType::Alpha, control_decoder.required_enum_from_optional_type() ); + let control_composite = control_decoder.optional_composite_decoder(); + assert_eq!(Some(77), control_composite.optional_counter()); let mut none_buffer = vec![0u8; 256]; let mut none_encoder = create_optional_enum_nullify_encoder(&mut none_buffer); none_encoder.optional_enum_opt(None); none_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Beta); + let mut none_composite = none_encoder.optional_composite_encoder(); + none_composite.optional_counter_opt(None); + let _none_encoder = none_composite.parent()?; let none_decoder = decode_optional_enum_nullify(none_buffer.as_slice()); assert_eq!(OenEnumType::NullVal, none_decoder.optional_enum()); @@ -406,14 +414,19 @@ fn nullify_optional_fields_sets_optional_enum_field_to_null_value() -> TestResul OenOptionalEncodingEnumType::Beta, none_decoder.required_enum_from_optional_type() ); + let none_composite = none_decoder.optional_composite_decoder(); + assert_eq!(None, none_composite.optional_counter()); let mut nullified_buffer = vec![0u8; 256]; let mut nullified_encoder = create_optional_enum_nullify_encoder(&mut nullified_buffer); nullified_encoder.optional_enum_opt(Some(OenEnumType::Two)); nullified_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Beta); + let mut nullified_composite = nullified_encoder.optional_composite_encoder(); + nullified_composite.optional_counter_opt(Some(88)); + nullified_encoder = nullified_composite.parent()?; // This is the behavior under test: nullify should route through *_opt(None) - // only for field-optional members, so `optional_enum` becomes NullVal while - // the required field remains unchanged even if its enum type encoding is optional. + // and recurse into composite fields, so `optional_enum` and composite optional + // members become null while required fields remain unchanged. nullified_encoder.nullify_optional_fields(); let nullified_decoder = decode_optional_enum_nullify(nullified_buffer.as_slice()); @@ -422,6 +435,8 @@ fn nullify_optional_fields_sets_optional_enum_field_to_null_value() -> TestResul OenOptionalEncodingEnumType::Beta, nullified_decoder.required_enum_from_optional_type() ); + let nullified_composite = nullified_decoder.optional_composite_decoder(); + assert_eq!(None, nullified_composite.optional_counter()); Ok(()) } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 0f51975b7a..58416f17bd 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -72,8 +72,8 @@ void generate( if (codecType == Encoder) { - final List optionalFields = RustGenerator.getNullifyOptionalFields(fields); - RustGenerator.appendImplEncoderTrait(sb, msgTypeName, optionalFields); + final RustGenerator.NullifyTargets nullifyTargets = RustGenerator.getNullifyTargets(fields); + RustGenerator.appendImplEncoderTrait(sb, msgTypeName, nullifyTargets); } else { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index b19cba2762..13edc8f67b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -82,6 +82,17 @@ interface ParentDef SubGroup addSubGroup(String name, int level, Token groupToken); } + static final class NullifyTargets + { + final List optionalFields = new ArrayList<>(); + final List compositeFieldEncoders = new ArrayList<>(); + + boolean isEmpty() + { + return optionalFields.isEmpty() && compositeFieldEncoders.isEmpty(); + } + } + private final Ir ir; private final RustOutputManager outputManager; private final String crateVersion; @@ -224,9 +235,9 @@ static String getBufOffset(final Token token) return "offset"; } - static List getNullifyOptionalFields(final List tokens) + static NullifyTargets getNullifyTargets(final List tokens) { - final List optionalFields = new ArrayList<>(); + final NullifyTargets targets = new NullifyTargets(); Generators.forEachField( tokens, (fieldToken, typeToken) -> @@ -237,16 +248,20 @@ static List getNullifyOptionalFields(final List tokens) { if (isOptionalPrimitiveScalar(typeToken)) { - optionalFields.add(fieldName); + targets.optionalFields.add(fieldName); } } else if (signal == BEGIN_ENUM && isOptionalEnum(typeToken, fieldToken)) { - optionalFields.add(fieldName); + targets.optionalFields.add(fieldName); + } + else if (signal == Signal.BEGIN_COMPOSITE) + { + targets.compositeFieldEncoders.add(compositeEncoderAccessorName(fieldToken.name())); } }); - return optionalFields; + return targets; } static void generateEncoderFields( @@ -297,17 +312,53 @@ static void generateEncoderFields( static void generateNullifyOptionalFieldsMethod( final Appendable out, final int level, - final List optionalFields) throws IOException + final NullifyTargets targets) throws IOException { indent(out, level, "/// Set all optional fields to their null values.\n"); indent(out, level, "#[inline]\n"); indent(out, level, "pub fn nullify_optional_fields(&mut self) -> &mut Self {\n"); - for (final String field : optionalFields) + appendNullifyOptionalFieldsBody(out, level + 1, targets); + indent(out, level + 1, "self\n"); + indent(out, level, "}\n\n"); + } + + private static void appendNullifyOptionalFieldsBody( + final Appendable out, + final int level, + final NullifyTargets targets) throws IOException + { + for (final String field : targets.optionalFields) { - indent(out, level + 1, "self.%s_opt(None);\n", field); + indent(out, level, "self.%s_opt(None);\n", field); } + + for (final String compositeFieldEncoder : targets.compositeFieldEncoders) + { + indent(out, level, "{\n"); + indent(out, level + 1, "let mut composite_encoder = core::mem::take(self).%s();\n", compositeFieldEncoder); + indent(out, level + 1, "composite_encoder.nullify_optional_fields();\n"); + indent(out, level + 1, "*self = composite_encoder.parent().expect(\"parent missing\");\n"); + indent(out, level, "}\n"); + } + } + + private static void appendTraitNullifyOptionalFieldsMethod( + final Appendable out, + final int level, + final NullifyTargets targets) throws IOException + { + if (targets.isEmpty()) + { + return; + } + + indent(out, 0, "\n"); + indent(out, level, "/// Set all optional fields to their 'null' values.\n"); + indent(out, level, "#[inline]\n"); + indent(out, level, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); + appendNullifyOptionalFieldsBody(out, level + 1, targets); indent(out, level + 1, "self\n"); - indent(out, level, "}\n\n"); + indent(out, level, "}\n"); } private static boolean isOptionalPrimitiveScalar(final Token typeToken) @@ -327,6 +378,11 @@ private static String rustEnumType(final Token typeToken) return format("%s::%s", toLowerSnakeCase(enumTypeName), formatStructName(enumTypeName)); } + private static String compositeEncoderAccessorName(final String name) + { + return toLowerSnakeCase(encoderName(name)); + } + static void generateEncoderGroups( final StringBuilder sb, final List tokens, @@ -743,7 +799,7 @@ private static void generateCompositeEncoder( final Token typeToken, final String name) throws IOException { - final String encoderName = toLowerSnakeCase(encoderName(name)); + final String encoderName = compositeEncoderAccessorName(name); final String encoderTypeName = format("%s::%s", codecModName(typeToken.referencedName() == null ? typeToken.name() : typeToken.referencedName()), encoderName(formatStructName(typeToken.applicableTypeName()))); @@ -1390,7 +1446,7 @@ private static void generateSingleBitSet( static void appendImplEncoderTrait( final Appendable out, final String typeName, - final List optionalFields) throws IOException + final NullifyTargets targets) throws IOException { indent(out, 1, "impl<%s> %s for %s {\n", BUF_LIFETIME, withBufLifetime("Writer"), withBufLifetime(typeName)); indent(out, 2, "#[inline]\n"); @@ -1410,19 +1466,7 @@ static void appendImplEncoderTrait( indent(out, 3, "self.limit = limit;\n"); indent(out, 2, "}\n"); - if (!optionalFields.isEmpty()) - { - indent(out, 0, "\n"); - indent(out, 2, "/// Set all optional fields to their 'null' values.\n"); - indent(out, 2, "#[inline]\n"); - indent(out, 2, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); - for (final String field : optionalFields) - { - indent(out, 3, "self.%s_opt(None);\n", field); - } - indent(out, 3, "self\n"); - indent(out, 2, "}\n"); - } + appendTraitNullifyOptionalFieldsMethod(out, 2, targets); indent(out, 1, "}\n\n"); } @@ -1695,7 +1739,7 @@ static void appendImplEncoderForComposite( final Appendable out, final int level, final String name, - final List optionalFields) throws IOException + final NullifyTargets targets) throws IOException { appendImplWriterForComposite(out, level, name); @@ -1711,19 +1755,7 @@ static void appendImplEncoderForComposite( indent(out, level + 2, "self.parent.as_mut().expect(\"parent missing\").set_limit(limit);\n"); indent(out, level + 1, "}\n"); - if (!optionalFields.isEmpty()) - { - indent(out, 0, "\n"); - indent(out, 2, "/// Set all optional fields to their 'null' values.\n"); - indent(out, 2, "#[inline]\n"); - indent(out, 2, "fn nullify_optional_fields(&mut self) -> &mut Self {\n"); - for (final String field : optionalFields) - { - indent(out, 3, "self.%s_opt(None);\n", field); - } - indent(out, 3, "self\n"); - indent(out, 2, "}\n"); - } + appendTraitNullifyOptionalFieldsMethod(out, 2, targets); indent(out, level, "}\n\n"); } @@ -1809,7 +1841,7 @@ private static void generateCompositeEncoder( indent(out, 3, "self.parent.take().ok_or(SbeErr::ParentNotSet)\n"); indent(out, 2, "}\n\n"); - final List optionalFields = new ArrayList<>(); + final NullifyTargets nullifyTargets = new NullifyTargets(); for (int i = 1, end = tokens.size() - 1; i < end; ) { final Token encodingToken = tokens.get(i); @@ -1823,7 +1855,7 @@ private static void generateCompositeEncoder( { generateOptionalPrimitiveEncoder(sb, 2, encodingToken, encodingToken.name(), encodingToken.encoding()); - optionalFields.add(formatFunctionName(encodingToken.name())); + nullifyTargets.optionalFields.add(formatFunctionName(encodingToken.name())); } break; case BEGIN_ENUM: @@ -1831,7 +1863,7 @@ private static void generateCompositeEncoder( if (isOptionalEnum(encodingToken, encodingToken)) { generateOptionalEnumEncoder(sb, 2, encodingToken, encodingToken.name()); - optionalFields.add(formatFunctionName(encodingToken.name())); + nullifyTargets.optionalFields.add(formatFunctionName(encodingToken.name())); } break; case BEGIN_SET: @@ -1839,6 +1871,7 @@ private static void generateCompositeEncoder( break; case BEGIN_COMPOSITE: generateCompositeEncoder(sb, 2, encodingToken, encodingToken.name()); + nullifyTargets.compositeFieldEncoders.add(compositeEncoderAccessorName(encodingToken.name())); break; default: break; @@ -1848,7 +1881,7 @@ private static void generateCompositeEncoder( i += encodingToken.componentTokenCount(); } - generateNullifyOptionalFieldsMethod(out, 2, optionalFields); + generateNullifyOptionalFieldsMethod(out, 2, nullifyTargets); indent(out, 1, "}\n"); // end impl indent(out, 0, "} // end encoder mod \n"); } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java index b465cee680..cae8e37546 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/SubGroup.java @@ -72,8 +72,8 @@ void generateEncoder( indent(sb, level, "initial_limit: usize,\n"); indent(sb, level - 1, "}\n\n"); - final List optionalFields = RustGenerator.getNullifyOptionalFields(fields); - RustGenerator.appendImplEncoderForComposite(sb, level - 1, name, optionalFields); + final RustGenerator.NullifyTargets nullifyTargets = RustGenerator.getNullifyTargets(fields); + RustGenerator.appendImplEncoderForComposite(sb, level - 1, name, nullifyTargets); // define impl... indent(sb, level - 1, "impl<'a, P> %s

      where P: Encoder<'a> + Default {\n", name); diff --git a/sbe-tool/src/test/resources/optional_enum_nullify.xml b/sbe-tool/src/test/resources/optional_enum_nullify.xml index 22478f92e3..81a20568fd 100644 --- a/sbe-tool/src/test/resources/optional_enum_nullify.xml +++ b/sbe-tool/src/test/resources/optional_enum_nullify.xml @@ -23,9 +23,13 @@ 3 4 + + + + From e73b2680bcf63c8e81cf3fe46fa78ec70017dbad Mon Sep 17 00:00:00 2001 From: Leonardo Arcari Date: Thu, 19 Feb 2026 18:41:28 +0100 Subject: [PATCH 737/805] fix(rust): make optional setters fluent --- .../sbe/generation/rust/RustGenerator.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 13edc8f67b..106941bda6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -37,7 +37,6 @@ import java.util.Set; import static java.lang.String.format; -import static java.lang.System.out; import static uk.co.real_logic.sbe.generation.rust.RustUtil.*; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectFields; import static uk.co.real_logic.sbe.ir.GenerationUtil.collectGroups; @@ -713,11 +712,13 @@ private static void generateOptionalPrimitiveEncoder( generateRustDoc(sb, level, typeToken, encoding); indent(sb, level, "/// Set to `None` to encode the field null value.\n"); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s_opt(&mut self, value: Option<%s>) {\n", functionName, rustPrimitiveType); + indent(sb, level, "pub fn %s_opt(&mut self, value: Option<%s>) -> &mut Self {\n", + functionName, rustPrimitiveType); indent(sb, level + 1, "match value {\n"); indent(sb, level + 2, "Some(value) => self.%s(value),\n", functionName); indent(sb, level + 2, "None => self.%s(%s),\n", functionName, nullLiteral); - indent(sb, level + 1, "}\n"); + indent(sb, level + 1, "};\n"); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } @@ -764,11 +765,12 @@ private static void generateOptionalEnumEncoder( generateRustDoc(sb, level, typeToken, typeToken.encoding()); indent(sb, level, "/// Set to `None` to encode the field null value.\n"); indent(sb, level, "#[inline]\n"); - indent(sb, level, "pub fn %s_opt(&mut self, value: Option<%s>) {\n", functionName, enumType); + indent(sb, level, "pub fn %s_opt(&mut self, value: Option<%s>) -> &mut Self {\n", functionName, enumType); indent(sb, level + 1, "match value {\n"); indent(sb, level + 2, "Some(value) => self.%s(value),\n", functionName); indent(sb, level + 2, "None => self.%s(%s::NullVal),\n", functionName, enumType); - indent(sb, level + 1, "}\n"); + indent(sb, level + 1, "};\n"); + indent(sb, level + 1, "self\n"); indent(sb, level, "}\n\n"); } From 9459cebfe41750faf8242de04993b5f69439bcf4 Mon Sep 17 00:00:00 2001 From: Leonardo Arcari Date: Thu, 19 Feb 2026 18:44:40 +0100 Subject: [PATCH 738/805] refactor(rust): use fluent API in unit test --- rust/tests/optional_field_nullify_test.rs | 119 ++++++++++++---------- 1 file changed, 64 insertions(+), 55 deletions(-) diff --git a/rust/tests/optional_field_nullify_test.rs b/rust/tests/optional_field_nullify_test.rs index fe2f5fc0d6..6963236a6e 100644 --- a/rust/tests/optional_field_nullify_test.rs +++ b/rust/tests/optional_field_nullify_test.rs @@ -123,32 +123,37 @@ fn encode_extension_car_for_optional_field_test( ); car = car.header(0).parent()?; - car.cup_holder_count_opt(cup_holder_count); if nullify { // When enabled, tests expect optional message fields to be encoded as "absent". - car.nullify_optional_fields(); + car.cup_holder_count_opt(cup_holder_count) + .nullify_optional_fields(); } - car.serial_number(1234); - car.model_year(2013); - car.available(ExtBooleanType::T); - car.code(ExtModel::A); - car.some_numbers(&[0, 1, 2, 3]); - car.vehicle_code(b"abcdef"); - - extras.set_cruise_control(true); - extras.set_sports_pack(true); - extras.set_sun_roof(false); + else + { + car.cup_holder_count_opt(cup_holder_count); + } + car.serial_number(1234) + .model_year(2013) + .available(ExtBooleanType::T) + .code(ExtModel::A) + .some_numbers(&[0, 1, 2, 3]) + .vehicle_code(b"abcdef"); + + extras + .set_cruise_control(true) + .set_sports_pack(true) + .set_sun_roof(false); car.extras(extras); let mut engine = car.engine_encoder(); - engine.capacity(2000); - engine.num_cylinders(4); - engine.manufacturer_code(b"123"); - engine.efficiency(35); - engine.booster_enabled(ExtBooleanType::T); + engine + .capacity(2000) + .num_cylinders(4) + .manufacturer_code(b"123") + .efficiency(35) + .booster_enabled(ExtBooleanType::T); let mut booster = engine.booster_encoder(); - booster.boost_type(ExtBoostType::NITROUS); - booster.horse_power(200); + booster.boost_type(ExtBoostType::NITROUS).horse_power(200); engine = booster.parent()?; let _car = engine.parent()?; @@ -210,36 +215,36 @@ fn nullify_on_composite_and_group_without_optional_fields_has_no_effect() -> Tes ); car = car.header(0).parent()?; - car.serial_number(1234); - car.model_year(2013); - car.available(ExtBooleanType::T); - car.code(ExtModel::A); - car.some_numbers(&[0, 1, 2, 3]); - car.vehicle_code(b"abcdef"); - - extras.set_cruise_control(true); - extras.set_sports_pack(true); - extras.set_sun_roof(false); + car.serial_number(1234) + .model_year(2013) + .available(ExtBooleanType::T) + .code(ExtModel::A) + .some_numbers(&[0, 1, 2, 3]) + .vehicle_code(b"abcdef"); + + extras + .set_cruise_control(true) + .set_sports_pack(true) + .set_sun_roof(false); car.extras(extras); let mut engine = car.engine_encoder(); - engine.capacity(2000); - engine.num_cylinders(4); - engine.manufacturer_code(b"123"); - engine.efficiency(35); - engine.booster_enabled(ExtBooleanType::T); + engine + .capacity(2000) + .num_cylinders(4) + .manufacturer_code(b"123") + .efficiency(35) + .booster_enabled(ExtBooleanType::T); // Engine has no optional primitive scalar fields, so nullify must be a no-op. engine.nullify_optional_fields(); let mut booster = engine.booster_encoder(); - booster.boost_type(ExtBoostType::NITROUS); - booster.horse_power(200); + booster.boost_type(ExtBoostType::NITROUS).horse_power(200); engine = booster.parent()?; car = engine.parent()?; fuel_figures = car.fuel_figures_encoder(1, fuel_figures); assert_eq!(Some(0), fuel_figures.advance()?); - fuel_figures.speed(77); - fuel_figures.mpg(12.5); + fuel_figures.speed(77).mpg(12.5); // FuelFigures group also has no optional primitive scalar fields; expect no change. fuel_figures.nullify_optional_fields(); let _car = fuel_figures.parent()?; @@ -263,8 +268,9 @@ fn nullify_on_composite_and_group_without_optional_fields_has_no_effect() -> Tes fn opt_setters_work_as_expected() -> TestResult { let mut some_buf = vec![0u8; 256]; let mut encoder = create_issue_895_encoder(&mut some_buf); - encoder.optional_float_opt(Some(2.07)); - encoder.optional_double_opt(Some(4.12)); + encoder + .optional_float_opt(Some(2.07)) + .optional_double_opt(Some(4.12)); let decoder = decode_issue_895(some_buf.as_slice()); assert_eq!(Some(2.07), decoder.optional_float()); @@ -272,8 +278,7 @@ fn opt_setters_work_as_expected() -> TestResult { let mut none_buf = vec![0u8; 256]; let mut encoder = create_issue_895_encoder(&mut none_buf); - encoder.optional_float_opt(None); - encoder.optional_double_opt(None); + encoder.optional_float_opt(None).optional_double_opt(None); let decoder = decode_issue_895(none_buf.as_slice()); assert_eq!(None, decoder.optional_float()); @@ -287,8 +292,9 @@ fn nullify_optional_fields_sets_all_to_none() -> TestResult { use issue_895::Encoder; let mut buf = vec![0u8; 256]; let mut encoder = create_issue_895_encoder(&mut buf); - encoder.optional_float_opt(Some(2.07)); - encoder.optional_double_opt(Some(4.12)); + encoder + .optional_float_opt(Some(2.07)) + .optional_double_opt(Some(4.12)); // Message-level nullify should clear every optional primitive scalar field. encoder.nullify_optional_fields(); @@ -306,8 +312,7 @@ fn composite_nullify_optional_fields_sets_fields_to_none() -> TestResult { let mut encoder = create_issue_972_encoder(&mut buffer); encoder.old_field(777); let mut new_composite_encoder = encoder.new_field_encoder(); - new_composite_encoder.f1(2007); - new_composite_encoder.f2(2012); + new_composite_encoder.f1(2007).f2(2012); // Composite-level nullify should clear composite optional primitive fields. new_composite_encoder.nullify_optional_fields(); let _encoder = new_composite_encoder.parent()?; @@ -353,9 +358,10 @@ fn group_nullify_optional_fields_sets_optional_fields_to_none() -> TestResult { quote_entries = quote_sets.quote_entries_encoder(1, quote_entries); assert_eq!(Some(0), quote_entries.advance()?); - quote_entries.security_id_opt(Some(111)); - quote_entries.bid_size_opt(Some(222)); - quote_entries.offer_size_opt(Some(333)); + quote_entries + .security_id_opt(Some(111)) + .bid_size_opt(Some(222)) + .offer_size_opt(Some(333)); // Group-level nullify should clear all optional primitive scalar fields in the entry. quote_entries.nullify_optional_fields(); @@ -384,9 +390,10 @@ fn nullify_optional_fields_sets_optional_enum_field_to_null_value() -> TestResul let mut control_buffer = vec![0u8; 256]; let mut control_encoder = create_optional_enum_nullify_encoder(&mut control_buffer); // Optionality is declared on the field, matching IR optional enum semantics. - control_encoder.optional_enum_opt(Some(OenEnumType::One)); // This field is required, even if its enum type encoding is optional. - control_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Alpha); + control_encoder + .optional_enum_opt(Some(OenEnumType::One)) + .required_enum_from_optional_type(OenOptionalEncodingEnumType::Alpha); let mut control_composite = control_encoder.optional_composite_encoder(); control_composite.optional_counter_opt(Some(77)); let _control_encoder = control_composite.parent()?; @@ -402,8 +409,9 @@ fn nullify_optional_fields_sets_optional_enum_field_to_null_value() -> TestResul let mut none_buffer = vec![0u8; 256]; let mut none_encoder = create_optional_enum_nullify_encoder(&mut none_buffer); - none_encoder.optional_enum_opt(None); - none_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Beta); + none_encoder + .optional_enum_opt(None) + .required_enum_from_optional_type(OenOptionalEncodingEnumType::Beta); let mut none_composite = none_encoder.optional_composite_encoder(); none_composite.optional_counter_opt(None); let _none_encoder = none_composite.parent()?; @@ -419,8 +427,9 @@ fn nullify_optional_fields_sets_optional_enum_field_to_null_value() -> TestResul let mut nullified_buffer = vec![0u8; 256]; let mut nullified_encoder = create_optional_enum_nullify_encoder(&mut nullified_buffer); - nullified_encoder.optional_enum_opt(Some(OenEnumType::Two)); - nullified_encoder.required_enum_from_optional_type(OenOptionalEncodingEnumType::Beta); + nullified_encoder + .optional_enum_opt(Some(OenEnumType::Two)) + .required_enum_from_optional_type(OenOptionalEncodingEnumType::Beta); let mut nullified_composite = nullified_encoder.optional_composite_encoder(); nullified_composite.optional_counter_opt(Some(88)); nullified_encoder = nullified_composite.parent()?; From f40acbb504ee956079c1324afe8050d317448b25 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 12 Mar 2026 10:59:34 +0000 Subject: [PATCH 739/805] [Java] Add a test for custom message header type. --- .../co/real_logic/sbe/ir/EncodedIrTest.java | 24 +++++++++++++++++++ .../src/test/resources/custom-header-type.xml | 19 +++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 sbe-tool/src/test/resources/custom-header-type.xml diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index c353a02d31..a8daf9bd2a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.xml.CompositeType; import uk.co.real_logic.sbe.xml.IrGenerator; import uk.co.real_logic.sbe.xml.MessageSchema; import uk.co.real_logic.sbe.xml.ParserOptions; @@ -28,6 +29,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; class EncodedIrTest @@ -175,6 +178,27 @@ void shouldPreservePackageNames() throws Exception testDecodeTypes("explicit-package-test-schema.xml"); } + @Test + void shouldUseCustomHeaderType() throws Exception + { + try (InputStream in = Tests.getLocalResource("custom-header-type.xml")) + { + final MessageSchema schema = parse(in, ParserOptions.DEFAULT); + final CompositeType messageHeader = schema.messageHeader(); + assertNotNull(messageHeader); + assertEquals("foo", messageHeader.name()); + + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final ByteBuffer buffer = ByteBuffer.allocate(CAPACITY); + try (IrEncoder irEncoder = new IrEncoder(buffer, ir)) + { + irEncoder.encode(); + assertThat(buffer.position(), greaterThan(0)); + } + } + } + private void testDecodeTypes(final String name1) throws Exception { try (InputStream in = Tests.getLocalResource(name1)) diff --git a/sbe-tool/src/test/resources/custom-header-type.xml b/sbe-tool/src/test/resources/custom-header-type.xml new file mode 100644 index 0000000000..689d60c055 --- /dev/null +++ b/sbe-tool/src/test/resources/custom-header-type.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + From fe703f59307ea5cefa1422e62ca8572bc00ca038 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:36:00 +0000 Subject: [PATCH 740/805] [Java] Upgrade to `Mockito` 5.23.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bbe626a7ef..d65f565d3e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ jqwik = "1.9.3" jmh = "1.37" json = "20251224" junit = "6.0.3" -mockito = "5.22.0" +mockito = "5.23.0" plexus = "3.3.0" shadow = "9.3.2" versions = "0.53.0" From 489a9443e0dc064485cf8d499a3b4d8e3b9c3219 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 16 Mar 2026 22:03:12 +0100 Subject: [PATCH 741/805] [Java] Upgrade to `Shadow` 9.4.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d65f565d3e..9c6d37c733 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20251224" junit = "6.0.3" mockito = "5.23.0" plexus = "3.3.0" -shadow = "9.3.2" +shadow = "9.4.0" versions = "0.53.0" [libraries] From 6e771ab8c299c1abcc9eb29c5ce82b21c16ca9eb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:02:20 +0100 Subject: [PATCH 742/805] [Java] Upgrade to `Gradle` 9.4.1. --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5be30bbeb2..c82ad3ff01 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0262dcbd52..739907dfd1 100755 --- a/gradlew +++ b/gradlew @@ -57,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/b631911858264c0b6e4d6603d677ff5218766cee/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. From 3eb1ac3c73a8a69548e4b5cb5508757dce695161 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:51:13 +0100 Subject: [PATCH 743/805] [Java] Upgrade to `Shadow` 9.4.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9c6d37c733..f4d2b11457 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20251224" junit = "6.0.3" mockito = "5.23.0" plexus = "3.3.0" -shadow = "9.4.0" +shadow = "9.4.1" versions = "0.53.0" [libraries] From 5cc53ab21fa1d9cbf01488453d8dd6fdb04a3272 Mon Sep 17 00:00:00 2001 From: Andrew Schwartz Date: Sat, 28 Mar 2026 07:27:32 -0700 Subject: [PATCH 744/805] [C++] mark a generated function SBE_CONSTEXPR (#1055) (#1083) * [C++] gate constexpr char-constant accessor on c++14 * [C++] initialize test buffer before manufacturer code read --- .../sbe/generation/cpp/CppGenerator.java | 11 ++++++-- sbe-tool/src/test/c/CodeGenTest.cpp | 2 ++ .../sbe/generation/cpp/CppGeneratorTest.java | 27 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 3ee0208cbb..ae795aeaeb 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -2630,12 +2630,19 @@ private void generateConstPropertyMethods( values); sb.append(String.format("\n" + + indent + " #if __cplusplus >= 201402L\n" + + indent + " SBE_NODISCARD static SBE_CONSTEXPR %1$s %2$s(const std::uint64_t index) SBE_NOEXCEPT\n" + + indent + " {\n" + + indent + " const std::uint8_t %2$sValues[] = { %3$s, 0 };\n\n" + + indent + " return (char)%2$sValues[index];\n" + + indent + " }\n" + + indent + " #else\n" + indent + " SBE_NODISCARD %1$s %2$s(const std::uint64_t index) const\n" + indent + " {\n" + indent + " static const std::uint8_t %2$sValues[] = { %3$s, 0 };\n\n" + - indent + " return (char)%2$sValues[index];\n" + - indent + " }\n", + indent + " }\n" + + indent + " #endif\n", cppTypeName, propertyName, values)); diff --git a/sbe-tool/src/test/c/CodeGenTest.cpp b/sbe-tool/src/test/c/CodeGenTest.cpp index 4135804ad3..474915d769 100644 --- a/sbe-tool/src/test/c/CodeGenTest.cpp +++ b/sbe-tool/src/test/c/CodeGenTest.cpp @@ -253,6 +253,7 @@ class CodeGenTest : public testing::Test output << static_cast(CGT(car_discountedModel(&car))) << ';'; char code_buf[4]; + memset(code_buf, 0, sizeof(code_buf)); CGT(engine) engine = {}; if (CGT(car_engine)(&car, &engine)) { @@ -354,6 +355,7 @@ class CodeGenTest : public testing::Test } char code_buf[4]; + memset(code_buf, 0, sizeof(code_buf)); CGT(engine) engine = {}; if (CGT(car_engine)(&car, &engine)) { diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index 2cdb37ecce..8d0b3995fa 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -75,6 +75,33 @@ void shouldUseConstexprWhenInitializingSemanticVersion() throws Exception } } + @Test + void shouldGenerateConstexprConstantCharAccessorOnlyForCpp14AndLater() throws Exception + { + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CppGenerator generator = new CppGenerator(ir, false, outputManager); + generator.generate(); + + final String source = outputManager.getSource("code.generation.test.Engine").toString(); + assertThat(source, containsString("#if __cplusplus >= 201402L")); + assertThat(source, containsString( + "SBE_NODISCARD static SBE_CONSTEXPR char fuel(const std::uint64_t index) SBE_NOEXCEPT")); + assertThat(source, containsString("const std::uint8_t fuelValues[] = { 80, 101, 116, 114, 111, 108, 0 };")); + assertThat(source, containsString("#else")); + assertThat(source, containsString("SBE_NODISCARD char fuel(const std::uint64_t index) const")); + assertThat(source, containsString( + "static const std::uint8_t fuelValues[] = { 80, 101, 116, 114, 111, 108, 0 };")); + } + } + @Test void dtosShouldReferenceTypesInDifferentPackages() throws Exception { From b0b7826cb7006c1faea7cdfe3b0b1e5a66df295f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:43:05 +0200 Subject: [PATCH 745/805] [C++] Protect against a segfault when dealing with empty `std::span` and `std::view`. Fixes #1100 --- .../sbe/generation/cpp/CppGenerator.java | 24 +++++---- sbe-tool/src/test/cpp/CodeGenTest.cpp | 53 ++++++++++++++++++- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index ae795aeaeb..14c01a981a 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -1240,7 +1240,7 @@ private void generateVarData( generateJsonEscapedStringGetter(sb, token, indent, propertyName); new Formatter(sb).format("\n" + - indent + " #if __cplusplus >= 201703L\n" + + indent + " #ifdef SBE_USE_STRING_VIEW\n" + indent + " std::string_view get%1$sAsStringView()\n" + indent + " {\n" + "%2$s" + @@ -1279,7 +1279,7 @@ private void generateVarData( lengthToken.encoding().applicableMaxValue().longValue()); new Formatter(sb).format("\n" + - indent + " #if __cplusplus >= 201703L\n" + + indent + " #ifdef SBE_USE_STRING_VIEW\n" + indent + " %1$s &put%2$s(const std::string_view str)\n" + indent + " {\n" + indent + " if (str.length() > %4$d)\n" + @@ -2323,7 +2323,10 @@ private void generateArrayProperty( indent + " {\n" + indent + " static_assert(N <= %5$d, \"array too large for put%2$s\");\n\n" + "%6$s" + - indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * N);\n" + + indent + " if (N > 0)\n" + + indent + " {\n" + + indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * N);\n" + + indent + " }\n\n" + indent + " for (std::size_t start = N; start < %5$d; ++start)\n" + indent + " {\n" + indent + " m_buffer[m_offset + %3$d + start] = 0;\n" + @@ -2350,9 +2353,11 @@ private void generateArrayProperty( indent + " {\n" + indent + " throw std::runtime_error(\"array too large for put%2$s [E106]\");\n" + indent + " }\n\n" + - "%6$s" + - indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * srcLength);\n" + + indent + " if (srcLength > 0)\n" + + indent + " {\n" + + indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * srcLength);\n" + + indent + " }\n\n" + indent + " for (std::size_t start = srcLength; start < %5$d; ++start)\n" + indent + " {\n" + indent + " m_buffer[m_offset + %3$d + start] = 0;\n" + @@ -2502,14 +2507,15 @@ private void generateArrayProperty( indent + " {\n" + indent + " throw std::runtime_error(\"string too large for put%2$s [E106]\");\n" + indent + " }\n\n" + - "%5$s" + - indent + " std::memcpy(m_buffer + m_offset + %3$d, str.data(), srcLength);\n" + + indent + " if (srcLength > 0)\n" + + indent + " {\n" + + indent + " std::memcpy(m_buffer + m_offset + %3$d, str.data(), srcLength);\n" + + indent + " }\n\n" + indent + " for (std::size_t start = srcLength; start < %4$d; ++start)\n" + indent + " {\n" + indent + " m_buffer[m_offset + %3$d + start] = 0;\n" + indent + " }\n\n" + - indent + " return *this;\n" + indent + " }\n" + indent + " #else\n" + @@ -2520,14 +2526,12 @@ private void generateArrayProperty( indent + " {\n" + indent + " throw std::runtime_error(\"string too large for put%2$s [E106]\");\n" + indent + " }\n\n" + - "%5$s" + indent + " std::memcpy(m_buffer + m_offset + %3$d, str.c_str(), srcLength);\n" + indent + " for (std::size_t start = srcLength; start < %4$d; ++start)\n" + indent + " {\n" + indent + " m_buffer[m_offset + %3$d + start] = 0;\n" + indent + " }\n\n" + - indent + " return *this;\n" + indent + " }\n" + indent + " #endif\n", diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index 991e1f96f3..c8a831d368 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -1101,6 +1101,21 @@ TEST_F(CodeGenTest, shouldBeAbleToUseStdStringViewMethods) } #endif +#ifdef SBE_USE_STRING_VIEW +TEST_F(CodeGenTest, shouldHandleEmptyStringView) +{ + char buffer[BUFFER_LEN] = {}; + + std::uint64_t baseOffset = MessageHeader::encodedLength(); + Car car; + car.wrapForEncode(buffer, baseOffset, sizeof(buffer)); + car.putVehicleCode(std::string_view{}); + + car.sbeRewind(); + EXPECT_EQ(car.getVehicleCodeAsStringView(), ""); +} +#endif + #ifdef SBE_USE_SPAN TEST_F(CodeGenTest, shouldBeAbleToUseStdSpanViewMethods) { @@ -1133,7 +1148,7 @@ TEST_F(CodeGenTest, shouldBeAbleToUseStdSpanViewMethods) #endif #ifdef SBE_USE_SPAN -TEST_F(CodeGenTest, shouldBeAbleToResolveStringLiterals) +TEST_F(CodeGenTest, shouldBeAbleToUseStringLiteralsWhenSpanIsEnabled) { char buffer[BUFFER_LEN] = {}; @@ -1144,6 +1159,42 @@ TEST_F(CodeGenTest, shouldBeAbleToResolveStringLiterals) car.sbeRewind(); EXPECT_EQ(car.getVehicleCodeAsStringView(), "ABCDE"); + auto res = car.getVehicleCodeAsSpan(); + EXPECT_EQ(6, res.size()); +} +#endif + +#ifdef SBE_USE_SPAN +TEST_F(CodeGenTest, shouldBeAbleToUseSpanToEncodeCharData) +{ + char buffer[BUFFER_LEN] = {}; + + std::uint64_t baseOffset = MessageHeader::encodedLength(); + Car car; + car.wrapForEncode(buffer, baseOffset, sizeof(buffer)); + car.putVehicleCode(std::span("ABCDE")); + + car.sbeRewind(); + EXPECT_EQ(car.getVehicleCodeAsStringView(), "ABCDE"); + auto res = car.getVehicleCodeAsSpan(); + EXPECT_EQ(6, res.size()); +} +#endif + +#ifdef SBE_USE_SPAN +TEST_F(CodeGenTest, shouldBeAbleToHandleEmptySpan) +{ + char buffer[BUFFER_LEN] = {}; + + std::uint64_t baseOffset = MessageHeader::encodedLength(); + Car car; + car.wrapForEncode(buffer, baseOffset, sizeof(buffer)); + car.putVehicleCode(std::span{}); + + car.sbeRewind(); + EXPECT_EQ(car.getVehicleCodeAsStringView(), ""); + auto res = car.getVehicleCodeAsSpan(); + EXPECT_EQ(0, res.size()); } #endif From 08ed6a986f5e104a6cf920a3f75cdde949e8aaeb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:46:37 +0200 Subject: [PATCH 746/805] [Java] Checkstyle fixes. --- .../java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 14c01a981a..5d3762c274 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -2356,7 +2356,8 @@ private void generateArrayProperty( "%6$s" + indent + " if (srcLength > 0)\n" + indent + " {\n" + - indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * srcLength);\n" + + indent + " std::memcpy(m_buffer + m_offset + %3$d, src.data(), sizeof(%4$s) * srcLength);" + + "\n" + indent + " }\n\n" + indent + " for (std::size_t start = srcLength; start < %5$d; ++start)\n" + indent + " {\n" + From 7932dd65081243384fac3f2366780239f13e25d2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:50:24 +0200 Subject: [PATCH 747/805] [C/C++] Upgrade to `CMake` 4.3.0. --- cppbuild/cppbuild | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cppbuild/cppbuild b/cppbuild/cppbuild index 26a8d8a345..fe14587073 100755 --- a/cppbuild/cppbuild +++ b/cppbuild/cppbuild @@ -5,7 +5,7 @@ BUILD_DIR="${SOURCE_DIR}/cppbuild/Release" EXTRA_CMAKE_ARGS="" BUILD_DELETE_CMAKE=false -BUILD_CMAKE_VERSION=4.2.1 +BUILD_CMAKE_VERSION=4.3.0 BUILD_CMAKE_DIR="${SOURCE_DIR}/cppbuild/cmake" ncpus=1 From 8452826d59421695a52cd0ddeeff10d2eb7a94e1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:57:12 +0200 Subject: [PATCH 748/805] [C++] Fix test assertion. --- sbe-tool/src/test/cpp/CodeGenTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index c8a831d368..40f769919b 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -1155,10 +1155,10 @@ TEST_F(CodeGenTest, shouldBeAbleToUseStringLiteralsWhenSpanIsEnabled) std::uint64_t baseOffset = MessageHeader::encodedLength(); Car car; car.wrapForEncode(buffer, baseOffset, sizeof(buffer)); - car.putVehicleCode("ABCDE"); + car.putVehicleCode("ABC"); car.sbeRewind(); - EXPECT_EQ(car.getVehicleCodeAsStringView(), "ABCDE"); + EXPECT_EQ(car.getVehicleCodeAsStringView(), "ABC"); auto res = car.getVehicleCodeAsSpan(); EXPECT_EQ(6, res.size()); } @@ -1194,7 +1194,7 @@ TEST_F(CodeGenTest, shouldBeAbleToHandleEmptySpan) car.sbeRewind(); EXPECT_EQ(car.getVehicleCodeAsStringView(), ""); auto res = car.getVehicleCodeAsSpan(); - EXPECT_EQ(0, res.size()); + EXPECT_EQ(6, res.size()); } #endif From 6a81d98a01663934ba6400d967a4e7bca6860bfb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 29 Mar 2026 16:01:57 +0200 Subject: [PATCH 749/805] [CI] Add Clang 22 and remove version older than 17. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c71672ec1..731426c973 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -173,7 +173,7 @@ jobs: strategy: fail-fast: false matrix: - version: [ '13', '14', '15', '16', '17', '18', '19', '20', '21' ] + version: [ '17', '18', '19', '20', '21', '22' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} @@ -186,7 +186,7 @@ jobs: run: | sudo mkdir -p /etc/apt/keyrings/ curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/llvm-snapshot.gpg - echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] http://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list + echo "deb [signed-by=/etc/apt/keyrings/llvm-snapshot.gpg] https://apt.llvm.org/noble/ llvm-toolchain-noble-${{ matrix.version }} main" | sudo tee /etc/apt/sources.list.d/llvm.list sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} - name: Setup java to run Gradle script From a96e8689190d20079f0efdcfba9bd48bd8e63345 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sun, 29 Mar 2026 16:03:20 +0200 Subject: [PATCH 750/805] [Doc] Add `C` to the list of supported languages. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce55a80bb2..5a819bd1fe 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Simple Binary Encoding (SBE) [SBE](https://github.com/FIXTradingCommunity/fix-simple-binary-encoding) is an OSI layer 6 presentation for encoding and decoding binary application messages for low-latency financial applications. This repository contains -the reference implementations in Java, C++, Golang, C#, and Rust. +the reference implementations in Java, C, C++, C#, Golang and Rust. More details on the design and usage of SBE can be found on the [Wiki](https://github.com/aeron-io/simple-binary-encoding/wiki). From fa98b3d89876d8e2495f09ffc681d5d4f3a4ba8e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 7 Apr 2026 14:41:16 +0200 Subject: [PATCH 751/805] [CI] Upgrade to Github Actions: - `actions/checkout@v6` - `gradle/actions/setup-gradle@v6` - `actions/upload-artifact@v7` diff --git c/.github/workflows/ci.yml i/.github/workflows/ci.yml index 731426c9..36d7f5db 100644 --- c/.github/workflows/ci.yml +++ i/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: echo "TMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "TEMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup java @@ -67,7 +67,7 @@ jobs: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build with Gradle run: ./gradlew - name: Copy test logs @@ -78,7 +78,7 @@ jobs: ./gradlew tarTestLogs - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: crash-logs-${{ matrix.os }}-java-${{ matrix.java }} path: ${{ steps.copy_test_logs.outputs.file }} @@ -96,7 +96,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script @@ -110,7 +110,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Cache NuGet dependencies uses: actions/cache@v4 with: @@ -143,7 +143,7 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Install compiler @@ -162,7 +162,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build run: ./cppbuild/cppbuild @@ -173,13 +173,13 @@ jobs: strategy: fail-fast: false matrix: - version: [ '17', '18', '19', '20', '21', '22' ] + version: [ '13', '14', '15', '16', '17', '18', '19', '20', '21', '22' ] env: CC: clang-${{ matrix.version }} CXX: clang++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Install compiler @@ -200,7 +200,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build run: ./cppbuild/cppbuild @@ -217,7 +217,7 @@ jobs: CXX: clang++ steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script @@ -231,7 +231,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -252,7 +252,7 @@ jobs: echo "TMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "TEMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script @@ -266,7 +266,7 @@ jobs: echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build run: cppbuild/cppbuild.cmd @@ -280,7 +280,7 @@ jobs: rust: [ stable, beta, nightly ] steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Rust setup @@ -298,7 +298,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - run: ./gradlew runRustTests golang-build: @@ -311,7 +311,7 @@ jobs: version: [ '1.23.x', '1.24.x' ] steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup Go @@ -329,7 +329,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Generate jar run: ./gradlew assemble - name: Run tests diff --git c/.github/workflows/codeql.yml i/.github/workflows/codeql.yml index b7e916b4..b763dfaf 100644 --- c/.github/workflows/codeql.yml +++ i/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} @@ -56,7 +56,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 @@ -89,7 +89,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} @@ -114,7 +114,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Setup dotnet uses: actions/setup-dotnet@v5 @@ -152,7 +152,7 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} @@ -169,7 +169,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Install compiler run: | diff --git c/.github/workflows/release.yml i/.github/workflows/release.yml index b33cf0c6..e49b419b 100644 --- c/.github/workflows/release.yml +++ i/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.ref }} - name: Setup java @@ -37,7 +37,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Publish with Gradle run: ./gradlew publish uploadArtifactsToCentralPortal env: diff --git c/.github/workflows/slow.yml i/.github/workflows/slow.yml index 0961c7a9..ed6585eb 100644 --- c/.github/workflows/slow.yml +++ i/.github/workflows/slow.yml @@ -40,7 +40,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup java uses: actions/setup-java@v5 with: @@ -57,7 +57,7 @@ jobs: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Setup dotnet uses: actions/setup-dotnet@v5 with: @@ -74,12 +74,12 @@ jobs: ./gradlew tarTestLogs - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: crash-logs-${{ matrix.os }}-property-tests-java-${{matrix.java}}-dotnet-${{matrix.dotnet}} path: ${{ steps.copy_test_logs.outputs.file }} - name: Upload test results - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 if: always() with: name: property-tests --- .github/workflows/ci.yml | 34 +++++++++++++++++----------------- .github/workflows/codeql.yml | 12 ++++++------ .github/workflows/release.yml | 4 ++-- .github/workflows/slow.yml | 8 ++++---- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 731426c973..defe4986ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: echo "TMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "TEMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup java @@ -67,7 +67,7 @@ jobs: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build with Gradle run: ./gradlew - name: Copy test logs @@ -78,7 +78,7 @@ jobs: ./gradlew tarTestLogs - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: crash-logs-${{ matrix.os }}-java-${{ matrix.java }} path: ${{ steps.copy_test_logs.outputs.file }} @@ -96,7 +96,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script @@ -110,7 +110,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Cache NuGet dependencies uses: actions/cache@v4 with: @@ -143,7 +143,7 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Install compiler @@ -162,7 +162,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build run: ./cppbuild/cppbuild @@ -179,7 +179,7 @@ jobs: CXX: clang++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Install compiler @@ -200,7 +200,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build run: ./cppbuild/cppbuild @@ -217,7 +217,7 @@ jobs: CXX: clang++ steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script @@ -231,7 +231,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -252,7 +252,7 @@ jobs: echo "TMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "TEMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script @@ -266,7 +266,7 @@ jobs: echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Build run: cppbuild/cppbuild.cmd @@ -280,7 +280,7 @@ jobs: rust: [ stable, beta, nightly ] steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Rust setup @@ -298,7 +298,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - run: ./gradlew runRustTests golang-build: @@ -311,7 +311,7 @@ jobs: version: [ '1.23.x', '1.24.x' ] steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} - name: Setup Go @@ -329,7 +329,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Generate jar run: ./gradlew assemble - name: Run tests diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b7e916b4fc..b763dfafcd 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} @@ -56,7 +56,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 @@ -89,7 +89,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} @@ -114,7 +114,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Setup dotnet uses: actions/setup-dotnet@v5 @@ -152,7 +152,7 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.sha }} @@ -169,7 +169,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Install compiler run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b33cf0c690..e49b419b17 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ github.ref }} - name: Setup java @@ -37,7 +37,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Publish with Gradle run: ./gradlew publish uploadArtifactsToCentralPortal env: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 0961c7a9ef..ed6585eb3b 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -40,7 +40,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup java uses: actions/setup-java@v5 with: @@ -57,7 +57,7 @@ jobs: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 + uses: gradle/actions/setup-gradle@v6 - name: Setup dotnet uses: actions/setup-dotnet@v5 with: @@ -74,12 +74,12 @@ jobs: ./gradlew tarTestLogs - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 with: name: crash-logs-${{ matrix.os }}-property-tests-java-${{matrix.java}}-dotnet-${{matrix.dotnet}} path: ${{ steps.copy_test_logs.outputs.file }} - name: Upload test results - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v7 if: always() with: name: property-tests From 989b40553f15d9299a74d4e8c2603ad2be900729 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Apr 2026 15:38:02 +0200 Subject: [PATCH 752/805] [Checkstyle] Allow inline return tags in the Javadoc comments + align with Aeron Checkstyle config. --- config/checkstyle/checkstyle.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index b97f363689..a0ad3423a9 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -41,7 +41,9 @@ - + + + @@ -50,9 +52,7 @@ - - - + @@ -80,7 +80,9 @@ - + + + @@ -192,7 +194,5 @@ - - From a06614ef6fd1b32015b3fe618a3b8b572b7aa011 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Wed, 22 Apr 2026 09:58:13 +1200 Subject: [PATCH 753/805] 1.38.0 release --- CHANGELOG.adoc | 11 ++++++++++- version.txt | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 5ae8575833..5675c0ddea 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,10 +1,19 @@ = Changelog -== 1.38.0 (unreleased) +== 1.38.0 (2026-04-22) +* **[Rust]** Recursively call nullify_optional_fields on composites +* **[Rust]** Generate setters for optional enum fields too. * **[Rust]** Generated encoders now produce fluent interface. (https://github.com/aeron-io/simple-binary-encoding/pull/1097[#1097]) * **[Rust]** Updated some function to `const`. (https://github.com/aeron-io/simple-binary-encoding/pull/1098[#1098]) * **[Rust]** Updated generator to correctly limit length of var data written. (https://github.com/aeron-io/simple-binary-encoding/pull/1096[#1096]) +* **[C++]** Protect against a segfault when dealing with empty `std::span` and `std::view`. +* **[C++]** mark a generated function SBE_CONSTEXPR (#1055) (#1083) +* Upgrade to `CMake` 4.3.0. +* Upgrade to `Shadow` 9.4.1. +* Upgrade to `Gradle` 9.4.1. +* Upgrade to `Shadow` 9.4.0. +* Upgrade to `Mockito` 5.23.0. == 1.37.1 (2026-01-13) * **[Java]** Ensure Java code generation for precedence checks always produces the same code without re-orderings. diff --git a/version.txt b/version.txt index 860bd0396d..ebeef2f2d6 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.38.0-SNAPSHOT +1.38.0 From 60ae2904b61388cc7b70d16ae3bd85c822799ff0 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Wed, 22 Apr 2026 10:45:40 +1200 Subject: [PATCH 754/805] 1.39.0 snapshot --- CHANGELOG.adoc | 2 ++ version.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 5675c0ddea..b6fe598b0b 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,7 @@ = Changelog +== 1.39.0 (unreleased) + == 1.38.0 (2026-04-22) * **[Rust]** Recursively call nullify_optional_fields on composites diff --git a/version.txt b/version.txt index ebeef2f2d6..40c214a46c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.38.0 +1.39.0-SNAPSHOT From e2e46fbab894331d1ac7a0d4f35336fce00a31bd Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:24:16 +0200 Subject: [PATCH 755/805] [Java] Upgrade to `Versions` 0.54.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f4d2b11457..9ef7516f81 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ junit = "6.0.3" mockito = "5.23.0" plexus = "3.3.0" shadow = "9.4.1" -versions = "0.53.0" +versions = "0.54.0" [libraries] agrona = { group = "org.agrona", name = "agrona", version.ref = "agrona" } From 13daf4fa32a2fb31b89eac26ed05a656a604d63f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:24:41 +0200 Subject: [PATCH 756/805] [Java] Upgrade to `Agrona` 2.4.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9ef7516f81..b365a2f26b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.4.0" +agrona = "2.4.1" checkstyle = "12.3.1" commons-codec = "1.15" commons-lang3 = "3.8.1" From 9ee637410cb6028ea37c1ed2ff03db420d090e7c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:27:25 +0200 Subject: [PATCH 757/805] [Doc] Changelog update. --- CHANGELOG.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index b6fe598b0b..1092b157be 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,6 +2,9 @@ == 1.39.0 (unreleased) +* Upgrade to `Agrona` 2.4.1. +* Upgrade to `Versions` 0.54.0. + == 1.38.0 (2026-04-22) * **[Rust]** Recursively call nullify_optional_fields on composites From 06fdf3cb1a14b0ecbc66727c69a1150964f0962b Mon Sep 17 00:00:00 2001 From: Victor Leyva <118840902+vleyva@users.noreply.github.com> Date: Fri, 24 Apr 2026 11:14:12 -0400 Subject: [PATCH 758/805] Update README to remove sales contact details (#1104) Removed commercial support contact information from README. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a819bd1fe..bef8bbff07 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,7 @@ For the latest version information and changes see the [Change Log](https://gith The Java and C++ SBE implementations work very efficiently with the [Aeron](https://github.com/aeron-io/aeron) messaging system for low-latency and high-throughput communications. The Java SBE implementation has a dependency on -[Agrona](https://github.com/aeron-io/agrona) for its buffer implementations. Commercial support is available from -[sales@real-logic.co.uk](mailto:sales@real-logic.co.uk?subject=SBE). +[Agrona](https://github.com/aeron-io/agrona) for its buffer implementations. Binaries -------- From 95f4e5c2e932c6befa2da58d19564ecf17670851 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Tue, 28 Apr 2026 05:55:58 +1200 Subject: [PATCH 759/805] 1.38.1 release --- CHANGELOG.adoc | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 1092b157be..0c25154a18 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,6 +1,6 @@ = Changelog -== 1.39.0 (unreleased) +== 1.38.1 (2026-04-28) * Upgrade to `Agrona` 2.4.1. * Upgrade to `Versions` 0.54.0. diff --git a/version.txt b/version.txt index 40c214a46c..11a36de972 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.39.0-SNAPSHOT +1.38.1 From e31f65007897844097e7933cd7e9f035ac65584e Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Tue, 28 Apr 2026 05:57:29 +1200 Subject: [PATCH 760/805] 1.39.0-SNAPSHOT --- CHANGELOG.adoc | 2 ++ version.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 0c25154a18..d43bd10cc2 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,7 @@ = Changelog +== 1.39.0 (unreleased) + == 1.38.1 (2026-04-28) * Upgrade to `Agrona` 2.4.1. diff --git a/version.txt b/version.txt index 11a36de972..40c214a46c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.38.1 +1.39.0-SNAPSHOT From a4a03a873f27645a9203c8af7477057482c3a2da Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:16:42 +0200 Subject: [PATCH 761/805] [Java] Upgrade to `Gradle` 9.5.0. --- CHANGELOG.adoc | 2 ++ gradle/wrapper/gradle-wrapper.jar | Bin 48966 -> 48462 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++- gradlew | 2 +- gradlew.bat | 31 ++++++++--------------- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index d43bd10cc2..de3e542650 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,6 +2,8 @@ == 1.39.0 (unreleased) +* Upgrade to `Gradle` 9.5.0. + == 1.38.1 (2026-04-28) * Upgrade to `Agrona` 2.4.1. diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d997cfc60f4cff0e7451d19d49a82fa986695d07..b1b8ef56b44f16b14dc800fa8103a6d89abb526f 100644 GIT binary patch delta 39760 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 e(*aw}>J`&Ep$5$o2mVP)i30-M3~u@DBh0 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 delta 40115 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 e{Sg5G5zENPNVU~b5#<2@M#Os+0czL&{q{eZe&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% @@ -65,7 +65,7 @@ echo. 1>&2 echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo location of your Java installation. 1>&2 -goto fail +"%COMSPEC%" /c exit 1 :execute @rem Setup the command line @@ -73,21 +73,10 @@ goto fail @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% From 3d19ac22e9d379f9ad893dbf92c07e66703b30c2 Mon Sep 17 00:00:00 2001 From: swadaptive <268603322+swadaptive@users.noreply.github.com> Date: Tue, 5 May 2026 11:29:33 +0100 Subject: [PATCH 762/805] (chore): Pin github actions to specific commit hashes (#1105) * Pin GitHub actions versions to hashes * Move to rust setup action that support Dependabot-friendly versioning --- .github/workflows/ci.yml | 60 +++++++++++++++++------------------ .github/workflows/codeql.yml | 38 +++++++++++----------- .github/workflows/release.yml | 6 ++-- .github/workflows/slow.yml | 14 ++++---- 4 files changed, 59 insertions(+), 59 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index defe4986ad..34d31eec0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,11 +41,11 @@ jobs: echo "TMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "TEMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Setup java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -62,12 +62,12 @@ jobs: echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "BUILD_JAVA_VERSION=${{ matrix.java }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup java to run Gradle - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build with Gradle run: ./gradlew - name: Copy test logs @@ -78,7 +78,7 @@ jobs: ./gradlew tarTestLogs - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: crash-logs-${{ matrix.os }}-java-${{ matrix.java }} path: ${{ steps.copy_test_logs.outputs.file }} @@ -96,11 +96,11 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -110,16 +110,16 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Cache NuGet dependencies - uses: actions/cache@v4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('csharp/**/*.sln') }} restore-keys: | ${{ runner.os }}-nuget- - name: Setup dotnet - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: dotnet-version: ${{ matrix.dotnet }} dotnet-quality: 'ga' @@ -143,7 +143,7 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Install compiler @@ -152,7 +152,7 @@ jobs: sudo apt-get update sudo apt-get install -y g++-${{ matrix.version }} - name: Setup java to run Gradle script - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -162,7 +162,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build run: ./cppbuild/cppbuild @@ -179,7 +179,7 @@ jobs: CXX: clang++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Install compiler @@ -190,7 +190,7 @@ jobs: sudo apt-get update sudo apt-get install -y clang-${{ matrix.version }} - name: Setup java to run Gradle script - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -200,7 +200,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build run: ./cppbuild/cppbuild @@ -217,11 +217,11 @@ jobs: CXX: clang++ steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -231,7 +231,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -252,11 +252,11 @@ jobs: echo "TMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "TEMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Setup java to run Gradle script - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -266,7 +266,7 @@ jobs: echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build run: cppbuild/cppbuild.cmd @@ -280,15 +280,15 @@ jobs: rust: [ stable, beta, nightly ] steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Rust setup - uses: dtolnay/rust-toolchain@stable + uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1.16.0 with: toolchain: ${{ matrix.rust }} - name: Setup java to run Gradle script - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -298,7 +298,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - run: ./gradlew runRustTests golang-build: @@ -311,15 +311,15 @@ jobs: version: [ '1.23.x', '1.24.x' ] steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version: ${{ matrix.version }} - name: Setup java to run Gradle script - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -329,7 +329,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Generate jar run: ./gradlew assemble - name: Run tests diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b763dfafcd..8892163a36 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -39,12 +39,12 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Setup java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -56,10 +56,10 @@ jobs: echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -68,7 +68,7 @@ jobs: run: ./gradlew - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: category: "/language:${{matrix.language}}" @@ -89,12 +89,12 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Cache NuGet dependencies - uses: actions/cache@v4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('csharp/**/*.sln') }} @@ -102,7 +102,7 @@ jobs: ${{ runner.os }}-nuget- - name: Setup java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -114,15 +114,15 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Setup dotnet - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: dotnet-version: ${{ matrix.dotnet }} - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -131,7 +131,7 @@ jobs: run: ./csharp/build.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: category: "/language:${{matrix.language}}" @@ -152,12 +152,12 @@ jobs: CXX: g++-${{ matrix.version }} steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.sha }} - name: Setup java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -169,14 +169,14 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Install compiler run: | sudo apt-get install -y g++-${{ matrix.version }} - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -185,14 +185,14 @@ jobs: run: ./cppbuild/cppbuild - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: category: "/language:${{ matrix.language }}" upload: false output: sarif-results - name: filter-sarif - uses: advanced-security/filter-sarif@v1 + uses: advanced-security/filter-sarif@2da736ff05ef065cb2894ac6892e47b5eac2c3c0 # v1.1 with: patterns: | -**/thirdparty/** @@ -200,6 +200,6 @@ jobs: output: sarif-results/${{ matrix.language }}.sarif - name: Upload SARIF - uses: github/codeql-action/upload-sarif@v4 + uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: sarif_file: sarif-results/${{ matrix.language }}.sarif diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e49b419b17..2808d09f66 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,11 +23,11 @@ jobs: runs-on: ubuntu-24.04 steps: - name: checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: ref: ${{ github.ref }} - name: Setup java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} @@ -37,7 +37,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Publish with Gradle run: ./gradlew publish uploadArtifactsToCentralPortal env: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index ed6585eb3b..e30649fbe6 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -40,9 +40,9 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ matrix.java }} @@ -52,14 +52,14 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Setup java to run Gradle script - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@v6 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Setup dotnet - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: dotnet-version: ${{ matrix.dotnet }} - name: Build .NET library @@ -74,12 +74,12 @@ jobs: ./gradlew tarTestLogs - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: crash-logs-${{ matrix.os }}-property-tests-java-${{matrix.java}}-dotnet-${{matrix.dotnet}} path: ${{ steps.copy_test_logs.outputs.file }} - name: Upload test results - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: name: property-tests From 430afa6a541273a4fa7aa177bb49c675794236f4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 5 May 2026 17:07:04 +0200 Subject: [PATCH 763/805] trigger CI --- CHANGELOG.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index de3e542650..da3c662e72 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -3,6 +3,7 @@ == 1.39.0 (unreleased) * Upgrade to `Gradle` 9.5.0. +* == 1.38.1 (2026-04-28) From 3cce26a26e6fb06c0989d7867bd721d5387f43f1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 20 May 2026 15:12:12 +0200 Subject: [PATCH 764/805] [Java] Upgrade to `JUnit` 6.1.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b365a2f26b..1f37604fc3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" json = "20251224" -junit = "6.0.3" +junit = "6.1.0" mockito = "5.23.0" plexus = "3.3.0" shadow = "9.4.1" From 36f87da67d0b3340d5b58a95baa6dd862b3f5b87 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 20 May 2026 15:12:25 +0200 Subject: [PATCH 765/805] [Java] Upgrade to `Gradle` 9.5.1. --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f193d72905..e74c8700b2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-all.zip networkTimeout=10000 retries=0 retryBackOffMs=500 From 69906a12a046bb4208b20d9a078af1539f4d826d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 20 May 2026 15:15:13 +0200 Subject: [PATCH 766/805] [Doc] Release notes. --- CHANGELOG.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index da3c662e72..34004f61dd 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,8 +2,8 @@ == 1.39.0 (unreleased) -* Upgrade to `Gradle` 9.5.0. -* +* Upgrade to `Gradle` 9.5.1. +* Upgrade to `JUnit` 6.1.0. == 1.38.1 (2026-04-28) From 2941e218b47885a0b6cd04b168dfad7eb4b2d399 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 22 May 2026 16:23:28 +0200 Subject: [PATCH 767/805] [CI] Use `cache-provider: basic` with `setup-gradle` action. --- .github/workflows/ci.yml | 16 ++++++++++++++++ .github/workflows/codeql.yml | 6 ++++++ .github/workflows/release.yml | 2 ++ .github/workflows/slow.yml | 2 ++ 4 files changed, 26 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34d31eec0b..0597a21e9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,6 +68,8 @@ jobs: java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Build with Gradle run: ./gradlew - name: Copy test logs @@ -111,6 +113,8 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Cache NuGet dependencies uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: @@ -163,6 +167,8 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Build run: ./cppbuild/cppbuild @@ -201,6 +207,8 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Build run: ./cppbuild/cppbuild @@ -232,6 +240,8 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -267,6 +277,8 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Build run: cppbuild/cppbuild.cmd @@ -299,6 +311,8 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - run: ./gradlew runRustTests golang-build: @@ -330,6 +344,8 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Generate jar run: ./gradlew assemble - name: Run tests diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8892163a36..327473dcf4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -57,6 +57,8 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Initialize CodeQL uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 @@ -115,6 +117,8 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Setup dotnet uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 @@ -170,6 +174,8 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Install compiler run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2808d09f66..782735172f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,6 +38,8 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Publish with Gradle run: ./gradlew publish uploadArtifactsToCentralPortal env: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index e30649fbe6..b0c7af5a5e 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -58,6 +58,8 @@ jobs: java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 + with: + cache-provider: basic - name: Setup dotnet uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0 with: From b0dd9b279d3611f9d49ad99817ac2e074e20007f Mon Sep 17 00:00:00 2001 From: Nate Bradac Date: Fri, 22 May 2026 15:11:47 -0500 Subject: [PATCH 768/805] add element descriptions to rust comments --- .../sbe/generation/rust/RustGenerator.java | 133 +++++++++---- .../rust/RustGeneratorDescriptionTest.java | 186 ++++++++++++++++++ .../rust-description-test-schema.xml | 48 +++++ .../rust-no-description-test-schema.xml | 47 +++++ 4 files changed, 380 insertions(+), 34 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustGeneratorDescriptionTest.java create mode 100644 sbe-tool/src/test/resources/rust-description-test-schema.xml create mode 100644 sbe-tool/src/test/resources/rust-no-description-test-schema.xml diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 106941bda6..628055a3e3 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -278,24 +278,25 @@ static void generateEncoderFields( switch (typeToken.signal()) { case ENCODING: - generatePrimitiveEncoder(sb, level, typeToken, name); + generatePrimitiveEncoder(sb, level, typeToken, name, fieldToken.description()); if (isOptionalPrimitiveScalar(typeToken)) { - generateOptionalPrimitiveEncoder(sb, level, typeToken, name, typeToken.encoding()); + generateOptionalPrimitiveEncoder(sb, level, typeToken, name, typeToken.encoding(), + fieldToken.description()); } break; case BEGIN_ENUM: generateEnumEncoder(sb, level, fieldToken, typeToken, name); if (isOptionalEnum(typeToken, fieldToken)) { - generateOptionalEnumEncoder(sb, level, typeToken, name); + generateOptionalEnumEncoder(sb, level, typeToken, name, fieldToken.description()); } break; case BEGIN_SET: - generateBitSetEncoder(sb, level, typeToken, name); + generateBitSetEncoder(sb, level, typeToken, name, fieldToken.description()); break; case BEGIN_COMPOSITE: - generateCompositeEncoder(sb, level, typeToken, name); + generateCompositeEncoder(sb, level, typeToken, name, fieldToken.description()); break; default: break; @@ -475,6 +476,7 @@ static void generateEncoderVarData( // function to write slice ... todo - handle character encoding ? indent(sb, level, "/// VAR_DATA ENCODER - character encoding: '%s'\n", characterEncoding); + appendFieldDocDescription(sb, level, varDataToken.description()); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\n", propertyName, varDataType); @@ -503,13 +505,38 @@ private static String rustNullLiteral(final Encoding encoding) return generateRustLiteral(encoding.primitiveType(), encoding.applicableNullValue()); } + private static void appendDocDescription( + final Appendable writer, + final int level, + final String description) throws IOException + { + if (Strings.isEmpty(description)) + { + return; + } + indent(writer, level, "/// %s\n", description); + } + + private static void appendFieldDocDescription( + final Appendable writer, + final int level, + final String description) throws IOException + { + if (Strings.isEmpty(description)) + { + return; + } + indent(writer, level, "/// - description: %s\n", description); + } private static void generateRustDoc( final StringBuilder sb, final int level, + final String fieldDescription, final Token typeToken, final Encoding encoding) throws IOException { + appendFieldDocDescription(sb, level, fieldDescription); indent(sb, level, "/// - min value: %s\n", encoding.applicableMinValue()); indent(sb, level, "/// - max value: %s\n", encoding.applicableMaxValue()); indent(sb, level, "/// - null value: %s\n", rustNullLiteral(encoding)); @@ -524,14 +551,15 @@ private static void generatePrimitiveArrayFromIterEncoder( final StringBuilder sb, final int level, final Token typeToken, - final String name) throws IOException + final String name, + final String fieldDescription) throws IOException { final Encoding encoding = typeToken.encoding(); final PrimitiveType primitiveType = encoding.primitiveType(); final String rustPrimitiveType = rustTypeName(primitiveType); indent(sb, level, "/// primitive array field '%s' from an Iterator\n", name); - generateRustDoc(sb, level, typeToken, encoding); + generateRustDoc(sb, level, fieldDescription, typeToken, encoding); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s_from_iter(&mut self, iter: impl Iterator) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); @@ -558,7 +586,8 @@ private static void generatePrimitiveArrayZeroPaddedEncoder( final StringBuilder sb, final int level, final Token typeToken, - final String name) throws IOException + final String name, + final String fieldDescription) throws IOException { final Encoding encoding = typeToken.encoding(); final PrimitiveType primitiveType = encoding.primitiveType(); @@ -566,7 +595,7 @@ private static void generatePrimitiveArrayZeroPaddedEncoder( final int arrayLength = typeToken.arrayLength(); indent(sb, level, "/// primitive array field '%s' with zero padding\n", name); - generateRustDoc(sb, level, typeToken, encoding); + generateRustDoc(sb, level, fieldDescription, typeToken, encoding); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s_zero_padded(&mut self, value: &[%s]) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); @@ -583,7 +612,8 @@ private static void generatePrimitiveArrayEncoder( final StringBuilder sb, final int level, final Token typeToken, - final String name) throws IOException + final String name, + final String fieldDescription) throws IOException { final Encoding encoding = typeToken.encoding(); final PrimitiveType primitiveType = encoding.primitiveType(); @@ -609,7 +639,7 @@ private static void generatePrimitiveArrayEncoder( indent(sb, level, "}\n\n"); indent(sb, level, "/// primitive array field '%s'\n", name); - generateRustDoc(sb, level, typeToken, encoding); + generateRustDoc(sb, level, fieldDescription, typeToken, encoding); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&mut self, value: &[%s]) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); @@ -646,20 +676,21 @@ private static void generatePrimitiveArrayEncoder( indent(sb, level, "}\n\n"); } - generatePrimitiveArrayFromIterEncoder(sb, level, typeToken, name); - generatePrimitiveArrayZeroPaddedEncoder(sb, level, typeToken, name); + generatePrimitiveArrayFromIterEncoder(sb, level, typeToken, name, fieldDescription); + generatePrimitiveArrayZeroPaddedEncoder(sb, level, typeToken, name, fieldDescription); } private static void generatePrimitiveEncoder( final StringBuilder sb, final int level, final Token typeToken, - final String name) throws IOException + final String name, + final String fieldDescription) throws IOException { final int arrayLength = typeToken.arrayLength(); if (arrayLength > 1) { - generatePrimitiveArrayEncoder(sb, level, typeToken, name); + generatePrimitiveArrayEncoder(sb, level, typeToken, name, fieldDescription); return; } @@ -670,7 +701,7 @@ private static void generatePrimitiveEncoder( return; } - generatePrimitiveSetterEncoder(sb, level, typeToken, name, encoding); + generatePrimitiveSetterEncoder(sb, level, typeToken, name, encoding, fieldDescription); } private static void generatePrimitiveSetterEncoder( @@ -678,13 +709,14 @@ private static void generatePrimitiveSetterEncoder( final int level, final Token typeToken, final String name, - final Encoding encoding) throws IOException + final Encoding encoding, + final String fieldDescription) throws IOException { final PrimitiveType primitiveType = encoding.primitiveType(); final String rustPrimitiveType = rustTypeName(primitiveType); indent(sb, level, "/// primitive field '%s'\n", name); - generateRustDoc(sb, level, typeToken, encoding); + generateRustDoc(sb, level, fieldDescription, typeToken, encoding); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\n", formatFunctionName(name), rustPrimitiveType); @@ -701,7 +733,8 @@ private static void generateOptionalPrimitiveEncoder( final int level, final Token typeToken, final String name, - final Encoding encoding) throws IOException + final Encoding encoding, + final String fieldDescription) throws IOException { final PrimitiveType primitiveType = encoding.primitiveType(); final String rustPrimitiveType = rustTypeName(primitiveType); @@ -709,7 +742,7 @@ private static void generateOptionalPrimitiveEncoder( final String nullLiteral = rustNullLiteral(encoding); indent(sb, level, "/// optional primitive field '%s'\n", name); - generateRustDoc(sb, level, typeToken, encoding); + generateRustDoc(sb, level, fieldDescription, typeToken, encoding); indent(sb, level, "/// Set to `None` to encode the field null value.\n"); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s_opt(&mut self, value: Option<%s>) -> &mut Self {\n", @@ -741,6 +774,7 @@ private static void generateEnumEncoder( final String rustPrimitiveType = rustTypeName(encoding.primitiveType()); indent(sb, level, "/// REQUIRED enum\n"); + appendFieldDocDescription(sb, level, fieldToken.description()); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&mut self, value: %s) -> &mut Self {\n", formatFunctionName(name), enumType); @@ -756,13 +790,14 @@ private static void generateOptionalEnumEncoder( final StringBuilder sb, final int level, final Token typeToken, - final String name) throws IOException + final String name, + final String fieldDescription) throws IOException { final String functionName = formatFunctionName(name); final String enumType = rustEnumType(typeToken); indent(sb, level, "/// optional enum field '%s'\n", name); - generateRustDoc(sb, level, typeToken, typeToken.encoding()); + generateRustDoc(sb, level, fieldDescription, typeToken, typeToken.encoding()); indent(sb, level, "/// Set to `None` to encode the field null value.\n"); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s_opt(&mut self, value: Option<%s>) -> &mut Self {\n", functionName, enumType); @@ -778,7 +813,8 @@ private static void generateBitSetEncoder( final StringBuilder sb, final int level, final Token bitsetToken, - final String name) throws IOException + final String name, + final String fieldDescription) throws IOException { final Encoding encoding = bitsetToken.encoding(); final String rustPrimitiveType = rustTypeName(encoding.primitiveType()); @@ -786,6 +822,7 @@ private static void generateBitSetEncoder( final String structTypeName = format("%s::%s", toLowerSnakeCase(referencedName == null ? bitsetToken.name() : referencedName), formatStructName(bitsetToken.applicableTypeName())); + appendFieldDocDescription(sb, level, fieldDescription); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&mut self, value: %s) {\n", formatFunctionName(name), structTypeName); @@ -799,13 +836,15 @@ private static void generateCompositeEncoder( final StringBuilder sb, final int level, final Token typeToken, - final String name) throws IOException + final String name, + final String fieldDescription) throws IOException { final String encoderName = compositeEncoderAccessorName(name); final String encoderTypeName = format("%s::%s", codecModName(typeToken.referencedName() == null ? typeToken.name() : typeToken.referencedName()), encoderName(formatStructName(typeToken.applicableTypeName()))); indent(sb, level, "/// COMPOSITE ENCODER\n"); + appendFieldDocDescription(sb, level, fieldDescription); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(self) -> %2$s {\n", encoderName, @@ -840,7 +879,7 @@ static void generateDecoderFields( generateEnumDecoder(sb, level, fieldToken, typeToken, name); break; case BEGIN_SET: - generateBitSetDecoder(sb, level, typeToken, name); + generateBitSetDecoder(sb, level, typeToken, name, fieldToken.description()); break; case BEGIN_COMPOSITE: generateCompositeDecoder(sb, level, fieldToken, typeToken, name); @@ -869,6 +908,7 @@ private static void generateCompositeDecoder( codecModName(referencedName == null ? typeToken.name() : referencedName), decoderName(formatStructName(typeToken.applicableTypeName()))); indent(sb, level, "/// COMPOSITE DECODER\n"); + appendFieldDocDescription(sb, level, fieldToken.description()); indent(sb, level, "#[inline]\n"); if (fieldToken.version() > 0) { @@ -900,7 +940,8 @@ private static void generateBitSetDecoder( final StringBuilder sb, final int level, final Token bitsetToken, - final String name) throws IOException + final String name, + final String fieldDescription) throws IOException { final Encoding encoding = bitsetToken.encoding(); final String rustPrimitiveType = rustTypeName(encoding.primitiveType()); @@ -909,6 +950,7 @@ private static void generateBitSetDecoder( toLowerSnakeCase(referencedName == null ? bitsetToken.name() : referencedName), formatStructName(bitsetToken.applicableTypeName())); indent(sb, level, "/// BIT SET DECODER\n"); + appendFieldDocDescription(sb, level, fieldDescription); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&self) -> %s {\n", formatFunctionName(name), structTypeName); @@ -940,7 +982,7 @@ private static void generatePrimitiveDecoder( } else if (encoding.presence() == Encoding.Presence.CONSTANT) { - generatePrimitiveConstantDecoder(sb, level, name, encoding); + generatePrimitiveConstantDecoder(sb, level, name, encoding, fieldToken.description()); } else if (encoding.presence() == Encoding.Presence.OPTIONAL) { @@ -966,6 +1008,7 @@ private static void generatePrimitiveArrayDecoder( final int arrayLength = typeToken.arrayLength(); assert arrayLength > 1; + appendFieldDocDescription(sb, level, fieldToken.description()); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&self) -> [%s; %d] {\n", formatFunctionName(name), @@ -1013,7 +1056,8 @@ private static void generatePrimitiveConstantDecoder( final StringBuilder sb, final int level, final String name, - final Encoding encoding) throws IOException + final Encoding encoding, + final String fieldDescription) throws IOException { assert encoding.presence() == Encoding.Presence.CONSTANT; final PrimitiveType primitiveType = encoding.primitiveType(); @@ -1021,6 +1065,7 @@ private static void generatePrimitiveConstantDecoder( final String characterEncoding = encoding.characterEncoding(); indent(sb, level, "/// CONSTANT \n"); + appendFieldDocDescription(sb, level, fieldDescription); final String rawConstValue = encoding.constValue().toString(); if (characterEncoding != null) { @@ -1070,6 +1115,8 @@ private static void generatePrimitiveOptionalDecoder( indent(sb, level, "/// primitive field - '%s' { null_value: '%s' }\n", encoding.presence(), rustNullLiteral(encoding)); + appendFieldDocDescription(sb, level, fieldToken.description()); + if (characterEncoding != null) { // ASCII and UTF-8 @@ -1122,6 +1169,8 @@ private static void generatePrimitiveRequiredDecoder( final String characterEncoding = encoding.characterEncoding(); indent(sb, level, "/// primitive field - '%s'\n", encoding.presence()); + appendFieldDocDescription(sb, level, fieldToken.description()); + if (characterEncoding != null) { // ASCII and UTF-8 @@ -1178,6 +1227,7 @@ private static void generateEnumDecoder( final String rustPrimitiveType = rustTypeName(encoding.primitiveType()); indent(sb, level, "/// REQUIRED enum\n"); + appendFieldDocDescription(sb, level, fieldToken.description()); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s(&self) -> %s {\n", formatFunctionName(name), enumType); @@ -1285,6 +1335,7 @@ static void generateDecoderVarData( final PrimitiveType lengthType = lengthEncoding.primitiveType(); indent(sb, level, "/// VAR_DATA DECODER - character encoding: '%s'\n", characterEncoding); + appendFieldDocDescription(sb, level, varDataToken.description()); indent(sb, level, "#[inline]\n"); indent(sb, level, "pub fn %s_decoder(&mut self) -> (usize, usize) {\n", propertyName); @@ -1368,6 +1419,7 @@ private static void generateSingleBitSet( { final Token beginToken = tokens.get(0); final String rustPrimitiveType = rustTypeName(beginToken.encoding().primitiveType()); + appendDocDescription(writer, 0, beginToken.description()); indent(writer, 0, "#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]\n"); indent(writer, 0, "pub struct %s(pub %s);\n", bitSetType, rustPrimitiveType); indent(writer, 0, "impl %s {\n", bitSetType); @@ -1394,6 +1446,7 @@ private static void generateSingleBitSet( final String choiceBitIndex = encoding.constValue().toString(); indent(writer, 0, "\n"); + appendDocDescription(writer, 1, token.description()); indent(writer, 1, "#[inline]\n"); indent(writer, 1, "pub fn get_%s(&self) -> bool {\n", choiceName); indent(writer, 2, "0 != self.0 & (1 << %s)\n", choiceBitIndex); @@ -1548,6 +1601,7 @@ private static void generateEnum( throw new IllegalArgumentException("No valid values provided for enum " + originalEnumName); } + appendDocDescription(writer, 0, enumTokens.get(0).description()); indent(writer, 0, "#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]\n"); final String primitiveType = rustTypeName(messageBody.get(0).encoding().primitiveType()); indent(writer, 0, "#[repr(%s)]\n", primitiveType); @@ -1557,6 +1611,7 @@ private static void generateEnum( { final Encoding encoding = token.encoding(); final String literal = generateRustLiteral(encoding.primitiveType(), encoding.constValue().toString()); + appendDocDescription(writer, 1, token.description()); indent(writer, 1, "%s = %s, \n", token.name(), literal); } @@ -1702,6 +1757,11 @@ private static void generateComposite( try (Writer out = outputManager.createOutput(compositeModName)) { + final String compositeDescription = token.description(); + if (!Strings.isEmpty(compositeDescription)) + { + indent(out, 0, "//! %s\n\n", compositeDescription); + } indent(out, 0, "use crate::*;\n\n"); indent(out, 0, "pub use encoder::%sEncoder;\n", formatStructName(compositeName)); @@ -1852,11 +1912,12 @@ private static void generateCompositeEncoder( switch (encodingToken.signal()) { case ENCODING: - generatePrimitiveEncoder(sb, 2, encodingToken, encodingToken.name()); + generatePrimitiveEncoder(sb, 2, encodingToken, encodingToken.name(), + encodingToken.description()); if (isOptionalPrimitiveScalar(encodingToken)) { generateOptionalPrimitiveEncoder(sb, 2, encodingToken, encodingToken.name(), - encodingToken.encoding()); + encodingToken.encoding(), encodingToken.description()); nullifyTargets.optionalFields.add(formatFunctionName(encodingToken.name())); } break; @@ -1864,15 +1925,18 @@ private static void generateCompositeEncoder( generateEnumEncoder(sb, 2, encodingToken, encodingToken, encodingToken.name()); if (isOptionalEnum(encodingToken, encodingToken)) { - generateOptionalEnumEncoder(sb, 2, encodingToken, encodingToken.name()); + generateOptionalEnumEncoder(sb, 2, encodingToken, encodingToken.name(), + encodingToken.description()); nullifyTargets.optionalFields.add(formatFunctionName(encodingToken.name())); } break; case BEGIN_SET: - generateBitSetEncoder(sb, 2, encodingToken, encodingToken.name()); + generateBitSetEncoder(sb, 2, encodingToken, encodingToken.name(), + encodingToken.description()); break; case BEGIN_COMPOSITE: - generateCompositeEncoder(sb, 2, encodingToken, encodingToken.name()); + generateCompositeEncoder(sb, 2, encodingToken, encodingToken.name(), + encodingToken.description()); nullifyTargets.compositeFieldEncoders.add(compositeEncoderAccessorName(encodingToken.name())); break; default: @@ -1938,7 +2002,8 @@ private static void generateCompositeDecoder( generateEnumDecoder(sb, 2, encodingToken, encodingToken, encodingToken.name()); break; case BEGIN_SET: - generateBitSetDecoder(sb, 2, encodingToken, encodingToken.name()); + generateBitSetDecoder(sb, 2, encodingToken, encodingToken.name(), + encodingToken.description()); break; case BEGIN_COMPOSITE: generateCompositeDecoder(sb, 2, encodingToken, encodingToken, encodingToken.name()); diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustGeneratorDescriptionTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustGeneratorDescriptionTest.java new file mode 100644 index 0000000000..e96f9bf45c --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/rust/RustGeneratorDescriptionTest.java @@ -0,0 +1,186 @@ +/* + * Copyright 2013-2025 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.rust; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +class RustGeneratorDescriptionTest +{ + @TempDir + Path tempDir; + + private Path generatedSrcDir; + + @BeforeEach + void generate() throws Exception + { + try (InputStream in = Tests.getLocalResource("rust-description-test-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + final RustOutputManager outputManager = new RustOutputManager( + tempDir.toString(), ir.applicableNamespace()); + final RustGenerator generator = new RustGenerator(ir, "0.1.0", outputManager); + generator.generate(); + + generatedSrcDir = tempDir.resolve("description_test").resolve("src"); + } + } + + @Test + void enumTypeDescriptionAppearsAsDocComment() throws Exception + { + final String source = readGeneratedFile("colour.rs"); + assertThat(source, containsString("/// The colour of the vehicle")); + } + + @Test + void enumVariantDescriptionsAppearAsDocComments() throws Exception + { + final String source = readGeneratedFile("colour.rs"); + assertThat(source, containsString("/// Red colour")); + assertThat(source, containsString("/// Green colour")); + assertThat(source, containsString("/// Blue colour")); + } + + @Test + void bitsetTypeDescriptionAppearsAsDocComment() throws Exception + { + final String source = readGeneratedFile("features.rs"); + assertThat(source, containsString("/// Optional features fitted to the vehicle")); + } + + @Test + void bitsetChoiceDescriptionsAppearAsDocComments() throws Exception + { + final String source = readGeneratedFile("features.rs"); + assertThat(source, containsString("/// Panoramic sun roof")); + assertThat(source, containsString("/// Sports handling pack")); + } + + @Test + void compositeDescriptionAppearsAsModuleDocComment() throws Exception + { + final String source = readGeneratedFile("engine_codec.rs"); + assertThat(source, containsString("//! Internal combustion engine specification")); + } + + @Test + void primitiveFieldDescriptionAppearsInDocComment() throws Exception + { + final String source = readGeneratedFile("vehicle_codec.rs"); + assertThat(source, containsString("/// - description: Unique serial number of the vehicle")); + } + + @Test + void enumFieldDescriptionAppearsInDocComment() throws Exception + { + final String source = readGeneratedFile("vehicle_codec.rs"); + assertThat(source, containsString("/// - description: Exterior colour of the vehicle")); + } + + @Test + void bitsetFieldDescriptionAppearsInDocComment() throws Exception + { + final String source = readGeneratedFile("vehicle_codec.rs"); + assertThat(source, containsString("/// - description: Bitset of optional features fitted")); + } + + @Test + void compositeFieldDescriptionAppearsInDocComment() throws Exception + { + final String source = readGeneratedFile("vehicle_codec.rs"); + assertThat(source, containsString("/// - description: Engine specification composite")); + } + + @Test + void groupDescriptionAppearsOnEncoderAndDecoder() throws Exception + { + final String source = readGeneratedFile("vehicle_codec.rs"); + assertThat(source, containsString( + "/// GROUP ENCODER (id=5, description='Passengers currently in the vehicle')")); + assertThat(source, containsString( + "/// GROUP DECODER (id=5, description='Passengers currently in the vehicle')")); + } + + @Test + void groupFieldDescriptionAppearsInDocComment() throws Exception + { + final String source = readGeneratedFile("vehicle_codec.rs"); + assertThat(source, containsString("/// - description: Age of the passenger in years")); + } + + @Test + void varDataDescriptionAppearsInDocComment() throws Exception + { + final String source = readGeneratedFile("vehicle_codec.rs"); + assertThat(source, containsString("/// - description: Full model name of the vehicle")); + } + + @Test + void generatorSucceedsAndProducesNoDescriptionCommentsWhenSchemaHasNoDescriptions() throws Exception + { + try (InputStream in = Tests.getLocalResource("rust-no-description-test-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + + final RustOutputManager outputManager = new RustOutputManager( + tempDir.toString(), ir.applicableNamespace()); + final RustGenerator generator = new RustGenerator(ir, "0.1.0", outputManager); + + assertDoesNotThrow(generator::generate); + + final Path srcDir = tempDir.resolve("no_description_test").resolve("src"); + final String enumSource = Files.readString(srcDir.resolve("colour.rs")); + final String bitsetSource = Files.readString(srcDir.resolve("features.rs")); + final String compositeSource = Files.readString(srcDir.resolve("engine_codec.rs")); + final String messageSource = Files.readString(srcDir.resolve("vehicle_codec.rs")); + + assertThat(enumSource, not(containsString("/// -"))); + assertThat(bitsetSource, not(containsString("/// -"))); + assertThat(compositeSource, not(containsString("//!"))); + assertThat(messageSource, not(containsString("/// - description:"))); + } + } + + private String readGeneratedFile(final String fileName) throws Exception + { + return Files.readString(generatedSrcDir.resolve(fileName)); + } +} diff --git a/sbe-tool/src/test/resources/rust-description-test-schema.xml b/sbe-tool/src/test/resources/rust-description-test-schema.xml new file mode 100644 index 0000000000..2b3c32d0fe --- /dev/null +++ b/sbe-tool/src/test/resources/rust-description-test-schema.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + + + 0 + 1 + + + + + + + + + + + + + diff --git a/sbe-tool/src/test/resources/rust-no-description-test-schema.xml b/sbe-tool/src/test/resources/rust-no-description-test-schema.xml new file mode 100644 index 0000000000..e445474b1a --- /dev/null +++ b/sbe-tool/src/test/resources/rust-no-description-test-schema.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + + + 0 + 1 + + + + + + + + + + + + + From c386066955329291cd79d5d2ce1d38ea058e5cae Mon Sep 17 00:00:00 2001 From: Nikolay Zdravkov Date: Tue, 2 Jun 2026 17:46:36 +0300 Subject: [PATCH 769/805] refactor: seal PrimitiveValue and PrimitiveType, make ThrowHelper static --- csharp/sbe-dll/PrimitiveType.cs | 2 +- csharp/sbe-dll/PrimitiveValue.cs | 27 +++++++++++---------------- csharp/sbe-dll/ThrowHelper.cs | 2 +- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/csharp/sbe-dll/PrimitiveType.cs b/csharp/sbe-dll/PrimitiveType.cs index d0d183eabc..3e54de6d54 100644 --- a/csharp/sbe-dll/PrimitiveType.cs +++ b/csharp/sbe-dll/PrimitiveType.cs @@ -71,7 +71,7 @@ /// /// /// - public class PrimitiveType + public sealed class PrimitiveType { ///

      /// Primitive type representation for SBE type CHAR diff --git a/csharp/sbe-dll/PrimitiveValue.cs b/csharp/sbe-dll/PrimitiveValue.cs index a579baa158..39be34975c 100644 --- a/csharp/sbe-dll/PrimitiveValue.cs +++ b/csharp/sbe-dll/PrimitiveValue.cs @@ -74,7 +74,7 @@ namespace Org.SbeTool.Sbe.Dll /// /// /// - public class PrimitiveValue + public sealed class PrimitiveValue { private enum Representation { @@ -485,26 +485,21 @@ public override string ToString() /// equivalence of values public override bool Equals(object value) { - if (null != value && this.GetType().Equals(value.GetType())) + if (value is PrimitiveValue rhs && _representation == rhs._representation) { - var rhs = (PrimitiveValue) value; - - if (_representation == rhs._representation) + switch (_representation) { - switch (_representation) - { - case Representation.Long: - return _longValue == rhs._longValue; + case Representation.Long: + return _longValue == rhs._longValue; - case Representation.ULong: - return _unsignedLongValue == rhs._unsignedLongValue; + case Representation.ULong: + return _unsignedLongValue == rhs._unsignedLongValue; - case Representation.Double: - return BitConverter.DoubleToInt64Bits(_doubleValue) == BitConverter.DoubleToInt64Bits(rhs._doubleValue); + case Representation.Double: + return BitConverter.DoubleToInt64Bits(_doubleValue) == BitConverter.DoubleToInt64Bits(rhs._doubleValue); - case Representation.ByteArray: - return _byteArrayValue.SequenceEqual(rhs._byteArrayValue); - } + case Representation.ByteArray: + return _byteArrayValue.SequenceEqual(rhs._byteArrayValue); } } diff --git a/csharp/sbe-dll/ThrowHelper.cs b/csharp/sbe-dll/ThrowHelper.cs index 30ca008c9c..9c1ffe4630 100644 --- a/csharp/sbe-dll/ThrowHelper.cs +++ b/csharp/sbe-dll/ThrowHelper.cs @@ -6,7 +6,7 @@ namespace Org.SbeTool.Sbe.Dll /// Helper class that provides non-returning methods that throw common exception /// from the generated C# code /// - public class ThrowHelper + public static class ThrowHelper { /// /// Throws a when the "count" parameter is out of range From e1e156934f9ab9357a3b5b3690d225685f997919 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:19:07 +0200 Subject: [PATCH 770/805] [Java] Upgrade to `Shadow` 9.4.2. --- CHANGELOG.adoc | 1 + gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 34004f61dd..5b4358588d 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -4,6 +4,7 @@ * Upgrade to `Gradle` 9.5.1. * Upgrade to `JUnit` 6.1.0. +* Upgrade to `Shadow` 9.4.2. == 1.38.1 (2026-04-28) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1f37604fc3..54618c5f17 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20251224" junit = "6.1.0" mockito = "5.23.0" plexus = "3.3.0" -shadow = "9.4.1" +shadow = "9.4.2" versions = "0.54.0" [libraries] From b9cf706d10b2c4e35f4331030303b8cc1d976e69 Mon Sep 17 00:00:00 2001 From: sunlei Date: Fri, 12 Jun 2026 22:04:21 +0800 Subject: [PATCH 771/805] [Rust] Inline generated header methods (#1110) --- .../uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java index 58416f17bd..6e1b317615 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/MessageCoderDef.java @@ -130,6 +130,7 @@ public SubGroup addSubGroup(final String name, final int level, final Token grou void appendMessageHeaderEncoderFn(final Appendable out) throws IOException { + indent(out, 2, "#[inline]\n"); indent(out, 2, "pub fn header(self, offset: usize) -> MessageHeaderEncoder {\n"); indent(out, 3, "let mut header = MessageHeaderEncoder::default().wrap(self, offset);\n"); indent(out, 3, "header.block_length(SBE_BLOCK_LENGTH);\n"); @@ -142,6 +143,7 @@ void appendMessageHeaderEncoderFn(final Appendable out) throws IOException void appendMessageHeaderDecoderFn(final Appendable out) throws IOException { + indent(out, 2, "#[inline]\n"); indent(out, 2, "pub fn header(self, mut header: MessageHeaderDecoder>, offset: usize) -> Self {\n"); indent(out, 3, "debug_assert_eq!(SBE_TEMPLATE_ID, header.template_id());\n"); indent(out, 3, "let acting_block_length = header.block_length();\n"); From 17bb431112c44c122bc3d5dde64245f983dbcf4c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:10:36 +0200 Subject: [PATCH 772/805] [Java] Upgrade to `jqwik` 1.10.1. --- CHANGELOG.adoc | 3 ++- gradle/libs.versions.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 5b4358588d..0060e94a3a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -5,6 +5,7 @@ * Upgrade to `Gradle` 9.5.1. * Upgrade to `JUnit` 6.1.0. * Upgrade to `Shadow` 9.4.2. +* Upgrade to `jqwik` 1.10.1. == 1.38.1 (2026-04-28) @@ -13,7 +14,7 @@ == 1.38.0 (2026-04-22) -* **[Rust]** Recursively call nullify_optional_fields on composites +* **[Rust]** Recursively call nullify_optional_fields on composites. * **[Rust]** Generate setters for optional enum fields too. * **[Rust]** Generated encoders now produce fluent interface. (https://github.com/aeron-io/simple-binary-encoding/pull/1097[#1097]) * **[Rust]** Updated some function to `const`. (https://github.com/aeron-io/simple-binary-encoding/pull/1098[#1098]) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 54618c5f17..482bafd9ea 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" httpcore = "4.4.14" -jqwik = "1.9.3" +jqwik = "1.10.1" jmh = "1.37" json = "20251224" junit = "6.1.0" From 4b0ef7702a9e1b24d9bf54dcfb2071c7293f1263 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:11:00 +0200 Subject: [PATCH 773/805] [Java] Upgrade to `json` 20260522. --- CHANGELOG.adoc | 1 + gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 0060e94a3a..cc7f956585 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -6,6 +6,7 @@ * Upgrade to `JUnit` 6.1.0. * Upgrade to `Shadow` 9.4.2. * Upgrade to `jqwik` 1.10.1. +* Upgrade to `json` 20260522. == 1.38.1 (2026-04-28) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 482bafd9ea..d6ffc9f7ac 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hamcrest = "3.0" httpcore = "4.4.14" jqwik = "1.10.1" jmh = "1.37" -json = "20251224" +json = "20260522" junit = "6.1.0" mockito = "5.23.0" plexus = "3.3.0" From effad488929942455590f9f5bedf598cab427550 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:15:18 +0200 Subject: [PATCH 774/805] [Doc] Release notes. --- CHANGELOG.adoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index cc7f956585..f4b9ddd8a1 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,6 +2,9 @@ == 1.39.0 (unreleased) +* **[Rust]** Inline generated header methods. (https://github.com/aeron-io/simple-binary-encoding/pull/1110[#1110]) +* **[Rust]** Add element descriptions to comments. +* **[C#]** Seal `PrimitiveValue` and `PrimitiveType`, make `ThrowHelper` static. (https://github.com/aeron-io/simple-binary-encoding/pull/1109[#1109]) * Upgrade to `Gradle` 9.5.1. * Upgrade to `JUnit` 6.1.0. * Upgrade to `Shadow` 9.4.2. @@ -25,7 +28,6 @@ * Upgrade to `CMake` 4.3.0. * Upgrade to `Shadow` 9.4.1. * Upgrade to `Gradle` 9.4.1. -* Upgrade to `Shadow` 9.4.0. * Upgrade to `Mockito` 5.23.0. == 1.37.1 (2026-01-13) From b48c2700a7a8315f4fb20dd268bce002834d29c3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:15:05 +0200 Subject: [PATCH 775/805] [Java] Upgrade to `Gradle` 9.6.0. --- CHANGELOG.adoc | 2 +- build.gradle | 19 ++++++++----------- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 ++-- gradlew.bat | 4 ++-- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index f4b9ddd8a1..e73ab0ef10 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -5,7 +5,7 @@ * **[Rust]** Inline generated header methods. (https://github.com/aeron-io/simple-binary-encoding/pull/1110[#1110]) * **[Rust]** Add element descriptions to comments. * **[C#]** Seal `PrimitiveValue` and `PrimitiveType`, make `ThrowHelper` static. (https://github.com/aeron-io/simple-binary-encoding/pull/1109[#1109]) -* Upgrade to `Gradle` 9.5.1. +* Upgrade to `Gradle` 9.6.0. * Upgrade to `JUnit` 6.1.0. * Upgrade to `Shadow` 9.4.2. * Upgrade to `jqwik` 1.10.1. diff --git a/build.gradle b/build.gradle index df2554c746..9a5a9b57d8 100644 --- a/build.gradle +++ b/build.gradle @@ -67,17 +67,14 @@ def getConfigProperty(final String projectPropertyName, final String envVarName) return value ? value : null } -ext { - isReleaseVersion = !sbeVersion.endsWith('-SNAPSHOT') - - sonatypeCentralPortalReleasesRepoUrl = 'https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/' - sonatypeCentralPortalSnapshotsRepoUrl = 'https://central.sonatype.com/repository/maven-snapshots/' - sonatypeCentralPortalUsername = getConfigProperty('sonatypeCentralPortalUsername', 'SONATYPE_CENTRAL_PORTAL_USERNAME') - sonatypeCentralPortalPassword = getConfigProperty('sonatypeCentralPortalPassword', 'SONATYPE_CENTRAL_PORTAL_PASSWORD') - - signingKey = getConfigProperty('signingKey', 'SIGNING_GPG_SECRET_KEY') // NOTE: ASCII armored secret key - signingPassword = getConfigProperty('signingPassword', 'SIGNING_GPG_PASSWORD') // NOTE: Plain text -} +def isReleaseVersion = !sbeVersion.endsWith('-SNAPSHOT') +def sonatypeCentralPortalReleasesRepoUrl = 'https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/' +def sonatypeCentralPortalSnapshotsRepoUrl = 'https://central.sonatype.com/repository/maven-snapshots/' +def sonatypeCentralPortalUsername = getConfigProperty('sonatypeCentralPortalUsername', 'SONATYPE_CENTRAL_PORTAL_USERNAME') +def sonatypeCentralPortalPassword = getConfigProperty('sonatypeCentralPortalPassword', 'SONATYPE_CENTRAL_PORTAL_PASSWORD') +def signingKey = getConfigProperty('signingKey', 'SIGNING_GPG_SECRET_KEY') // NOTE: ASCII armored secret key +def signingPassword = getConfigProperty('signingPassword', 'SIGNING_GPG_PASSWORD') // NOTE: Plain text +def libs = rootProject.libs def projectPom = { name = 'sbe' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e74c8700b2..11cae1e003 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-all.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/gradlew b/gradlew index b9bb139f79..249efbb032 100755 --- a/gradlew +++ b/gradlew @@ -20,7 +20,7 @@ ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -29,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: diff --git a/gradlew.bat b/gradlew.bat index 24c62d56f2..a51ec4f588 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -19,7 +19,7 @@ @if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem gradlew startup script for Windows @rem @rem ########################################################################## @@ -72,7 +72,7 @@ echo location of your Java installation. 1>&2 -@rem Execute Gradle +@rem Execute gradlew @rem endlocal doesn't take effect until after the line is parsed and variables are expanded @rem which allows us to clear the local environment before executing the java command endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel From 1a8ed757cd4d6d2e7a6c355de49aec350b17e3ae Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:02:04 +0200 Subject: [PATCH 776/805] [Java] Upgrade to `Gradle` 9.6.1. --- CHANGELOG.adoc | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index e73ab0ef10..93549d2c56 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -5,7 +5,7 @@ * **[Rust]** Inline generated header methods. (https://github.com/aeron-io/simple-binary-encoding/pull/1110[#1110]) * **[Rust]** Add element descriptions to comments. * **[C#]** Seal `PrimitiveValue` and `PrimitiveType`, make `ThrowHelper` static. (https://github.com/aeron-io/simple-binary-encoding/pull/1109[#1109]) -* Upgrade to `Gradle` 9.6.0. +* Upgrade to `Gradle` 9.6.1. * Upgrade to `JUnit` 6.1.0. * Upgrade to `Shadow` 9.4.2. * Upgrade to `jqwik` 1.10.1. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 11cae1e003..8747320212 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-all.zip networkTimeout=10000 retries=0 retryBackOffMs=500 From 5e62b099f57e5cde3690d34144cc789ae46a52a4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:02:23 +0200 Subject: [PATCH 777/805] [Java] Upgrade to `JUint` 6.1.1. --- CHANGELOG.adoc | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 93549d2c56..35c3eff295 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -6,7 +6,7 @@ * **[Rust]** Add element descriptions to comments. * **[C#]** Seal `PrimitiveValue` and `PrimitiveType`, make `ThrowHelper` static. (https://github.com/aeron-io/simple-binary-encoding/pull/1109[#1109]) * Upgrade to `Gradle` 9.6.1. -* Upgrade to `JUnit` 6.1.0. +* Upgrade to `JUnit` 6.1.1. * Upgrade to `Shadow` 9.4.2. * Upgrade to `jqwik` 1.10.1. * Upgrade to `json` 20260522. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d6ffc9f7ac..706e8a1c2b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.10.1" jmh = "1.37" json = "20260522" -junit = "6.1.0" +junit = "6.1.1" mockito = "5.23.0" plexus = "3.3.0" shadow = "9.4.2" From 722d4e32a20e4350137c0e69f5e87e8ac8ad0a6b Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:02:45 +0200 Subject: [PATCH 778/805] [Java] Upgrade to `Shadow` 9.4.3. --- CHANGELOG.adoc | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 35c3eff295..2be155bbef 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -7,7 +7,7 @@ * **[C#]** Seal `PrimitiveValue` and `PrimitiveType`, make `ThrowHelper` static. (https://github.com/aeron-io/simple-binary-encoding/pull/1109[#1109]) * Upgrade to `Gradle` 9.6.1. * Upgrade to `JUnit` 6.1.1. -* Upgrade to `Shadow` 9.4.2. +* Upgrade to `Shadow` 9.4.3. * Upgrade to `jqwik` 1.10.1. * Upgrade to `json` 20260522. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 706e8a1c2b..ee44af3ea9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20260522" junit = "6.1.1" mockito = "5.23.0" plexus = "3.3.0" -shadow = "9.4.2" +shadow = "9.4.3" versions = "0.54.0" [libraries] From 625ccbbce4e4b9ec1b275aeb8060c84f1ee1baac Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:30:28 +0200 Subject: [PATCH 779/805] [Java] Upgrade to `Agrona` 2.5.0. --- CHANGELOG.adoc | 23 ++++++++++++----------- gradle/libs.versions.toml | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 2be155bbef..f986ef19dd 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -5,16 +5,17 @@ * **[Rust]** Inline generated header methods. (https://github.com/aeron-io/simple-binary-encoding/pull/1110[#1110]) * **[Rust]** Add element descriptions to comments. * **[C#]** Seal `PrimitiveValue` and `PrimitiveType`, make `ThrowHelper` static. (https://github.com/aeron-io/simple-binary-encoding/pull/1109[#1109]) -* Upgrade to `Gradle` 9.6.1. -* Upgrade to `JUnit` 6.1.1. -* Upgrade to `Shadow` 9.4.3. -* Upgrade to `jqwik` 1.10.1. -* Upgrade to `json` 20260522. +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.5.0[Agrona 2.5.0]. +* **[Java]** Upgrade to `Gradle` 9.6.1. +* **[Java]** Upgrade to `JUnit` 6.1.1. +* **[Java]** Upgrade to `Shadow` 9.4.3. +* **[Java]** Upgrade to `jqwik` 1.10.1. +* **[Java]** Upgrade to `json` 20260522. == 1.38.1 (2026-04-28) -* Upgrade to `Agrona` 2.4.1. -* Upgrade to `Versions` 0.54.0. +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.4.1[Agrona 2.4.1]. +* **[Java]** Upgrade to `Versions` 0.54.0. == 1.38.0 (2026-04-22) @@ -25,10 +26,10 @@ * **[Rust]** Updated generator to correctly limit length of var data written. (https://github.com/aeron-io/simple-binary-encoding/pull/1096[#1096]) * **[C++]** Protect against a segfault when dealing with empty `std::span` and `std::view`. * **[C++]** mark a generated function SBE_CONSTEXPR (#1055) (#1083) -* Upgrade to `CMake` 4.3.0. -* Upgrade to `Shadow` 9.4.1. -* Upgrade to `Gradle` 9.4.1. -* Upgrade to `Mockito` 5.23.0. +* **[Java]** Upgrade to `CMake` 4.3.0. +* **[Java]** Upgrade to `Shadow` 9.4.1. +* **[Java]** Upgrade to `Gradle` 9.4.1. +* **[Java]** Upgrade to `Mockito` 5.23.0. == 1.37.1 (2026-01-13) * **[Java]** Ensure Java code generation for precedence checks always produces the same code without re-orderings. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ee44af3ea9..da86c24cd3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.4.1" +agrona = "2.5.0" checkstyle = "12.3.1" commons-codec = "1.15" commons-lang3 = "3.8.1" From e773b57cac6b2008ce30dd219a33de49766c6013 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:32:54 +0200 Subject: [PATCH 780/805] 1.39.0 released. --- CHANGELOG.adoc | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index f986ef19dd..195b640ec8 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,6 +1,6 @@ = Changelog -== 1.39.0 (unreleased) +== 1.39.0 (2026-07-03) * **[Rust]** Inline generated header methods. (https://github.com/aeron-io/simple-binary-encoding/pull/1110[#1110]) * **[Rust]** Add element descriptions to comments. diff --git a/version.txt b/version.txt index 40c214a46c..5edffce6d5 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.39.0-SNAPSHOT +1.39.0 From 4f4deee2463c102a7212bd228366a1b601950679 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:33:08 +0200 Subject: [PATCH 781/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 5edffce6d5..69670a655a 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.39.0 +1.40.0-SNAPSHOT From f40cdde6b60745cee572f688ac786cb90074e772 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 6 Jul 2026 11:09:41 +0200 Subject: [PATCH 782/805] [Java] Upgrade to `Shadow` 9.5.0. --- CHANGELOG.adoc | 4 ++++ gradle/libs.versions.toml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 195b640ec8..03b9f3f2de 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,9 @@ = Changelog +== 1.40.0 (unreleased) + +* **[Java]** Upgrade to `Shadow` 9.5.0. + == 1.39.0 (2026-07-03) * **[Rust]** Inline generated header methods. (https://github.com/aeron-io/simple-binary-encoding/pull/1110[#1110]) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index da86c24cd3..ae2ec8e9d8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20260522" junit = "6.1.1" mockito = "5.23.0" plexus = "3.3.0" -shadow = "9.4.3" +shadow = "9.5.0" versions = "0.54.0" [libraries] From 15f2b9c2380b9814d1d0f5ec2ef42e6baf01d78e Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 6 Jul 2026 16:30:53 +0200 Subject: [PATCH 783/805] [Java] Upgrade to `Shadow` 9.5.1. --- CHANGELOG.adoc | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 03b9f3f2de..01b178c5da 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,7 +2,7 @@ == 1.40.0 (unreleased) -* **[Java]** Upgrade to `Shadow` 9.5.0. +* **[Java]** Upgrade to `Shadow` 9.5.1. == 1.39.0 (2026-07-03) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ae2ec8e9d8..273db3db0f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20260522" junit = "6.1.1" mockito = "5.23.0" plexus = "3.3.0" -shadow = "9.5.0" +shadow = "9.5.1" versions = "0.54.0" [libraries] From 10dd521cb195ba60e960c84997a3df41961725fb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 9 Jul 2026 13:15:00 +0200 Subject: [PATCH 784/805] [Java] Fix links to `javadoc.io` to avoid build warnings/failures. --- README.md | 2 +- build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bef8bbff07..bdb0e51ba5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Simple Binary Encoding (SBE) ============================ -[![Javadocs](https://www.javadoc.io/badge/uk.co.real-logic/sbe-tool.svg)](https://www.javadoc.io/doc/uk.co.real-logic/sbe-tool) +[![Javadocs](https://www.javadoc.io/badge/uk.co.real-logic/sbe-tool.svg)](https://www.javadoc.io/static/uk.co.real-logic/sbe-tool) [![GitHub](https://img.shields.io/github/license/aeron-io/simple-binary-encoding.svg)](https://github.com/aeron-io/simple-binary-encoding/blob/master/LICENSE) [![Actions Status](https://github.com/aeron-io/simple-binary-encoding/workflows/Continuous%20Integration/badge.svg)](https://github.com/aeron-io/simple-binary-encoding/actions) diff --git a/build.gradle b/build.gradle index 9a5a9b57d8..4d18230ac7 100644 --- a/build.gradle +++ b/build.gradle @@ -206,7 +206,7 @@ subprojects { options.encoding = 'UTF-8' options.docEncoding = 'UTF-8' options.charSet = 'UTF-8' - options.links("https://www.javadoc.io/doc/org.agrona/agrona/${libs.versions.agrona.get()}/") + options.links("https://www.javadoc.io/static/org.agrona/agrona/${libs.versions.agrona.get()}/") if (isEarlyAccessJavaVersion) { options.links("https://download.java.net/java/early_access/jdk${buildJavaVersion}/docs/api/") } From 9e48af34bfdefb502f66244f40fe8ef5fb82d051 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:15:55 +0200 Subject: [PATCH 785/805] [Java] Upgrade to `Shadow` 9.6.0. --- CHANGELOG.adoc | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 01b178c5da..c5e9614fb1 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,7 +2,7 @@ == 1.40.0 (unreleased) -* **[Java]** Upgrade to `Shadow` 9.5.1. +* **[Java]** Upgrade to `Shadow` 9.6.0. == 1.39.0 (2026-07-03) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 273db3db0f..06d742df4f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20260522" junit = "6.1.1" mockito = "5.23.0" plexus = "3.3.0" -shadow = "9.5.1" +shadow = "9.6.0" versions = "0.54.0" [libraries] From 71c10ebc5a701c35c80e5b23d681248e84072dee Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:16:27 +0200 Subject: [PATCH 786/805] [Java] Apply same `Shadow` config across all projects. --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index 4d18230ac7..e63452a9ef 100644 --- a/build.gradle +++ b/build.gradle @@ -428,6 +428,12 @@ project(':sbe-all') { 'Implementation-Vendor': 'Adaptive Financial Consulting Limited', 'Automatic-Module-Name': 'uk.co.real_logic.sbe.all' ) + + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + mergeServiceFiles() + filesMatching('META-INF/services/**') { + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } } jar.finalizedBy shadowJar From 4d9fb7a3b6031a594e7c33da2e791848b8c86dfa Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 16 Jul 2026 15:17:19 +0200 Subject: [PATCH 787/805] [Java] Upgrade to `JUnit` 6.1.2. --- CHANGELOG.adoc | 1 + gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index c5e9614fb1..4707ae6a8a 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,6 +2,7 @@ == 1.40.0 (unreleased) +* **[Java]** Upgrade to `JUnit` 6.1.2. * **[Java]** Upgrade to `Shadow` 9.6.0. == 1.39.0 (2026-07-03) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 06d742df4f..055ffc156c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.10.1" jmh = "1.37" json = "20260522" -junit = "6.1.1" +junit = "6.1.2" mockito = "5.23.0" plexus = "3.3.0" shadow = "9.6.0" From 44b04492d67aff2cd1fab19da77f365860b1e8c8 Mon Sep 17 00:00:00 2001 From: "amir.langer" Date: Mon, 27 Jul 2026 09:23:05 +0100 Subject: [PATCH 788/805] New agreed Aeron checkstyle and fixes (MissingOverride and NewLineAtEndOfFile). --- config/checkstyle/checkstyle.xml | 11 ++++++++++- .../main/java/uk/co/real_logic/sbe/package-info.java | 2 +- .../real_logic/sbe/examples/ExampleTokenListener.java | 11 +++++++++++ .../uk/co/real_logic/sbe/examples/package-info.java | 2 +- .../uk/co/real_logic/sbe/codec/java/package-info.java | 2 +- .../sbe/generation/TargetCodeGeneratorLoader.java | 5 +++++ .../uk/co/real_logic/sbe/generation/c/CGenerator.java | 1 + .../co/real_logic/sbe/generation/c/package-info.java | 2 +- .../sbe/generation/common/FieldPrecedenceModel.java | 3 +++ .../sbe/generation/cpp/CppDtoGenerator.java | 1 + .../uk/co/real_logic/sbe/generation/cpp/CppDtos.java | 1 + .../real_logic/sbe/generation/cpp/CppGenerator.java | 1 + .../real_logic/sbe/generation/cpp/package-info.java | 2 +- .../co/real_logic/sbe/generation/csharp/CSharp.java | 1 + .../sbe/generation/csharp/CSharpDtoGenerator.java | 1 + .../real_logic/sbe/generation/csharp/CSharpDtos.java | 1 + .../sbe/generation/csharp/CSharpGenerator.java | 1 + .../sbe/generation/csharp/package-info.java | 2 +- .../golang/flyweight/GolangFlyweightGenerator.java | 1 + .../sbe/generation/golang/package-info.java | 2 +- .../sbe/generation/golang/struct/GolangGenerator.java | 1 + .../sbe/generation/java/JavaDtoGenerator.java | 1 + .../co/real_logic/sbe/generation/java/JavaDtos.java | 1 + .../real_logic/sbe/generation/java/JavaGenerator.java | 1 + .../sbe/generation/java/JavaOutputManager.java | 2 ++ .../co/real_logic/sbe/generation/java/JavaUtil.java | 1 + .../real_logic/sbe/generation/java/package-info.java | 2 +- .../uk/co/real_logic/sbe/generation/package-info.java | 2 +- .../real_logic/sbe/generation/rust/package-info.java | 2 +- .../main/java/uk/co/real_logic/sbe/ir/Encoding.java | 1 + .../main/java/uk/co/real_logic/sbe/ir/IrDecoder.java | 1 + .../main/java/uk/co/real_logic/sbe/ir/IrEncoder.java | 1 + .../src/main/java/uk/co/real_logic/sbe/ir/Token.java | 1 + .../java/uk/co/real_logic/sbe/ir/package-info.java | 2 +- .../uk/co/real_logic/sbe/json/JsonTokenListener.java | 11 +++++++++++ .../java/uk/co/real_logic/sbe/json/package-info.java | 2 +- .../co/real_logic/sbe/otf/AbstractTokenListener.java | 11 +++++++++++ .../java/uk/co/real_logic/sbe/otf/package-info.java | 2 +- .../main/java/uk/co/real_logic/sbe/package-info.java | 2 +- .../java/uk/co/real_logic/sbe/xml/CompositeType.java | 2 ++ .../uk/co/real_logic/sbe/xml/EncodedDataType.java | 1 + .../main/java/uk/co/real_logic/sbe/xml/EnumType.java | 3 +++ .../java/uk/co/real_logic/sbe/xml/ErrorHandler.java | 1 + .../src/main/java/uk/co/real_logic/sbe/xml/Field.java | 1 + .../main/java/uk/co/real_logic/sbe/xml/Message.java | 1 + .../real_logic/sbe/xml/SchemaTransformerFactory.java | 1 + .../main/java/uk/co/real_logic/sbe/xml/SetType.java | 3 +++ .../sbe/xml/SinceVersionSchemaTransformer.java | 1 + .../java/uk/co/real_logic/sbe/xml/package-info.java | 2 +- .../uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java | 2 +- .../co/real_logic/sbe/xml/RelativeXIncludeTest.java | 2 +- .../sbe/xml/SchemaTransformerFactoryTest.java | 2 +- 52 files changed, 103 insertions(+), 19 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index a0ad3423a9..355c4ee478 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -25,7 +25,7 @@ - + @@ -33,12 +33,16 @@ + + + + @@ -194,5 +198,10 @@ + + + + + diff --git a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java index 88ae5ee4ba..503fb61954 100644 --- a/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-benchmarks/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -16,4 +16,4 @@ /** * Basic benchmarks for encoding and decoding of messages with SBE. */ -package uk.co.real_logic.sbe; \ No newline at end of file +package uk.co.real_logic.sbe; diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java index 51302141d0..d5ff41086d 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/ExampleTokenListener.java @@ -52,6 +52,7 @@ public ExampleTokenListener(final PrintWriter out) /** * {@inheritDoc} */ + @Override public void onBeginMessage(final Token token) { namedScope.push(token.name() + "."); @@ -60,6 +61,7 @@ public void onBeginMessage(final Token token) /** * {@inheritDoc} */ + @Override public void onEndMessage(final Token token) { namedScope.pop(); @@ -68,6 +70,7 @@ public void onEndMessage(final Token token) /** * {@inheritDoc} */ + @Override public void onEncoding( final Token fieldToken, final DirectBuffer buffer, @@ -87,6 +90,7 @@ public void onEncoding( /** * {@inheritDoc} */ + @Override public void onEnum( final Token fieldToken, final DirectBuffer buffer, @@ -129,6 +133,7 @@ public void onEnum( /** * {@inheritDoc} */ + @Override public void onBitSet( final Token fieldToken, final DirectBuffer buffer, @@ -161,6 +166,7 @@ public void onBitSet( /** * {@inheritDoc} */ + @Override public void onBeginComposite( final Token fieldToken, final List tokens, final int fromIndex, final int toIndex) { @@ -171,6 +177,7 @@ public void onBeginComposite( /** * {@inheritDoc} */ + @Override public void onEndComposite(final Token fieldToken, final List tokens, final int fromIndex, final int toIndex) { --compositeLevel; @@ -180,6 +187,7 @@ public void onEndComposite(final Token fieldToken, final List tokens, fin /** * {@inheritDoc} */ + @Override public void onGroupHeader(final Token token, final int numInGroup) { printScope(); @@ -192,6 +200,7 @@ public void onGroupHeader(final Token token, final int numInGroup) /** * {@inheritDoc} */ + @Override public void onBeginGroup(final Token token, final int groupIndex, final int numInGroup) { namedScope.push(token.name() + "."); @@ -200,6 +209,7 @@ public void onBeginGroup(final Token token, final int groupIndex, final int numI /** * {@inheritDoc} */ + @Override public void onEndGroup(final Token token, final int groupIndex, final int numInGroup) { namedScope.pop(); @@ -208,6 +218,7 @@ public void onEndGroup(final Token token, final int groupIndex, final int numInG /** * {@inheritDoc} */ + @Override public void onVarData( final Token fieldToken, final DirectBuffer buffer, diff --git a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java index 1924360927..b1fc7c8247 100644 --- a/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java +++ b/sbe-samples/src/main/java/uk/co/real_logic/sbe/examples/package-info.java @@ -16,4 +16,4 @@ /** * Samples showing usage of generated codecs and On-The-Fly (OTF) decoding. */ -package uk.co.real_logic.sbe.examples; \ No newline at end of file +package uk.co.real_logic.sbe.examples; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java index a97ba65c46..8c0e70a225 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/codec/java/package-info.java @@ -16,4 +16,4 @@ /** * Annotation for marking the order of groups in generated code to provide metadata. */ -package uk.co.real_logic.sbe.codec.java; \ No newline at end of file +package uk.co.real_logic.sbe.codec.java; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java index db33966a89..4a119a3d6a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/TargetCodeGeneratorLoader.java @@ -48,6 +48,7 @@ public enum TargetCodeGeneratorLoader implements TargetCodeGenerator /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { final JavaOutputManager outputManager = new JavaOutputManager(outputDir, ir.applicableNamespace()); @@ -88,6 +89,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { return new CGenerator(ir, new COutputManager(outputDir, ir.applicableNamespace())); @@ -102,6 +104,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { final NamespaceOutputManager outputManager = new NamespaceOutputManager( @@ -140,6 +143,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { if ("true".equals(System.getProperty(GO_GENERATE_FLYWEIGHTS))) @@ -166,6 +170,7 @@ public CodeGenerator newInstance(final Ir ir, final String outputDir) /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { return new RustGenerator( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java index 427034515d..b6dd9639f3 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/CGenerator.java @@ -125,6 +125,7 @@ List generateTypesToIncludes(final List tokens) /** * {@inheritDoc} */ + @Override public void generate() throws IOException { generateMessageHeaderStub(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java index 5cba823b2d..291771f60b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/c/package-info.java @@ -16,4 +16,4 @@ /** * Generation of codecs for the C programming language. */ -package uk.co.real_logic.sbe.generation.c; \ No newline at end of file +package uk.co.real_logic.sbe.generation.c; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java index e9c8dcc1f9..fc52813d89 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java @@ -616,6 +616,7 @@ public String name() /** * {@inheritDoc}. */ + @Override public int compareTo(final State other) { final int result = Integer.compare(number, other.number); @@ -629,6 +630,7 @@ public int compareTo(final State other) /** * {@inheritDoc} */ + @Override public String toString() { return "State{" + @@ -697,6 +699,7 @@ public String exampleCode() /** * {@inheritDoc} */ + @Override public String toString() { return "Transition{" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java index 8aa13494ad..ca2d09f568 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtoGenerator.java @@ -94,6 +94,7 @@ private String[] fetchTypesPackageName(final Token token, final Ir ir) /** * {@inheritDoc} */ + @Override public void generate() throws IOException { namespaceByType.clear(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java index 1dde335d57..3cd8d2659b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppDtos.java @@ -29,6 +29,7 @@ public class CppDtos implements TargetCodeGenerator /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { return new CppDtoGenerator(ir, false, new NamespaceOutputManager(outputDir, ir.applicableNamespace())); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java index 5d3762c274..f6dbcced9a 100755 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/CppGenerator.java @@ -189,6 +189,7 @@ private List generateTypesToIncludes(final List tokens) /** * {@inheritDoc} */ + @Override public void generate() throws IOException { namespaceByType.clear(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java index 49a0229afc..4c5df2f938 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/cpp/package-info.java @@ -16,4 +16,4 @@ /** * Generation of codecs for the C++ programming language. */ -package uk.co.real_logic.sbe.generation.cpp; \ No newline at end of file +package uk.co.real_logic.sbe.generation.cpp; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java index 5125f79246..3be301705e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharp.java @@ -33,6 +33,7 @@ public class CSharp implements TargetCodeGenerator /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { final boolean shouldSupportTypesPackageNames = Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java index ed55bae37b..0bfcb7763b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtoGenerator.java @@ -95,6 +95,7 @@ private String fetchTypesPackageName(final Token token, final Ir ir) /** * {@inheritDoc} */ + @Override public void generate() throws IOException { packageNameByTypes.clear(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java index ab5b591b48..ee526328b5 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpDtos.java @@ -30,6 +30,7 @@ public class CSharpDtos implements TargetCodeGenerator /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { final boolean shouldSupportTypesPackageNames = Boolean.getBoolean(TYPES_PACKAGE_OVERRIDE); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index d3b063631a..414b68e2a9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -162,6 +162,7 @@ private String fetchTypesPackageName(final Token token, final Ir ir) /** * {@inheritDoc} */ + @Override public void generate() throws IOException { packageNameByTypes.clear(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java index 53c5a9418d..1adec5c7a8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/package-info.java @@ -16,4 +16,4 @@ /** * Generation of codecs for the C# programming language. */ -package uk.co.real_logic.sbe.generation.csharp; \ No newline at end of file +package uk.co.real_logic.sbe.generation.csharp; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java index 8b2d65ab62..30db48127e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java @@ -593,6 +593,7 @@ private void generateTypeStubs() throws IOException /** * {@inheritDoc} */ + @Override public void generate() throws IOException { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java index a11cc42072..5973b8464e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/package-info.java @@ -16,4 +16,4 @@ /** * Generation of codecs for the Go Lang programming language. */ -package uk.co.real_logic.sbe.generation.golang; \ No newline at end of file +package uk.co.real_logic.sbe.generation.golang; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java index d96f4c8e57..b0b33e5c7e 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java @@ -146,6 +146,7 @@ public void generateMessageHeaderStub() throws IOException /** * {@inheritDoc} */ + @Override public void generate() throws IOException { // Add the Marshalling from the big or little endian diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java index d8a4d6f245..dc7ce730f1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtoGenerator.java @@ -100,6 +100,7 @@ private String fetchTypesPackageName(final Token token, final Ir ir) /** * {@inheritDoc} */ + @Override public void generate() throws IOException { generateDtosForTypes(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java index 852e6bdd04..a1df9d2e8b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaDtos.java @@ -30,6 +30,7 @@ public class JavaDtos implements TargetCodeGenerator /** * {@inheritDoc} */ + @Override public CodeGenerator newInstance(final Ir ir, final String outputDir) { return new JavaDtoGenerator( diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java index 4e48e9bd08..7c14607d6a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java @@ -250,6 +250,7 @@ private String registerTypesPackageName(final Token token, final Ir ir) /** * {@inheritDoc} */ + @Override public void generate() throws IOException { packageNameByTypes.clear(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java index 51817dc04c..029bccdfb6 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaOutputManager.java @@ -51,6 +51,7 @@ public JavaOutputManager(final String baseDirName, final String packageName) /** * {@inheritDoc} */ + @Override public void setPackageName(final String packageName) { actingPackageOutputManager = outputManagerByPackageName.get(packageName); @@ -69,6 +70,7 @@ private void resetPackage() /** * {@inheritDoc} */ + @Override public Writer createOutput(final String name) throws IOException { return new FilterWriter(actingPackageOutputManager.createOutput(name)) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java index e8e6808c01..680bc02c76 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaUtil.java @@ -69,6 +69,7 @@ void appendToGeneratedBuilder(final StringBuilder builder, final String indent) /** * {@inheritDoc} */ + @Override public String toString() { return String.valueOf(symbol); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java index ee4ebf09fc..a53e241dd0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/package-info.java @@ -16,4 +16,4 @@ /** * Generation of codecs for the Java programming language. */ -package uk.co.real_logic.sbe.generation.java; \ No newline at end of file +package uk.co.real_logic.sbe.generation.java; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java index 2c9b0501aa..bbb33505cf 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/package-info.java @@ -16,4 +16,4 @@ /** * Codec generators for various programming languages which take {@link uk.co.real_logic.sbe.ir.Ir} as input. */ -package uk.co.real_logic.sbe.generation; \ No newline at end of file +package uk.co.real_logic.sbe.generation; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java index 2c817689c3..399b4c1db1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/package-info.java @@ -16,4 +16,4 @@ /** * Generation of codecs for the Rust programming language. */ -package uk.co.real_logic.sbe.generation.rust; \ No newline at end of file +package uk.co.real_logic.sbe.generation.rust; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java index 0a7b332130..7817b11694 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Encoding.java @@ -271,6 +271,7 @@ public String semanticType() /** * {@inheritDoc} */ + @Override public String toString() { return diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index 7bd1ed693d..72ff961276 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -100,6 +100,7 @@ public IrDecoder(final ByteBuffer buffer) /** * {@inheritDoc} */ + @Override public void close() { CloseHelper.quietClose(channel); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java index ad5888b95a..ba3a2bfa2b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java @@ -95,6 +95,7 @@ public IrEncoder(final ByteBuffer buffer, final Ir ir) /** * {@inheritDoc} */ + @Override public void close() { CloseHelper.quietClose(channel); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java index 7ea00920c0..8fb58cf703 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/Token.java @@ -352,6 +352,7 @@ public boolean isOptionalEncoding() /** * {@inheritDoc} */ + @Override public String toString() { return "Token{" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java index f317c5e7f3..691b15ef2f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/package-info.java @@ -17,4 +17,4 @@ * Intermediate Representation for the parsed XML message schema which can be used for generating codecs or * performing OTF decoding. */ -package uk.co.real_logic.sbe.ir; \ No newline at end of file +package uk.co.real_logic.sbe.ir; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java index 18001ae9fa..cb7c87e1c0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/JsonTokenListener.java @@ -50,6 +50,7 @@ public JsonTokenListener(final StringBuilder output) /** * {@inheritDoc} */ + @Override public void onBeginMessage(final Token token) { startObject(); @@ -58,6 +59,7 @@ public void onBeginMessage(final Token token) /** * {@inheritDoc} */ + @Override public void onEndMessage(final Token token) { endObject(); @@ -66,6 +68,7 @@ public void onEndMessage(final Token token) /** * {@inheritDoc} */ + @Override public void onEncoding( final Token fieldToken, final DirectBuffer buffer, @@ -81,6 +84,7 @@ public void onEncoding( /** * {@inheritDoc} */ + @Override public void onEnum( final Token fieldToken, final DirectBuffer buffer, @@ -122,6 +126,7 @@ public void onEnum( /** * {@inheritDoc} */ + @Override public void onBitSet( final Token fieldToken, final DirectBuffer buffer, @@ -158,6 +163,7 @@ public void onBitSet( /** * {@inheritDoc} */ + @Override public void onBeginComposite( final Token fieldToken, final List tokens, final int fromIndex, final int toIndex) { @@ -170,6 +176,7 @@ public void onBeginComposite( /** * {@inheritDoc} */ + @Override public void onEndComposite( final Token fieldToken, final List tokens, final int fromIndex, final int toIndex) { @@ -180,6 +187,7 @@ public void onEndComposite( /** * {@inheritDoc} */ + @Override public void onGroupHeader(final Token token, final int numInGroup) { property(token.name()); @@ -196,6 +204,7 @@ public void onGroupHeader(final Token token, final int numInGroup) /** * {@inheritDoc} */ + @Override public void onBeginGroup(final Token token, final int groupIndex, final int numInGroup) { startObject(); @@ -204,6 +213,7 @@ public void onBeginGroup(final Token token, final int groupIndex, final int numI /** * {@inheritDoc} */ + @Override public void onEndGroup(final Token token, final int groupIndex, final int numInGroup) { endObject(); @@ -217,6 +227,7 @@ public void onEndGroup(final Token token, final int groupIndex, final int numInG /** * {@inheritDoc} */ + @Override public void onVarData( final Token fieldToken, final DirectBuffer buffer, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java index 476fe58c1c..c007499288 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/json/package-info.java @@ -16,4 +16,4 @@ /** * An OTF decoder for decoding and printing messages in JSON format. */ -package uk.co.real_logic.sbe.json; \ No newline at end of file +package uk.co.real_logic.sbe.json; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java index 1422092ba1..bb45ad2a88 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/AbstractTokenListener.java @@ -31,6 +31,7 @@ public abstract class AbstractTokenListener implements TokenListener /** * {@inheritDoc} */ + @Override public void onBeginMessage(final Token token) { // no op @@ -39,6 +40,7 @@ public void onBeginMessage(final Token token) /** * {@inheritDoc} */ + @Override public void onEndMessage(final Token token) { // no op @@ -47,6 +49,7 @@ public void onEndMessage(final Token token) /** * {@inheritDoc} */ + @Override public void onEncoding( final Token fieldToken, final DirectBuffer buffer, @@ -60,6 +63,7 @@ public void onEncoding( /** * {@inheritDoc} */ + @Override public void onEnum( final Token fieldToken, final DirectBuffer buffer, @@ -75,6 +79,7 @@ public void onEnum( /** * {@inheritDoc} */ + @Override public void onBitSet( final Token fieldToken, final DirectBuffer buffer, @@ -90,6 +95,7 @@ public void onBitSet( /** * {@inheritDoc} */ + @Override public void onBeginComposite( final Token fieldToken, final List tokens, final int fromIndex, final int toIndex) { @@ -99,6 +105,7 @@ public void onBeginComposite( /** * {@inheritDoc} */ + @Override public void onEndComposite( final Token fieldToken, final List tokens, final int fromIndex, final int toIndex) { @@ -108,6 +115,7 @@ public void onEndComposite( /** * {@inheritDoc} */ + @Override public void onGroupHeader(final Token token, final int numInGroup) { // no op @@ -116,6 +124,7 @@ public void onGroupHeader(final Token token, final int numInGroup) /** * {@inheritDoc} */ + @Override public void onBeginGroup(final Token token, final int groupIndex, final int numInGroup) { // no op @@ -124,6 +133,7 @@ public void onBeginGroup(final Token token, final int groupIndex, final int numI /** * {@inheritDoc} */ + @Override public void onEndGroup(final Token token, final int groupIndex, final int numInGroup) { // no op @@ -132,6 +142,7 @@ public void onEndGroup(final Token token, final int groupIndex, final int numInG /** * {@inheritDoc} */ + @Override public void onVarData( final Token fieldToken, final DirectBuffer buffer, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java index 04cf0dddd4..7515e0baee 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/otf/package-info.java @@ -16,4 +16,4 @@ /** * On-The-Fly (OTF) decoding of messages based on {@link uk.co.real_logic.sbe.ir.Ir} using a visitor pattern. */ -package uk.co.real_logic.sbe.otf; \ No newline at end of file +package uk.co.real_logic.sbe.otf; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java index fd30d70f78..0663eec56a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/package-info.java @@ -16,4 +16,4 @@ /** * SBE Tool for generating encoders and decoders in multiple languages. */ -package uk.co.real_logic.sbe; \ No newline at end of file +package uk.co.real_logic.sbe; diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java index 37b8b0e808..9fc1b478f0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/CompositeType.java @@ -388,6 +388,7 @@ public void checkForValidOffsets(final Node node) /** * {@inheritDoc} */ + @Override public boolean isVariableLength() { return false; @@ -499,6 +500,7 @@ private Type addType(final Node subTypeNode, final String name, final Type type) /** * {@inheritDoc} */ + @Override public String toString() { return "CompositeType{" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java index 0239e864ec..e0f0443bc8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EncodedDataType.java @@ -422,6 +422,7 @@ private PrimitiveValue processConstantChar(final Node node, final String lengthA /** * {@inheritDoc} */ + @Override public String toString() { return "EncodedDataType{" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java index bedafa57b3..045801a669 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/EnumType.java @@ -233,6 +233,7 @@ public Collection validValues() /** * {@inheritDoc} */ + @Override public boolean isVariableLength() { return false; @@ -241,6 +242,7 @@ public boolean isVariableLength() /** * {@inheritDoc} */ + @Override public String toString() { return "EnumType{" + @@ -332,6 +334,7 @@ public int deprecated() /** * {@inheritDoc} */ + @Override public String toString() { return "ValidValue{" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java index ceb020e85b..f0fa5b0d1f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/ErrorHandler.java @@ -135,6 +135,7 @@ public int warningCount() /** * {@inheritDoc} */ + @Override public String toString() { return "ErrorHandler{" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java index aa91b6ff31..7382646a5f 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Field.java @@ -380,6 +380,7 @@ public String timeUnit() /** * {@inheritDoc} */ + @Override public String toString() { return "Field{name='" + name + '\'' + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java index 9fbdfc7789..0a3886a435 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/Message.java @@ -479,6 +479,7 @@ private static void validateBlockLength( /** * {@inheritDoc} */ + @Override public String toString() { return "Message{" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java index 7b0e678c88..7ae28dfa5d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java @@ -41,6 +41,7 @@ public SchemaTransformerFactory(final String schemaTransformConfig) /** * {@inheritDoc} */ + @Override public MessageSchema transform(final MessageSchema originalSchema) { return transformer.transform(originalSchema); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java index 467ac93b80..9c2763ffae 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java @@ -180,6 +180,7 @@ public Collection choices() *

      * {@inheritDoc} */ + @Override public boolean isVariableLength() { return false; @@ -188,6 +189,7 @@ public boolean isVariableLength() /** * {@inheritDoc} */ + @Override public String toString() { return "SetType{" + @@ -284,6 +286,7 @@ public int deprecated() /** * {@inheritDoc} */ + @Override public String toString() { return "Choice{" + diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java index a5d876baab..ae161c164b 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java @@ -29,6 +29,7 @@ class SinceVersionSchemaTransformer implements SchemaTransformer /** * {@inheritDoc} */ + @Override public MessageSchema transform(final MessageSchema originalSchema) { final Collection types = originalSchema.types(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java index 7c0ead4286..1b7bcb8c2c 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/package-info.java @@ -16,4 +16,4 @@ /** * Parser and types for the XML based messages schemas. */ -package uk.co.real_logic.sbe.xml; \ No newline at end of file +package uk.co.real_logic.sbe.xml; diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java index 09ff6834e4..992ba63e8f 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/BasicSchemaFileTest.java @@ -78,4 +78,4 @@ void shouldHandleBasicAllTypes() throws Exception assertThat(fields.get(4).name(), is("int64Field")); } } -} \ No newline at end of file +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java index c710b46e04..4643bbd9da 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/RelativeXIncludeTest.java @@ -39,4 +39,4 @@ void shouldParseFileInSubDir() throws Exception assertNotNull(messageSchema.getType("Symbol")); } -} \ No newline at end of file +} diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java index d92183e2d0..efab1bc608 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java @@ -64,4 +64,4 @@ void shouldHandleMultiSchemaTransformation() (SinceVersionSchemaTransformer)transformer.lookupTransformer(89732465); assertEquals(5, schemaTransformerDefault.sinceVersion()); } -} \ No newline at end of file +} From 5d5ff493e054b96bed6ce1c2c0ea9fdafdd00d68 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:25:55 +0200 Subject: [PATCH 789/805] [Java] Upgrade to `Versions` 0.61.0. --- CHANGELOG.adoc | 6 ++++-- gradle/libs.versions.toml | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 4707ae6a8a..bef7f6f04f 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,8 +2,10 @@ == 1.40.0 (unreleased) -* **[Java]** Upgrade to `JUnit` 6.1.2. -* **[Java]** Upgrade to `Shadow` 9.6.0. +* **[Java]** Upgrade to `Gradle` 9.7.0. +* **[Java]** Upgrade to `JUnit` 6.1.3. +* **[Java]** Upgrade to `Shadow` 9.6.1. +* **[Java]** Upgrade to `Versions` 0.61.0. == 1.39.0 (2026-07-03) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 055ffc156c..3961afd42e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ junit = "6.1.2" mockito = "5.23.0" plexus = "3.3.0" shadow = "9.6.0" -versions = "0.54.0" +versions = "0.61.0" [libraries] agrona = { group = "org.agrona", name = "agrona", version.ref = "agrona" } @@ -30,4 +30,4 @@ plexus-utils = { group = "org.codehaus.plexus", name = "plexus-utils", version.r [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } -versions = { id = "com.github.ben-manes.versions", version.ref = "versions" } +versions = { id = "io.github.ben-manes.versions", version.ref = "versions" } From a6eba5471404f2a7538c56bfe031743088e8f1bc Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:26:12 +0200 Subject: [PATCH 790/805] [Java] Upgrade to `JUnit` 6.1.3. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3961afd42e..9139c8245f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.10.1" jmh = "1.37" json = "20260522" -junit = "6.1.2" +junit = "6.1.3" mockito = "5.23.0" plexus = "3.3.0" shadow = "9.6.0" From 205808ab8a05144a5c00c330fb9bdf59b73287da Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:26:28 +0200 Subject: [PATCH 791/805] [Java] Upgrade to `Shadow` 9.6.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9139c8245f..f7f892363b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20260522" junit = "6.1.3" mockito = "5.23.0" plexus = "3.3.0" -shadow = "9.6.0" +shadow = "9.6.1" versions = "0.61.0" [libraries] From 0c0a474f1ae34295873b304dde46672bde8ee38c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:26:49 +0200 Subject: [PATCH 792/805] [Java] Upgrade to `Gradle` 9.7.0. --- gradle/wrapper/gradle-wrapper.jar | Bin 48462 -> 47505 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index b1b8ef56b44f16b14dc800fa8103a6d89abb526f..eddabd2eef8d94a5437d6168ff9c87a78ff725b3 100644 GIT binary patch delta 39079 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 F{Rc_uT_ykk delta 40101 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8747320212..c6f915a79d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-all.zip networkTimeout=10000 retries=0 retryBackOffMs=500 From 7f828bc934a08a49597383815baf0cdea6beab05 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:27:53 +0200 Subject: [PATCH 793/805] [Java] Upgrade to `json` 20260814. --- CHANGELOG.adoc | 1 + gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index bef7f6f04f..fe6c691165 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -3,6 +3,7 @@ == 1.40.0 (unreleased) * **[Java]** Upgrade to `Gradle` 9.7.0. +* **[Java]** Upgrade to `json` 20260814. * **[Java]** Upgrade to `JUnit` 6.1.3. * **[Java]** Upgrade to `Shadow` 9.6.1. * **[Java]** Upgrade to `Versions` 0.61.0. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f7f892363b..1b9d098da7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hamcrest = "3.0" httpcore = "4.4.14" jqwik = "1.10.1" jmh = "1.37" -json = "20260522" +json = "20260814" junit = "6.1.3" mockito = "5.23.0" plexus = "3.3.0" From c30680a3bb0ad59f22a7387612ddda19548130f5 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:03:13 +0200 Subject: [PATCH 794/805] [Java] Upgrade to `Gradle` 9.7.1. --- CHANGELOG.adoc | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index fe6c691165..47aa8e26c1 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,7 +2,7 @@ == 1.40.0 (unreleased) -* **[Java]** Upgrade to `Gradle` 9.7.0. +* **[Java]** Upgrade to `Gradle` 9.7.1. * **[Java]** Upgrade to `json` 20260814. * **[Java]** Upgrade to `JUnit` 6.1.3. * **[Java]** Upgrade to `Shadow` 9.6.1. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c6f915a79d..8c15739002 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-all.zip networkTimeout=10000 retries=0 retryBackOffMs=500 From 73101496c1f050ca7af6cc04a81cb1e80f5525a3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:03:51 +0200 Subject: [PATCH 795/805] [Java] Upgrade to `Agrona` 2.6.0. --- CHANGELOG.adoc | 1 + gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 47aa8e26c1..106cde87ff 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,6 +2,7 @@ == 1.40.0 (unreleased) +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.6.0[Agrona 2.6.0]. * **[Java]** Upgrade to `Gradle` 9.7.1. * **[Java]** Upgrade to `json` 20260814. * **[Java]** Upgrade to `JUnit` 6.1.3. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1b9d098da7..dc7d6adc01 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.5.0" +agrona = "2.6.0" checkstyle = "12.3.1" commons-codec = "1.15" commons-lang3 = "3.8.1" From 4f8d88f77baf8fb31c68b01829a05921ade35a98 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Fri, 21 Aug 2026 13:43:41 +1200 Subject: [PATCH 796/805] 1.40.0 release --- CHANGELOG.adoc | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 106cde87ff..19e60b33ac 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,6 +1,6 @@ = Changelog -== 1.40.0 (unreleased) +== 1.40.0 (2026-08-21) * **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.6.0[Agrona 2.6.0]. * **[Java]** Upgrade to `Gradle` 9.7.1. diff --git a/version.txt b/version.txt index 69670a655a..32b7211cb6 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.40.0-SNAPSHOT +1.40.0 From aeeb8d41ce3eaf796092adca1661e278c5a24c13 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Fri, 21 Aug 2026 13:46:06 +1200 Subject: [PATCH 797/805] 1.41.0 snapshot --- CHANGELOG.adoc | 2 ++ version.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 19e60b33ac..43cc78a1e9 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,7 @@ = Changelog +== 1.41.0 (unreleased) + == 1.40.0 (2026-08-21) * **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.6.0[Agrona 2.6.0]. diff --git a/version.txt b/version.txt index 32b7211cb6..263ee2cdaa 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.40.0 +1.41.0-SNAPSHOT From b18882a6db7ebd46d0c17eeeec6e5af0f8dbb40f Mon Sep 17 00:00:00 2001 From: raphaelroshan <49832307+raphaelroshan@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:36:37 +0800 Subject: [PATCH 798/805] [Java] Reject negative choice values in SetType. (#1112) A value is a bit position and must be in [0, size * 8). The bounds check only guarded the upper limit, so a negative value passed validation and was later emitted as a shift amount in generated code, where 1 << -1 is silently masked to 1 << 31 -- producing wrong encode/decode masking for an invalid schema. Reject negative values too. --- .../java/uk/co/real_logic/sbe/xml/SetType.java | 2 +- .../uk/co/real_logic/sbe/xml/SetTypeTest.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java index 9c2763ffae..b3249e3bb1 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SetType.java @@ -225,7 +225,7 @@ public Choice(final Node node, final PrimitiveType encodingType) deprecated = Integer.parseInt(getAttributeValue(node, "deprecated", "0")); // choice values are bit positions (0, 1, 2, 3, 4, etc.) from LSB to MSB - if (value.longValue() >= (encodingType.size() * 8L)) + if (value.longValue() < 0 || value.longValue() >= (encodingType.size() * 8L)) { throw new IllegalArgumentException("Choice value out of bounds: " + value.longValue()); } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java index 60d09daa15..fcaf2a020b 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SetTypeTest.java @@ -175,6 +175,21 @@ void shouldThrowExceptionWhenValueOutOfBoundsSpecified() parseTestXmlWithMap("/types/set", testXmlString)); } + @Test + void shouldThrowExceptionWhenNegativeValueSpecified() + { + final String testXmlString = + "" + + "" + + " 0" + + " -1" + + "" + + ""; + + assertThrows(IllegalArgumentException.class, () -> + parseTestXmlWithMap("/types/set", testXmlString)); + } + @Test void shouldHandleEncodingTypesWithNamedTypes() throws Exception { From b91a783ee697ec3c6a92e415ecb9faeb2b557e6c Mon Sep 17 00:00:00 2001 From: be0hhh Date: Fri, 21 Aug 2026 13:38:20 +0000 Subject: [PATCH 799/805] [C++] expose schema version from IrDecoder (#1117) --- sbe-tool/src/main/cpp/otf/IrDecoder.h | 6 ++++++ sbe-tool/src/test/cpp/VersionedMessageTest.cpp | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index fb077cb30c..289f5b985e 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -141,6 +141,10 @@ class IrDecoder return m_id; } + int schemaVersion() const { + return m_version; + } + protected: // OS specifics static long long getFileSize(const char *filename) @@ -188,6 +192,7 @@ class IrDecoder std::unique_ptr m_buffer; std::uint64_t m_length = 0; int m_id = 0; + int m_version = 0; int decodeIr() { @@ -221,6 +226,7 @@ class IrDecoder std::uint64_t headerLength = readHeader(offset); m_id = frame.irId(); + m_version = frame.schemaVersion(); offset += headerLength; diff --git a/sbe-tool/src/test/cpp/VersionedMessageTest.cpp b/sbe-tool/src/test/cpp/VersionedMessageTest.cpp index af4a90c442..ceed72059c 100644 --- a/sbe-tool/src/test/cpp/VersionedMessageTest.cpp +++ b/sbe-tool/src/test/cpp/VersionedMessageTest.cpp @@ -16,6 +16,7 @@ #include +#include "otf/IrDecoder.h" #include "versmsg/VersionedMessageV1.h" #include "versmsg/VersionedMessageV2.h" @@ -55,3 +56,12 @@ TEST_F(VersionedMessageTest, shouldV1DecodeV2Message) EXPECT_EQ(m_versionedMessageV1Decoder.decodeLength(), (uint64_t)26); } + +TEST_F(VersionedMessageTest, shouldExposeSchemaVersionFromIr) +{ + IrDecoder irDecoder = {}; + + ASSERT_GE(irDecoder.decode("versioned-message-v2.sbeir"), 0); + EXPECT_EQ(irDecoder.schemaId(), 1); + EXPECT_EQ(irDecoder.schemaVersion(), 2); +} From 3e8f1c0dcbc164e029e665e0bc7c5152d77bbbfc Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:42:56 +0200 Subject: [PATCH 800/805] [Doc] 1.40.1 release notes. --- CHANGELOG.adoc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 43cc78a1e9..0500ac85da 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -2,8 +2,14 @@ == 1.41.0 (unreleased) +== 1.40.1 (2026-08-21) + +* **[Java]** Reject negative choice values in `SetType`. (https://github.com/aeron-io/simple-binary-encoding/pull/1112[#1112]) +* **[C{plus}{plus}]** Expose schema version from `IrDecoder`. (https://github.com/aeron-io/simple-binary-encoding/pull/1117[#1117]). + == 1.40.0 (2026-08-21) +* **[Java]** New agreed Aeron checkstyle and fixes (`MissingOverride` and `NewLineAtEndOfFile`). * **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.6.0[Agrona 2.6.0]. * **[Java]** Upgrade to `Gradle` 9.7.1. * **[Java]** Upgrade to `json` 20260814. @@ -35,8 +41,8 @@ * **[Rust]** Generated encoders now produce fluent interface. (https://github.com/aeron-io/simple-binary-encoding/pull/1097[#1097]) * **[Rust]** Updated some function to `const`. (https://github.com/aeron-io/simple-binary-encoding/pull/1098[#1098]) * **[Rust]** Updated generator to correctly limit length of var data written. (https://github.com/aeron-io/simple-binary-encoding/pull/1096[#1096]) -* **[C++]** Protect against a segfault when dealing with empty `std::span` and `std::view`. -* **[C++]** mark a generated function SBE_CONSTEXPR (#1055) (#1083) +* **[C{plus}{plus}]** Protect against a segfault when dealing with empty `std::span` and `std::view`. +* **[C{plus}{plus}]** mark a generated function SBE_CONSTEXPR (#1055) (#1083) * **[Java]** Upgrade to `CMake` 4.3.0. * **[Java]** Upgrade to `Shadow` 9.4.1. * **[Java]** Upgrade to `Gradle` 9.4.1. From b8855ade64d66482b25724c2084855c6a75e3a85 Mon Sep 17 00:00:00 2001 From: Sebastian Klose Date: Fri, 21 Aug 2026 06:52:25 -0700 Subject: [PATCH 801/805] match fixed length string behavior of java/c++ in go (#1119) Co-authored-by: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> --- CHANGELOG.adoc | 9 +- .../flyweight/src/composite/Composite_test.go | 122 ++++++++++++++++++ gocode/struct/src/baseline/Car_test.go | 99 ++++++++++++++ .../flyweight/GolangFlyweightGenerator.java | 79 +++++++++--- .../golang/struct/GolangGenerator.java | 18 ++- 5 files changed, 309 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 0500ac85da..f5a49cc44e 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -6,6 +6,13 @@ * **[Java]** Reject negative choice values in `SetType`. (https://github.com/aeron-io/simple-binary-encoding/pull/1112[#1112]) * **[C{plus}{plus}]** Expose schema version from `IrDecoder`. (https://github.com/aeron-io/simple-binary-encoding/pull/1117[#1117]). +* **[Go]** Fix padding on fixed length character arrays so they are null padded in the Go flyweight codec, matching +the Java and C{plus}{plus} codecs. Setters now also reject values longer than the field rather than overrunning into +the following field. (https://github.com/aeron-io/simple-binary-encoding/pull/1119[#1119]) +* **[Go]** `RangeCheck` in the Go struct codec no longer rejects null padded fixed length character arrays. `NullValue` +for `char` is `0`, which sits below `MinValue` of `0x20`, so null padding written by any codec previously failed +validation, including when decoding a buffer produced by the Java or C{plus}{plus} codec. +(https://github.com/aeron-io/simple-binary-encoding/pull/1119[#1119]) == 1.40.0 (2026-08-21) @@ -1231,4 +1238,4 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru * Project structure updated to be a Gradle modular build. * RC4 features are available for testing if appropriate RC4 XSD schema is provided or schema validation is turned off. * Generated code is marked with the @Generated annotation. -* C{plus}{plus} updated to C{plus}{plus} 11. \ No newline at end of file +* C{plus}{plus} updated to C{plus}{plus} 11. diff --git a/gocode/flyweight/src/composite/Composite_test.go b/gocode/flyweight/src/composite/Composite_test.go index 20e5c9e757..d7bf75235f 100644 --- a/gocode/flyweight/src/composite/Composite_test.go +++ b/gocode/flyweight/src/composite/Composite_test.go @@ -1,6 +1,7 @@ package composite import ( + "bytes" "testing" ) @@ -50,3 +51,124 @@ func TestEncodeDecode(t *testing.T) { t.Fail() } } + +// wrapDirtyComposite wraps a buffer pre-filled with a non-zero sentinel, so that a setter which fails to pad +// cannot pass by accident on a freshly zeroed buffer. +func wrapDirtyComposite(t *testing.T, data []byte) *Composite { + t.Helper() + + for i := range data { + data[i] = 0xFF + } + + var in Composite + in.WrapForEncode(data, 0, uint64(len(data))) + + return &in +} + +// name is a char[5], so every value shorter than 5 bytes must leave the remainder of the field NUL filled. +func TestSetNamePadsShortStringWithNul(t *testing.T) { + tests := []struct { + value string + expected []byte + }{ + {"start", []byte{'s', 't', 'a', 'r', 't'}}, + {"end", []byte{'e', 'n', 'd', 0, 0}}, + {"a", []byte{'a', 0, 0, 0, 0}}, + {"", []byte{0, 0, 0, 0, 0}}, + } + + for _, test := range tests { + var data [256]byte + point := wrapDirtyComposite(t, data[:]).Start() + + point.SetName(test.value) + + if actual := point.Name(); !bytes.Equal(actual, test.expected) { + t.Errorf("SetName(%q) encoded %v, expected %v", test.value, actual, test.expected) + } + if actual := point.GetNameAsString(); actual != test.value { + t.Errorf("SetName(%q) decoded as %q", test.value, actual) + } + } +} + +// Overwriting a longer value with a shorter one must not leave the tail of the previous value behind. +func TestSetNameOverwriteDoesNotLeakPreviousValue(t *testing.T) { + var data [256]byte + point := wrapDirtyComposite(t, data[:]).Start() + + point.SetName("start") + point.SetName("end") + + if actual := point.GetNameAsString(); actual != "end" { + t.Errorf("expected \"end\" after overwrite, got %q", actual) + } + if actual := point.Name(); !bytes.Equal(actual, []byte{'e', 'n', 'd', 0, 0}) { + t.Errorf("stale bytes left after overwrite: %v", actual) + } +} + +// PutName shares the padding contract with SetName so the invariant holds whichever setter is used. +func TestPutNamePadsShortValueWithNul(t *testing.T) { + var data [256]byte + point := wrapDirtyComposite(t, data[:]).Start() + + point.PutName([]byte("start")) + point.PutName([]byte("end")) + + if actual := point.Name(); !bytes.Equal(actual, []byte{'e', 'n', 'd', 0, 0}) { + t.Errorf("PutName left stale bytes: %v", actual) + } +} + +// A value longer than the field must be rejected rather than overrun into the following field, matching the +// Java and C++ codecs which throw. +func TestSetNameTooLongPanics(t *testing.T) { + var data [256]byte + point := wrapDirtyComposite(t, data[:]).Start() + + defer func() { + if recover() == nil { + t.Error("expected SetName to panic for a value longer than the field") + } + }() + + point.SetName("toolong") +} + +func TestPutNameTooLongPanics(t *testing.T) { + var data [256]byte + point := wrapDirtyComposite(t, data[:]).Start() + + defer func() { + if recover() == nil { + t.Error("expected PutName to panic for a value longer than the field") + } + }() + + point.PutName([]byte("toolong")) +} + +// The padding must stop at the end of the field and not spill into whatever follows it. +func TestSetNamePaddingDoesNotDisturbAdjacentFields(t *testing.T) { + var data [256]byte + in := wrapDirtyComposite(t, data[:]) + + in.Start().SetName("end").SetD(3.14).SetI(7) + in.End().SetName("x") + + if actual := in.Start().GetNameAsString(); actual != "end" { + t.Errorf("start.name corrupted: %q", actual) + } + if actual := in.Start().D(); actual != 3.14 { + t.Errorf("start.d corrupted by name setter: %v", actual) + } + if actual := in.Start().I(); actual != 7 { + t.Errorf("start.i corrupted by name setter: %v", actual) + } + if actual := in.End().GetNameAsString(); actual != "x" { + t.Errorf("end.name corrupted: %q", actual) + } +} diff --git a/gocode/struct/src/baseline/Car_test.go b/gocode/struct/src/baseline/Car_test.go index f0e601dd21..61f368620a 100644 --- a/gocode/struct/src/baseline/Car_test.go +++ b/gocode/struct/src/baseline/Car_test.go @@ -137,3 +137,102 @@ func TestDecodeJavaBuffer(t *testing.T) { // fmt.Println(c) return } + +// newRangeCheckableCar builds a Car that passes RangeCheck, so that tests below can vary a single +// character array and attribute any failure to that field alone. +func newRangeCheckableCar(vehicleCode [6]byte, manufacturerCode [3]byte) Car { + var optionalExtras [8]bool + optionalExtras[OptionalExtrasChoice.CruiseControl] = true + + engine := Engine{2000, 4, 0, manufacturerCode, [6]byte{}, 42, BooleanType.T, + EngineBooster{BoostType.NITROUS, 200}} + + fuel := []CarFuelFigures{{30, 35.9, []uint8("Urban Cycle")}} + acceleration := []CarPerformanceFiguresAcceleration{{30, 3.8}} + performance := []CarPerformanceFigures{{95, acceleration}} + + return Car{1234, 2013, BooleanType.T, Model.A, [4]uint32{0, 1, 2, 3}, vehicleCode, + optionalExtras, Model.A, engine, fuel, performance, + []uint8("Honda"), []uint8("Civic VTi"), []uint8("deadbeef")} +} + +func makeVehicleCode(value string) [6]byte { + var code [6]byte + copy(code[:], value) + + return code +} + +// vehicleCode is a char[6]. NUL is the pad byte written by the Java, C++ and Go flyweight codecs, and is +// also what the idiomatic `copy` into a zeroed Go array leaves behind, so RangeCheck has to accept it. +// Space padding must keep working, and genuinely out of range bytes must still be rejected. +func TestRangeCheckAcceptsPaddedCharArrays(t *testing.T) { + var manufacturerCode [3]byte + copy(manufacturerCode[:], "123") + + tests := []struct { + name string + code [6]byte + wantError bool + }{ + {"exact length", makeVehicleCode("abcdef"), false}, + {"NUL padded", makeVehicleCode("abc"), false}, + {"space padded", makeVehicleCode("abc "), false}, + {"all NUL", makeVehicleCode(""), false}, + {"all space", makeVehicleCode(" "), false}, + {"below range", [6]byte{'a', 'b', 'c', 0x01, 0, 0}, true}, + {"above range", [6]byte{'a', 'b', 'c', 0x7F, 0, 0}, true}, + } + + for _, test := range tests { + c := newRangeCheckableCar(test.code, manufacturerCode) + err := c.RangeCheck(c.SbeSchemaVersion(), c.SbeSchemaVersion()) + + if test.wantError && err == nil { + t.Errorf("%s (%q): expected RangeCheck to fail, got nil", test.name, test.code) + } + if !test.wantError && err != nil { + t.Errorf("%s (%q): expected RangeCheck to pass, got %v", test.name, test.code, err) + } + } +} + +// A NUL padded char array must survive a round trip with range checking enabled at both ends. +func TestEncodeDecodeNulPaddedCharArray(t *testing.T) { + var manufacturerCode [3]byte + copy(manufacturerCode[:], "12") + + in := newRangeCheckableCar(makeVehicleCode("abc"), manufacturerCode) + + m := NewSbeGoMarshaller() + buf := new(bytes.Buffer) + if err := in.Encode(m, buf, true); err != nil { + t.Fatalf("Encode with range check failed: %v", err) + } + + var out Car + if err := out.Decode(m, buf, in.SbeSchemaVersion(), in.SbeBlockLength(), true); err != nil { + t.Fatalf("Decode with range check failed: %v", err) + } + + if in.VehicleCode != out.VehicleCode { + t.Errorf("VehicleCode round trip: encoded %q, decoded %q", in.VehicleCode, out.VehicleCode) + } + if in.Engine.ManufacturerCode != out.Engine.ManufacturerCode { + t.Errorf("ManufacturerCode round trip: encoded %q, decoded %q", + in.Engine.ManufacturerCode, out.Engine.ManufacturerCode) + } +} + +// The NullValue escape must apply only to character arrays; numeric arrays keep strict range checking. +func TestRangeCheckStillStrictForNumericArrays(t *testing.T) { + var manufacturerCode [3]byte + copy(manufacturerCode[:], "123") + + c := newRangeCheckableCar(makeVehicleCode("abcdef"), manufacturerCode) + c.SomeNumbers[2] = c.SomeNumbersMaxValue() + 1 + + if err := c.RangeCheck(c.SbeSchemaVersion(), c.SbeSchemaVersion()); err == nil { + t.Error("expected RangeCheck to reject an out of range uint32 array element, got nil") + } +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java index 30db48127e..0d12e794af 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java @@ -1855,14 +1855,22 @@ private void generateArrayProperty( offset, formatClassName(containingClassName)); - new Formatter(sb).format("\n" + - indent + "func (m *%1$s) Put%2$s(src []byte) *%1$s {\n" + - indent + " copy(m.buffer[(m.offset+%3$d):], src)\n" + - indent + " return m\n" + - indent + "}\n", - formatClassName(containingClassName), - formatPropertyName(propertyName), - offset); + if (primitiveType == PrimitiveType.CHAR) + { + generateNullPaddedSetter( + sb, containingClassName, "Put", propertyName, "[]byte", offset, arrayLength, indent); + } + else + { + new Formatter(sb).format("\n" + + indent + "func (m *%1$s) Put%2$s(src []byte) *%1$s {\n" + + indent + " copy(m.buffer[(m.offset+%3$d):], src)\n" + + indent + " return m\n" + + indent + "}\n", + formatClassName(containingClassName), + formatPropertyName(propertyName), + offset); + } if (arrayLength > 1 && arrayLength <= 4) { @@ -1922,17 +1930,56 @@ private void generateArrayProperty( generateJsonEscapedStringGetter(sb, encodingToken, indent, propertyName, containingClassName); - new Formatter(sb).format("\n" + - indent + "func (m *%1$s) Set%2$s(src string) *%1$s {\n" + - indent + " copy(m.buffer[(m.offset+%3$d):], []byte(src))\n" + - indent + " return m\n" + - indent + "}\n", - formatClassName(containingClassName), - formatPropertyName(propertyName), - offset); + generateNullPaddedSetter( + sb, containingClassName, "Set", propertyName, "string", offset, arrayLength, indent); } } + /** + * Generate a setter for a fixed length character array which pads any unused trailing bytes with NUL, matching + * the Java and C{plus}{plus} codecs. The field is therefore fully defined after the call regardless of what the + * buffer previously held, which is what {@code Get<name>AsString} relies on when it trims at the first NUL. + * + * @param sb to append the generated code to. + * @param containingClassName of the flyweight the setter belongs to. + * @param methodPrefix of the generated method, either {@code Set} or {@code Put}. + * @param propertyName of the field being set. + * @param srcGoType Go type of the source parameter, either {@code string} or {@code []byte}. + * @param offset of the field within the containing block. + * @param arrayLength declared length of the character array. + * @param indent for the generated code. + */ + private void generateNullPaddedSetter( + final StringBuilder sb, + final String containingClassName, + final String methodPrefix, + final String propertyName, + final String srcGoType, + final int offset, + final int arrayLength, + final String indent) + { + new Formatter(sb).format("\n" + + indent + "func (m *%1$s) %2$s%3$s(src %4$s) *%1$s {\n" + + indent + " length := uint64(len(src))\n" + + indent + " if length > %6$d {\n" + + indent + " panic(\"src too large for %2$s%3$s [E106]\")\n" + + indent + " }\n\n" + + indent + " start := m.offset + %5$d\n" + + indent + " copy(m.buffer[start:start+%6$d], src)\n" + + indent + " for i := length; i < %6$d; i++ {\n" + + indent + " m.buffer[start+i] = 0\n" + + indent + " }\n\n" + + indent + " return m\n" + + indent + "}\n", + formatClassName(containingClassName), + methodPrefix, + formatPropertyName(propertyName), + srcGoType, + offset, + arrayLength); + } + private void generateJsonEscapedStringGetter( final StringBuilder sb, final Token token, diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java index b0b33e5c7e..32f61dec82 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/struct/GolangGenerator.java @@ -477,10 +477,26 @@ private void generateRangeCheckPrimitive( imports.peek().add("fmt"); if (token.arrayLength() > 1) { + // A character array holding a value shorter than its declared length is NUL padded by the Java, + // C++ and Go flyweight codecs, and NullValue for CHAR (0) sits below MinValue (0x20), so the pad + // bytes have to be accepted here too. Space padded values are unaffected either way because the + // pad character is itself within Min->Max. + // Structured this way for go fmt sanity on both cases. + final String elementCheck; + if (token.encoding().primitiveType() == PrimitiveType.CHAR) + { + elementCheck = "\t\t\tif %1$s[idx] != %1$sNullValue() && " + + "(%1$s[idx] < %1$sMinValue() || %1$s[idx] > %1$sMaxValue()) {\n"; + } + else + { + elementCheck = "\t\t\tif %1$s[idx] < %1$sMinValue() || %1$s[idx] > %1$sMaxValue() {\n"; + } + sb.append(String.format( "\tif %1$sInActingVersion(actingVersion) {\n" + "\t\tfor idx := 0; idx < %2$s; idx++ {\n" + - "\t\t\tif %1$s[idx] < %1$sMinValue() || %1$s[idx] > %1$sMaxValue() {\n" + + elementCheck + "\t\t\t\treturn fmt.Errorf(\"Range check failed on %1$s[%%d] " + "(%%v < %%v > %%v)\", idx, %1$sMinValue(), %1$s[idx], %1$sMaxValue())\n" + "\t\t\t}\n" + From 2f1c1d3a0b54f1b4f7ac7017346d331882b66bc1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:55:18 +0200 Subject: [PATCH 802/805] Tidy up after #1119. --- .../flyweight/GolangFlyweightGenerator.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java index 0d12e794af..036ffbf7ae 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/golang/flyweight/GolangFlyweightGenerator.java @@ -1935,20 +1935,6 @@ private void generateArrayProperty( } } - /** - * Generate a setter for a fixed length character array which pads any unused trailing bytes with NUL, matching - * the Java and C{plus}{plus} codecs. The field is therefore fully defined after the call regardless of what the - * buffer previously held, which is what {@code Get<name>AsString} relies on when it trims at the first NUL. - * - * @param sb to append the generated code to. - * @param containingClassName of the flyweight the setter belongs to. - * @param methodPrefix of the generated method, either {@code Set} or {@code Put}. - * @param propertyName of the field being set. - * @param srcGoType Go type of the source parameter, either {@code string} or {@code []byte}. - * @param offset of the field within the containing block. - * @param arrayLength declared length of the character array. - * @param indent for the generated code. - */ private void generateNullPaddedSetter( final StringBuilder sb, final String containingClassName, @@ -1959,6 +1945,8 @@ private void generateNullPaddedSetter( final int arrayLength, final String indent) { + // Generate a setter for a fixed length character array which pads any unused trailing bytes with NUL, + // matching the Java and C++ codecs new Formatter(sb).format("\n" + indent + "func (m *%1$s) %2$s%3$s(src %4$s) *%1$s {\n" + indent + " length := uint64(len(src))\n" + From ac796a16fcf7f0b1ab3aeedb94668ac8f34ac6d2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:56:09 +0200 Subject: [PATCH 803/805] 1.40.1 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 263ee2cdaa..53a714f1dd 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.41.0-SNAPSHOT +1.40.1 From d908f362fee24f6e751df965865ae4b2ab6dc345 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:56:21 +0200 Subject: [PATCH 804/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 53a714f1dd..263ee2cdaa 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.40.1 +1.41.0-SNAPSHOT From 7373f23c4c59a178827752d094fc31a90857de8e Mon Sep 17 00:00:00 2001 From: s1amese2003 Date: Sat, 22 Aug 2026 10:42:57 +0000 Subject: [PATCH 805/805] [Rust] Use the schema's null value when generating enums (#1120) The Rust generator emitted the primitive type's default null value for an enum instead of the one declared in the schema, so a uint8 enum encoding that declares nullValue="254" generated NullVal = 0xff_u8. Java, C++ and Go generate 254 for the same schema, so a Rust encoder wrote a null value a peer in another language does not recognise. IrGenerator records the null value on the enum's BEGIN_ENUM token, while the VALID_VALUE tokens carry only byteOrder, primitiveType and constValue. generateEnum read it from messageBody.get(0), a valid value token, so applicableNullValue() fell back to primitiveType.nullValue(). JavaGenerator reads it from tokens.get(0), which is why Java is unaffected. The same mistake appeared in the enum discriminant and in From for . Resolve the null value once and pass it down so the two cannot disagree. optional_enum_nullify.xml already covers an enum with a declared null value, but declares 255, which is also the uint8 default, so it passes either way. The new issue1116 schema declares 254 to separate the two. Resolves #1116 --- build.gradle | 1 + rust/Cargo.toml | 1 + rust/tests/issue_1116_test.rs | 44 +++++++++++++++++++ .../sbe/generation/rust/RustGenerator.java | 16 +++---- sbe-tool/src/test/resources/issue1116.xml | 25 +++++++++++ 5 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 rust/tests/issue_1116_test.rs create mode 100644 sbe-tool/src/test/resources/issue1116.xml diff --git a/build.gradle b/build.gradle index e63452a9ef..28e6d6f3dc 100644 --- a/build.gradle +++ b/build.gradle @@ -682,6 +682,7 @@ tasks.register('generateRustTestCodecs', JavaExec) { 'sbe-tool/src/test/resources/issue1028.xml', 'sbe-tool/src/test/resources/issue1057.xml', 'sbe-tool/src/test/resources/issue1066.xml', + 'sbe-tool/src/test/resources/issue1116.xml', 'sbe-tool/src/test/resources/optional_enum_nullify.xml', 'sbe-tool/src/test/resources/basic-variable-length-schema.xml', 'sbe-tool/src/test/resources/example-bigendian-test-schema.xml', diff --git a/rust/Cargo.toml b/rust/Cargo.toml index df19774eb3..1853a174fc 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -19,6 +19,7 @@ issue_987 = { path = "../generated/rust/issue987" } issue_1028 = { path = "../generated/rust/issue1028" } issue_1057 = { path = "../generated/rust/issue1057" } issue_1066 = { path = "../generated/rust/issue1066" } +issue_1116 = { path = "../generated/rust/issue1116" } baseline_bigendian = { path = "../generated/rust/baseline_bigendian" } nested_composite_name = { path = "../generated/rust/nested_composite_name" } sbe_tests = { path = "../generated/rust/sbe_tests" } diff --git a/rust/tests/issue_1116_test.rs b/rust/tests/issue_1116_test.rs new file mode 100644 index 0000000000..41e08bba2f --- /dev/null +++ b/rust/tests/issue_1116_test.rs @@ -0,0 +1,44 @@ +use issue_1116::{ + foo_bar::FooBar, + issue_1116_codec::{self, Issue1116Decoder, Issue1116Encoder}, + message_header_codec, ReadBuf, WriteBuf, +}; + +/// The schema declares `nullValue="254"` on the type `FooBar` encodes to, so the generated null +/// value has to be 254 rather than the uint8 default of 255. The Java, C++ and Go generators all +/// emit 254 for this schema. +#[test] +fn enum_null_value_comes_from_the_schema() { + // The discriminant, which is what the encoder writes. + assert_eq!(FooBar::NullVal as u8, 254); + + // The `From` conversion, which is generated separately from the discriminant. + assert_eq!(u8::from(FooBar::NullVal), 254); + + assert_eq!(FooBar::from(254), FooBar::NullVal); +} + +/// A peer decoding this message in another language reads the schema's null value off the wire, so +/// that is the byte the Rust encoder has to write. +#[test] +fn encodes_and_decodes_the_schema_null_value() { + let mut buffer = vec![0u8; 256]; + + { + let mut encoder = Issue1116Encoder::default().wrap( + WriteBuf::new(&mut buffer), + message_header_codec::ENCODED_LENGTH, + ); + encoder.foo_bar(FooBar::NullVal); + } + + assert_eq!(buffer[message_header_codec::ENCODED_LENGTH], 254); + + let decoder = Issue1116Decoder::default().wrap( + ReadBuf::new(&buffer), + message_header_codec::ENCODED_LENGTH, + issue_1116_codec::SBE_BLOCK_LENGTH, + 0, + ); + assert_eq!(decoder.foo_bar(), FooBar::NullVal); +} diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java index 628055a3e3..2d6b310e62 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/rust/RustGenerator.java @@ -1615,10 +1615,13 @@ private static void generateEnum( indent(writer, 1, "%s = %s, \n", token.name(), literal); } + // The null value is declared on the enum itself, or on the type it encodes to, so it + // has to be read from the enum token. A valid value token never carries one, which makes + // applicableNullValue() fall back to the primitive type default instead of the schema one. + final CharSequence nullVal = rustNullLiteral(enumTokens.get(0).encoding()); + // null value { - final Encoding encoding = messageBody.get(0).encoding(); - final CharSequence nullVal = rustNullLiteral(encoding); indent(writer, 1, "#[default]\n"); indent(writer, 1, "NullVal = %s, \n", nullVal); } @@ -1628,7 +1631,7 @@ private static void generateEnum( generateFromPrimitiveForEnum(enumRustName, primitiveType, messageBody, writer); // Into impl - generateFromEnumForPrimitive(enumRustName, primitiveType, messageBody, writer); + generateFromEnumForPrimitive(enumRustName, primitiveType, messageBody, nullVal, writer); // FromStr impl generateFromStrImplForEnum(enumRustName, messageBody, writer); @@ -1666,6 +1669,7 @@ private static void generateFromEnumForPrimitive( final String enumRustName, final String primitiveType, final List messageBody, + final CharSequence nullVal, final Appendable writer) throws IOException { indent(writer, 0, "impl From<%s> for %s {\n", enumRustName, primitiveType); @@ -1680,11 +1684,7 @@ private static void generateFromEnumForPrimitive( indent(writer, 3, "%s::%s => %s, \n", enumRustName, token.name(), literal); } - { - final Encoding encoding = messageBody.get(0).encoding(); - final CharSequence nullVal = rustNullLiteral(encoding); - indent(writer, 3, "%s::NullVal => %s,\n", enumRustName, nullVal); - } + indent(writer, 3, "%s::NullVal => %s,\n", enumRustName, nullVal); indent(writer, 2, "}\n"); indent(writer, 1, "}\n"); indent(writer, 0, "}\n"); diff --git a/sbe-tool/src/test/resources/issue1116.xml b/sbe-tool/src/test/resources/issue1116.xml new file mode 100644 index 0000000000..229a76fada --- /dev/null +++ b/sbe-tool/src/test/resources/issue1116.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + 0 + 1 + + + + + +

      eiA2GR@p!BxfkB$9OMKXKst*+I> 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 AyZ`_I diff --git a/sbe-tool/src/test/c/CMakeLists.txt b/sbe-tool/src/test/c/CMakeLists.txt index fab918f0b3..646b9e43c9 100644 --- a/sbe-tool/src/test/c/CMakeLists.txt +++ b/sbe-tool/src/test/c/CMakeLists.txt @@ -16,16 +16,15 @@ function(sbe_test name) add_executable("C${name}" "${name}.cpp") + add_dependencies(C${name} gmock) target_include_directories("C${name}" - PRIVATE ${GTEST_SOURCE_DIR}/googletest/include - PRIVATE ${C_CODEC_TARGET_DIR} + PRIVATE ${C_CODEC_TARGET_DIR} ) target_compile_options("C${name}" PRIVATE $<$:-Werror>) target_compile_options("C${name}" PRIVATE $<$:-Werror>) target_compile_options("C${name}" PRIVATE $<$:-Werror -Wno-maybe-uninitialized>) - target_link_libraries("C${name}" ${GTEST_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries("C${name}" gmock_main ${CMAKE_THREAD_LIBS_INIT}) add_test(NAME C${name} COMMAND C${name} WORKING_DIRECTORY ${C_CODEC_TARGET_DIR}) - add_dependencies(C${name} gtest) if (${ARGC} GREATER 1) add_dependencies(C${name} ${ARGV1}) endif () diff --git a/sbe-tool/src/test/cpp/CMakeLists.txt b/sbe-tool/src/test/cpp/CMakeLists.txt index 06dab75f9b..0137b6de35 100644 --- a/sbe-tool/src/test/cpp/CMakeLists.txt +++ b/sbe-tool/src/test/cpp/CMakeLists.txt @@ -16,17 +16,15 @@ function(sbe_test name) add_executable("${name}" "${name}.cpp") + add_dependencies(${name} gmock) target_include_directories("${name}" - PRIVATE ${GTEST_SOURCE_DIR}/googletest/include - PRIVATE ${GTEST_SOURCE_DIR}/googlemock/include PRIVATE ${CXX_CODEC_TARGET_DIR} ) target_compile_options("${name}" PRIVATE $<$:-Werror>) target_compile_options("${name}" PRIVATE $<$:-Werror>) target_compile_options("${name}" PRIVATE $<$:-Werror>) - target_link_libraries("${name}" sbe ${GTEST_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries("${name}" sbe gmock_main ${CMAKE_THREAD_LIBS_INIT}) add_test(NAME ${name} COMMAND ${name} WORKING_DIRECTORY ${CXX_CODEC_TARGET_DIR}) - add_dependencies(${name} gtest) if (${ARGC} GREATER 1) add_dependencies(${name} ${ARGV1}) endif () From 9296871ab1fa2f95acf0b1e361ec32c0cdcfa6b1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:21:30 +0200 Subject: [PATCH 651/805] [CI] Add `C#` 9 through 13 to the build matrix. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3c08cb75f..f0c40b4609 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: strategy: fail-fast: false matrix: - dotnet: [ '8.0.x' ] + dotnet: [ '8.0.x', '9.0.x', '10.0.x', '11.0.x', '12.0.x', '13.0.x' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 From 473904db59080fc7ba9dd2381f69f5d90db0e360 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:22:34 +0200 Subject: [PATCH 652/805] [CI] Bump `setup-dotnet` to v5. --- .github/workflows/ci.yml | 2 +- .github/workflows/codeql.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0c40b4609..4b960d8b1b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,7 +114,7 @@ jobs: restore-keys: | ${{ runner.os }}-nuget- - name: Setup dotnet - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: ${{ matrix.dotnet }} - name: Build diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4832f66097..05a2b98aa4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -117,7 +117,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Setup dotnet - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: ${{ matrix.dotnet }} From 2429e586a87be8c9b4df079765d19e6711d8e1f6 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:25:54 +0200 Subject: [PATCH 653/805] [CI] Simplify `setup-dotnet` version specification. --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b960d8b1b..4164ffee03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: strategy: fail-fast: false matrix: - dotnet: [ '8.0.x', '9.0.x', '10.0.x', '11.0.x', '12.0.x', '13.0.x' ] + dotnet: [ '8', '9', '10', '11', '12', '13' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 @@ -117,6 +117,7 @@ jobs: uses: actions/setup-dotnet@v5 with: dotnet-version: ${{ matrix.dotnet }} + dotnet-quality: 'ga' - name: Build run: ./csharp/build.sh - name: Run tests From 6c7f2bb42d3b5dfb46e0d4baa00b6875eb8235a1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:31:56 +0200 Subject: [PATCH 654/805] [CI] Remove non-installable .NET versions. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4164ffee03..7560413329 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: strategy: fail-fast: false matrix: - dotnet: [ '8', '9', '10', '11', '12', '13' ] + dotnet: [ '8', '9', '10' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 From c398c8a966f7690d23fa0c7b47baa8b438cc7a2a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:43:36 +0200 Subject: [PATCH 655/805] [CI] Run slow tests using .NET 10. --- .github/workflows/slow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 0e40379a1d..7ff980090d 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -34,7 +34,7 @@ jobs: strategy: matrix: java: [ '25' ] - dotnet: [ '8.0.x' ] + dotnet: [ '10' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 From 8c5c57858eacf5676f6769a08c63620a5b8b4383 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:49:53 +0200 Subject: [PATCH 656/805] [CI] Update actions in the slow build. --- .github/workflows/codeql.yml | 2 +- .github/workflows/slow.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 05a2b98aa4..e4951b67f8 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -83,7 +83,7 @@ jobs: fail-fast: false matrix: language: [ 'csharp' ] - dotnet: [ '8.0.x' ] + dotnet: [ '10' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index 7ff980090d..ae634eb04b 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -40,7 +40,7 @@ jobs: DOTNET_CLI_TELEMETRY_OPTOUT: 1 steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Setup java uses: actions/setup-java@v5 with: @@ -52,14 +52,14 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Setup java to run Gradle script - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - name: Setup dotnet - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v5 with: dotnet-version: ${{ matrix.dotnet }} - name: Build .NET library From d78946a08925a11d8db31531668c1700d053d4b8 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:18:07 +0200 Subject: [PATCH 657/805] [Java] Bump `Gradle` to 9.1.0. --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 --- gradlew.bat | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 48b43d3506..a35649f5fc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index ef07e0162b..adff685a03 100755 --- a/gradlew +++ b/gradlew @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/gradlew.bat b/gradlew.bat index db3a6ac207..c4bdd3ab8e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell From 21ee4a2301d11c2d4b7f509ca36620f8cba75b02 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 22 Sep 2025 10:18:25 +0200 Subject: [PATCH 658/805] [Java] Bump `Mockito` to 5.20.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b241820484..3ab54e41ae 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ jqwik = "1.9.3" jmh = "1.37" json = "20250517" junit = "5.13.4" -mockito = "5.19.0" +mockito = "5.20.0" plexus = "3.3.0" shadow = "9.1.0" versions = "0.52.0" From 7122a817522dfc90ed4a552b2467020a79d669ac Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 11:45:25 +0200 Subject: [PATCH 659/805] [Java] Bump `Versions` to 0.53.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ab54e41ae..f5bfc0788f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ junit = "5.13.4" mockito = "5.20.0" plexus = "3.3.0" shadow = "9.1.0" -versions = "0.52.0" +versions = "0.53.0" [libraries] agrona = { group = "org.agrona", name = "agrona", version.ref = "agrona" } From 6aaa314e3e45af9f198f2e6721df901bfa573b17 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 11:45:40 +0200 Subject: [PATCH 660/805] [Java] Bump `Shadow` to 9.2.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f5bfc0788f..00c6ac6232 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20250517" junit = "5.13.4" mockito = "5.20.0" plexus = "3.3.0" -shadow = "9.1.0" +shadow = "9.2.2" versions = "0.53.0" [libraries] From 08f0a6be9d0fe84d4c0eddb104095457332d20c2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 11:46:02 +0200 Subject: [PATCH 661/805] [Java] Bump `Checkstyle` to 11.1.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 00c6ac6232..14662e3f55 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.2.4" -checkstyle = "11.0.0" +checkstyle = "11.1.0" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From d6e38b3d0d3d3e8cb340e5527e7aee204e222917 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 11:46:14 +0200 Subject: [PATCH 662/805] [Java] Bump `Agrona` to 2.3.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 14662e3f55..559965ee68 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.2.4" +agrona = "2.3.0" checkstyle = "11.1.0" commons-codec = "1.15" commons-lang3 = "3.8.1" From 553afe1a927591a625ac40924d0137237614e1bb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 12:12:39 +0200 Subject: [PATCH 663/805] [Doc] Migrate to AsciiDoc. --- CHANGELOG.adoc | 96 ++++++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 111 ------------------------------------------------- 2 files changed, 96 insertions(+), 111 deletions(-) create mode 100644 CHANGELOG.adoc delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc new file mode 100644 index 0000000000..8b41172297 --- /dev/null +++ b/CHANGELOG.adoc @@ -0,0 +1,96 @@ += Changelog + +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.6[1.35.6] - 2025-06-27 + +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.4[Agrona 2.2.4]. +* **[Java]** Upgrade to `JUnit` 5.13.2. +* **[Java]** Upgrade to `Checkstyle` 10.26.0. +* **[Java]** Upgrade to `Shadow` 8.3.7. + +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.5[1.35.5] - 2025-06-20 + +* **[Java/C{plus}{plus}/C#]** Fix a bug in overzealous DTO validation. (https://github.com/aeron-io/simple-binary-encoding/pull/1073[#1073]) +* **[Java]** Improve JsonPrinter's conformance with the JSON specification (e.g., escaping control characters and using correct delimiters). +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.3[Agrona 2.2.3]. + +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.4[1.35.4] - 2025-06-12 + +* **[Rust]** Return None for optional primite field if its version is less than actingVersion. (https://github.com/aeron-io/simple-binary-encoding/pull/1067[#1067]) +* **[Java]** Adjust Java Dto generateComputeEncodedLength to acount for character encoding. (https://github.com/aeron-io/simple-binary-encoding/pull/1072[#1072]) +* **[Java]** Upgrade to `JUnit` 5.13.1. +* **[Java]** Upgrade to `jqwik` 1.9.3. + +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.3[1.35.3] - 2025-06-06 + +* **[Java]** Publish release artifacts to Central Portal using OSSRH Staging API service. +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.2[Agrona 2.2.2]. +* **[Java]** Upgrade to `Checkstyle` 10.25.0. +* **[Java]** Upgrade to `Gradle` 8.14.2. + +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.1[1.35.1] - 2025-06-02 + +* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.1[Agrona 2.2.1]. +* Upgrade to `JUnit` 5.13.0. + +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.0[1.35.0] - 2025-05-26 + +* **[Java]** include field 'deprecated' in ir encoding and decoding. +* **[Java]** Adjust Java DTO Choice Set Access. (https://github.com/aeron-io/simple-binary-encoding/issues/1064[#1064]) +* **[Rust]** get proper version for composite types. (https://github.com/aeron-io/simple-binary-encoding/pull/1058[#1058]) +* **[C#]** Read NuGet package version from version file (https://github.com/aeron-io/simple-binary-encoding/pull/1061[#1061]) +* **[C#]** Enable dual build for netstandard2.0 & netstandard2.1. (https://github.com/aeron-io/simple-binary-encoding/pull/1062[#1062]) +* Update `Implementation-Vendor`. +* **[Rust]** Elide explicit ActingVersion lifetime. (https://github.com/aeron-io/simple-binary-encoding/pull/1053[#1053]) +* **[CI]** Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. +* **[CI]** Enable JDK 24 GA build. +* **[CI]** Simplify error log upload. +* **[CI]** Remove Ubuntu 20.04 based builds. +* **[CI]** Bump Go build to use 1.23.x and 1.24.x. +* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.0[Agrona 2.2.0]. +* Upgrade to `Gradle` 8.14.1. +* Upgrade to `Checkstyle` 10.24.0. +* Bump `json` to 20250517. +* Upgrade to `JUnit` 5.12.2. +* Upgrade to `Mockito` 5.18.0. +* Upgrade to `Shadow` 8.3.6. +* Bump `Versions` to 0.52. + +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.1[1.34.1] - 2025-01-13 + +* *Doc:* Add `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` to the example execution. +* **[Rust]** encoding primitive arrays now supports slice instead of array (issue https://github.com/aeron-io/simple-binary-encoding/issues/[#1021]). (https://github.com/aeron-io/simple-binary-encoding/pull/1040[#1040]) +* **[C{plus}{plus}]** check for not wrapped state in `decodeLength()` when precedence checks are enabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1046[#1046]) +* **[C{plus}{plus}]** use `m_actingBlockLength` in `decodeLength()`. (https://github.com/aeron-io/simple-binary-encoding/pull/1045[#1045]) +* Bump `json` to 20250107. +* Upgrade to `Mockito` 5.15.2. + +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.0[1.34.0] - 2024-12-17 + +* **[C{plus}{plus}]** hide the m_codecStatePtr behind ifdefs to avoid overhead when precedence checking is disabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1036[#1036]) +* **[C{plus}{plus}]** use constexpr to define precedence checks lookup tables. +* **[Rust]** Enhance enum supporting fromstr and display and into. (https://github.com/aeron-io/simple-binary-encoding/pull/1020[#1020]) +* **[Rust]** codegen of primitive enums now implement 'From' instead of 'Into'. (https://github.com/aeron-io/simple-binary-encoding/pull/1029[#1029]) +* **[Java]** Update Checkstyle rules and apply them. +* *Breaking:* Upgrade to `Agrona` 2.0.0. ++ +_**Note:** `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` JVM option must be specified in order to generate codecs or use the generated Java classes. For example:_ ++ +[source,shell] +---- +$ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=true -Dsbe.target.language=Cpp -Dsbe.target.namespace=sbe -Dsbe.output.dir=include/gen -Dsbe.errorLog=yes -jar sbe-all/build/libs/sbe-all-${SBE_TOOL_VERSION}.jar my-sbe-messages.xml +---- + +* **[C{plus}{plus}]** Fix field precedence check issue https://github.com/aeron-io/simple-binary-encoding/issues/1031[#1031]. (https://github.com/aeron-io/simple-binary-encoding/pull/1033[#1033]) +* **[C{plus}{plus}]** respect the package override option for C{plus}{plus} codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) +* **[C#]** respect the package override option for C# codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) +* **[Go]** Fix warning about used args in GolangFlyweightGenerator. +* **[Rust]** Updated code generator to resolve Issue https://github.com/aeron-io/simple-binary-encoding/issues/1028[#1028]. (https://github.com/aeron-io/simple-binary-encoding/pull/1037[#1037]) +* **[Java]** Prevent collision when field name is 'value'. +* **[Java]** Preserve byte order throughout IR transformations. +* **[C{plus}{plus}]** Integrate std::span support for flyweight API. (https://github.com/aeron-io/simple-binary-encoding/pull/1038[#1038], https://github.com/aeron-io/simple-binary-encoding/pull/1027[#1027]) +* **[Rust]** generate message schema level info in lib.rs. (https://github.com/aeron-io/simple-binary-encoding/pull/1019[#1019]) +* Upgrade to `Gradle` 8.11.1. +* Upgrade to `Checkstyle` 10.21.0. +* Upgrade to `ByteBuddy` 1.15.11. +* Upgrade to `JUnit` 5.11.4. +* Upgrade to `jqwik` 1.9.2. diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b9e90464f5..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,111 +0,0 @@ -# Changelog - -## [1.35.6] - 2025-06-27 -### Changed -* **Java:** Bump `Agrona` to [2.2.4](https://github.com/aeron-io/agrona/releases/tag/2.2.4). -* **Java:** Bump `JUnit` to 5.13.2. -* **Java:** Bump `Checkstyle` to 10.26.0. -* **Java:** Bump `Shadow` to 8.3.7. - -## [1.35.5] - 2025-06-20 -### Changed -* **Java/C++/C#:** Fix a bug in overzealous DTO validation. ([#1073](https://github.com/aeron-io/simple-binary-encoding/pull/1073)) -* **Java:** Improve JsonPrinter's conformance with the JSON specification (e.g., escaping control characters and using correct delimiters). -* **Java:** Bump `Agrona` to 2.2.3. - -## [1.35.4] - 2025-06-12 -### Changed -* **Rust:** Return None for optional primite field if its version is less than actingVersion. ([#1067](https://github.com/aeron-io/simple-binary-encoding/pull/1067)) -* **Java:** Adjust Java Dto generateComputeEncodedLength to acount for character encoding. ([#1072](https://github.com/aeron-io/simple-binary-encoding/pull/1072)) -* **Java:** Bump `JUnit` to 5.13.1. -* **Java:** Bump `jqwik` to 1.9.3. - -## [1.35.3] - 2025-06-06 -### Changed -* **Java:** Publish release artifacts to Central Portal using OSSRH Staging API service. -* **Java:** Bump `Agrona` to 2.2.2. -* **Java:** Bump `Checkstyle` to 10.25.0. -* **Java:** Bump `Gradle` to 8.14.2. - -## [1.35.1] - 2025-06-02 -### Changed -* Bump `Agrona` to 2.2.1. -* Bump `JUnit` to 5.13.0. - -## [1.35.0] - 2025-05-26 -### Changed -* Update `Implementation-Vendor`. -* **Rust:** Elide explicit ActingVersion lifetime. ([#1053](https://github.com/aeron-io/simple-binary-encoding/pull/1053)) -* **CI:** Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. -* **CI:** Enable JDK 24 GA build. -* **CI:** Simplify error log upload. -* **CI:** Remove Ubuntu 20.04 based builds. -* **CI:** Bump Go build to use 1.23.x and 1.24.x. -* Bump `Agrona` to 2.2.0. -* Bump `Gradle` to 8.14.1. -* Bump `Checkstyle` to 10.24.0. -* Bump `json` to 20250517. -* Bump `JUnit` to 5.12.2. -* Bump `Mockito` to 5.18.0. -* Bump `Shadow` to 8.3.6. -* Bump `Versions` to 0.52. - -### Fixed -* **Java:** include field 'deprecated' in ir encoding and decoding. -* **Java:** Adjust Java DTO Choice Set Access. ([#1064](https://github.com/aeron-io/simple-binary-encoding/issues/1064)) -* **Rust:** get proper version for composite types. ([#1058](https://github.com/aeron-io/simple-binary-encoding/pull/1058)) -* **C#:** Read NuGet package version from version file ([#1061](https://github.com/aeron-io/simple-binary-encoding/pull/1061)) -* **C#:** Enable dual build for netstandard2.0 & netstandard2.1. ([#1062](https://github.com/aeron-io/simple-binary-encoding/pull/1062)) - -## [1.34.1] - 2025-01-13 -### Changed -* Bump `json` to 20250107. -* Bump `Mockito` to 5.15.2. - -### Added -* **Doc:** Add `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` to the example execution. -* **Rust:** encoding primitive arrays now supports slice instead of array (issue [#1021](https://github.com/aeron-io/simple-binary-encoding/issues/)). ([#1040](https://github.com/aeron-io/simple-binary-encoding/pull/1040)) - -### Fixed -* **C++:** check for not wrapped state in `decodeLength()` when precedence checks are enabled. ([#1046](https://github.com/aeron-io/simple-binary-encoding/pull/1046)) -* **C++:** use `m_actingBlockLength` in `decodeLength()`. ([#1045](https://github.com/aeron-io/simple-binary-encoding/pull/1045)) - -## [1.34.0] - 2024-12-17 -### Changed -* **C++:** hide the m_codecStatePtr behind ifdefs to avoid overhead when precedence checking is disabled. ([#1036](https://github.com/aeron-io/simple-binary-encoding/pull/1036)) -* **C++:** use constexpr to define precedence checks lookup tables. -* **Rust:** Enhance enum supporting fromstr and display and into. ([#1020](https://github.com/aeron-io/simple-binary-encoding/pull/1020)) -* **Rust:** codegen of primitive enums now implement 'From' instead of 'Into'. ([#1029](https://github.com/aeron-io/simple-binary-encoding/pull/1029)) -* **Java:** Update Checkstyle rules and apply them. -* **Breaking:** Bump `Agrona` to 2.0.0. - _**Note:** `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` JVM option must be specified in order to generate codecs or use the generated Java classes. For example:_ - ```shell - $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=true -Dsbe.target.language=Cpp -Dsbe.target.namespace=sbe -Dsbe.output.dir=include/gen -Dsbe.errorLog=yes -jar sbe-all/build/libs/sbe-all-${SBE_TOOL_VERSION}.jar my-sbe-messages.xml - ``` -* Bump `Gradle` to 8.11.1. -* Bump `Checkstyle` to 10.21.0. -* Bump `ByteBuddy` to 1.15.11. -* Bump `JUnit` to 5.11.4. -* Bump `jqwik` to 1.9.2. - -### Added -* **C++:** Integrate std::span support for flyweight API. ([#1038](https://github.com/aeron-io/simple-binary-encoding/pull/1038), [#1027](https://github.com/aeron-io/simple-binary-encoding/pull/1027)) -* **Rust:** generate message schema level info in lib.rs. ([#1019](https://github.com/aeron-io/simple-binary-encoding/pull/1019)) - -### Fixed -* **C++:** Fix field precedence check issue [#1031](https://github.com/aeron-io/simple-binary-encoding/issues/1031). ([#1033](https://github.com/aeron-io/simple-binary-encoding/pull/1033)) -* **C++:** respect the package override option for C++ codecs and DTOs. ([#1024](https://github.com/aeron-io/simple-binary-encoding/pull/1024)) -* **C#:** respect the package override option for C# codecs and DTOs. ([#1024](https://github.com/aeron-io/simple-binary-encoding/pull/1024)) -* **Go:** Fix warning about used args in GolangFlyweightGenerator. -* **Rust:** Updated code generator to resolve Issue [#1028](https://github.com/aeron-io/simple-binary-encoding/issues/1028). ([#1037](https://github.com/aeron-io/simple-binary-encoding/pull/1037)) -* **Java:** Prevent collision when field name is 'value'. -* **Java:** Preserve byte order throughout IR transformations. - -[1.35.6]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.6 -[1.35.5]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.5 -[1.35.4]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.4 -[1.35.3]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.3 -[1.35.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.1 -[1.35.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.0 -[1.34.1]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.1 -[1.34.0]: https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.0 From 71a8ada4de2801156c3fedfaed145a7f98af1222 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 12:31:13 +0200 Subject: [PATCH 664/805] [Doc] Add release notes. --- CHANGELOG.adoc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 8b41172297..f0fc9cc19c 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,26 @@ = Changelog +== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.36.0[1.36.0] - 2025-09-29 + +* **[C{plus}{plus}]** Fix composite encode generation to use formatted property names, i.e. escape keywords. +* **[C{plus}{plus}]** Fix property name usage in display code generator. +* **[C{plus}{plus}]** Add getter for schema id on the `IrDecoder` (https://github.com/aeron-io/simple-binary-encoding/pull/1077[#1077]) +* **[Java]** Fix var data and composite code generation to use property name instead of plain name. Also use property name for access order check methods. (https://github.com/aeron-io/simple-binary-encoding/issues/1081[#1081]) +* **[Java]** Handle `null` values when encoding enums, i.e. use `Enum.NULL_VAL` if the value was not assigned. +* **[Java]** Handle primitive arrays correctly in the generated DTO code. +* **[Go]** Handle `_` and `String` as keywords and use property name when generating variable data section. +* **[C#]** Replaced empty array creation by `Array.Empty`, issue (https://github.com/aeron-io/simple-binary-encoding/issues/1079[#1079]). (https://github.com/aeron-io/simple-binary-encoding/pull/1080[#1080]) +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.0[Agrona 2.3.0]. +* **[Java]** Upgrade to `JUnit` 5.13.4. +* **[Java]** Upgrade to `Mockito` 5.20.0. +* **[Java]** Upgrade to `Checkstyle` 11.1.0. +* **[Java]** Upgrade to `Shadow` 9.2.2. +* **[Java]** Upgrade to `Version` 0.53.0. +* **[C]** Upgrade to `GoogleTest` to 1.14.0. +* **[C]** Bump minimium required CMake version to `3.30`. +* **[CI]** Add `Clang` 21 to the build matrix. +* **[CI]** Add `Java` 25 to the build matrix. + == https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.6[1.35.6] - 2025-06-27 * **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.4[Agrona 2.2.4]. From 1f6ec0e59e17f105dd666f76a6d6dcfcf883af14 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 12:54:51 +0200 Subject: [PATCH 665/805] [Java] Preserve `packageName` in the IR. Fixes #1089. --- .../uk/co/real_logic/sbe/ir/IrDecoder.java | 3 + .../uk/co/real_logic/sbe/ir/IrEncoder.java | 3 + .../sbe/ir/generated/TokenCodecDecoder.java | 167 ++++++++++++++++++ .../sbe/ir/generated/TokenCodecEncoder.java | 113 +++++++++++- sbe-tool/src/main/resources/sbe-ir.xml | 1 + .../sbe/ir/BasicXmlIrGenerationTest.java | 2 +- .../co/real_logic/sbe/ir/EncodedIrTest.java | 14 +- 7 files changed, 300 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java index 63881c0ae7..7bd1ed693d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrDecoder.java @@ -266,6 +266,9 @@ private Token decodeToken() final String referencedName = tokenDecoder.referencedName(); tokenBuilder.referencedName(referencedName.isEmpty() ? null : referencedName); + final String packageName = tokenDecoder.packageName(); + tokenBuilder.packageName(packageName.isEmpty() ? null : packageName); + offset += tokenDecoder.encodedLength(); return tokenBuilder.encoding(encBuilder.build()).build(); diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java index 756f0829ab..ad5888b95a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/IrEncoder.java @@ -223,6 +223,9 @@ private int encodeToken(final Token token) final byte[] referencedNameBytes = getBytes(token.referencedName(), referencedNameCharacterEncoding()); tokenEncoder.putReferencedName(referencedNameBytes, 0, referencedNameBytes.length); + + final byte[] packageNameBytes = getBytes(token.packageName(), packageNameCharacterEncoding()); + tokenEncoder.putPackageName(packageNameBytes, 0, packageNameBytes.length); } catch (final UnsupportedEncodingException ex) { diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java index 7b2e69831b..ea9144e0b8 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecDecoder.java @@ -59,6 +59,8 @@ public final class TokenCodecDecoder * V0_SEMANTICTYPE_DONE -> V0_DESCRIPTION_DONE [label=" description(?) "]; * V0_DESCRIPTION_DONE -> V0_DESCRIPTION_DONE [label=" referencedNameLength() "]; * V0_DESCRIPTION_DONE -> V0_REFERENCEDNAME_DONE [label=" referencedName(?) "]; + * V0_REFERENCEDNAME_DONE -> V0_REFERENCEDNAME_DONE [label=" packageNameLength() "]; + * V0_REFERENCEDNAME_DONE -> V0_PACKAGENAME_DONE [label=" packageName(?) "]; * } * } */ @@ -77,6 +79,7 @@ private static class CodecStates private static final int V0_SEMANTICTYPE_DONE = 10; private static final int V0_DESCRIPTION_DONE = 11; private static final int V0_REFERENCEDNAME_DONE = 12; + private static final int V0_PACKAGENAME_DONE = 13; private static final String[] STATE_NAME_LOOKUP = { @@ -93,6 +96,7 @@ private static class CodecStates "V0_SEMANTICTYPE_DONE", "V0_DESCRIPTION_DONE", "V0_REFERENCEDNAME_DONE", + "V0_PACKAGENAME_DONE", }; private static final String[] STATE_TRANSITIONS_LOOKUP = @@ -109,6 +113,7 @@ private static class CodecStates "\"semanticTypeLength()\", \"semanticType(?)\"", "\"descriptionLength()\", \"description(?)\"", "\"referencedNameLength()\", \"referencedName(?)\"", + "\"packageNameLength()\", \"packageName(?)\"", "", }; @@ -2667,6 +2672,164 @@ public String referencedName() return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); } + public static int packageNameId() + { + return 22; + } + + public static int packageNameSinceVersion() + { + return 0; + } + + public static String packageNameCharacterEncoding() + { + return java.nio.charset.StandardCharsets.UTF_8.name(); + } + + public static String packageNameMetaAttribute(final MetaAttribute metaAttribute) + { + if (MetaAttribute.PRESENCE == metaAttribute) + { + return "required"; + } + + return ""; + } + + public static int packageNameHeaderLength() + { + return 2; + } + + void onPackageNameLengthAccessed() + { + switch (codecState()) + { + case CodecStates.V0_REFERENCEDNAME_DONE: + codecState(CodecStates.V0_REFERENCEDNAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot decode length of var data \"packageName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + private void onPackageNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_REFERENCEDNAME_DONE: + codecState(CodecStates.V0_PACKAGENAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"packageName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecDecoder#CodecStates."); + } + } + + public int packageNameLength() + { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameLengthAccessed(); + } + + final int limit = parentMessage.limit(); + return (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); + } + + public int skipPackageName() + { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + + final int headerLength = 2; + final int limit = parentMessage.limit(); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); + final int dataOffset = limit + headerLength; + parentMessage.limit(dataOffset + dataLength); + + return dataLength; + } + + public int getPackageName(final MutableDirectBuffer dst, final int dstOffset, final int length) + { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + + final int headerLength = 2; + final int limit = parentMessage.limit(); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); + final int bytesCopied = Math.min(length, dataLength); + parentMessage.limit(limit + headerLength + dataLength); + buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); + + return bytesCopied; + } + + public int getPackageName(final byte[] dst, final int dstOffset, final int length) + { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + + final int headerLength = 2; + final int limit = parentMessage.limit(); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); + final int bytesCopied = Math.min(length, dataLength); + parentMessage.limit(limit + headerLength + dataLength); + buffer.getBytes(limit + headerLength, dst, dstOffset, bytesCopied); + + return bytesCopied; + } + + public void wrapPackageName(final DirectBuffer wrapBuffer) + { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + + final int headerLength = 2; + final int limit = parentMessage.limit(); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); + parentMessage.limit(limit + headerLength + dataLength); + wrapBuffer.wrap(buffer, limit + headerLength, dataLength); + } + + public String packageName() + { + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + + final int headerLength = 2; + final int limit = parentMessage.limit(); + final int dataLength = (buffer.getShort(limit, BYTE_ORDER) & 0xFFFF); + parentMessage.limit(limit + headerLength + dataLength); + + if (0 == dataLength) + { + return ""; + } + + final byte[] tmp = new byte[dataLength]; + buffer.getBytes(limit + headerLength, tmp, 0, dataLength); + + return new String(tmp, java.nio.charset.StandardCharsets.UTF_8); + } + public String toString() { if (null == buffer) @@ -2770,6 +2933,9 @@ public StringBuilder appendTo(final StringBuilder builder) builder.append('|'); builder.append("referencedName="); builder.append('\'').append(referencedName()).append('\''); + builder.append('|'); + builder.append("packageName="); + builder.append('\'').append(packageName()).append('\''); limit(originalLimit); @@ -2790,6 +2956,7 @@ public TokenCodecDecoder sbeSkip() skipSemanticType(); skipDescription(); skipReferencedName(); + skipPackageName(); return this; } diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java index 9e201cbf52..057e7f129d 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ir/generated/TokenCodecEncoder.java @@ -59,6 +59,8 @@ public final class TokenCodecEncoder * V0_SEMANTICTYPE_DONE -> V0_DESCRIPTION_DONE [label=" description(?) "]; * V0_DESCRIPTION_DONE -> V0_DESCRIPTION_DONE [label=" referencedNameLength() "]; * V0_DESCRIPTION_DONE -> V0_REFERENCEDNAME_DONE [label=" referencedName(?) "]; + * V0_REFERENCEDNAME_DONE -> V0_REFERENCEDNAME_DONE [label=" packageNameLength() "]; + * V0_REFERENCEDNAME_DONE -> V0_PACKAGENAME_DONE [label=" packageName(?) "]; * } * } */ @@ -77,6 +79,7 @@ private static class CodecStates private static final int V0_SEMANTICTYPE_DONE = 10; private static final int V0_DESCRIPTION_DONE = 11; private static final int V0_REFERENCEDNAME_DONE = 12; + private static final int V0_PACKAGENAME_DONE = 13; private static final String[] STATE_NAME_LOOKUP = { @@ -93,6 +96,7 @@ private static class CodecStates "V0_SEMANTICTYPE_DONE", "V0_DESCRIPTION_DONE", "V0_REFERENCEDNAME_DONE", + "V0_PACKAGENAME_DONE", }; private static final String[] STATE_TRANSITIONS_LOOKUP = @@ -109,6 +113,7 @@ private static class CodecStates "\"semanticTypeLength()\", \"semanticType(?)\"", "\"descriptionLength()\", \"description(?)\"", "\"referencedNameLength()\", \"referencedName(?)\"", + "\"packageNameLength()\", \"packageName(?)\"", "", }; @@ -2009,6 +2014,112 @@ public TokenCodecEncoder referencedName(final String value) return this; } + public static int packageNameId() + { + return 22; + } + + public static String packageNameCharacterEncoding() + { + return java.nio.charset.StandardCharsets.UTF_8.name(); + } + + public static String packageNameMetaAttribute(final MetaAttribute metaAttribute) + { + if (MetaAttribute.PRESENCE == metaAttribute) + { + return "required"; + } + + return ""; + } + + public static int packageNameHeaderLength() + { + return 2; + } + + private void onPackageNameAccessed() + { + switch (codecState()) + { + case CodecStates.V0_REFERENCEDNAME_DONE: + codecState(CodecStates.V0_PACKAGENAME_DONE); + break; + default: + throw new IllegalStateException("Illegal field access order. " + + "Cannot access field \"packageName\" in state: " + CodecStates.name(codecState()) + + ". Expected one of these transitions: [" + CodecStates.transitions(codecState()) + + "]. Please see the diagram in the Javadoc of the class TokenCodecEncoder#CodecStates."); + } + } + + public TokenCodecEncoder putPackageName(final DirectBuffer src, final int srcOffset, final int length) + { + if (length > 65534) + { + throw new IllegalStateException("length > maxValue for type: " + length); + } + + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + + final int headerLength = 2; + final int limit = parentMessage.limit(); + parentMessage.limit(limit + headerLength + length); + buffer.putShort(limit, (short)length, BYTE_ORDER); + buffer.putBytes(limit + headerLength, src, srcOffset, length); + + return this; + } + + public TokenCodecEncoder putPackageName(final byte[] src, final int srcOffset, final int length) + { + if (length > 65534) + { + throw new IllegalStateException("length > maxValue for type: " + length); + } + + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + + final int headerLength = 2; + final int limit = parentMessage.limit(); + parentMessage.limit(limit + headerLength + length); + buffer.putShort(limit, (short)length, BYTE_ORDER); + buffer.putBytes(limit + headerLength, src, srcOffset, length); + + return this; + } + + public TokenCodecEncoder packageName(final String value) + { + final byte[] bytes = (null == value || value.isEmpty()) ? org.agrona.collections.ArrayUtil.EMPTY_BYTE_ARRAY : value.getBytes(java.nio.charset.StandardCharsets.UTF_8); + + final int length = bytes.length; + if (length > 65534) + { + throw new IllegalStateException("length > maxValue for type: " + length); + } + + if (SBE_ENABLE_IR_PRECEDENCE_CHECKS) + { + onPackageNameAccessed(); + } + + final int headerLength = 2; + final int limit = parentMessage.limit(); + parentMessage.limit(limit + headerLength + length); + buffer.putShort(limit, (short)length, BYTE_ORDER); + buffer.putBytes(limit + headerLength, bytes, 0, length); + + return this; + } + public String toString() { if (null == buffer) @@ -2038,7 +2149,7 @@ public void checkEncodingIsComplete() { switch (codecState) { - case CodecStates.V0_REFERENCEDNAME_DONE: + case CodecStates.V0_PACKAGENAME_DONE: return; default: throw new IllegalStateException("Not fully encoded, current state: " + diff --git a/sbe-tool/src/main/resources/sbe-ir.xml b/sbe-tool/src/main/resources/sbe-ir.xml index 4b55318f53..d2941ca3bf 100644 --- a/sbe-tool/src/main/resources/sbe-ir.xml +++ b/sbe-tool/src/main/resources/sbe-ir.xml @@ -96,5 +96,6 @@ + diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java index 97faca7848..0d2edc2173 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/BasicXmlIrGenerationTest.java @@ -319,7 +319,7 @@ void shouldRegenerateIrWithSameByteOrder() throws Exception final MessageSchema schema = parse(in, ParserOptions.DEFAULT); final IrGenerator generator = new IrGenerator(); final Ir firstIr = generator.generate(schema); - final ByteBuffer firstIrOutputBuffer = ByteBuffer.allocate(8 * 1024); + final ByteBuffer firstIrOutputBuffer = ByteBuffer.allocate(16 * 1024); final int length; try (IrEncoder firstIrEncoder = new IrEncoder(firstIrOutputBuffer, firstIr)) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java index 122c0ef41d..c353a02d31 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/ir/EncodedIrTest.java @@ -166,7 +166,18 @@ void shouldDecodeHeader() throws Exception @Test void shouldDecodeMessagesAndTypes() throws Exception { - try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + testDecodeTypes("code-generation-schema.xml"); + } + + @Test + void shouldPreservePackageNames() throws Exception + { + testDecodeTypes("explicit-package-test-schema.xml"); + } + + private void testDecodeTypes(final String name1) throws Exception + { + try (InputStream in = Tests.getLocalResource(name1)) { final MessageSchema schema = parse(in, ParserOptions.DEFAULT); final IrGenerator irg = new IrGenerator(); @@ -216,6 +227,7 @@ void shouldDecodeMessagesAndTypes() throws Exception private void assertEqual(final Token lhs, final Token rhs) { assertThat(lhs.name(), is(rhs.name())); + assertThat(lhs.packageName(), is(rhs.packageName())); assertThat(lhs.version(), is(rhs.version())); assertThat(lhs.offset(), is(rhs.offset())); assertThat((long)lhs.id(), is((long)rhs.id())); From 67bb9be306598794bb75e7050f6d7aea614b3830 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 13:10:52 +0200 Subject: [PATCH 666/805] [C++] Add `referencedName` and `packageName` to the `Token` definition. --- sbe-tool/src/main/cpp/otf/IrDecoder.h | 5 ++++- sbe-tool/src/main/cpp/otf/Token.h | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/sbe-tool/src/main/cpp/otf/IrDecoder.h b/sbe-tool/src/main/cpp/otf/IrDecoder.h index 947d5c31e3..fb077cb30c 100644 --- a/sbe-tool/src/main/cpp/otf/IrDecoder.h +++ b/sbe-tool/src/main/cpp/otf/IrDecoder.h @@ -289,6 +289,9 @@ class IrDecoder tmpLen = tokenCodec.getReferencedName(tmpBuffer, sizeof(tmpBuffer)); std::string referencedName(tmpBuffer, tmpLen); + tmpLen = tokenCodec.getPackageName(tmpBuffer, sizeof(tmpBuffer)); + std::string packageName(tmpBuffer, tmpLen); + Encoding encoding( type, presence, @@ -302,7 +305,7 @@ class IrDecoder timeUnit, semanticType); - Token token(tokenOffset, id, version, tokenSize, componentTokenCount, signal, name, description, encoding); + Token token(tokenOffset, id, version, tokenSize, componentTokenCount, signal, name, description, encoding, referencedName, packageName); tokens->push_back(token); diff --git a/sbe-tool/src/main/cpp/otf/Token.h b/sbe-tool/src/main/cpp/otf/Token.h index 2855c2a86c..f5ba05e511 100644 --- a/sbe-tool/src/main/cpp/otf/Token.h +++ b/sbe-tool/src/main/cpp/otf/Token.h @@ -77,7 +77,10 @@ class Token Signal signal, std::string name, std::string description, - Encoding encoding) : + Encoding encoding, + std::string referencedName = "", + std::string packageName = "" + ) : m_offset(offset), m_fieldId(fieldId), m_version(version), @@ -86,7 +89,9 @@ class Token m_signal(signal), m_name(std::move(name)), m_description(std::move(description)), - m_encoding(std::move(encoding)) + m_encoding(std::move(encoding)), + m_referencedName(std::move(referencedName)), + m_packageName(std::move(packageName)) { } @@ -105,6 +110,16 @@ class Token return m_description; } + inline const std::string &referencedName() const + { + return m_referencedName; + } + + inline const std::string &packageName() const + { + return m_packageName; + } + inline std::int32_t fieldId() const { return m_fieldId; @@ -150,6 +165,8 @@ class Token const std::string m_name; const std::string m_description; const Encoding m_encoding; + const std::string m_referencedName; + const std::string m_packageName; }; }} From 04ea6358535a344fc29e0f69fd864b46877b5c9f Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 13:18:42 +0200 Subject: [PATCH 667/805] [C#] Fix typo. --- sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index 92f000cae5..7ba93c7bd0 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -412,7 +412,7 @@ private static boolean isSbeGolangIdentifierPart(final char c) "short", "sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", - "unsafe", "ushort", "using", "using static", "virtual", + "unsafe", "ushort", "using", "virtual", "void", "volatile", "while"); /** From a4c1ca1b557f7b53d9fcf9d53769c617978287f2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 13:29:42 +0200 Subject: [PATCH 668/805] [Go] Add `packageName` to the `Token` definition. --- sbe-tool/src/main/golang/otf/irdecoder.go | 2 ++ sbe-tool/src/main/golang/otf/token.go | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/main/golang/otf/irdecoder.go b/sbe-tool/src/main/golang/otf/irdecoder.go index d90876e637..24a9e5efb7 100644 --- a/sbe-tool/src/main/golang/otf/irdecoder.go +++ b/sbe-tool/src/main/golang/otf/irdecoder.go @@ -164,6 +164,7 @@ func (decoder *IrDecoder) decodeAndAddToken(tokens *[]Token, offset uint64) uint semanticType := tokenCodec.GetSemanticTypeAsString() description := tokenCodec.GetDescriptionAsString() referencedName := tokenCodec.GetReferencedNameAsString() + packageName := tokenCodec.GetPackageNameAsString() encoding := NewEncoding( primitiveType, @@ -188,6 +189,7 @@ func (decoder *IrDecoder) decodeAndAddToken(tokens *[]Token, offset uint64) uint signal: signal, name: name, referencedName: referencedName, + packageName: packageName, description: description, encoding: encoding, } diff --git a/sbe-tool/src/main/golang/otf/token.go b/sbe-tool/src/main/golang/otf/token.go index 442b6d5d80..b2ef627d84 100644 --- a/sbe-tool/src/main/golang/otf/token.go +++ b/sbe-tool/src/main/golang/otf/token.go @@ -76,10 +76,15 @@ type Token struct { signal Signal name string referencedName string + packageName string description string encoding Encoding } +func (token Token) PackageName() string { + return token.packageName +} + func (token Token) ReferencedName() string { return token.referencedName } @@ -149,9 +154,11 @@ func (token Token) IsOptionalEncoding() bool { func (token Token) String() string { return fmt.Sprintf( - "Token{signal: %s, name: %s, description: %s, fieldId: %d, tokenVersion: %d, encoding: %s, encodedLength: %d, offset: %d, componentTokenCount: %d}", + "Token{signal: %s, name: %s, referencedName: %s, packageName: %s, description: %s, fieldId: %d, tokenVersion: %d, encoding: %s, encodedLength: %d, offset: %d, componentTokenCount: %d}", token.signal, token.name, + token.referencedName, + token.packageName, token.description, token.fieldId, token.version, From cd4841ababc93fb0d1369539f296f5c49582affc Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 13:34:37 +0200 Subject: [PATCH 669/805] [C/C++] Allow overriding Gradle wrapper location. Fixes #1091. --- CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 32f07dd810..ce164c285b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,8 +137,16 @@ file(GLOB_RECURSE SBE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/sbe-tool/src/main/java/*.java" ) +if (NOT DEFINED GRADLE_WRAPPER) + if (MSVC) + set(GRADLE_WRAPPER "gradlew.bat" CACHE INTERNAL "Location of the Gradle wrapper script") + else () + set(GRADLE_WRAPPER "./gradlew" CACHE INTERNAL "Location of the Gradle wrapper script") + endif () +endif () + add_custom_command(OUTPUT ${SBE_JAR} - COMMAND ./gradlew assemble -x javadoc --console=plain + COMMAND ${GRADLE_WRAPPER} assemble -x javadoc --console=plain DEPENDS ${SBE_SOURCES} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Generating SBE jar" From 8b49cf5dbc15a31d25aefae76de64544a3a92957 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 13:38:49 +0200 Subject: [PATCH 670/805] [Doc] Update release notes. --- CHANGELOG.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index f0fc9cc19c..7062e70ebb 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -10,6 +10,8 @@ * **[Java]** Handle primitive arrays correctly in the generated DTO code. * **[Go]** Handle `_` and `String` as keywords and use property name when generating variable data section. * **[C#]** Replaced empty array creation by `Array.Empty`, issue (https://github.com/aeron-io/simple-binary-encoding/issues/1079[#1079]). (https://github.com/aeron-io/simple-binary-encoding/pull/1080[#1080]) +* **[C/C{plus}{plus}]** Allow overriding Gradle wrapper location. (https://github.com/aeron-io/simple-binary-encoding/issues/1091[#1091]). +* **[Java/C{plus}{plus}/Go]** Preserve `packageName` in the IR. (https://github.com/aeron-io/simple-binary-encoding/issues/1089[#1089]) * **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.0[Agrona 2.3.0]. * **[Java]** Upgrade to `JUnit` 5.13.4. * **[Java]** Upgrade to `Mockito` 5.20.0. From 88e2c7533140a7021b94f87398e1f59a493e923c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 13:39:05 +0200 Subject: [PATCH 671/805] 1.36.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index aa69911fd7..39fc130ef8 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.0-SNAPSHOT +1.36.0 From d93e0a5057f2220d7ca5f9bdfe3dab08a8c16aa1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 29 Sep 2025 13:39:16 +0200 Subject: [PATCH 672/805] post release bump. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 39fc130ef8..7991f09416 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.0 +1.37.0-SNAPSHOT From 34b27b599bab1a433c20984868378cf4e1ef68cf Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 30 Sep 2025 14:55:21 +0200 Subject: [PATCH 673/805] [Java] Bump `JUnit` to 6.0.0. --- gradle/libs.versions.toml | 2 +- .../co/real_logic/sbe/generation/java/QualifiedYieldTest.java | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 559965ee68..c8d66da919 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" json = "20250517" -junit = "5.13.4" +junit = "6.0.0" mockito = "5.20.0" plexus = "3.3.0" shadow = "9.2.2" diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java index 5f0900a9f8..8906748ac8 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/QualifiedYieldTest.java @@ -20,8 +20,6 @@ import org.agrona.generation.CompilerUtil; import org.agrona.generation.StringWriterOutputManager; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledForJreRange; -import org.junit.jupiter.api.condition.JRE; import uk.co.real_logic.sbe.Tests; import uk.co.real_logic.sbe.ir.Ir; import uk.co.real_logic.sbe.xml.IrGenerator; @@ -44,7 +42,6 @@ public class QualifiedYieldTest private final StringWriterOutputManager outputManager = new StringWriterOutputManager(); @Test - @EnabledForJreRange(min = JRE.JAVA_17) void shouldGenerateValidJava() throws Exception { try (InputStream in = Tests.getLocalResource("issue910.xml")) From a972a5e78e3a1fe9c1ab29c31a5f13acb6af60ff Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 30 Sep 2025 15:17:42 +0200 Subject: [PATCH 674/805] [C++] Use common buffer size. --- sbe-tool/src/test/c/CodeGenTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/test/c/CodeGenTest.cpp b/sbe-tool/src/test/c/CodeGenTest.cpp index 6f2a195a11..4d33156149 100644 --- a/sbe-tool/src/test/c/CodeGenTest.cpp +++ b/sbe-tool/src/test/c/CodeGenTest.cpp @@ -1093,7 +1093,7 @@ void testUsageDescription(CGT(car_fuelFigures) *const fuelFigures, const std::st TEST_F(CodeGenTest, shouldBeAbleToUseStdStringMethodsForDecode) { - char buffer[2048] = {}; + char buffer[BUFFER_LEN] = {}; CGT(car) carEncoder; CGT(car_reset)(&carEncoder, buffer, 0, sizeof(buffer), CGT(car_sbe_block_length)(), CGT(car_sbe_schema_version)()); @@ -1185,7 +1185,7 @@ TEST_F(CodeGenTest, shouldBeAbleToUseStdStringMethodsForDecode) TEST_F(CodeGenTest, shouldAllowForMultipleIterations2) { - char buffer[2048] = {}; + char buffer[BUFFER_LEN] = {}; std::uint64_t hdrSz = encodeHdr(buffer, 0, sizeof(buffer)); std::uint64_t carEncodedLength = encodeCar( From f40270a516560e4d7b1015f3dfef3edd5eb24141 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:37:05 +0200 Subject: [PATCH 675/805] [Java] Upgrade `Checkstyle` to 12.1.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c8d66da919..90aaac3a53 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.3.0" -checkstyle = "11.1.0" +checkstyle = "12.1.0" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 8b2052e00c71b0cb90ec7e5f5e5fd2caf906261e Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 27 Oct 2025 21:07:07 +0100 Subject: [PATCH 676/805] [CI] Use temporary storage driver on Windows to speed up build. --- .github/workflows/ci.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7560413329..a2706d0b1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,25 @@ jobs: java: [ '17', '21', '25' ] os: [ 'ubuntu-24.04', 'windows-latest', 'macos-15' ] steps: + - name: Use faster temporary storage (Windows) + if: runner.os == 'Windows' + run: | + $fast_dir = "D:\fast-dir" + New-Item -ItemType Directory -Path "$fast_dir" + New-Item -ItemType Directory -Path "$fast_dir\temp" + New-Item -ItemType Directory -Path "$fast_dir\.m2" + New-Item -ItemType Directory -Path "$fast_dir\.gradle" + + if (Test-Path "$env:userprofile\.m2") + { + Remove-Item "$env:userprofile\.m2" -Recurse + } + New-Item -ItemType SymbolicLink -Path "$env:userprofile\.m2" -Target "$fast_dir\.m2" + + echo "TMP=$fast_dir\temp" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "TEMP=$fast_dir\temp" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "M2_HOME=$fast_dir\.m2" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "GRADLE_USER_HOME=$fast_dir\.gradle" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code uses: actions/checkout@v5 with: @@ -242,6 +261,24 @@ jobs: CC: cl CXX: cl steps: + - name: Use faster temporary storage (Windows) + run: | + $fast_dir = "D:\fast-dir" + New-Item -ItemType Directory -Path "$fast_dir" + New-Item -ItemType Directory -Path "$fast_dir\temp" + New-Item -ItemType Directory -Path "$fast_dir\.m2" + New-Item -ItemType Directory -Path "$fast_dir\.gradle" + + if (Test-Path "$env:userprofile\.m2") + { + Remove-Item "$env:userprofile\.m2" -Recurse + } + New-Item -ItemType SymbolicLink -Path "$env:userprofile\.m2" -Target "$fast_dir\.m2" + + echo "TMP=$fast_dir\temp" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "TEMP=$fast_dir\temp" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "M2_HOME=$fast_dir\.m2" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "GRADLE_USER_HOME=$fast_dir\.gradle" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code uses: actions/checkout@v5 with: From edebd1dce2d8905897fa001a76905f6507b8bdc6 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 27 Oct 2025 21:21:37 +0100 Subject: [PATCH 677/805] [Java] Upgrade `Checkstyle` to 12.1.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90aaac3a53..b757f613f2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.3.0" -checkstyle = "12.1.0" +checkstyle = "12.1.1" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 6663c18cfdeb0e6f9d373c463102c9455ef80b07 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 27 Oct 2025 21:32:43 +0100 Subject: [PATCH 678/805] [CI] Upgrade to `setup-gradle` and `upload-artifact` to v5. --- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/codeql.yml | 6 +++--- .github/workflows/release.yml | 2 +- .github/workflows/slow.yml | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2706d0b1e..ef58311b57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,7 +81,7 @@ jobs: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Build with Gradle run: ./gradlew - name: Copy test logs @@ -92,7 +92,7 @@ jobs: ./gradlew tarTestLogs - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: crash-logs-${{ matrix.os }}-java-${{ matrix.java }} path: ${{ steps.copy_test_logs.outputs.file }} @@ -124,7 +124,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Cache NuGet dependencies uses: actions/cache@v4 with: @@ -176,7 +176,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Build run: ./cppbuild/cppbuild @@ -214,7 +214,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Build run: ./cppbuild/cppbuild @@ -245,7 +245,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Build run: cmake --version && ./cppbuild/cppbuild @@ -294,7 +294,7 @@ jobs: echo "BUILD_JAVA_HOME=$env:JAVA_HOME" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Build run: cppbuild/cppbuild.cmd @@ -326,7 +326,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - run: ./gradlew runRustTests golang-build: @@ -357,7 +357,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Generate jar run: ./gradlew assemble - name: Run tests diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e4951b67f8..2efa60259b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -56,7 +56,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ matrix.java }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -114,7 +114,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Setup dotnet uses: actions/setup-dotnet@v5 @@ -169,7 +169,7 @@ jobs: echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Install compiler run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e643e54186..b33cf0c690 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,7 +37,7 @@ jobs: echo "BUILD_JAVA_HOME=${JAVA_HOME}" >> $GITHUB_ENV echo "BUILD_JAVA_VERSION=${{ env.JAVA_VERSION }}" >> $GITHUB_ENV - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Publish with Gradle run: ./gradlew publish uploadArtifactsToCentralPortal env: diff --git a/.github/workflows/slow.yml b/.github/workflows/slow.yml index ae634eb04b..0961c7a9ef 100644 --- a/.github/workflows/slow.yml +++ b/.github/workflows/slow.yml @@ -57,7 +57,7 @@ jobs: distribution: 'zulu' java-version: ${{ env.JAVA_VERSION }} - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Setup dotnet uses: actions/setup-dotnet@v5 with: @@ -74,12 +74,12 @@ jobs: ./gradlew tarTestLogs - name: Upload crash logs if: always() && steps.copy_test_logs.outputs.file == 'build/distributions/test_logs.tbz2' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: crash-logs-${{ matrix.os }}-property-tests-java-${{matrix.java}}-dotnet-${{matrix.dotnet}} path: ${{ steps.copy_test_logs.outputs.file }} - name: Upload test results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 if: always() with: name: property-tests From f472113efc7ffdf28b3364b93c894fb8de18ced4 Mon Sep 17 00:00:00 2001 From: Dmitry Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:16:17 +0100 Subject: [PATCH 679/805] [CI] Simplify Windows `D:` drive usage. --- .github/workflows/ci.yml | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef58311b57..6c71672ec1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,22 +38,8 @@ jobs: - name: Use faster temporary storage (Windows) if: runner.os == 'Windows' run: | - $fast_dir = "D:\fast-dir" - New-Item -ItemType Directory -Path "$fast_dir" - New-Item -ItemType Directory -Path "$fast_dir\temp" - New-Item -ItemType Directory -Path "$fast_dir\.m2" - New-Item -ItemType Directory -Path "$fast_dir\.gradle" - - if (Test-Path "$env:userprofile\.m2") - { - Remove-Item "$env:userprofile\.m2" -Recurse - } - New-Item -ItemType SymbolicLink -Path "$env:userprofile\.m2" -Target "$fast_dir\.m2" - - echo "TMP=$fast_dir\temp" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - echo "TEMP=$fast_dir\temp" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - echo "M2_HOME=$fast_dir\.m2" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - echo "GRADLE_USER_HOME=$fast_dir\.gradle" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "TMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "TEMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code uses: actions/checkout@v5 with: @@ -263,22 +249,8 @@ jobs: steps: - name: Use faster temporary storage (Windows) run: | - $fast_dir = "D:\fast-dir" - New-Item -ItemType Directory -Path "$fast_dir" - New-Item -ItemType Directory -Path "$fast_dir\temp" - New-Item -ItemType Directory -Path "$fast_dir\.m2" - New-Item -ItemType Directory -Path "$fast_dir\.gradle" - - if (Test-Path "$env:userprofile\.m2") - { - Remove-Item "$env:userprofile\.m2" -Recurse - } - New-Item -ItemType SymbolicLink -Path "$env:userprofile\.m2" -Target "$fast_dir\.m2" - - echo "TMP=$fast_dir\temp" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - echo "TEMP=$fast_dir\temp" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - echo "M2_HOME=$fast_dir\.m2" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - echo "GRADLE_USER_HOME=$fast_dir\.gradle" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "TMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append + echo "TEMP=$env:RUNNER_TEMP" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append - name: Checkout code uses: actions/checkout@v5 with: From f6914c26347709225c447a30d4fdd0e8433e35c4 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:45:21 +0100 Subject: [PATCH 680/805] [CI] Use .NET 9 in codeql. --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2efa60259b..b5c633b1f1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -83,7 +83,7 @@ jobs: fail-fast: false matrix: language: [ 'csharp' ] - dotnet: [ '10' ] + dotnet: [ '9' ] env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 From 9367f9d608a62556a97cae9ca1fad0e936618518 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:06:26 +0100 Subject: [PATCH 681/805] [Java] Upgrade to `JUnit` 6.0.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b757f613f2..96fc0881bb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" json = "20250517" -junit = "6.0.0" +junit = "6.0.1" mockito = "5.20.0" plexus = "3.3.0" shadow = "9.2.2" From d0ae48ac4dc4e8dd6486eedb4507a0c23d6c0db2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:06:37 +0100 Subject: [PATCH 682/805] [Java] Upgrade to `Agrona` 2.3.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 96fc0881bb..41e68f43fb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.3.0" +agrona = "2.3.1" checkstyle = "12.1.1" commons-codec = "1.15" commons-lang3 = "3.8.1" From 582af43aaefef8fb8ac3be8b11b6f7303bab066f Mon Sep 17 00:00:00 2001 From: Nikolay Zdravkov Date: Mon, 3 Nov 2025 16:14:35 +0200 Subject: [PATCH 683/805] [C#] fix: handle case when valueRef is with enum type prefix (#1092) --- .../sbe/generation/csharp/CSharpGenerator.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index a5dc0b2354..81f323ef39 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -2069,6 +2069,18 @@ private CharSequence generateEnumProperty( if (fieldToken.isConstantEncoding()) { final String constValue = fieldToken.encoding().constValue().toString(); + + // If constValue already contains the type prefix (e.g., "filterType.TrailingDelta"), + // extract just the enum value name + final String enumValue; + if (constValue.contains(".")) + { + enumValue = constValue.substring(constValue.lastIndexOf('.') + 1); + } + else + { + enumValue = constValue; + } return String.format("\n" + "%1$s" + @@ -2076,13 +2088,14 @@ private CharSequence generateEnumProperty( indent + INDENT + "{\n" + indent + INDENT + INDENT + "get\n" + indent + INDENT + INDENT + "{\n" + - indent + INDENT + INDENT + INDENT + "return %4$s;\n" + + indent + INDENT + INDENT + INDENT + "return %4$s.%5$s;\n" + indent + INDENT + INDENT + "}\n" + indent + INDENT + "}\n\n", generateDocumentation(indent + INDENT, fieldToken), enumName, toUpperFirstChar(propertyName), - constValue); + enumName, + enumValue); } else { From 8c7c43fdd8939b5a011050cf41c5eac1e1e59a85 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:30:40 +0100 Subject: [PATCH 684/805] [Java] Tidy up after #1092. --- .../sbe/generation/csharp/CSharpGenerator.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java index 81f323ef39..d3b063631a 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/csharp/CSharpGenerator.java @@ -2069,18 +2069,10 @@ private CharSequence generateEnumProperty( if (fieldToken.isConstantEncoding()) { final String constValue = fieldToken.encoding().constValue().toString(); - + final int lastDotIndex = constValue.lastIndexOf('.'); // If constValue already contains the type prefix (e.g., "filterType.TrailingDelta"), // extract just the enum value name - final String enumValue; - if (constValue.contains(".")) - { - enumValue = constValue.substring(constValue.lastIndexOf('.') + 1); - } - else - { - enumValue = constValue; - } + final String enumValue = -1 == lastDotIndex ? constValue : constValue.substring(lastDotIndex + 1); return String.format("\n" + "%1$s" + From 1428382a03aada1f9f58a5bd426be4caa9d56b3a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:55:51 +0100 Subject: [PATCH 685/805] [C#] Exclude generated sources. --- .gitignore | 14 ++------------ csharp/sbe-generated/mktdata/README.txt | 4 ---- 2 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 csharp/sbe-generated/mktdata/README.txt diff --git a/.gitignore b/.gitignore index c34ba580f9..554fcc27e0 100644 --- a/.gitignore +++ b/.gitignore @@ -85,18 +85,8 @@ csharp/*/bin csharp/*/obj csharp/.vs csharp/TestResults -csharp/sbe-generated/baseline -csharp/sbe-generated/baseline-bigendian -csharp/sbe-generated/extension -csharp/sbe-generated/issue435 -csharp/sbe-generated/issue483 -csharp/sbe-generated/issue560 -csharp/sbe-generated/issue661 -csharp/sbe-generated/since-deprecated -csharp/sbe-generated/order_check -csharp/sbe-generated/mktdata/*.cs -csharp/sbe-generated/uk_co_real_logic_sbe_benchmarks_fix -csharp/sbe-generated/test_message_schema +csharp/sbe-generated/ +!csharp/sbe-generated/sbe-generated.csproj csharp/sbe-tests/*.sbe csharp/nuget/ csharp/csharp.sln.DotSettings.user diff --git a/csharp/sbe-generated/mktdata/README.txt b/csharp/sbe-generated/mktdata/README.txt deleted file mode 100644 index 606c4c5376..0000000000 --- a/csharp/sbe-generated/mktdata/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -The csharp code can be regenerated via the top level gradle environment. - -The FixBinary specification is from: ftp://ftp.cmegroup.com/SBEFix/NRCert/Templates/ and is -kept locally ~sbe-tool/src/test/resources/FixBinary.xml From f270f66d2d28634b8488bf42d9f38abec986edae Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:31:03 +0100 Subject: [PATCH 686/805] [C#] Add tests for #1092. --- .../sbe/generation/cpp/CppGeneratorTest.java | 31 +++++++++++++++++ .../csharp/CSharpGeneratorTest.java | 33 +++++++++++++++++++ ...atorTest.java => GolangGeneratorTest.java} | 33 +++++++++++++++++-- .../generation/java/JavaGeneratorTest.java | 15 +++++++++ .../test/resources/code-generation-schema.xml | 7 ++++ 5 files changed, 117 insertions(+), 2 deletions(-) rename sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/{GolangStructGeneratorTest.java => GolangGeneratorTest.java} (93%) diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java index 6d4990df3b..2cdb37ecce 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/cpp/CppGeneratorTest.java @@ -140,4 +140,35 @@ void shouldUseConstexprWhenDefiningPrecedenceChecksLookupTables() throws Excepti assertThat(source, containsString("static constexpr const char *STATE_TRANSITIONS_LOOKUP[] =")); } } + + @Test + void shouldHandleLowerCaseEnumValueReference() throws Exception + { + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CppGenerator generator = new CppGenerator( + ir, + false, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context().shouldGeneratePrecedenceChecks(true)), + false, + outputManager); + generator.generate(); + + final java.util.Map sources = outputManager.getSources(); + final String source = sources.get("code.generation.test.LowerCaseValueRef").toString(); + assertThat(source, containsString(""" + SBE_NODISCARD LowerCaseEnum::Value x() const + { + return LowerCaseEnum::Value::TwO; + } + """)); + } + } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java index e78952d1d2..d19639b2fd 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/csharp/CSharpGeneratorTest.java @@ -72,4 +72,37 @@ void dtosShouldReferenceTypesInDifferentPackages() throws Exception assertThat(source, containsString("using Test.Message.Schema.Common;")); } } + + @Test + void shouldGenerateValidCode() throws Exception + { + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final CSharpGenerator generator = new CSharpGenerator( + ir, + PrecedenceChecks.newInstance(new PrecedenceChecks.Context()), + true, + outputManager); + generator.generate(); + + final java.util.Map sources = outputManager.getSources(); + final String source = sources.get("code.generation.test.LowerCaseValueRef").toString(); + assertThat(source, containsString(""" + public LowerCaseEnum X + { + get + { + return LowerCaseEnum.TwO; + } + } + """)); + } + } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java similarity index 93% rename from sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java rename to sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java index aa578e2de9..f622f8081a 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangStructGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/golang/GolangGeneratorTest.java @@ -26,10 +26,12 @@ import java.io.InputStream; -import static org.junit.jupiter.api.Assertions.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; -class GolangStructGeneratorTest +class GolangGeneratorTest { @Test @SuppressWarnings("MethodLength") @@ -485,4 +487,31 @@ void shouldUseUpperCaseTypeNamesWhenReferencingBitSet() throws Exception "}\n", messageSource); } } + + @Test + @SuppressWarnings("MethodLength") + void shouldHandleLowerCaseEnumValueReference() throws Exception + { + try (InputStream in = Tests.getLocalResource("code-generation-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + + final GolangGenerator generator = new GolangGenerator(ir, outputManager); + generator.generate(); + + final java.util.Map sources = outputManager.getSources(); + final String source = sources.get("code.generation.test.LowerCaseValueRef").toString(); + assertThat(source, containsString(""" + func LowerCaseValueRefInit(l *LowerCaseValueRef) { + \tl.X = LowerCaseEnum.TwO + \treturn + } + """)); + } + } } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java index 4b50d633e6..e5d4a1f5a1 100644 --- a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorTest.java @@ -740,6 +740,21 @@ void shouldValidateNotImplementedReadOnlyBufferClass() () -> new JavaGenerator(ir, BUFFER_NAME, "java.nio.ByteBuffer", false, false, false, outputManager)); } + @Test + void shouldHandleLowerCaseEnumValueReference() throws Exception + { + generator().generate(); + + final java.util.Map sources = outputManager.getSources(); + final String source = sources.get("code.generation.test.LowerCaseValueRefDecoder").toString(); + assertThat(source, containsString(""" + public LowerCaseEnum x() + { + return LowerCaseEnum.TwO; + } + """)); + } + private Class compileCarEncoder() throws Exception { final String className = "CarEncoder"; diff --git a/sbe-tool/src/test/resources/code-generation-schema.xml b/sbe-tool/src/test/resources/code-generation-schema.xml index 2e530a3af5..b07106ba4d 100644 --- a/sbe-tool/src/test/resources/code-generation-schema.xml +++ b/sbe-tool/src/test/resources/code-generation-schema.xml @@ -74,6 +74,10 @@ 1 2 + + 0 + 5 + @@ -188,4 +192,7 @@ + + + From d8cd23580a28a8882fdfe1c67371051c1f168172 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:41:24 +0100 Subject: [PATCH 687/805] [Doc] Format release notes. --- CHANGELOG.adoc | 142 ++++++++++++++++++++++++------------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 7062e70ebb..d5932da0a9 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,74 +1,74 @@ = Changelog -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.36.0[1.36.0] - 2025-09-29 - -* **[C{plus}{plus}]** Fix composite encode generation to use formatted property names, i.e. escape keywords. -* **[C{plus}{plus}]** Fix property name usage in display code generator. -* **[C{plus}{plus}]** Add getter for schema id on the `IrDecoder` (https://github.com/aeron-io/simple-binary-encoding/pull/1077[#1077]) -* **[Java]** Fix var data and composite code generation to use property name instead of plain name. Also use property name for access order check methods. (https://github.com/aeron-io/simple-binary-encoding/issues/1081[#1081]) -* **[Java]** Handle `null` values when encoding enums, i.e. use `Enum.NULL_VAL` if the value was not assigned. -* **[Java]** Handle primitive arrays correctly in the generated DTO code. -* **[Go]** Handle `_` and `String` as keywords and use property name when generating variable data section. +== 1.36.0 (2025-09-29) + +* *[C{plus}{plus}]* Fix composite encode generation to use formatted property names, i.e. escape keywords. +* *[C{plus}{plus}]* Fix property name usage in display code generator. +* *[C{plus}{plus}]* Add getter for schema id on the `IrDecoder` (https://github.com/aeron-io/simple-binary-encoding/pull/1077[#1077]) +* *[Java]* Fix var data and composite code generation to use property name instead of plain name. Also use property name for access order check methods. (https://github.com/aeron-io/simple-binary-encoding/issues/1081[#1081]) +* *[Java]* Handle `null` values when encoding enums, i.e. use `Enum.NULL_VAL` if the value was not assigned. +* *[Java]* Handle primitive arrays correctly in the generated DTO code. +* *[Go]* Handle `_` and `String` as keywords and use property name when generating variable data section. * **[C#]** Replaced empty array creation by `Array.Empty`, issue (https://github.com/aeron-io/simple-binary-encoding/issues/1079[#1079]). (https://github.com/aeron-io/simple-binary-encoding/pull/1080[#1080]) -* **[C/C{plus}{plus}]** Allow overriding Gradle wrapper location. (https://github.com/aeron-io/simple-binary-encoding/issues/1091[#1091]). -* **[Java/C{plus}{plus}/Go]** Preserve `packageName` in the IR. (https://github.com/aeron-io/simple-binary-encoding/issues/1089[#1089]) -* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.0[Agrona 2.3.0]. -* **[Java]** Upgrade to `JUnit` 5.13.4. -* **[Java]** Upgrade to `Mockito` 5.20.0. -* **[Java]** Upgrade to `Checkstyle` 11.1.0. -* **[Java]** Upgrade to `Shadow` 9.2.2. -* **[Java]** Upgrade to `Version` 0.53.0. -* **[C]** Upgrade to `GoogleTest` to 1.14.0. -* **[C]** Bump minimium required CMake version to `3.30`. -* **[CI]** Add `Clang` 21 to the build matrix. -* **[CI]** Add `Java` 25 to the build matrix. - -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.6[1.35.6] - 2025-06-27 - -* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.4[Agrona 2.2.4]. -* **[Java]** Upgrade to `JUnit` 5.13.2. -* **[Java]** Upgrade to `Checkstyle` 10.26.0. -* **[Java]** Upgrade to `Shadow` 8.3.7. - -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.5[1.35.5] - 2025-06-20 +* *[C/C{plus}{plus}]* Allow overriding Gradle wrapper location. (https://github.com/aeron-io/simple-binary-encoding/issues/1091[#1091]). +* *[Java/C{plus}{plus}/Go]* Preserve `packageName` in the IR. (https://github.com/aeron-io/simple-binary-encoding/issues/1089[#1089]) +* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.0[Agrona 2.3.0]. +* *[Java]* Upgrade to `JUnit` 5.13.4. +* *[Java]* Upgrade to `Mockito` 5.20.0. +* *[Java]* Upgrade to `Checkstyle` 11.1.0. +* *[Java]* Upgrade to `Shadow` 9.2.2. +* *[Java]* Upgrade to `Version` 0.53.0. +* *[C]* Upgrade to `GoogleTest` to 1.14.0. +* *[C]* Bump minimium required CMake version to `3.30`. +* *[CI]* Add `Clang` 21 to the build matrix. +* *[CI]* Add `Java` 25 to the build matrix. + +== 1.35.6 (2025-06-27) + +* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.4[Agrona 2.2.4]. +* *[Java]* Upgrade to `JUnit` 5.13.2. +* *[Java]* Upgrade to `Checkstyle` 10.26.0. +* *[Java]* Upgrade to `Shadow` 8.3.7. + +== 1.35.5 (2025-06-20) * **[Java/C{plus}{plus}/C#]** Fix a bug in overzealous DTO validation. (https://github.com/aeron-io/simple-binary-encoding/pull/1073[#1073]) -* **[Java]** Improve JsonPrinter's conformance with the JSON specification (e.g., escaping control characters and using correct delimiters). -* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.3[Agrona 2.2.3]. +* *[Java]* Improve JsonPrinter's conformance with the JSON specification (e.g., escaping control characters and using correct delimiters). +* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.3[Agrona 2.2.3]. -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.4[1.35.4] - 2025-06-12 +== 1.35.4 (2025-06-12) -* **[Rust]** Return None for optional primite field if its version is less than actingVersion. (https://github.com/aeron-io/simple-binary-encoding/pull/1067[#1067]) -* **[Java]** Adjust Java Dto generateComputeEncodedLength to acount for character encoding. (https://github.com/aeron-io/simple-binary-encoding/pull/1072[#1072]) -* **[Java]** Upgrade to `JUnit` 5.13.1. -* **[Java]** Upgrade to `jqwik` 1.9.3. +* *[Rust]* Return None for optional primite field if its version is less than actingVersion. (https://github.com/aeron-io/simple-binary-encoding/pull/1067[#1067]) +* *[Java]* Adjust Java Dto generateComputeEncodedLength to account for character encoding. (https://github.com/aeron-io/simple-binary-encoding/pull/1072[#1072]) +* *[Java]* Upgrade to `JUnit` 5.13.1. +* *[Java]* Upgrade to `jqwik` 1.9.3. -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.3[1.35.3] - 2025-06-06 +== 1.35.3 (2025-06-06) -* **[Java]** Publish release artifacts to Central Portal using OSSRH Staging API service. -* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.2[Agrona 2.2.2]. -* **[Java]** Upgrade to `Checkstyle` 10.25.0. -* **[Java]** Upgrade to `Gradle` 8.14.2. +* *[Java]* Publish release artifacts to Central Portal using OSSRH Staging API service. +* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.2[Agrona 2.2.2]. +* *[Java]* Upgrade to `Checkstyle` 10.25.0. +* *[Java]* Upgrade to `Gradle` 8.14.2. -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.1[1.35.1] - 2025-06-02 +== 1.35.1 (2025-06-02) * Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.1[Agrona 2.2.1]. * Upgrade to `JUnit` 5.13.0. -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.35.0[1.35.0] - 2025-05-26 +== 1.35.0 (2025-05-26) -* **[Java]** include field 'deprecated' in ir encoding and decoding. -* **[Java]** Adjust Java DTO Choice Set Access. (https://github.com/aeron-io/simple-binary-encoding/issues/1064[#1064]) -* **[Rust]** get proper version for composite types. (https://github.com/aeron-io/simple-binary-encoding/pull/1058[#1058]) +* *[Java]* include field 'deprecated' in ir encoding and decoding. +* *[Java]* Adjust Java DTO Choice Set Access. (https://github.com/aeron-io/simple-binary-encoding/issues/1064[#1064]) +* *[Rust]* get proper version for composite types. (https://github.com/aeron-io/simple-binary-encoding/pull/1058[#1058]) * **[C#]** Read NuGet package version from version file (https://github.com/aeron-io/simple-binary-encoding/pull/1061[#1061]) * **[C#]** Enable dual build for netstandard2.0 & netstandard2.1. (https://github.com/aeron-io/simple-binary-encoding/pull/1062[#1062]) * Update `Implementation-Vendor`. -* **[Rust]** Elide explicit ActingVersion lifetime. (https://github.com/aeron-io/simple-binary-encoding/pull/1053[#1053]) -* **[CI]** Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. -* **[CI]** Enable JDK 24 GA build. -* **[CI]** Simplify error log upload. -* **[CI]** Remove Ubuntu 20.04 based builds. -* **[CI]** Bump Go build to use 1.23.x and 1.24.x. +* *[Rust]* Elide explicit ActingVersion lifetime. (https://github.com/aeron-io/simple-binary-encoding/pull/1053[#1053]) +* *[CI]* Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. +* *[CI]* Enable JDK 24 GA build. +* *[CI]* Simplify error log upload. +* *[CI]* Remove Ubuntu 20.04 based builds. +* *[CI]* Bump Go build to use 1.23.x and 1.24.x. * Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.0[Agrona 2.2.0]. * Upgrade to `Gradle` 8.14.1. * Upgrade to `Checkstyle` 10.24.0. @@ -78,22 +78,22 @@ * Upgrade to `Shadow` 8.3.6. * Bump `Versions` to 0.52. -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.1[1.34.1] - 2025-01-13 +== 1.34.1 (2025-01-13) * *Doc:* Add `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` to the example execution. -* **[Rust]** encoding primitive arrays now supports slice instead of array (issue https://github.com/aeron-io/simple-binary-encoding/issues/[#1021]). (https://github.com/aeron-io/simple-binary-encoding/pull/1040[#1040]) -* **[C{plus}{plus}]** check for not wrapped state in `decodeLength()` when precedence checks are enabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1046[#1046]) -* **[C{plus}{plus}]** use `m_actingBlockLength` in `decodeLength()`. (https://github.com/aeron-io/simple-binary-encoding/pull/1045[#1045]) +* *[Rust]* encoding primitive arrays now supports slice instead of array (issue https://github.com/aeron-io/simple-binary-encoding/issues/[#1021]). (https://github.com/aeron-io/simple-binary-encoding/pull/1040[#1040]) +* *[C{plus}{plus}]* check for not wrapped state in `decodeLength()` when precedence checks are enabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1046[#1046]) +* *[C{plus}{plus}]* use `m_actingBlockLength` in `decodeLength()`. (https://github.com/aeron-io/simple-binary-encoding/pull/1045[#1045]) * Bump `json` to 20250107. * Upgrade to `Mockito` 5.15.2. -== https://github.com/aeron-io/simple-binary-encoding/releases/tag/1.34.0[1.34.0] - 2024-12-17 +== 1.34.0 (2024-12-17) -* **[C{plus}{plus}]** hide the m_codecStatePtr behind ifdefs to avoid overhead when precedence checking is disabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1036[#1036]) -* **[C{plus}{plus}]** use constexpr to define precedence checks lookup tables. -* **[Rust]** Enhance enum supporting fromstr and display and into. (https://github.com/aeron-io/simple-binary-encoding/pull/1020[#1020]) -* **[Rust]** codegen of primitive enums now implement 'From' instead of 'Into'. (https://github.com/aeron-io/simple-binary-encoding/pull/1029[#1029]) -* **[Java]** Update Checkstyle rules and apply them. +* *[C{plus}{plus}]* hide the m_codecStatePtr behind ifdefs to avoid overhead when precedence checking is disabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1036[#1036]) +* *[C{plus}{plus}]* use constexpr to define precedence checks lookup tables. +* *[Rust]* Enhance enum supporting fromstr and display and into. (https://github.com/aeron-io/simple-binary-encoding/pull/1020[#1020]) +* *[Rust]* codegen of primitive enums now implement 'From' instead of 'Into'. (https://github.com/aeron-io/simple-binary-encoding/pull/1029[#1029]) +* *[Java]* Update Checkstyle rules and apply them. * *Breaking:* Upgrade to `Agrona` 2.0.0. + _**Note:** `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` JVM option must be specified in order to generate codecs or use the generated Java classes. For example:_ @@ -103,15 +103,15 @@ _**Note:** `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` JVM option must $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=true -Dsbe.target.language=Cpp -Dsbe.target.namespace=sbe -Dsbe.output.dir=include/gen -Dsbe.errorLog=yes -jar sbe-all/build/libs/sbe-all-${SBE_TOOL_VERSION}.jar my-sbe-messages.xml ---- -* **[C{plus}{plus}]** Fix field precedence check issue https://github.com/aeron-io/simple-binary-encoding/issues/1031[#1031]. (https://github.com/aeron-io/simple-binary-encoding/pull/1033[#1033]) -* **[C{plus}{plus}]** respect the package override option for C{plus}{plus} codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) +* *[C{plus}{plus}]* Fix field precedence check issue https://github.com/aeron-io/simple-binary-encoding/issues/1031[#1031]. (https://github.com/aeron-io/simple-binary-encoding/pull/1033[#1033]) +* *[C{plus}{plus}]* respect the package override option for C{plus}{plus} codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) * **[C#]** respect the package override option for C# codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) -* **[Go]** Fix warning about used args in GolangFlyweightGenerator. -* **[Rust]** Updated code generator to resolve Issue https://github.com/aeron-io/simple-binary-encoding/issues/1028[#1028]. (https://github.com/aeron-io/simple-binary-encoding/pull/1037[#1037]) -* **[Java]** Prevent collision when field name is 'value'. -* **[Java]** Preserve byte order throughout IR transformations. -* **[C{plus}{plus}]** Integrate std::span support for flyweight API. (https://github.com/aeron-io/simple-binary-encoding/pull/1038[#1038], https://github.com/aeron-io/simple-binary-encoding/pull/1027[#1027]) -* **[Rust]** generate message schema level info in lib.rs. (https://github.com/aeron-io/simple-binary-encoding/pull/1019[#1019]) +* *[Go]* Fix warning about used args in GolangFlyweightGenerator. +* *[Rust]* Updated code generator to resolve Issue https://github.com/aeron-io/simple-binary-encoding/issues/1028[#1028]. (https://github.com/aeron-io/simple-binary-encoding/pull/1037[#1037]) +* *[Java]* Prevent collision when field name is 'value'. +* *[Java]* Preserve byte order throughout IR transformations. +* *[C{plus}{plus}]* Integrate std::span support for flyweight API. (https://github.com/aeron-io/simple-binary-encoding/pull/1038[#1038], https://github.com/aeron-io/simple-binary-encoding/pull/1027[#1027]) +* *[Rust]* generate message schema level info in lib.rs. (https://github.com/aeron-io/simple-binary-encoding/pull/1019[#1019]) * Upgrade to `Gradle` 8.11.1. * Upgrade to `Checkstyle` 10.21.0. * Upgrade to `ByteBuddy` 1.15.11. From 02f5a68bd54750d9a373ac10f9f0fc6bd38bcfdc Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:58:50 +0100 Subject: [PATCH 688/805] [Doc] Complete release since the beginning of time. --- CHANGELOG.adoc | 1056 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1051 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index d5932da0a9..aac63dd520 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,12 @@ = Changelog +== 1.36.1 (2025-11-03) + +* *[C#]* Handle case when `valueRef` is with enum type prefix. (https://github.com/aeron-io/simple-binary-encoding/pull/1092[#1092]) +* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.1[Agrona 2.3.1]. +* *[Java]* Upgrade to `JUnit` 6.0.1. +* *[Java]* Upgrade to `Checkstyle` 12.1.1. + == 1.36.0 (2025-09-29) * *[C{plus}{plus}]* Fix composite encode generation to use formatted property names, i.e. escape keywords. @@ -9,7 +16,7 @@ * *[Java]* Handle `null` values when encoding enums, i.e. use `Enum.NULL_VAL` if the value was not assigned. * *[Java]* Handle primitive arrays correctly in the generated DTO code. * *[Go]* Handle `_` and `String` as keywords and use property name when generating variable data section. -* **[C#]** Replaced empty array creation by `Array.Empty`, issue (https://github.com/aeron-io/simple-binary-encoding/issues/1079[#1079]). (https://github.com/aeron-io/simple-binary-encoding/pull/1080[#1080]) +* *[C#]* Replaced empty array creation by `Array.Empty`, issue (https://github.com/aeron-io/simple-binary-encoding/issues/1079[#1079]). (https://github.com/aeron-io/simple-binary-encoding/pull/1080[#1080]) * *[C/C{plus}{plus}]* Allow overriding Gradle wrapper location. (https://github.com/aeron-io/simple-binary-encoding/issues/1091[#1091]). * *[Java/C{plus}{plus}/Go]* Preserve `packageName` in the IR. (https://github.com/aeron-io/simple-binary-encoding/issues/1089[#1089]) * *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.0[Agrona 2.3.0]. @@ -32,7 +39,7 @@ == 1.35.5 (2025-06-20) -* **[Java/C{plus}{plus}/C#]** Fix a bug in overzealous DTO validation. (https://github.com/aeron-io/simple-binary-encoding/pull/1073[#1073]) +* *[Java/C{plus}{plus}/C#]* Fix a bug in overzealous DTO validation. (https://github.com/aeron-io/simple-binary-encoding/pull/1073[#1073]) * *[Java]* Improve JsonPrinter's conformance with the JSON specification (e.g., escaping control characters and using correct delimiters). * *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.3[Agrona 2.2.3]. @@ -60,8 +67,8 @@ * *[Java]* include field 'deprecated' in ir encoding and decoding. * *[Java]* Adjust Java DTO Choice Set Access. (https://github.com/aeron-io/simple-binary-encoding/issues/1064[#1064]) * *[Rust]* get proper version for composite types. (https://github.com/aeron-io/simple-binary-encoding/pull/1058[#1058]) -* **[C#]** Read NuGet package version from version file (https://github.com/aeron-io/simple-binary-encoding/pull/1061[#1061]) -* **[C#]** Enable dual build for netstandard2.0 & netstandard2.1. (https://github.com/aeron-io/simple-binary-encoding/pull/1062[#1062]) +* *[C#]* Read NuGet package version from version file (https://github.com/aeron-io/simple-binary-encoding/pull/1061[#1061]) +* *[C#]* Enable dual build for netstandard2.0 & netstandard2.1. (https://github.com/aeron-io/simple-binary-encoding/pull/1062[#1062]) * Update `Implementation-Vendor`. * *[Rust]* Elide explicit ActingVersion lifetime. (https://github.com/aeron-io/simple-binary-encoding/pull/1053[#1053]) * *[CI]* Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. @@ -105,7 +112,7 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru * *[C{plus}{plus}]* Fix field precedence check issue https://github.com/aeron-io/simple-binary-encoding/issues/1031[#1031]. (https://github.com/aeron-io/simple-binary-encoding/pull/1033[#1033]) * *[C{plus}{plus}]* respect the package override option for C{plus}{plus} codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) -* **[C#]** respect the package override option for C# codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) +* *[C#]* respect the package override option for C# codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) * *[Go]* Fix warning about used args in GolangFlyweightGenerator. * *[Rust]* Updated code generator to resolve Issue https://github.com/aeron-io/simple-binary-encoding/issues/1028[#1028]. (https://github.com/aeron-io/simple-binary-encoding/pull/1037[#1037]) * *[Java]* Prevent collision when field name is 'value'. @@ -117,3 +124,1042 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru * Upgrade to `ByteBuddy` 1.15.11. * Upgrade to `JUnit` 5.11.4. * Upgrade to `jqwik` 1.9.2. + +== 1.33.2 (2024-11-08) + +* *[Rust]* Help decoding multiple messages using rust by resolving https://github.com/aeron-io/simple-binary-encoding/issues/987[#987]. +* *[Go]* SBE implementation in Go using flyweights. +* *[Java]* DTOs respect the optional package field in the schema definition. +* *[Java]* Fix bug in DTO `decodeFrom` signature. + +== 1.33.1 (2024-09-23) + +* *[Java]* Fix #1012 DTO char array setter visibility. +* *[Rust]* Indicate the anonymous lifetime in set's Display impl (https://github.com/aeron-io/simple-binary-encoding/pull/1014[#1014]). +* *[Java]* Style consistency and add JavadocVariable Checkstyle test. +* *[Java]* Use version catalogs. +* *[Java]* Upgrade to JUnit 5.13.0. +* *[Java]* Upgrade to Gradle 8.10.1. +* *[Java]* Upgrade to Shadow 8.3.2. +* *[Java]* Upgrade to Checkstyle 10.18.1. + +== 1.33.0 (2024-08-24) + +=== Breaking changes + +* *JDK 17 is required for compiling and running!* + +=== Changelog + +* *[CI]* Execute tests using `ubuntu-24.04` and `macos-latest`. +* *[Java]* Upgrade to Agrona 1.23.0. +* *[Java]* Upgrade to Gradle 8.10. +* *[Java]* Upgrade to Shadow 8.3.0. +* *[Java]* Upgrade to Mockito 5.12.0. + +== 1.32.2 (2024-08-23) + +* *[Rust]* Generate imports in alphabetical order. #997 +* *[Rust]* Make Rust crate version configurable. #996 +* *[C]* fix compilation error in C string view functions. #1010 +* *[Java]* Upgrade to JUnit 5.11.0. + +== 1.32.1 (2024-08-05) + +* *[Java]* Upgrade to Agrona 1.22.0. +* *[Java]* Upgrade to Hamcrest 3.0. + +== 1.32.0 (2024-08-02) + +* [C#,C{plus}{plus},Java] Generate DTOs for non-perf-sensitive usecases. #957 +* [C{plus}{plus}, C#] Only generate range validation code when specifying a range smaller than the associate type. +* *[C#]* Fix ToString() to avoid state changes on message. #992 +* *[C]* Add a #define for each template id. #1006 +* [Java, C#, C{plus}{plus}] Check enum value for language specific keywords and apply `sbe.keyword.append.token` when appropriate. #1009 #1008 + +== 1.31.0 (2024-04-03) + +* *[Java]* Remove unused initialOffset member from generated codecs. +* *[Java]* Check for being in a composite when generating array access methods based on version. +* *[Java]* Captured types in IR should be for the minimum version used in a schema. https://github.com/aeron-io/simple-binary-encoding/pull/967[#967]. +* *[C{plus}{plus}]* Provide access to acting block length of repeating group via the sbeActingBlockLength() method. Issue #968. +* *[C{plus}{plus}]* message header members constexpr https://github.com/aeron-io/simple-binary-encoding/pull/971[#971]. +* *[C{plus}{plus}]* Code tidy up and address Issue #970. +* *[Java]* Cope with optional sets not being present when pretty printing decoders for debugging. https://github.com/aeron-io/simple-binary-encoding/pull/977[#977]. +* *[C{plus}{plus}]* small test fix https://github.com/aeron-io/simple-binary-encoding/pull/980[#980]. +* *[Rust]* Updated RustGenerator.generatePrimitiveOptionalDecoder() https://github.com/aeron-io/simple-binary-encoding/pull/981[#981]. +* *[Rust]* Take slices by reference https://github.com/aeron-io/simple-binary-encoding/pull/979[#979]. +* *[Rust]* updated code generator to prevent rust warning for "ambiguous glob re-exports" https://github.com/aeron-io/simple-binary-encoding/pull/982[#982]. +* *[Go]* Handle mixed case enums and BitSets. Fixes #983. +* *[Java]* Use `BYTE_ORDER` constant instead of accessing `java.nio.ByteOrder` directly. +* Upgrade .NET SDK to 8.0.201 (https://github.com/aeron-io/simple-binary-encoding/pull/978[#978]). +* *[Java]* Upgrade to Agrona 1.21.1. +* *[Java]* Upgrade to ASM 9.7. +* *[Java]* Upgrade to JUnit 5.10.2. +* *[Java]* Upgrade to Versions 0.51.0. + +== 1.30.0 (2023-12-06) + +* [Java, C{plus}{plus}, C#] Add support to https://github.com/aeron-io/simple-binary-encoding/wiki/Safe-Flyweight-Usage[check the safe usage of flyweights (w.r.t. field access order)]. https://github.com/aeron-io/simple-binary-encoding/pull/948[#948]. +* *[C#]* Fix invalid code generated when using some length types for var data https://github.com/aeron-io/simple-binary-encoding/issues/955[#955] +* *[Java]* Support valueRef with camelCase enum type identifiers https://github.com/aeron-io/simple-binary-encoding/pull/963[#963] +* *[Rust]* update how "use declarations" are generated, now deriving Defaults for enums https://github.com/aeron-io/simple-binary-encoding/pull/952[#952] +* *[C{plus}{plus}]* Rely on NAN from limits rather than pulling in cmath (https://github.com/aeron-io/simple-binary-encoding/issues/956) +* *[Java]* Fix javadoc link for JDK 21 GA +* *[Java]* Expose actingVersion https://github.com/aeron-io/simple-binary-encoding/pull/953[#953] +* Upgrade Agrona to 1.20.0 +* Upgrade to ASM 9.6 +* Upgrade to JMH 1.27 +* Upgrade to JUnit 5.10.1 +* Upgrade Versions to 0.50.0 + +== 1.29.0 (2023-07-21) + +* *[Rust]* Add derive Copy Clone traits for decoders (PR #940). +* *[Rust]* Fix clippy lint (PR #941). +* *[Rust]* Fix array syntax error (PR #946). +* *[Rust]* Improve rust performance (PR #944). +* JsonPrinter remove trailing garbage after non-printable char (PR #950). +* Upgrade to Agrona 1.19.0. +* Upgrade to versions 0.47.0. + +== 1.28.3 (2023-06-08) + +* CppGenerator: operator<< take messages as const-ref (PR #939) +* JDK 21-ea warning fixes. +* Upgrade to Agrona 1.18.2. +* Upgrade to JUnit 5.9.3. +* Upgrade to ASM 9.5 for JDK 21-ea support. +* Upgrade to Shadow 8.1.1. +* Upgrade to Gradle 8.1.1. + +== 1.28.2 (2023-04-17) + +* Upgrade to Agrona 1.18.1. + +== 1.28.1 (2023-03-29) + +* Fix SBE_SEMANTIC_VERSION field generation for C{plus}{plus}. + +== 1.28.0 (2023-03-29) + +* Added semantic version as a static public member. PR #931. +* *[Rust]* Nested composite name should not be based on field name. PR #922. +* *[C/C{plus}{plus}]* Prevent clashing defines in C/C{plus}{plus} codecs when multiple generated schemas are used. Issue #884. +* *[C#]* Compare `PrimitiveValue` with doubles in the same way as Java by the raw bits, so NaN and Infinity are correctly handled. +* Add CodeQL workflow. +* *[C#]* Add `ToString` for `PrimitiveType` +* *[C{plus}{plus}]* Pass by reference rather than value when streaming to a string. +* *[C{plus}{plus}]* Address duplicate guard issues. +* *[Java]* More efficient attribute parsing in XML with a more precise error message. +* *[Java]* Validate IR file for decoding is not greater than Integer.MAX_VALUE. +* *[C/C{plus}{plus}]* Move check for existing `SBE_BOUNDS_CHECK_EXPECT` define to outer condition to capture all platforms. +* *[Java]* Print warnings for undersize header fields. +* Upgrade to Agrona 1.18.0. +* Upgrade to Mockito 4.11.0. +* Upgrade to Junit 5.9.2. +* Upgrade to JMH 1.36. +* Upgrade to versions plugin 0.45.0. +* Upgrade to Gradle 7.6. + +== 1.27.0 (2022-10-11) + +* *[Java]* Add preview support for package override on types from SBE 2.0. https://github.com/aeron-io/simple-binary-encoding/pull/904[#904], https://github.com/aeron-io/simple-binary-encoding/pull/915[#915]. +* Add support for transforming a schema to generate code for older versions when checking compatibility. +* *[Java]* Support binary var data in `JsonPrinter`. https://github.com/aeron-io/simple-binary-encoding/pull/914[#914]. +* *[Java]* Qualify methods with name `yield` to avoid warning in Java 17. https://github.com/aeron-io/simple-binary-encoding/pull/910[#910]. +* Carry down the the `sinceVersion` value into composite types to make parsing OTF easier. https://github.com/aeron-io/simple-binary-encoding/issues/908[Issue #908]. +* Set the size for constant encoded data type to be zero in IR. +* Upgrade to Google Test 1.21.1. +* Upgrade to Mockito 4.7.0. +* Upgrade to JUnit 5.9.1. +* Upgrade to Gradle 7.5.1. +* Upgrade to Agrona 1.17.1. + +== 1.26.0 (2022-07-11) + +* *[Java]* Provide raw access to type for bitset. https://github.com/aeron-io/simple-binary-encoding/issues/893[Issue #893]. +* *[C{plus}{plus}]* Generate `skip` function with loop rather than lambda to avoid compilation errors on some compilers. https://github.com/aeron-io/simple-binary-encoding/issues/903[Issue #903]. +* Check `sinceVersion` is valid on elements against schema version. https://github.com/aeron-io/simple-binary-encoding/issues/902[Issue #902]. +* *[Rust]* Fix generated comparator when value is `NaN`. https://github.com/aeron-io/simple-binary-encoding/pull/896[#896]. +* *[Rust]* Fix resource leak in Rust generator running in Java SBE compiler. +* *[Java]* Generate `@SuppressWarnings` annotation on enums types. https://github.com/aeron-io/simple-binary-encoding/issues/894[Issue #894]. +* Upgrade to Mockito 4.6.1. +* Upgrade to Agrona 1.16.0. + +== 1.25.3 (2022-04-14) + +* Set correct version range for Agrona dependency check. +* Upgrade to Gradle 7.4.2. +* Upgrade to JMH 1.35. +* Upgrade to Agrona 1.15.1. + +== 1.25.2 (2022-03-18) + +* *[Java]* Calling `toString()` on decoder should not disturb repeating group. https://github.com/aeron-io/simple-binary-encoding/pull/892[#892]. +* *[All]* Generate `NULL_VALUE` for enums based on correct type. https://github.com/aeron-io/simple-binary-encoding/issues/889[Issue #889]. +* *[C{plus}{plus}]* Check for version before outputting to stream for composites and bitsets. https://github.com/aeron-io/simple-binary-encoding/pull/888[#888]. +* *[Java]* Charset handling improvements for more efficient string decoding. https://github.com/aeron-io/simple-binary-encoding/pull/887[#887]. +* Add descriptions to schema for IR. +* Set warnings as errors in build and clean up existing warnings. +* Add ability to set the error stream in `ParserOptions`. +* Remove some unnecessary checks in `XmlSchemaParser` to improve generation performance. +* Upgrade to Versions 0.42.0. +* Upgrade to Checkstyle 9.3. +* Upgrade to JMH 1.34. +* Upgrade to Mockito 4.4.0. +* Upgrade to Shadow 7.1.2. +* Upgrade to JUnit 5.8.2. +* Upgrade to Gradle 7.4.1. +* Upgrade to Agrona 1.15.0. + +== 1.25.1 (2021-11-24) + +* Upgrade to Mockito 4.1.0. +* Upgrade to Agrona 1.14.0. + +== 1.25.0 (2021-11-17) + +* *[C#]* Add support for wrapping `ArraySegment` in `DirectBuffer`. https://github.com/aeron-io/simple-binary-encoding/pull/878[#878]. +* *[Java]* Add `@Deprecated` annotation to message codecs that have been marked as deprecated in SBE schema. https://github.com/aeron-io/simple-binary-encoding/pull/876[#876]. +* *[C{plus}{plus}]* Only generate necessary macros and includes for enum types. +* *[Rust]* Reinstate improved Rust codec generation. +* *[Java]* Add `sbeSkip` and `sbeDecodedLength` methods to codecs. https://github.com/aeron-io/simple-binary-encoding/pull/865[#865]. +* Upgrade to JUnit 5.8.1. +* Upgrade to Shadow 7.1.0. +* Upgrade to Mockito 4.0.0. +* Upgrade to Checkstyle 9.1. +* Upgrade to JMH 1.33. +* Upgrade to Gradle 7.2. +* Upgrade to Agrona 1.13.0. + +== 1.24.0 (2021-08-06) + +* *[Java]* Improve efficiency of encoding `CharSequence` when ASCII character encoding is used. +* *[Java]* Check that IR codecs are regenerated on codec change. +* *[Java/C{plus}{plus}/C]* Add `sbeRewind` to decoders so they can rewind to the beginning of a message and begin decoding again. +* Upgrade to Google Test 1.11.0 +* Upgrade to ByteBuddy 1.11.3 +* Upgrade to Mockito 3.11.2. +* Upgrade to Gradle 7.1.1. +* Upgrade to Agrona 1.12.0. + +== 1.23.0 (2021-06-13) + +* *[C#]* Add `ToString()` method to generated codecs. https://github.com/aeron-io/simple-binary-encoding/pull/853[#853]. +* *[C#]* Add more string read and write methods to codecs. https://github.com/aeron-io/simple-binary-encoding/pull/845[#845]. +* *[Go]* Fix tokens passed when generating composites. https://github.com/aeron-io/simple-binary-encoding/pull/850[#850]. +* *[C/C{plus}{plus}]* Add Clang 12 to the matrix build. +* Upgrade to Versions 0.39.0. +* Upgrade to JUnit 5.7.2. +* Upgrade to Mockito 3.11.1. +* Upgrade to ByteBuddy 1.11.2. +* Upgrade to JMH 1.32. +* Upgrade to Shadow 7.0.0. +* Upgrade to Gradle 7.0.2. +* Upgrade to Agrona 1.11.0. + +== 1.22.0 (2021-04-16) + +* *[C#]* Convert benchmarks to use DotNetBenchmark. https://github.com/aeron-io/agrona/pull/841[#841]. +* *[C#]* Help compiler to inline `DirectBuffer.CheckLimit` for better performance. https://github.com/aeron-io/simple-binary-encoding/pull/840[#840]. +* Add Java 17-ea to the build matrix. +* Test with CME FixBinary version 9. +* *[C{plus}{plus}]* Capture `actingBlockLength` and use it for prettying printing output in version aware codecs. https://github.com/aeron-io/simple-binary-encoding/issues/839[Issue #839]. +* *[C{plus}{plus}]* Remove invalid use of `noexcept` on `resetCountToIndex`. https://github.com/aeron-io/simple-binary-encoding/issues/838[Issue #838]. +* *[Java]* Generate a `wrapAndApplyHeader` method for decoders to verify template then apply acting version and offset. +* *[C{plus}{plus}]* Clean up and improve samples. +* *[C{plus}{plus}]* Pass elements by reference rather than value in `forEach` for more efficient skip operations. +* Upgrade to Version 0.38.0. +* Upgrade to JMH 1.29. +* Upgrade to JUnit 5.7.1. +* Upgrade to Mockito 3.9.0. +* Upgrade to Gradle 6.8.3. +* Upgrade to Agrona 1.10.0. + +== 1.21.0 (2021-01-15) + +* *[Java]* Generate metadata methods to groups for min and max count values. https://github.com/aeron-io/simple-binary-encoding/pull/834[#834]. +* *[Java]* Declare generated classes as final to allow for better optimisation and increased performance. +* *[C{plus}{plus}]* Null terminate constant char arrays to avoid warnings. https://github.com/aeron-io/simple-binary-encoding/issues/832[Issue #832]. +* *[C{plus}{plus}]* Add support for decoding unknown enum values from later versions by enabling `sbe.decode.unknown.enum.values` and provide access to raw values. +* Clean up warnings in bash scripts. +* Upgrade to Checkstyle 8.39. +* Upgrade to Mockito 3.7.0. + +== 1.20.4 (2020-12-22) + +* Add parsing of CME iLink order protocol to tests. +* *[C{plus}{plus}]* Generate literal marked up for correct type when shifting for bitsets using `uint64`. https://github.com/aeron-io/simple-binary-encoding/pull/829[#829]. +* *[Java]* Generate `@return` in javadoc for bitset values. https://github.com/aeron-io/simple-binary-encoding/issues/828[Issue #828]. +* *[Java]* Escape basic HTML characters for javadoc. https://github.com/aeron-io/simple-binary-encoding/issues/826[Issue #826]. +* *[Go]* Fix decoding into struct with pre-allocated slices. https://github.com/aeron-io/simple-binary-encoding/pull/825[#825]. +* *[C{plus}{plus}]* Fix spelling of `_cplusplus` macro. https://github.com/aeron-io/simple-binary-encoding/issues/823[Issue #821]. +* *[C#]* Fix repeating group encode overflow. https://github.com/aeron-io/simple-binary-encoding/pull/823[#823]. +* *[C]* Fix argument order for wrap_and_apply_header methods. https://github.com/aeron-io/simple-binary-encoding/pull/821[#821]. +* *[Java]* Generate bulk methods for fixed length `uint8` arrays. https://github.com/aeron-io/simple-binary-encoding/pull/819[#819]. +* Add Java 16 EA to the build matrix. +* Upgrade to JMH 1.27. +* Upgrade to Checkstyle 8.38. +* Upgrade to Versions 0.36.0. +* Upgrade to Mockito 3.6.28. +* Upgrade to Gradle 6.7.1. +* Upgrade to Agrona 1.9.0. + +== 1.20.3 (2020-10-13) + +* Fix generation of `GroupOrder` annotations on Java codecs. +* Java codecs have a new method `MessageDecoderFlyweight.appendTo(StringBuilder)` for the interface. https://github.com/aeron-io/agrona/pull/220[#220]. +* Reduce scope of some fields in Java codecs which were protected and should have been package or private. +* Add GCC 10 and Clang 10 to build mix. +* Add Java 15 to build mix. +* Upgrade to JMH 1.26. +* Upgrade to Checkstyle 8.36.2. +* Upgrade to Mockito 3.5.13. +* Upgrade to Agrona 1.8.0. + +== 1.20.2 (2020-09-18) + +* Indicate files are auto-generated for C# so they can be ignored by VS. https://github.com/aeron-io/simple-binary-encoding/pull/814[#814]. +* Fix CMake install on MacOS. +* Support CMake 3.6.1 as a minimum version. +* Upgrade to Versions 0.33.0. +* Upgrade to JUnit 5.7.0. +* Upgrade to Agrona 1.7.2. + +== 1.20.1 (2020-09-12) + +* Validate enum values are in the range for type considering min and max value, excluding null value. +* Upgrade to Versions 0.31.0. +* Upgrade to Checkstyle 8.36. +* Upgrade to Mockito 3.5.10. +* Upgrade to JMH 1.25.2. +* Upgrade to Agrona 1.7.1. + +== 1.20.0 (2020-08-29) + +* Improve validation and error messages when parsing invalid SBE schemas. +* Generate SBE header constants in C{plus}{plus} codecs so they can be used more easily in switch statements. +* Generate C{plus}{plus} style casts rather than C style casts in C{plus}{plus} codecs. +* Generate enum literals beyond `int` range correctly for C and C{plus}{plus}. +* Enum get methods for C{plus}{plus} codecs should not be `noexcept`. https://github.com/aeron-io/simple-binary-encoding/pull/806[#806]. +* Improve javadoc. +* Update Gradle build script so IDEA can more easily get the dependencies correct for generated code. +* Upgrade to Gradle 6.6.1. +* Upgrade to Mockito 3.5.7. +* Upgrade to JMH 1.25.1. +* Upgrade to Checkstyle 8.35. +* Upgrade to Version 0.29.0. +* Upgrade to Agrona 1.7.0. + +== 1.19.0 (2020-07-14) + +* Improve edge case generation for `JsonPrinter` when groups have num in group of zero. https://github.com/aeron-io/simple-binary-encoding/issues/800[Issue #800]. +* Improve edge case generation for `JsonPrinter` when messages are empty. https://github.com/aeron-io/simple-binary-encoding/issues/799[Issue #799]. +* Fix case of generated variables in C{plus}{plus} `computeLength` method which could cause compilation errors. https://github.com/aeron-io/simple-binary-encoding/issues/796[Issue #796]. +* Enable Java 14 build in CI. +* Improve Javadoc. +* Remove use of `constexpr` from `computeLength` generated methods in C{plus}{plus} codecs to address compilation errors. +* Validate usage of group and var data types within composite elements when XSDs are not used. +* Improve C# samples. +* Improve C{plus}{plus} samples. +* Reduce warnings in C{plus}{plus} build on Windows. +* Upgrade to .net core 3.1 LTS for for CI. +* Upgrade to Mockito 3.4.0. +* Upgrade to Checkstyle 8.34. +* Upgrade to Shadow 6.0.0. +* Upgrade to Gradle 6.5.1. +* Upgrade to Agrona 1.6.0. + +== 1.18.2 (2020-05-27) + +* Fix SbeMarshalling.go file generation based on template. https://github.com/aeron-io/simple-binary-encoding/issues/789[Issue #789]. +* Fix numerous MSVC warnings about C and C{plus}{plus} codec generation and testing. + +== 1.18.1 (2020-05-23) + +* Fix case of importing buffers when var data is used in nested groups for Java codecs. + +== 1.18.0 (2020-05-23) + +* Only generate imports for Java codecs when required to address warnings. +* Access fixed length arrays as Spans in C# codecs. https://github.com/aeron-io/simple-binary-encoding/pull/780[#780]. +* Add `SbeSchemaId` and `SbeSchemaVersion` as constants in fixed flyweights for C# codecs. +* Generate source docs from schema descriptions for C# codecs. https://github.com/aeron-io/simple-binary-encoding/pull/778[#778]. +* Add offset and wrap methods to C# codecs for ease of use. https://github.com/aeron-io/simple-binary-encoding/pull/777[#777]. +* Support non-standard message headers form the C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/775[#775]. +* Fix version support for enums in C codecs. https://github.com/aeron-io/simple-binary-encoding/issues/773[Issue #773]. +* Improve formatting of generated C codecs. +* Require a strict dependency on Agrona. +* Upgrade to Agrona 1.5.0. +* Upgrade to javadoc-links 5.1.0. +* Upgrade to JUnit 5.6.2. +* Upgrade to Gradle 6.4.1. + +== 1.17.0 (2020-03-28) + +* Remove redundant generated casts from Java codecs. https://github.com/aeron-io/simple-binary-encoding/issues/766[Issue #766]. +* Add ability to compute the length of an encoded message before encoding for C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/761[#761]. +* Remove Rust support due to lack of community support. +* Use `sinceVersion` from field which overrides type in C# codecs. https://github.com/aeron-io/simple-binary-encoding/issues/763[Issue #763]. +* Upgrade to JUnit 5.6.1. +* Upgrade to Gradle 6.3. +* Upgrade to Agrona 1.4.1. + +== 1.16.3 (2020-02-28) + +* Re-generate Java IR codecs. +* Make Java codec `toString()` methods version aware so the wrapped `actingVersion` and `actingBlockLength` are accounted for. + +== 1.16.2 (2020-02-27) + +* Variable data string improvements in C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/758[#758]. +* Short circuit `toString` and `appendTo` in Java codes when buffer is null to avoid debugging issues. +* CLang Tidy fixes for C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/757[#757]. +* Eliminate allocation when calling `appendTo` on set based fields in Java codecs. https://github.com/aeron-io/simple-binary-encoding/pull/755[#755]. +* Support optional groups which is a non-standard feature. https://github.com/aeron-io/simple-binary-encoding/issues/754[Issue #754]. +* Fix issue with populating optional arrays in Go codecs. https://github.com/aeron-io/simple-binary-encoding/pull/750[#750]. +* Migrate to maven-publish plugin for Gradle. +* C{plus}{plus} codec `sbePosition()` method should be SBE_NOEXCEPT. +* Upgrade to Versions 0.28.0. +* Upgrade to Mockito 3.3.0. +* Upgrade to Agrona 1.4.0. +* Upgrade to Gradle 6.2.1. +* Upgrade to JMH 1.23. + +== 1.16.1 (2020-01-21) + +* Simplify the generation of `MetaAttribute` lookup on fields in C{plus}{plus} codecs to reduce code size. +* Allow setting a count for groups and then later setting it to the value of index. This allows for streaming operations when the count is not known but can be limited and then later set to index for what is encoded. Applied to Java, C{plus}{plus}, and C# codecs. https://github.com/aeron-io/simple-binary-encoding/pull/746[#746]. +* Fix generation of Java Decoder names when message names start with lowercase. https://github.com/aeron-io/simple-binary-encoding/issues/745[Issue #745]. +* Upgrade to Agrona 1.3.0. +* Upgrade to JUnit 5.6.0. + +== 1.16.0 (2020-01-10) + +* Generate simpler `MetaAttribute` lookup in Java Codecs which avoids the generation of a synthetic class. +* Don't default timeunit and epoch for var data fields when parsing. This results in more compact IR. +* Move CI build to GitHub Actions. +* Track `initialOffset` on Java codecs so `toString()` can be called on the decoder at any time during decoding. This allows SBE decoding to be debugged. +* Use skip methods to avoid unused warning in C{plus}{plus} codecs. +* Upgrade to Agrona 1.2.0. +* Upgrade to Checkstyle 8.28. +* Upgrade to JUnit 5.6.0-RC1. +* Upgrade to javadoc-links 4.1.6. +* Upgrade to Mockito 3.2.4. +* Upgrade to Gradle 6.0.1. +* Upgrade to gtest 1.10.0. + +== 1.15.0 (2019-11-21) + +* Add skip methods for var data fields in C{plus}{plus} and Java codecs. +* Handle encoding of Nan, Infinity, and -Infinity for floating point values in Java `JsonPrinter`. +* Fix handling of `sinceVersion` in IR, Java codecs, and C{plus}{plus} codecs so that the max value is taken from type in field. +* Set javadoc encoding to UTF-8. +* Upgrade to javadoc-links 4.1.4. +* Upgrade to Hamcrest 2.2. +* Upgrade to Checkstyle 8.26. +* Upgrade to Shadow 5.2.0. +* Upgrade to Agrona 1.1.0. + +== 1.14.1 (2019-11-06) + +* Regenerate the Java IR Codecs to benefit for less allocation when pretty printing. +* Add null enum value lookup into the switch for Java codecs. https://github.com/aeron-io/simple-binary-encoding/pull/732[#732]. +* Upgrade to JMH 1.22. +* Upgrade to Agrona 1.0.11. + +== 1.14.0 (2019-10-27) + +* Provide consistent API for constant char arrays to be compatible with mutable char arrays. +* Cast length type for memcpy to address warning. https://github.com/aeron-io/simple-binary-encoding/pull/730[#730]. +* Reduce string copying to improve performance of C{plus}{plus} codec generators. +* Provide property accessor methods for getting string values Json escaped in C{plus}{plus} codecs. +* Escape Json string in C{plus}{plus} codec pretty printing. https://github.com/aeron-io/simple-binary-encoding/issues/718[Issue #718]. +* Escape Json strings in Java `JsonTokenListener`. +* Upgrade to javadoc-links 4.1.3. +* Upgrade to Checkstyle 8.25. +* Upgrade to Gradle 5.6.3. +* Upgrade to Agrona 1.0.9. + +== 1.13.3 (2019-10-08) + +* Fix type conversion warnings in C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/725[#725]. +* Allow setting of raw value for bit sets in C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/724[#724]. +* Fix initialisation of C{plus}{plus} codecs samples for printing as JSON. +* Print non-printable char in C{plus}{plus} codecs as int. https://github.com/aeron-io/simple-binary-encoding/pull/716[#716]. +* Fix unsigned conversation warning and use better default value for group index initialisation in C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/issues/714[Issue #714]. +* Declare primitive accessors as `noexcept` for C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/709[#709]. +* Upgrade to Checkstyle 8.24. +* Upgrade to javadoc-links 4.1.2. +* Upgrade to Mockito 3.1.0. +* Upgrade to Gradle 5.6.2. +* Upgrade to Agrona 1.0.8. + +== 1.13.2 (2019-08-16) + +* Cope with optional composite values being pretty printed in Java codecs. https://github.com/aeron-io/simple-binary-encoding/issues/708[Issue #708]. + +== 1.13.1 (2019-08-14) + +* Reduce allocation and copying in Java codec generator to make stub generation more efficient. +* Update C# README. +* Generate package-info.java for codec Javadoc. https://github.com/aeron-io/simple-binary-encoding/issues/703[Issue #703]. +* Upgrade to javadoc-links 3.8.4. +* Upgrade to Agrona 1.0.7. + +== 1.13.0 (2019-08-02) + +* *[C#]* Add system property to allow squashing of namespace generation. https://github.com/aeron-io/simple-binary-encoding/pull/702[#702]. +* *[C{plus}{plus}]* Use `*[nodiscard]*` attribute where applicable. https://github.com/aeron-io/simple-binary-encoding/pull/700[#700]. +* *[C#]* Use ThrowHelper and simplify bounds checks to improve inlining. https://github.com/aeron-io/simple-binary-encoding/pull/695[#695]. +* *[Java]* Javadoc to `MetaAttribute` generation. +* Upgrade to Agrona 1.0.6. +* Upgrade to javadoc-links 3.8.1. +* Upgrade to Checkstyle 8.23. +* Upgrade to Mockito 2.30.0. +* Upgrade to Gradle 5.5.1. + +== 1.12.8 (2019-07-12) + +* More efficient approach for truncating an existing file when generating IR. +* Improve Javadoc for IR. +* More efficient implementation for appending to an `Appendable` for var-data in Java codecs. +* Use raw string literals in C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/688[#685]. +* Enhancements to Rust codecs. https://github.com/aeron-io/simple-binary-encoding/pull/688[#685]. +* Generate pretty printers for encoded data inspection for C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/683[#683]. +* Test C{plus}{plus} codecs with a greater range of compilers. +* Upgrade to javadoc-links 3.7.5. +* Upgrade to Shadow 5.1.0. +* Upgrade to Checkstyle 8.22. +* Upgrade to Mockito 2.28.2. +* Upgrade to Agrona 1.0.3. + +== 1.12.7 (2019-05-26) + +* Truncate existing serialised IR file when generating to avoid garbage at the end when new IR is shorter. https://github.com/aeron-io/simple-binary-encoding/issues/682[Issue #682]. + +== 1.12.6 (2019-05-25) + +* Remove the need for dimensions member in C codecs. https://github.com/aeron-io/simple-binary-encoding/pull/681[#681]. +* Improve Rust codec generator. https://github.com/aeron-io/simple-binary-encoding/pull/679[#679]. +* Upgrade to javadoc-links 3.6.4 to allow for offline builds. +* Upgrade to hamcrest 2.1. +* Upgrade to Agrona 1.0.1. + +== 1.12.5 (2019-05-03) + +* Fix warnings in generated Rust codecs. https://github.com/aeron-io/simple-binary-encoding/pull/676[#676]. +* Generate null values for enums in Rust codecs. https://github.com/aeron-io/simple-binary-encoding/pull/675[#675]. +* Reduce footprint of repeating group by replacing field with stack allocated object for dimensions in C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/pull/674[#674]. +* Don't generate an encode method for a constant enum in Java codecs. https://github.com/aeron-io/simple-binary-encoding/issues/670[Issue #670]. +* Remove redundant code for put string methods on arrays in C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/issues/668[Issue #668]. +* Generate overload with a 2-4 arg methods for setting array values to support the likes of UUIDs and cryptographic hashes efficiently for Java and C{plus}{plus} codecs. +* Add missing storage class specifier for C codecs. https://github.com/aeron-io/simple-binary-encoding/pull/666[#666]. +* Create a executable binary for C# benchmarks. https://github.com/aeron-io/simple-binary-encoding/pull/664[#664]. +* Always return a value bit set type in C# codec. https://github.com/aeron-io/simple-binary-encoding/pull/663[#663]. +* Add the ability to query length of var data from C# codecs. https://github.com/aeron-io/simple-binary-encoding/pull/622[#622]. +* Provide output on failure for ctest. +* Upgrade to io.freefair.javadoc-links 3.2.1. +* Upgrade to Checkstyle 8.20. +* Upgrade to Mockito 2.27.0. +* Upgrade to Gradle 5.4.1. +* Upgrade to Agrona 1.0.0. + +== 1.12.4 (2019-03-28) + +* Reduce module warnings when using Java 11. +* Fix incremental build due to annotation processor directory clash with generated code directory. +* Various clean ups to C and C{plus}{plus} codecs. +* Cast Java message header flyweight returns to int if interfaces are used. https://github.com/aeron-io/simple-binary-encoding/pull/635[#635]. +* Add a C codec generator. https://github.com/aeron-io/simple-binary-encoding/pull/638[#638]. +* Improve C{plus}{plus} generated codecs to use member initialisation lists for cleaner and easier to optimise code. https://github.com/aeron-io/simple-binary-encoding/pull/650[#650]. +* Fix Javadoc links so they use HTTPS and work with OpenJDK and Java 11. +* Upgrade Checkstyle DTD and apply checkstyle to method Javadoc. +* Upgrade to Agrona 0.9.35. +* Upgrade to Mockito 2.25.1. +* Upgrade to Gradle 5.3.1. + +== 1.12.3 (2019-03-10) + +* Include links when generating Javadoc. +* Update examples so they use relative path for XInclude. +* Set `systemId` for message schemas so that XInclude can have a relative path. https://github.com/aeron-io/simple-binary-encoding/pull/649[#649]. +* Fix generated Java codec for optional fixed length character arrays. https://github.com/aeron-io/simple-binary-encoding/pull/648[#648]. +* Trim strings decoded from fixed length character arrays for C{plus}{plus} codec. https://github.com/aeron-io/simple-binary-encoding/issues/646[Issue #646]. +* Fix padding on fixed length character arrays so they are null padded in C{plus}{plus} codec. https://github.com/aeron-io/simple-binary-encoding/issues/646[Issue #646]. +* Fix generated include files. https://github.com/aeron-io/simple-binary-encoding/pull/644[#644]. +* Upgrade to Checkstyle 8.18. +* Upgrade to Mockito 2.25.0. +* Upgrade to Gradle 5.2.1. +* Upgrade to Shadow 5.0.0. +* Upgrade to Agrona 0.9.34. + +== 1.12.2 (2019-02-16) + +* Add `wrapAndAppyHeader` method for ease of use for C{plus}{plus} codecs. +* Generate `sbe.h` for C{plus}{plus} client to avoid namespace clash and dependencies. https://github.com/aeron-io/simple-binary-encoding/issues/626[Issue #626]. +* Make C{plus}{plus} IR decode use params. https://github.com/aeron-io/simple-binary-encoding/issues/643[Issue #]. +* Upgrade to Agrona 0.9.33. + +== 1.12.1 (2019-02-05) + +* Don't generate id methods for members of a composite. https://github.com/aeron-io/simple-binary-encoding/issues/641[Issue #641]. +* Fix broken code generation that resulted from merging https://github.com/aeron-io/simple-binary-encoding/pull/631[#631]. +* Add ability to get var data members as a `string_view` to remove copy with C{plus}{plus}17. https://github.com/aeron-io/simple-binary-encoding/issues/550[Issue #550]. +* Add `Automatic-Module-Name` to help support modular Java systems that include SBE. +* Update C{plus}{plus} build to be more inline with Aeron. https://github.com/aeron-io/simple-binary-encoding/pull/635[#635]. +* Upgrade to Mockito 2.24.0. +* Upgrade to Agrona 0.9.32. + +== 1.12.0 (2019-01-30) + +* Fixes and improves to CMake build. https://github.com/aeron-io/simple-binary-encoding/pull/632[#632]. +* Add support for getting and setting a `string_view` on char array fields when C{plus}{plus}17. https://github.com/aeron-io/simple-binary-encoding/pull/631[#631]. +* Simplify C{plus}{plus} generator and modernise for C{plus}{plus}11. https://github.com/aeron-io/simple-binary-encoding/pull/630[#630]. +* Allow other types than `UINT16` for message header fields but issue a warning. https://github.com/aeron-io/simple-binary-encoding/pull/629[#629]. +* Change Golang codecs to no longer assume ordering of fields in group header. https://github.com/aeron-io/simple-binary-encoding/pull/627[#627]. +* Upgrade to Google Test 1.8.0. +* Upgrade to Checkstyle 8.17. +* Upgrade to Agrona 0.9.31. + +== 1.11.0 (2019-01-21) + +* Better handing of null passed for string encoding to Java codecs. +* Provide a fluent API for encoding array elements in Java and C{plus}{plus} codecs. +* Add support for XInclude so common definitions can be included into a schema and update samples to reflect usage. https://github.com/aeron-io/simple-binary-encoding/issues/624[Issue #624]. +* Upgrade to Shadow 4.0.4. +* Upgrade to Agrona 0.9.30. + +== 1.10.2 (2019-01-06) + +* Only generate lower bounds check in C{plus}{plus} codecs when necessary to add compile warning. +* Improve C{plus}{plus} OTF code to be more strict and eliminate build warnings. +* Improve build for optional build and include JAR dependency. https://github.com/aeron-io/simple-binary-encoding/pull/623[#623]. +* Upgrade to Checkstyle 8.15. +* Upgrade to Agrona 0.9.29. + +== 1.10.1 (2018-12-16) + +* Warnings clean up in code base. +* Add OS X to Travis for native build. +* Fix golang generated codec for metadata attributes. https://github.com/aeron-io/simple-binary-encoding/issues/620[Issue #620]. +* Add `Span` support to generated C# codecs. https://github.com/aeron-io/simple-binary-encoding/pull/589[#589]. +* Upgrade to Checkstyle 8.15. +* Upgrade to Gradle 4.10.3. +* Upgrade to Agrona 0.9.28. + +== 1.10.0 (2018-11-25) + +* Add support for `Span` in C# codecs. https://github.com/aeron-io/simple-binary-encoding/pull/589[#589]. +* Check when wrapping the same buffer in all types to avoid Java GC write barrier where possible. +* Set `parentMessage` on construction of group codecs and remove need for dimensions composite to reduce footprint and improve performance. +* Allow signed `numInGroup` and issue warning to support `int32` type. https://github.com/aeron-io/simple-binary-encoding/pull/617[#617]. +* Allow flexibility on group header member ordering in codecs. https://github.com/aeron-io/simple-binary-encoding/pull/614[#614]. +* Fix Golang return type bug. https://github.com/aeron-io/simple-binary-encoding/pull/611[#611]. +* Allow `uint32` for `blockLength` in Java codecs but issue warning. https://github.com/aeron-io/simple-binary-encoding/issues/609[Issue #609]. +* Add non-const buffer access method to C{plus}{plus} codecs. +* Upgrade to Mockito 2.23.4. +* Upgrade to Shadow 4.0.3. +* Upgrade to Agrona 0.9.27. + +== 1.9.0 (2018-10-29) + +* This is the first release that supports building and running on Java 11. +* Add a `wrap(DirectBuffer)` to Java codecs for more efficient consumption of strings. +* Return `const char *` from `buffer()` method in C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/issues/601[Issue #601]. +* Support constant members in message header Java codecs. https://github.com/aeron-io/simple-binary-encoding/issues/602[#602]. +* Generate static constexpr methods for C{plus}{plus} codecs for constant enums. https://github.com/aeron-io/simple-binary-encoding/issues/591[Issue #591]. +* Added encoding offset and other metadata to C{plus}{plus} composite codecs. https://github.com/aeron-io/simple-binary-encoding/issues/594[Issue #594]. +* Fix length encoding on arrays for C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/issues/595[Issue #595]. +* Add methods to access schema id and version for all fixed flyweights for Java and C{plus}{plus}. https://github.com/aeron-io/simple-binary-encoding/issues/593[Issue #593]. +* Detect duplication ids in message fields. https://github.com/aeron-io/simple-binary-encoding/issues/597[Issue #597]. +* Add Travis build matrix for Java 8 and 11 for OpenJDK and Oracle JDK. +* Upgrade to Checkstyle 8.14. +* Upgrade to Mockito 0.23.0. +* Upgrade to Agrona 0.9.26. + +== 1.8.9 (2018-10-05) + +* Fix string format warnings in Rust and Golang generators. +* Add Travis build. +* Upgrade to Shadow 4.0.0. +* Upgrade to Gradle 4.10.1. +* Upgrade to Agrona 0.9.25. + +== 1.8.8 (2018-09-12) + +* Fix initialisation of encoding type with length is zero for C{plus}{plus}. https://github.com/aeron-io/simple-binary-encoding/issues/583[Issue #583]. +* Fix formatting of property access methods for Java within composites. https://github.com/aeron-io/simple-binary-encoding/issues/582[Issue #582]. +* Upgrade to Mockito 2.22.0. +* Upgrade to Gradle 4.10. +* Upgrade to Agrona 0.9.24. + +== 1.8.7 (2018-08-18) + +* Use find package to discover java executable when building C{plus}{plus} codecs tests. +* Use pointers in golang codecs to improve efficiency. https://github.com/aeron-io/simple-binary-encoding/pull/578[#578]. +* Upgrade to Checkstyle 8.12. +* Upgrade to Mockito 2.21.0. +* Upgrade to Agrona 0.9.23. + +== 1.8.6 (2018-07-30) + +* Provide the ability to query for an empty bit set in Java and C{plus}{plus} codecs for simplicity. https://github.com/aeron-io/simple-binary-encoding/pull/575[#575]. +* Upgrade to Mockito 2.20.1. +* Upgrade to Gradle 4.9. +* Upgrade to Agrona 0.9.22. + +== 1.8.5 (2018-07-19) + +* Invalid Java generated for codec with an extension string field that is appendable. https://github.com/aeron-io/simple-binary-encoding/pull/574[#574]. + +== 1.8.4 (2018-07-16) + +* Upgrade to Mockito 2.19.1. +* Upgrade to Agrona 0.9.21. + +== 1.8.3 (2018-07-07) + +* Regenerate IR Codecs to quote strings when printing. +* Upgrade to Checkstyle 8.11. +* Upgrade to Gradle 4.8.1. +* Upgrade to Agrona 0.9.20. + +== 1.8.2 (2018-07-03) + +* Update to latest CME fix binary market template for testing. +* Allow, with warning, `numInGroup` type to use `uint32` for repeating groups. +* Add support to C# codecs for constant presence enums. +* Fix issue with loss of IR data on encoding the IR for constant presence enums. https://github.com/aeron-io/simple-binary-encoding/issues/560[Issue #560]. +* Complete functionality for `JsonPrinter` so that an SBE message can be transformed to JSON for debugging. https://github.com/aeron-io/simple-binary-encoding/issues/560[Issue #560]. +* Remove debugging output from C{plus}{plus} IR decoder. https://github.com/aeron-io/simple-binary-encoding/issues/559[Issue #559]. +* Make `HEADER_SIZE` a public constant in Java codecs for repeating groups. +* Allow Java decoders to use an `Appendable` for ASCII strings. https://github.com/aeron-io/simple-binary-encoding/pull/557[#557]. +* Upgrade to Mockito 2.19.0. +* Upgrade to Checkstyle 8.10.1. +* Upgrade to Agrona 0.9.19. +* Upgrade to GSON 2.8.5. + +== 1.8.1 (2018-05-04) + +* Upgrade to JMH 1.21. +* Upgrade to Checkstyle 8.10. +* Upgrade to Shadow 2.0.4. +* Upgrade to Agrona 0.9.18. + +== 1.8.0 (2018-04-29) + +* Use `Constructor` to dynamically create new instances to avoid deprecated warning in Java 10. +* Remove use of `javax.annotation.Generated` so that the generated codecs compile and and run on Java 10. +* Rename `position` methods in C{plus}{plus} generated codecs to `sbePosition` to avoid clash with Aeron codecs for the archive and clustering. *Note:* this is a breaking change for those who have used these methods. +* Upgrade to Gradle 4.7. +* Upgrade to Agrona 0.9.17. + +== 1.7.10 (2018-04-23) + +* Return `NULL_VAL` for unknown `enum` value so it can be used in a Java switch. https://github.com/aeron-io/simple-binary-encoding/pull/548[#548] +* Improve C{plus}{plus} Unit tests. https://github.com/aeron-io/simple-binary-encoding/pull/549[#459]. +* Use since version from field rather than type in Java codecs. https://github.com/aeron-io/simple-binary-encoding/pull/548[#548]. +* Generate put `CharSequence` methods for ASCII encoded fields in Java. https://github.com/aeron-io/simple-binary-encoding/pull/547[#547] +* Cleaning up unit tests' global namespaces for C{plus}{plus}. https://github.com/aeron-io/simple-binary-encoding/pull/545[#545] +* Generates invalid CSharp code when using sinceVersion attribute inside groups. https://github.com/aeron-io/simple-binary-encoding/pull/555[#555]. +* Add support for netstandard2.0 removing support for 1.3 for .NET. +* Upgrade to Shadow 2.0.3. +* Upgrade to Mockito 2.18.3. +* Upgrade to Gradle 4.6. +* Upgrade to Checkstyle 8.9. +* Upgrade to Agrona 0.9.16. + +== 1.7.9 (2018-03-09) + +* Remove redundant throws clause from Java `TargetCodeGenerator`. +* Removed the using of namespace in generated C{plus}{plus} headers. Issue https://github.com/aeron-io/simple-binary-encoding/pull/544[#544]. +* Fix generated C# code for version checking of fields. Issue https://github.com/aeron-io/simple-binary-encoding/issues/543[#543]. +* Upgrade to Agrona 0.9.15. + +== 1.7.8 (2018-02-23) + +* Advance toString() operation on Java decoders when raw bytes for var data is encountered. Issue https://github.com/aeron-io/simple-binary-encoding/issues/542[#542]. +* Add C{plus}{plus} classes for OTF and header include to the sources jar. Issue https://github.com/aeron-io/simple-binary-encoding/issues/540[#540]. +* Upgrade to Agrona 0.9.14. + +== 1.7.7 (2018-02-23) + +* Regenerate IR codecs. +* Provide `ByteOrder` as a constant available in the generated Java codecs. +* Do not allocate when putting or getting an empty string in Java codecs. +* Apply strict indentation code style. +* Upgrade to JMH 1.20.0. +* Upgrade to Gradle 4.5.1. +* Upgrade to Checkstyle 8.8. +* Reduce Hamcrest dependency from all to library. +* Upgrade to Mockito 2.15.0. +* Upgrade to Agrona 0.9.13. + +== 1.7.6 (2017-12-15) + +* Fix build of golang code due to failing test. Issue https://github.com/aeron-io/simple-binary-encoding/issues/532[#532]. +* Generate getters for constant properties in Java decoders. Issue https://github.com/aeron-io/simple-binary-encoding/issues/531[#531]. +* Rework C{plus}{plus} OTF to support unaligned access. +* Generate field accessors in C{plus}{plus} to use `memcpy` to support platforms requiring aligned access and X86 when the XMM registers are used. Issue https://github.com/aeron-io/simple-binary-encoding/issues/506[#506]. +* Rework C{plus}{plus} generated code for options sets to work with Visual Studio. +* Upgrade to Mockito 2.13.0. +* Upgrade to Checkstyle 8.5. +* Upgrade to JShadow 2.0.1. +* Upgrade to Gradle 4.4. +* Upgrade to Agrona 0.9.12. + +== 1.7.5 (2017-11-15) + +* Support lookup of an enum value to be used as the value for a constant primitive type in a composite or message. Issue https://github.com/aeron-io/simple-binary-encoding/issues/529[#529]. +* Take account of constant fields when computing block length. Issue https://github.com/aeron-io/simple-binary-encoding/issues/528[#528]. +* Validate the type is correct in a `valueRef` attribute. +* Update to Mockito 2.12.0. +* Update to Checkstyle 8.4. +* Update to Agrona 0.9.11. + +== 1.7.4 (2017-11-01) + +* Generate Javadocs for major types in codecs based on descriptions. Simple fields to come later. +* Take the max of type and field version rather than just having the field take precedence. +* Expose a `JsonPrinter` method that takes an `UnsafeBuffer` rather than a `ByteBuffer`. +* Update to Mockito 2.11.0. + +== 1.7.3 (2017-10-16) + +* Fix the generated group name for arrays within groups for c++ codecs. https://github.com/aeron-io/simple-binary-encoding/pull/521[#521]. +* Upgrade to Agrona 0.9.9. + +== 1.7.2 (2017-10-11) + +* Fix move constructors and assignment operators for c++ 11 code generation. +* Add bit twiddling methods to codecs for bitsets. Issue https://github.com/aeron-io/simple-binary-encoding/issues/489[#489]. +* Remove old SBE typedefs from C{plus}{plus} codecs. +* Handle case of constant array of char with length of 1. Issue https://github.com/aeron-io/simple-binary-encoding/issues/505[#505]. +* Capture types by `ref` name for support refs in refs. Issuehttps://github.com/aeron-io/simple-binary-encoding/issues/496[#496]. +* Improvements to efficiency of introducing c++ 11 functionality. +* Initial support for Rust language. +* Upgrade to GSON 2.8.2. +* Upgrade to Checkstyle 8.3. +* Upgrade to Mockito 2.10.0. +* Upgrade to Agrona 0.9.8. + +== 1.7.1 (2017-08-21) + +* Add accessors for buffer length on C{plus}{plus} codecs. https://github.com/aeron-io/simple-binary-encoding/issues/479[Issue #479]. +* Add the ability to lookup message tokens when decoding IR by template id for C{plus}{plus}. https://github.com/aeron-io/simple-binary-encoding/issues/484[Issue #484]. +* Don't dereference a null character encoding. https://github.com/aeron-io/simple-binary-encoding/pull/491[Issue #491]. +* Add metadata attribute for presence. https://github.com/aeron-io/simple-binary-encoding/issues/483[Issue #483]. +* Add `noexcept` specifier for C{plus}{plus} https://github.com/aeron-io/simple-binary-encoding/pull/480[#480] +* Capture referenced name when dealing with simple types for refs. https://github.com/aeron-io/simple-binary-encoding/issues/477[Issue #477]. +* Handle `presence=optional` better in Golang generator. https://github.com/aeron-io/simple-binary-encoding/pull/475[#475]. +* Validate message names and field names are unique in a given context. https://github.com/aeron-io/simple-binary-encoding/issues/470[Issue #470] +* Copy elements of correct size in C{plus}{plus} fix arrays. https://github.com/aeron-io/simple-binary-encoding/issues/402[Issue #402]. +* Generate a field accessor as a `char` for constant Java char arrays exactly 1 in length. +* Generate a field accessor as a `String` for constant Java char arrays greater than 1 in length. +* Generate garbage free settors for Java strings and char arrays when the encoding is US_ASCII. +* Use compiler detections to guard pragmas to suppress excessive warnings. https://github.com/aeron-io/simple-binary-encoding/issues/437[Issue #437]. +* Provide dotnet core support. https://github.com/aeron-io/simple-binary-encoding/pull/456[#456]. +* Correct defaults for `UINT32` type as per specification. *Note:* this maybe breaking for those relying on hardcoded references for the values. https://github.com/aeron-io/simple-binary-encoding/issues/455[Issue #455]. +* Upgrade to Mockito 2.8.47. +* Upgrade to JMH 1.19 for Java benchmarks. +* Upgrade to sevntu-checks:1.24.1. +* Upgrade to Checkstyle 8.1. +* Upgrade to Gradle 4.1. +* Upgrade to Agrona 0.9.7. + +== 1.7.0 (2017-04-14) + +* Use compiler detections to guard pragmas to suppress excessive warnings in C{plus}{plus} #454 +* Reinstate C# support but consider it beta. +* Fix min/max macro conflicts on Windows for C{plus}{plus}. +* Remove `sinceVersion=1` from `deprecated` attribute in IR as the base IR has no message header. +* Support generation of var-data methods for raw data which do not have a `characterEncoding`. +* Default to `US-ASCII` rather than `UTF-8` for `char` type as per specification. +* Generate `wrapAndApplyHeader()` method to Java encoders for convenience. +* Upgrade to Agrona 0.9.6. +* Upgrade to Checkstyle 7.7. + +== 1.6.2 (2017-04-12) + +* Upgrade to Agrona 0.9.5. +* Upgrade to Gradle 3.5. +* Upgrade to Mockito 2.7.22. + +== 1.6.1 (2017-04-06) + +* Share some test code with Golang. +* Upgrade to Checkstyle 7.6.1. +* Upgrade to Agrona 0.9.4. +* Upgrade to Gradle 3.4.1. +* Upgrade to Mockito 2.7.21. + +== 1.6.0 (2017-02-22) + +* Allow complex types to be included in the `messageHeader` for a schema. +* Fixed bug https://github.com/aeron-io/simple-binary-encoding/issues/435[#435] so that the name is correctly picked up for ref types in composites. +* Add `referencedName` to the IR so that is can be used with ref types. +* Code clean ups for C{plus}{plus}. +* Go lang support beta complete. +* Upgrade to Agrona 0.9.3. +* Upgrade to Gradle 3.4. +* Upgrade to Mockito 2.7.9. + +== 1.5.7 (2017-02-08) + +* Make name clash with language keywords a warning rather than error. Issue https://github.com/aeron-io/simple-binary-encoding/issues/433[#433]. +* Capture byte order as a field in the IR for convenience. +* Add missing accessor methods for C{plus}{plus} OTF `Token` and `Encoding`. +* Golang additions in preparation for beta launch. +* Upgrade to Checkstyle 7.5.1. + +== 1.5.6 (2017-01-23) + +* Fix bug with generating composites within composites. +* Fix bug with message `sinceVersion` being over written by schema version id. +* Add `deprecated` version information from the XML to the IR. +* Add Golang support to generator. +* Upgrade to Agrona 0.9.2. +* Upgrade to JMH 1.17.4. +* Upgrade to Checkstyle 7.4. +* Upgrade to sevntu-checks 1.23.0. +* Upgrade to Mockito 2.6.8. +* Upgrade to Gradle 3.3. + +== 1.5.5 (2016-12-20) + +* Correct issues with message extension on types other than basic encoded types. +* Removed unneeded fields from the Java codecs to reduce footprint. +* Capture `sinceVersion` and `description` attributes for all types in the XML schema and store in the IR. +* Expose the buffer and offset as accessor methods in the Java stubs. +* Generate encoding offset and length as static methods for fields in the codec stubs. +* Upgrade to JMH 1.17.3. +* Upgrade to Checkstyle 7.3. +* Upgrade to sevntu-checks 1.22.0. +* Upgrade to Mockito 2.2.29. +* Upgrade to Agrona 0.9.1. +* Upgrade to Gradle 3.2.1. + +== 1.5.4 (2016-11-17) + +* Added optional support for decoding unknown extended enums. +* Upgrade to JMH 1.16. +* Upgrade to sevntu-checks 1.21.1. +* Upgrade to Mockito 2.2.16. +* Upgrade to Agrona 0.9.0. +* Upgrade to Gradle 3.2. + +== 1.5.3 (2016-11-03) + +* Add String convenience accessors to Java generated stubs for char array types. +* Upgrade to Mockito 2.2.9. +* Upgrade to Agrona 0.5.6. +* Upgrade to Checkstyle 7.2. + +== 1.5.2 (2016-10-15) + +* Added checks for extension var data and repeating groups in OTF for Java and C{plus}{plus}. +* Added `sinceVerion` and `inActingVersion` to repeating groups for C{plus}{plus}. +* Added acting version guard to repeating groups and var data for extensions. +* Added `sinceVersion` metadata methods for all field types in Java generated stubs. +* Expose buffer and offset in fixed flyweights for C{plus}{plus}. +* Use static constexpr for C{plus}{plus} constants. +* Upgrade to Agrona 0.5.5. +* Upgrade to Checkstyle 7.1.2. +* Upgrade to JMH 1.15. +* Upgrade to Gradle 3.1. + +== 1.5.1 (2016-08-24) + +* Target CMake 3.0.2 minimum. +* Correctly encode int64 min value in C{plus}{plus}. +* Apply constexpr's where possible in C{plus}{plus}. +* Upgrade to Agrona 0.5.4. +* Upgrade to Gradle 2.14.1. + +== 1.5.0 (2016-07-22) + +* Reference the 1.0 final SBE schema XSD. +* Generate a `toString()` method for the Java codecs stubs to help with debugging. +* Update to Agrona 0.5.3. +* Update to Checkstyle 7.0. + +== 1.4.2-RC2 2016-06-29 + +* Added `sbe.cpp.namespaces.collapse` system property so c++ nested namespaces are collapsed to a single namespace, separated by underscores, which defaults to false. +* Move generated interfaces for flyweights to https://github.com/aeron-io/Agrona[Agrona]* and allow configuration via `sbe.java.generate.interfaces` system property which defaults to false. +* Update to Agrona 0.5.2. +* Update to Checkstyle 6.19. +* Update to Gradle 2.14. + +== 1.4.1-RC4 2016-05-23 + +* Update to Agrona 0.5.1. +* Update to Checkstyle 6.18. +* Update to Gradle 2.13. + +== 1.4.0-RC4 2016-04-22 + +* Correct examples for illustration of how to do message extension. +* Update On-The-Fly decoding to assign contextual names for types within composites. +* Add feature support for the https://github.com/FIXTradingCommunity/fix-simple-binary-encoding/tree/master/v1-0-RC4[RC4 Specification] which adds offsets and refs in composites, plus restricted ranges on repeating groups. +* Upgrade to Agrona 0.5 to bring in support for encoding into expandable buffers. +* Upgrade to Checkstyle 6.17. +* Upgrade to JMH 1.12. + +== 1.3.5-RC3 2016-04-01 + +* Performance improvements to C{plus}{plus} generated stub by using move constructors where possible. +* Add a check for string length to avoid truncation in C{plus}{plus} generated stubs. +* Validate that number of items as a repeat count is within range for groups in Java generated stubs. +* Use UINT16, rather than UINT8, for number of times a group repeats in the examples. +* Use UINT32 length strings in the examples. +* Support for UINT32 length var-data strings as fields. Previously allowed UINT8 and UINT16 length strings. +* Fix bug with UINT32 type in Java not treating the most significant bit correctly. + +== 1.3.4-RC3 2016-03-24 + +* Generate MessageEncoder and MessageDecoder interfaces to common message methods. +* Fix up code for Agrona changes to org.agrona package structure. +* Update to Checkstyle 6.16.1. +* Update to Gradle 2.12. +* Update to Agrona 0.4.13. + +== 1.3.3-RC3 2016-03-01 + +* Validate length of encoded var data strings against length type of var data in schema. +* Update var data length type in IR and examples to be uint16 to support larger strings. +* Added the ability to append a token to property names that have keyword clashes. +* Added fluent API support for putting strings into var data fields. +* Update to Checkstyle 6.15. +* Update to Gradle 2.11. +* Update to Agrona 0.4.11. + +== 1.3.2-RC3 2016-02-06 + +* Warn that optional presence is not allowed on var data fields. +* Bring C{plus}{plus} inline with Java features. +* Update to Agrona 0.4.11. +* Constant values for enums need to be in US-ASCII rather than default encoding. +* Code quality changes to reduce number of Sonar warnings. + +== 1.3.1-RC3 2016-01-18 + +* Add Checkstyle for indentation and fix violations. +* Update to JMH 1.11.3 +* Check for keywords class on formatted property field. +* Update to Agrona 0.4.10. +* Fix publishing of sbe-all JAR to Maven Central. + +== 1.3-RC3 2016-01-06 + +* Updated implementation to reflect the https://github.com/FIXTradingCommunity/fix-simple-binary-encoding/tree/master/v1-0-RC3/doc[RC3 Specification]. RC3 is more generally useful with support added for var data in repeating groups and composites that can contain other types than just primitive encodings. +* Significant rewrite of Java and C{plus}{plus} OTF implementation to be more efficient with no back or re-scanning of the IR, plus they are now similar in usage and API. +* Java generated stubs are no longer dependent on CodecUtil and one level less for better inlining by the optimiser. +* IR updated to carry the description and count of tokens per component. +* Other language implementations have been removed until ports for RC3 are available. +* Project structure updated to be a Gradle modular build. +* RC4 features are available for testing if appropriate RC4 XSD schema is provided or schema validation is turned off. +* Generated code is marked with the @Generated annotation. +* C{plus}{plus} updated to C{plus}{plus} 11. \ No newline at end of file From ee188a9e482346f3a1a965d397a8d64603040498 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:00:25 +0100 Subject: [PATCH 689/805] 1.36.1 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 7991f09416..f107550c29 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.37.0-SNAPSHOT +1.36.1 From 8d371375d09dc036eae29fd7cd8b03698a8c5f16 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 3 Nov 2025 18:00:37 +0100 Subject: [PATCH 690/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index f107550c29..7991f09416 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.1 +1.37.0-SNAPSHOT From 3dc0f60c584a30c10c8134f1a412b73252171ef3 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 8 Nov 2025 10:51:41 +0100 Subject: [PATCH 691/805] [Java] Upgrade to `Agrona` 2.3.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 41e68f43fb..6e10340b5d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.3.1" +agrona = "2.3.2" checkstyle = "12.1.1" commons-codec = "1.15" commons-lang3 = "3.8.1" From a84f9b70da28d55ad1103972769e3b3afc7cba3a Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 8 Nov 2025 10:52:20 +0100 Subject: [PATCH 692/805] [Doc] Release notes. --- CHANGELOG.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index aac63dd520..d798f2bd60 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,9 @@ = Changelog +== 1.36.2 (2025-11-08) + +* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.2[Agrona 2.3.2]. + == 1.36.1 (2025-11-03) * *[C#]* Handle case when `valueRef` is with enum type prefix. (https://github.com/aeron-io/simple-binary-encoding/pull/1092[#1092]) From bc3be5f22625120c5b58d2cbfd3a5701f1de814d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 8 Nov 2025 10:53:19 +0100 Subject: [PATCH 693/805] 1.36.2 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 7991f09416..c6a567b8eb 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.37.0-SNAPSHOT +1.36.2 From 0d6fcba0a160c90c4b01e77a8203371bc0b32a65 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Sat, 8 Nov 2025 10:53:31 +0100 Subject: [PATCH 694/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index c6a567b8eb..7991f09416 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.36.2 +1.37.0-SNAPSHOT From 6232181bbffa23091b5b15dc9680f64f6a00e03c Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 25 Nov 2025 13:55:15 +0100 Subject: [PATCH 695/805] [Java] Upgrade to `Checkstyle` 12.1.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6e10340b5d..aa2e4500b5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.3.2" -checkstyle = "12.1.1" +checkstyle = "12.1.2" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From d296042a5f34a1198d22f589371f0cd84defd6b9 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 28 Nov 2025 10:01:22 +0100 Subject: [PATCH 696/805] [Java] Upgrade to `Gradle` 9.2.1. --- gradle/wrapper/gradle-wrapper.jar | Bin 45457 -> 45633 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8bdaf60c75ab801e22807dde59e12a8735a34077..f8e1ee3125fe0768e9a76ee977ac089eb657005e 100644 GIT binary patch delta 36466 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 delta 36287 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 TbTtHgKIb=}#OPPBcmMwnM9LS( diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a35649f5fc..4eac4a84cc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From e7c1bbd0d8311d2a3991019bcb039194f06ac74d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:39:46 +0100 Subject: [PATCH 697/805] [Java] Upgrade to `Checkstyle` 12.2.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aa2e4500b5..722f599e87 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.3.2" -checkstyle = "12.1.2" +checkstyle = "12.2.0" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From e22b6c226fdb1dcefe942b395745f83ccb121cdd Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:39:21 +0100 Subject: [PATCH 698/805] [C] Handle fields in the correct order and use all declared fields. --- sbe-tool/src/test/c/CodeGenTest.cpp | 61 ++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/sbe-tool/src/test/c/CodeGenTest.cpp b/sbe-tool/src/test/c/CodeGenTest.cpp index 4d33156149..4135804ad3 100644 --- a/sbe-tool/src/test/c/CodeGenTest.cpp +++ b/sbe-tool/src/test/c/CodeGenTest.cpp @@ -46,6 +46,7 @@ static const char FUEL_FIGURES_3_USAGE_DESCRIPTION[] = "Highway Cycle"; static const char MANUFACTURER[] = "Honda"; static const char MODEL[] = "Civic VTi"; static const char ACTIVATION_CODE[] = "deadbeef"; +static const char COLOR[] = "silver/white"; static const std::size_t VEHICLE_CODE_LENGTH = sizeof(VEHICLE_CODE); static const std::size_t MANUFACTURER_CODE_LENGTH = sizeof(MANUFACTURER_CODE); @@ -55,12 +56,13 @@ static const std::size_t FUEL_FIGURES_3_USAGE_DESCRIPTION_LENGTH = strlen(FUEL_F static const std::size_t MANUFACTURER_LENGTH = strlen(MANUFACTURER); static const std::size_t MODEL_LENGTH = strlen(MODEL); static const std::size_t ACTIVATION_CODE_LENGTH = strlen(ACTIVATION_CODE); +static const std::size_t COLOR_LENGTH = strlen(COLOR); static const std::uint8_t PERFORMANCE_FIGURES_COUNT = 2; static const std::uint8_t FUEL_FIGURES_COUNT = 3; static const std::uint8_t ACCELERATION_COUNT = 3; static const std::uint64_t expectedHeaderSize = 8; -static const std::uint64_t expectedCarEncodedLength = 191; +static const std::uint64_t expectedCarEncodedLength = 207; static const std::uint16_t fuel1Speed = 30; static const float fuel1Mpg = 35.9f; @@ -107,13 +109,14 @@ class CodeGenTest : public testing::Test CGT(car_set_modelYear)(&car, MODEL_YEAR); CGT(car_set_available)(&car, AVAILABLE); CGT(car_set_code)(&car, CODE); - CGT(car_put_vehicleCode)(&car, VEHICLE_CODE); for (std::uint64_t i = 0; i < CGT(car_someNumbers_length)(); i++) { CGT(car_set_someNumbers_unsafe)(&car, i, static_cast(i)); } + CGT(car_put_vehicleCode)(&car, VEHICLE_CODE); + CGT(optionalExtras) extras; if (!CGT(car_extras)(&car, &extras)) { @@ -213,9 +216,10 @@ class CodeGenTest : public testing::Test CGT(car_performanceFigures_acceleration_set_mph)(&acc, perf2cMph); CGT(car_performanceFigures_acceleration_set_seconds)(&acc, perf2cSeconds); - CGT(car_put_manufacturer)(&car, MANUFACTURER, static_cast(strlen(MANUFACTURER))); - CGT(car_put_model)(&car, MODEL, static_cast(strlen(MODEL))); - CGT(car_put_activationCode)(&car, ACTIVATION_CODE, static_cast(strlen(ACTIVATION_CODE))); + CGT(car_put_manufacturer)(&car, MANUFACTURER, MANUFACTURER_LENGTH); + CGT(car_put_model)(&car, MODEL, MODEL_LENGTH); + CGT(car_put_activationCode)(&car, ACTIVATION_CODE, ACTIVATION_CODE_LENGTH); + CGT(car_put_color)(&car, COLOR, COLOR_LENGTH); return CGT(car_encoded_length)(&car); } @@ -246,6 +250,8 @@ class CodeGenTest : public testing::Test CGT(optionalExtras_cruiseControl)(&extras) << ';'; } + output << static_cast(CGT(car_discountedModel(&car))) << ';'; + char code_buf[4]; CGT(engine) engine = {}; if (CGT(car_engine)(&car, &engine)) @@ -307,6 +313,16 @@ class CodeGenTest : public testing::Test { output << std::string(model.data, model.length) << ';'; } + CGT(car_string_view) activationCode = CGT(car_get_activationCode_as_string_view(&car)); + if (nullptr != activationCode.data) + { + output << std::string(activationCode.data, activationCode.length) << ';'; + } + CGT(car_string_view) color = CGT(car_get_color_as_string_view(&car)); + if (nullptr != color.data) + { + output << std::string(color.data, color.length) << ';'; + } return output.str(); } @@ -653,6 +669,10 @@ TEST_F(CodeGenTest, shouldBeAbleToEncodeCarCorrectly) offset += sizeof(std::uint16_t); EXPECT_EQ(std::string(bp + offset, ACTIVATION_CODE_LENGTH), ACTIVATION_CODE); offset += ACTIVATION_CODE_LENGTH; + EXPECT_EQ(*(std::uint32_t *)(bp + offset), static_cast(COLOR_LENGTH)); + offset += sizeof(std::uint32_t); + EXPECT_EQ(std::string(bp + offset, COLOR_LENGTH), COLOR); + offset += COLOR_LENGTH; EXPECT_EQ(sz, offset); } @@ -670,10 +690,10 @@ TEST_F(CodeGenTest, shouldBeAbleToEncodeHeaderPlusCarCorrectly) EXPECT_EQ(carEncodedLength, expectedCarEncodedLength); EXPECT_EQ(*((std::uint16_t *)bp), CGT(car_sbe_block_length)()); - const size_t activationCodePosition = hdrSz + carEncodedLength - ACTIVATION_CODE_LENGTH; - const size_t activationCodeLengthPosition = activationCodePosition - sizeof(std::uint16_t); - EXPECT_EQ(*(std::uint16_t *)(bp + activationCodeLengthPosition), ACTIVATION_CODE_LENGTH); - EXPECT_EQ(std::string(bp + activationCodePosition, ACTIVATION_CODE_LENGTH), ACTIVATION_CODE); + const size_t colorPosition = hdrSz + carEncodedLength - COLOR_LENGTH; + const size_t colorLengthPosition = colorPosition - sizeof(std::uint32_t); + EXPECT_EQ(*(std::uint16_t *)(bp + colorLengthPosition), COLOR_LENGTH); + EXPECT_EQ(std::string(bp + colorPosition, COLOR_LENGTH), COLOR); } TEST_F(CodeGenTest, shouldBeAbleToEncodeAndDecodeHeaderPlusCarCorrectly) @@ -845,6 +865,9 @@ TEST_F(CodeGenTest, shouldBeAbleToEncodeAndDecodeHeaderPlusCarCorrectly) EXPECT_EQ(CGT(car_activationCode_length)(&m_carDecoder), ACTIVATION_CODE_LENGTH); EXPECT_EQ(std::string(CGT(car_activationCode)(&m_carDecoder), ACTIVATION_CODE_LENGTH), ACTIVATION_CODE); + EXPECT_EQ(CGT(car_color_length)(&m_carDecoder), COLOR_LENGTH); + EXPECT_EQ(std::string(CGT(car_color)(&m_carDecoder), COLOR_LENGTH), COLOR); + EXPECT_EQ(CGT(car_encoded_length)(&m_carDecoder), expectedCarEncodedLength); } @@ -968,9 +991,12 @@ TEST_F(CodeGenTest, shouldBeAbleUseOnStackCodecsAndGroupForEach) EXPECT_EQ(CGT(car_get_model)(&carDecoder, tmp, sizeof(tmp)), MODEL_LENGTH); EXPECT_EQ(std::string(tmp, MODEL_LENGTH), MODEL); - EXPECT_EQ(CGT(car_get_manufacturer)(&carDecoder, tmp, sizeof(tmp)), ACTIVATION_CODE_LENGTH); + EXPECT_EQ(CGT(car_get_activationCode)(&carDecoder, tmp, sizeof(tmp)), ACTIVATION_CODE_LENGTH); EXPECT_EQ(std::string(tmp, ACTIVATION_CODE_LENGTH), ACTIVATION_CODE); + EXPECT_EQ(CGT(car_get_color)(&carDecoder, tmp, sizeof(tmp)), COLOR_LENGTH); + EXPECT_EQ(std::string(tmp, COLOR_LENGTH), COLOR); + EXPECT_EQ(CGT(car_encoded_length)(&carDecoder), expectedCarEncodedLength); } @@ -997,6 +1023,7 @@ TEST_F(CodeGenTest, shouldBeAbleToUseStdStringMethodsForEncode) std::string manufacturer(MANUFACTURER, MANUFACTURER_LENGTH); std::string model(MODEL, MODEL_LENGTH); std::string activationCode(ACTIVATION_CODE, ACTIVATION_CODE_LENGTH); + std::string color(COLOR, COLOR_LENGTH); char buffer[BUFFER_LEN] = {}; auto baseOffset = static_cast(CGT(messageHeader_encoded_length)()); @@ -1046,6 +1073,8 @@ TEST_F(CodeGenTest, shouldBeAbleToUseStdStringMethodsForEncode) CGT(car_put_model)(&car, model_c, static_cast(strlen(model_c))); const char *acti = activationCode.c_str(); CGT(car_put_activationCode)(&car, acti, static_cast(strlen(acti))); + const char *col = color.c_str(); + CGT(car_put_color)(&car, col, static_cast(strlen(col))); EXPECT_EQ(CGT(car_encoded_length)(&car), expectedCarEncodedLength); @@ -1179,6 +1208,18 @@ TEST_F(CodeGenTest, shouldBeAbleToUseStdStringMethodsForDecode) std::string(ptr, length), std::string(ACTIVATION_CODE, ACTIVATION_CODE_LENGTH)); } + { + const uint16_t length = CGT(car_color_length)(&carDecoder); + const char *const ptr = CGT(car_color)(&carDecoder); + if (!ptr) + { + throw std::runtime_error(sbe_strerror(errno)); + } + + EXPECT_EQ( + std::string(ptr, length), + std::string(COLOR, COLOR_LENGTH)); + } EXPECT_EQ(CGT(car_encoded_length)(&carDecoder), expectedCarEncodedLength); } From 2471de05c130d3d41de8077e6afe1dfb90cfe316 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 8 Dec 2025 13:30:23 +0100 Subject: [PATCH 699/805] [Java] Upgrade to `Shadow` 9.3.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 722f599e87..e5a20fe97c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20250517" junit = "6.0.1" mockito = "5.20.0" plexus = "3.3.0" -shadow = "9.2.2" +shadow = "9.3.0" versions = "0.53.0" [libraries] From b5a6cb29cc66e799bfe995f31e764317e58279cb Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Fri, 12 Dec 2025 14:12:40 +0100 Subject: [PATCH 700/805] [Java] Upgrade to `Mockito` 5.21.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e5a20fe97c..84779da7fc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,7 @@ jqwik = "1.9.3" jmh = "1.37" json = "20250517" junit = "6.0.1" -mockito = "5.20.0" +mockito = "5.21.0" plexus = "3.3.0" shadow = "9.3.0" versions = "0.53.0" From 4c27d42071661a0ac85f6f6618cd9a86d2a32c16 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 22 Dec 2025 21:57:12 +0100 Subject: [PATCH 701/805] [CI] Upgrade to `CodeQL` v4. --- .github/workflows/codeql.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b5c633b1f1..b7e916b4fc 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -59,7 +59,7 @@ jobs: uses: gradle/actions/setup-gradle@v5 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -68,7 +68,7 @@ jobs: run: ./gradlew - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" @@ -122,7 +122,7 @@ jobs: dotnet-version: ${{ matrix.dotnet }} - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -131,7 +131,7 @@ jobs: run: ./csharp/build.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" @@ -176,7 +176,7 @@ jobs: sudo apt-get install -y g++-${{ matrix.version }} - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} config-file: ./.github/codeql/codeql-config.yml @@ -185,7 +185,7 @@ jobs: run: ./cppbuild/cppbuild - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{ matrix.language }}" upload: false @@ -200,6 +200,6 @@ jobs: output: sarif-results/${{ matrix.language }}.sarif - name: Upload SARIF - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: sarif-results/${{ matrix.language }}.sarif From 149f9d06f19a2c40a28a29a6d47b6afecbe1fec0 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 14:47:38 +0100 Subject: [PATCH 702/805] [Java] Upgrade to `Checkstyle` 12.3.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 84779da7fc..bd97d1d2ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] agrona = "2.3.2" -checkstyle = "12.2.0" +checkstyle = "12.3.0" commons-codec = "1.15" commons-lang3 = "3.8.1" hamcrest = "3.0" From 08636256cafab42ef9e79f51c1baee99fb7d4178 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 14:48:03 +0100 Subject: [PATCH 703/805] [Java] Upgrade to `json` 20251224. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bd97d1d2ef..e657b94a0e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ hamcrest = "3.0" httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" -json = "20250517" +json = "20251224" junit = "6.0.1" mockito = "5.21.0" plexus = "3.3.0" From b702404b331236c8a3fe132a899663798db3857d Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 14:48:19 +0100 Subject: [PATCH 704/805] [Java] Upgrade to `Agrona` 2.4.0. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e657b94a0e..d85c88eafd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agrona = "2.3.2" +agrona = "2.4.0" checkstyle = "12.3.0" commons-codec = "1.15" commons-lang3 = "3.8.1" From 408dbc532231b1cd16c58925e7b8cd95bb8ddcdd Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 15:04:55 +0100 Subject: [PATCH 705/805] [C] Download and install `CMake` during build. --- .gitignore | 1 + cppbuild/cppbuild | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 554fcc27e0..02c31be8a8 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ cppbuild/*.cache cppbuild/Debug cppbuild/Release cppbuild/Win32 +cppbuild/cmake # golang gocode/pkg diff --git a/cppbuild/cppbuild b/cppbuild/cppbuild index 28f48c15aa..26a8d8a345 100755 --- a/cppbuild/cppbuild +++ b/cppbuild/cppbuild @@ -4,16 +4,44 @@ SOURCE_DIR="$(pwd)" BUILD_DIR="${SOURCE_DIR}/cppbuild/Release" EXTRA_CMAKE_ARGS="" +BUILD_DELETE_CMAKE=false +BUILD_CMAKE_VERSION=4.2.1 +BUILD_CMAKE_DIR="${SOURCE_DIR}/cppbuild/cmake" + ncpus=1 case "$(uname)" in Darwin* ) ncpus=$(sysctl -n hw.ncpu) + BUILD_CMAKE_OS="macos-universal" + BUILD_CMAKE_PATH="${BUILD_CMAKE_DIR}/CMake.app/Contents/bin" ;; Linux*) ncpus=$(lscpu -p | grep -c -E -v '^#') + BUILD_CMAKE_OS="linux-$(arch)" + BUILD_CMAKE_PATH="${BUILD_CMAKE_DIR}/bin" ;; esac +function install_cmake() +{ + if [[ true = "${BUILD_DELETE_CMAKE}" ]] + then + echo "Removing old CMake installation" + rm -rf "${BUILD_CMAKE_DIR}" + fi + + local version_file="${BUILD_CMAKE_DIR}/version.txt" + local version_info="${BUILD_CMAKE_VERSION}-${BUILD_CMAKE_OS}" + if [[ "${version_info}" != "$(cat "${version_file}")" ]] + then + echo "Installing CMake ${version_info}" + rm -rf "${BUILD_CMAKE_DIR}" + mkdir -p "${BUILD_CMAKE_DIR}" + (curl -LJ "https://github.com/Kitware/CMake/releases/download/v${BUILD_CMAKE_VERSION}/cmake-${BUILD_CMAKE_VERSION}-${BUILD_CMAKE_OS}.tar.gz" | tar xzf - -C "${BUILD_CMAKE_DIR}" --strip-components 1 + echo "${version_info}" > "${version_file}") + fi +} + while [[ $# -gt 0 ]] do option="${1}" @@ -39,6 +67,16 @@ do echo "Enabling sanitise build" shift ;; + --rebuild-cmake) + BUILD_DELETE_CMAKE=true + shift + ;; + --cmake-version) + BUILD_CMAKE_VERSION=${2} + echo "Setting BUILD_CMAKE_VERSION=${2}" + shift + shift + ;; -h|--help) echo "${0} [--c-warnings-as-errors] [--cxx-warnings-as-errors] [--debug-build] [--sanitise-build]" exit @@ -59,6 +97,9 @@ if [ -d "${BUILD_DIR}" ] ; then fi mkdir -p "${BUILD_DIR}" + +install_cmake + cd "${BUILD_DIR}" || exit -(cmake -G "Unix Makefiles" ${EXTRA_CMAKE_ARGS} "${SOURCE_DIR}" && make clean && make -j ${ncpus} all && ctest -C Release --output-on-failure) +("${BUILD_CMAKE_PATH}/cmake" -G "Unix Makefiles" ${EXTRA_CMAKE_ARGS} "${SOURCE_DIR}" && make clean && make -j ${ncpus} all && "${BUILD_CMAKE_PATH}/ctest" -C Release --output-on-failure) From 17d700dcd327168533b3ddd892785509aebe2cce Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 15:28:49 +0100 Subject: [PATCH 706/805] [C/C++] Add complete list of keywords + add `assert` as keyword so it is escaped correctly. --- .../uk/co/real_logic/sbe/ValidationUtil.java | 191 +++++++++++++++--- 1 file changed, 161 insertions(+), 30 deletions(-) diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java index 7ba93c7bd0..e6881b1276 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/ValidationUtil.java @@ -26,15 +26,67 @@ public class ValidationUtil private static final Pattern PATTERN = Pattern.compile("\\."); private static final Set C_KEYWORDS = Set.of( - "auto", "_Alignas", "_Alignof", "_Atomic", "bool", - "_Bool", "break", "case", "_Complex", - "char", "const", "continue", "default", - "do", "double", "else", "enum", "extern", "false", - "float", "for", "_Generic", "goto", "if", "_Imaginary", "inline", - "int", "long", "_Noreturn", "register", "restrict", "return", "short", - "signed", "sizeof", "static", "_Static_assert", - "struct", "switch", "_Thread_local", "true", "typedef", "union", - "unsigned", "void", "volatile", "wchar_t", "while"); + "alignas", + "alignof", + "assert", + "auto", + "bool", + "break", + "case", + "char", + "const", + "constexpr", + "continue", + "default", + "do", + "double", + "else", + "enum", + "extern", + "false", + "float", + "for", + "goto", + "if", + "inline", + "int", + "long", + "nullptr", + "register", + "restrict", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "struct", + "switch", + "thread_local", + "true", + "typedef", + "typeof", + "typeof_unqual", + "union", + "unsigned", + "void", + "volatile", + "while", + "_Alignas", + "_Alignof", + "_Atomic", + "_BitInt", + "_Bool", + "_Complex", + "_Decimal128", + "_Decimal32", + "_Decimal64", + "_Generic", + "_Imaginary", + "_Noreturn", + "_Static_assert", + "_Thread_local" + ); /** * Check value for validity of usage as a C identifier. A programmatic variable @@ -113,26 +165,105 @@ private static boolean isSbeCIdentifierPart(final char c) } private static final Set CPP_KEYWORDS = Set.of( - "alignas", "and", "and_eq", "asm", "auto", - "bitand", "bitor", "bool", "break", "case", - "catch", "char", "class", "compl", "const", - "const_cast", "continue", "char16_t", "char32_t", "default", - "delete", "do", "double", "dynamic_cast", "else", - "enum", "explicit", "export", "extern", "false", - "float", "for", "friend", "goto", "if", - "inline", "int", "long", "mutable", "namespace", - "new", "not", "not_eq", "noexcept", "operator", - "or", "or_eq", "private", "protected", "public", - "register", "reinterpret_cast", "return", "short", "signed", - "sizeof", "static", "static_cast", "struct", "switch", - "template", "this", "throw", "true", "try", - "typedef", "typeid", "typename", "union", "unsigned", - "using", "virtual", "void", "volatile", "wchar_t", - "while", "xor", "xor_eq", "override", - // since C++11 - "alignof", "constexpr", "decltype", "nullptr", "static_assert", "thread_local", - // since C++11 have special meaning, so avoid - "final"); + "alignas", + "alignof", + "and", + "and_eq", + "assert", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char8_t", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "consteval", + "constexpr", + "constinit", + "const_cast", + "continue", + "contract_assert", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "reflexpr", + "register", + "reinterpret_cast", + "requires", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq"); /** * Check value for validity of usage as a C++ identifier. A programmatic variable @@ -393,7 +524,7 @@ private static boolean isSbeGolangIdentifierPart(final char c) /** * C# keywords. * - * C# keywords + * C# keywords * Note this does not include the contextual keywords * Note "virtual" is no longer but was in early versions of C# */ From fefb1f0e1b80954eb1dd4ecf257e09ecde5b5340 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 16:01:40 +0100 Subject: [PATCH 707/805] [C++] Add test for handling keywords. --- sbe-tool/src/test/cpp/CodeGenTest.cpp | 30 ++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/test/cpp/CodeGenTest.cpp b/sbe-tool/src/test/cpp/CodeGenTest.cpp index 25c645248f..991e1f96f3 100644 --- a/sbe-tool/src/test/cpp/CodeGenTest.cpp +++ b/sbe-tool/src/test/cpp/CodeGenTest.cpp @@ -19,6 +19,7 @@ #include "gtest/gtest.h" #include "code_generation_test/MessageHeader.h" #include "code_generation_test/Car.h" +#include "code_generation_test/GlobalKeywords.h" using namespace code::generation::test; @@ -1144,4 +1145,31 @@ TEST_F(CodeGenTest, shouldBeAbleToResolveStringLiterals) car.sbeRewind(); EXPECT_EQ(car.getVehicleCodeAsStringView(), "ABCDE"); } -#endif \ No newline at end of file +#endif + +TEST_F(CodeGenTest, shouldComputeEncodedLengthCorrectlyForVarDataFields) +{ + char buffer[BUFFER_LEN] = {}; + + std::uint64_t baseOffset = MessageHeader::encodedLength(); + GlobalKeywords keywords; + keywords.wrapForEncode(buffer, baseOffset, sizeof(buffer)); + keywords.type(7); + keywords.assertX(16); + + GlobalKeywords::Data &data = keywords.dataCount(1); + + data.next() + .thisX(3); + + GlobalKeywords::Data::Super &super = data.superCount(2); + + super.next() + .mph(100); + + super.next() + .mph(200) + .putImport(std::string("this super long string value right here")); + + EXPECT_EQ(337, keywords.encodedLength()); +} From 7bfa96a2d84b9aab3420a94f4b4a1819a4827982 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 22:44:10 +0100 Subject: [PATCH 708/805] [C] Implement `--sanitise-build` support. --- CMakeLists.txt | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce164c285b..b3ab7a0ef2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,10 +75,13 @@ endif () find_package(Threads) +# all UNIX-based platform compiler flags if (UNIX) - add_compile_options(-Wall -Wpedantic -Wextra -Wno-unused-parameter) + add_compile_options(-fstrict-aliasing -Wall -Wpedantic -Wextra -Wno-unused-parameter -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer) - if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "21.0") + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "11.0") + add_compile_options(-Wno-error=maybe-uninitialized) + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "21.0") # See gtest: https://github.com/google/googletest/issues/4762 add_compile_options(-Wno-error=character-conversion) endif () @@ -90,13 +93,28 @@ if (UNIX) if (CXX_WARNINGS_AS_ERRORS) add_compile_options($<$:-Werror>) endif (CXX_WARNINGS_AS_ERRORS) + + if (SANITISE_BUILD) + if (NOT DEFINED APPLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=leak -fsanitize=undefined") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=leak -fsanitize=undefined") + endif () + endif (SANITISE_BUILD) endif () +# platform specific flags if (APPLE) - # -Wall doesn't enable everything we want to see add_compile_options(-Wsign-compare) add_definitions(-DDarwin) add_compile_options(-Wno-deprecated-register) + + if (SANITISE_BUILD) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=undefined") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=undefined") + endif (SANITISE_BUILD) +elseif (CYGWIN) + add_definitions(-DWIN32) + set(CMAKE_CXX_EXTENSIONS ON) elseif (MSVC) add_definitions(-DWIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS) @@ -108,10 +126,15 @@ elseif (MSVC) add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE) endif () - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd /Od /Zi /MP") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /MP") - set(CMAKE_C_FLAGS_DEBUG "/MTd") - set(CMAKE_C_FLAGS_RELEASE "/MT") + add_compile_options(/Oy-) + add_compile_options($<$,$>:/MD>) + add_compile_options($<$,$>:/MDd>) + add_compile_options($<$:/MP>) + add_compile_options($<$:/wd4251>) + add_compile_options($<$,$>:/MD>) + add_compile_options($<$,$>:/MDd>) + add_compile_options($<$,$>:/Od>) + add_compile_options($<$,$>:/Zi>) if (C_WARNINGS_AS_ERRORS) add_compile_options($<$:/WX>) @@ -120,8 +143,12 @@ elseif (MSVC) if (CXX_WARNINGS_AS_ERRORS) add_compile_options($<$:/WX>) endif (CXX_WARNINGS_AS_ERRORS) -else () - add_definitions(-D_GNU_SOURCE) + + if (SANITISE_BUILD) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Zi") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Zi") + endif (SANITISE_BUILD) + endif () set(LIBPREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}") From 4d5c43355adc523b0cb006edb64bef3ec23879f1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 22:51:38 +0100 Subject: [PATCH 709/805] [C++] Add a test with an additional `varData` encoding with `char` as a primitive type. --- sbe-tool/src/test/cpp/DtoTest.cpp | 4 +++- sbe-tool/src/test/resources/dto-test-schema.xml | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sbe-tool/src/test/cpp/DtoTest.cpp b/sbe-tool/src/test/cpp/DtoTest.cpp index f5d2d0cd58..c7eb7ce88c 100644 --- a/sbe-tool/src/test/cpp/DtoTest.cpp +++ b/sbe-tool/src/test/cpp/DtoTest.cpp @@ -48,6 +48,7 @@ static const char *MANUFACTURER = "Honda"; static const char *MODEL = "Civic VTi"; static const char *ACTIVATION_CODE = "deadbeef"; static const char *ADDED5 = "feedface"; +static const char *VARCHARDATA = "this is variable length data with `char` data type"; static const std::uint8_t PERFORMANCE_FIGURES_COUNT = 2; static const std::uint8_t FUEL_FIGURES_COUNT = 3; @@ -161,7 +162,8 @@ class DtoTest : public testing::Test car.putManufacturer(MANUFACTURER, static_cast(strlen(MANUFACTURER))) .putModel(MODEL, static_cast(strlen(MODEL))) .putActivationCode(ACTIVATION_CODE, static_cast(strlen(ACTIVATION_CODE))) - .putAdded5(ADDED5, static_cast(strlen(ADDED5))); + .putAdded5(ADDED5, static_cast(strlen(ADDED5))) + .putVarCharData(VARCHARDATA, static_cast(strlen(VARCHARDATA))); return car.encodedLength(); } diff --git a/sbe-tool/src/test/resources/dto-test-schema.xml b/sbe-tool/src/test/resources/dto-test-schema.xml index dd7bae3f8b..7cd26c57aa 100644 --- a/sbe-tool/src/test/resources/dto-test-schema.xml +++ b/sbe-tool/src/test/resources/dto-test-schema.xml @@ -28,6 +28,10 @@ + + + + @@ -122,6 +126,7 @@ + From ea3de439c7ad75030d18b913ecbd2e148c9c40ab Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:20:39 +0100 Subject: [PATCH 710/805] [Doc] Add release notes. --- CHANGELOG.adoc | 366 +++++++++++++++++++++++++------------------------ 1 file changed, 189 insertions(+), 177 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index d798f2bd60..79db065ce0 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,65 +1,77 @@ = Changelog +== 1.37.0 (2025-12-25) + +* **[C]** Implement `--sanitise-build` support. +* **[C/C{plus}{plus}]** Add complete list of keywords + add `assert` as keyword so it is escaped correctly. +* **[C]** Download and install `CMake` during the build. +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.4.0[Agrona 2.4.0]. +* **[Java]** Upgrade to `Checkstyle` 12.3.0. +* **[Java]** Upgrade to `json` 20251224. +* **[Java]** Upgrade to `Mockito` 5.21.0. +* **[Java]** Upgrade to `Shadow` 9.3.0. +* **[Java]** Upgrade to `Gradle` 9.2.1. + == 1.36.2 (2025-11-08) -* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.2[Agrona 2.3.2]. +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.2[Agrona 2.3.2]. == 1.36.1 (2025-11-03) -* *[C#]* Handle case when `valueRef` is with enum type prefix. (https://github.com/aeron-io/simple-binary-encoding/pull/1092[#1092]) -* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.1[Agrona 2.3.1]. -* *[Java]* Upgrade to `JUnit` 6.0.1. -* *[Java]* Upgrade to `Checkstyle` 12.1.1. +* **[C#]** Handle case when `valueRef` is with enum type prefix. (https://github.com/aeron-io/simple-binary-encoding/pull/1092[#1092]) +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.1[Agrona 2.3.1]. +* **[Java]** Upgrade to `JUnit` 6.0.1. +* **[Java]** Upgrade to `Checkstyle` 12.1.1. == 1.36.0 (2025-09-29) -* *[C{plus}{plus}]* Fix composite encode generation to use formatted property names, i.e. escape keywords. -* *[C{plus}{plus}]* Fix property name usage in display code generator. -* *[C{plus}{plus}]* Add getter for schema id on the `IrDecoder` (https://github.com/aeron-io/simple-binary-encoding/pull/1077[#1077]) -* *[Java]* Fix var data and composite code generation to use property name instead of plain name. Also use property name for access order check methods. (https://github.com/aeron-io/simple-binary-encoding/issues/1081[#1081]) -* *[Java]* Handle `null` values when encoding enums, i.e. use `Enum.NULL_VAL` if the value was not assigned. -* *[Java]* Handle primitive arrays correctly in the generated DTO code. -* *[Go]* Handle `_` and `String` as keywords and use property name when generating variable data section. -* *[C#]* Replaced empty array creation by `Array.Empty`, issue (https://github.com/aeron-io/simple-binary-encoding/issues/1079[#1079]). (https://github.com/aeron-io/simple-binary-encoding/pull/1080[#1080]) -* *[C/C{plus}{plus}]* Allow overriding Gradle wrapper location. (https://github.com/aeron-io/simple-binary-encoding/issues/1091[#1091]). -* *[Java/C{plus}{plus}/Go]* Preserve `packageName` in the IR. (https://github.com/aeron-io/simple-binary-encoding/issues/1089[#1089]) -* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.0[Agrona 2.3.0]. -* *[Java]* Upgrade to `JUnit` 5.13.4. -* *[Java]* Upgrade to `Mockito` 5.20.0. -* *[Java]* Upgrade to `Checkstyle` 11.1.0. -* *[Java]* Upgrade to `Shadow` 9.2.2. -* *[Java]* Upgrade to `Version` 0.53.0. -* *[C]* Upgrade to `GoogleTest` to 1.14.0. -* *[C]* Bump minimium required CMake version to `3.30`. -* *[CI]* Add `Clang` 21 to the build matrix. -* *[CI]* Add `Java` 25 to the build matrix. +* **[C{plus}{plus}]** Fix composite encode generation to use formatted property names, i.e. escape keywords. +* **[C{plus}{plus}]** Fix property name usage in display code generator. +* **[C{plus}{plus}]** Add getter for schema id on the `IrDecoder` (https://github.com/aeron-io/simple-binary-encoding/pull/1077[#1077]) +* **[Java]** Fix var data and composite code generation to use property name instead of plain name. Also use property name for access order check methods. (https://github.com/aeron-io/simple-binary-encoding/issues/1081[#1081]) +* **[Java]** Handle `null` values when encoding enums, i.e. use `Enum.NULL_VAL` if the value was not assigned. +* **[Java]** Handle primitive arrays correctly in the generated DTO code. +* **[Go]** Handle `_` and `String` as keywords and use property name when generating variable data section. +* **[C#]** Replaced empty array creation by `Array.Empty`, issue (https://github.com/aeron-io/simple-binary-encoding/issues/1079[#1079]). (https://github.com/aeron-io/simple-binary-encoding/pull/1080[#1080]) +* **[C/C{plus}{plus}]** Allow overriding Gradle wrapper location. (https://github.com/aeron-io/simple-binary-encoding/issues/1091[#1091]). +* **[Java/C{plus}{plus}/Go]** Preserve `packageName` in the IR. (https://github.com/aeron-io/simple-binary-encoding/issues/1089[#1089]) +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.3.0[Agrona 2.3.0]. +* **[Java]** Upgrade to `JUnit` 5.13.4. +* **[Java]** Upgrade to `Mockito` 5.20.0. +* **[Java]** Upgrade to `Checkstyle` 11.1.0. +* **[Java]** Upgrade to `Shadow` 9.2.2. +* **[Java]** Upgrade to `Version` 0.53.0. +* **[C]** Upgrade to `GoogleTest` to 1.14.0. +* **[C]** Bump minimium required CMake version to `3.30`. +* **[CI]** Add `Clang` 21 to the build matrix. +* **[CI]** Add `Java` 25 to the build matrix. == 1.35.6 (2025-06-27) -* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.4[Agrona 2.2.4]. -* *[Java]* Upgrade to `JUnit` 5.13.2. -* *[Java]* Upgrade to `Checkstyle` 10.26.0. -* *[Java]* Upgrade to `Shadow` 8.3.7. +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.4[Agrona 2.2.4]. +* **[Java]** Upgrade to `JUnit` 5.13.2. +* **[Java]** Upgrade to `Checkstyle` 10.26.0. +* **[Java]** Upgrade to `Shadow` 8.3.7. == 1.35.5 (2025-06-20) -* *[Java/C{plus}{plus}/C#]* Fix a bug in overzealous DTO validation. (https://github.com/aeron-io/simple-binary-encoding/pull/1073[#1073]) -* *[Java]* Improve JsonPrinter's conformance with the JSON specification (e.g., escaping control characters and using correct delimiters). -* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.3[Agrona 2.2.3]. +* **[Java/C{plus}{plus}/C#]** Fix a bug in overzealous DTO validation. (https://github.com/aeron-io/simple-binary-encoding/pull/1073[#1073]) +* **[Java]** Improve JsonPrinter's conformance with the JSON specification (e.g., escaping control characters and using correct delimiters). +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.3[Agrona 2.2.3]. == 1.35.4 (2025-06-12) -* *[Rust]* Return None for optional primite field if its version is less than actingVersion. (https://github.com/aeron-io/simple-binary-encoding/pull/1067[#1067]) -* *[Java]* Adjust Java Dto generateComputeEncodedLength to account for character encoding. (https://github.com/aeron-io/simple-binary-encoding/pull/1072[#1072]) -* *[Java]* Upgrade to `JUnit` 5.13.1. -* *[Java]* Upgrade to `jqwik` 1.9.3. +* **[Rust]** Return None for optional primite field if its version is less than actingVersion. (https://github.com/aeron-io/simple-binary-encoding/pull/1067[#1067]) +* **[Java]** Adjust Java Dto generateComputeEncodedLength to account for character encoding. (https://github.com/aeron-io/simple-binary-encoding/pull/1072[#1072]) +* **[Java]** Upgrade to `JUnit` 5.13.1. +* **[Java]** Upgrade to `jqwik` 1.9.3. == 1.35.3 (2025-06-06) -* *[Java]* Publish release artifacts to Central Portal using OSSRH Staging API service. -* *[Java]* Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.2[Agrona 2.2.2]. -* *[Java]* Upgrade to `Checkstyle` 10.25.0. -* *[Java]* Upgrade to `Gradle` 8.14.2. +* **[Java]** Publish release artifacts to Central Portal using OSSRH Staging API service. +* **[Java]** Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.2[Agrona 2.2.2]. +* **[Java]** Upgrade to `Checkstyle` 10.25.0. +* **[Java]** Upgrade to `Gradle` 8.14.2. == 1.35.1 (2025-06-02) @@ -68,18 +80,18 @@ == 1.35.0 (2025-05-26) -* *[Java]* include field 'deprecated' in ir encoding and decoding. -* *[Java]* Adjust Java DTO Choice Set Access. (https://github.com/aeron-io/simple-binary-encoding/issues/1064[#1064]) -* *[Rust]* get proper version for composite types. (https://github.com/aeron-io/simple-binary-encoding/pull/1058[#1058]) -* *[C#]* Read NuGet package version from version file (https://github.com/aeron-io/simple-binary-encoding/pull/1061[#1061]) -* *[C#]* Enable dual build for netstandard2.0 & netstandard2.1. (https://github.com/aeron-io/simple-binary-encoding/pull/1062[#1062]) +* **[Java]** include field 'deprecated' in ir encoding and decoding. +* **[Java]** Adjust Java DTO Choice Set Access. (https://github.com/aeron-io/simple-binary-encoding/issues/1064[#1064]) +* **[Rust]** get proper version for composite types. (https://github.com/aeron-io/simple-binary-encoding/pull/1058[#1058]) +* **[C#]** Read NuGet package version from version file (https://github.com/aeron-io/simple-binary-encoding/pull/1061[#1061]) +* **[C#]** Enable dual build for netstandard2.0 & netstandard2.1. (https://github.com/aeron-io/simple-binary-encoding/pull/1062[#1062]) * Update `Implementation-Vendor`. -* *[Rust]* Elide explicit ActingVersion lifetime. (https://github.com/aeron-io/simple-binary-encoding/pull/1053[#1053]) -* *[CI]* Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. -* *[CI]* Enable JDK 24 GA build. -* *[CI]* Simplify error log upload. -* *[CI]* Remove Ubuntu 20.04 based builds. -* *[CI]* Bump Go build to use 1.23.x and 1.24.x. +* **[Rust]** Elide explicit ActingVersion lifetime. (https://github.com/aeron-io/simple-binary-encoding/pull/1053[#1053]) +* **[CI]** Use `gradle/actions/setup-gradle` action for caching Gradle dependencies. +* **[CI]** Enable JDK 24 GA build. +* **[CI]** Simplify error log upload. +* **[CI]** Remove Ubuntu 20.04 based builds. +* **[CI]** Bump Go build to use 1.23.x and 1.24.x. * Upgrade to https://github.com/aeron-io/agrona/releases/tag/2.2.0[Agrona 2.2.0]. * Upgrade to `Gradle` 8.14.1. * Upgrade to `Checkstyle` 10.24.0. @@ -92,19 +104,19 @@ == 1.34.1 (2025-01-13) * *Doc:* Add `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` to the example execution. -* *[Rust]* encoding primitive arrays now supports slice instead of array (issue https://github.com/aeron-io/simple-binary-encoding/issues/[#1021]). (https://github.com/aeron-io/simple-binary-encoding/pull/1040[#1040]) -* *[C{plus}{plus}]* check for not wrapped state in `decodeLength()` when precedence checks are enabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1046[#1046]) -* *[C{plus}{plus}]* use `m_actingBlockLength` in `decodeLength()`. (https://github.com/aeron-io/simple-binary-encoding/pull/1045[#1045]) +* **[Rust]** encoding primitive arrays now supports slice instead of array (issue https://github.com/aeron-io/simple-binary-encoding/issues/[#1021]). (https://github.com/aeron-io/simple-binary-encoding/pull/1040[#1040]) +* **[C{plus}{plus}]** check for not wrapped state in `decodeLength()` when precedence checks are enabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1046[#1046]) +* **[C{plus}{plus}]** use `m_actingBlockLength` in `decodeLength()`. (https://github.com/aeron-io/simple-binary-encoding/pull/1045[#1045]) * Bump `json` to 20250107. * Upgrade to `Mockito` 5.15.2. == 1.34.0 (2024-12-17) -* *[C{plus}{plus}]* hide the m_codecStatePtr behind ifdefs to avoid overhead when precedence checking is disabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1036[#1036]) -* *[C{plus}{plus}]* use constexpr to define precedence checks lookup tables. -* *[Rust]* Enhance enum supporting fromstr and display and into. (https://github.com/aeron-io/simple-binary-encoding/pull/1020[#1020]) -* *[Rust]* codegen of primitive enums now implement 'From' instead of 'Into'. (https://github.com/aeron-io/simple-binary-encoding/pull/1029[#1029]) -* *[Java]* Update Checkstyle rules and apply them. +* **[C{plus}{plus}]** hide the m_codecStatePtr behind ifdefs to avoid overhead when precedence checking is disabled. (https://github.com/aeron-io/simple-binary-encoding/pull/1036[#1036]) +* **[C{plus}{plus}]** use constexpr to define precedence checks lookup tables. +* **[Rust]** Enhance enum supporting fromstr and display and into. (https://github.com/aeron-io/simple-binary-encoding/pull/1020[#1020]) +* **[Rust]** codegen of primitive enums now implement 'From' instead of 'Into'. (https://github.com/aeron-io/simple-binary-encoding/pull/1029[#1029]) +* **[Java]** Update Checkstyle rules and apply them. * *Breaking:* Upgrade to `Agrona` 2.0.0. + _**Note:** `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` JVM option must be specified in order to generate codecs or use the generated Java classes. For example:_ @@ -114,15 +126,15 @@ _**Note:** `--add-opens java.base/jdk.internal.misc=ALL-UNNAMED` JVM option must $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=true -Dsbe.target.language=Cpp -Dsbe.target.namespace=sbe -Dsbe.output.dir=include/gen -Dsbe.errorLog=yes -jar sbe-all/build/libs/sbe-all-${SBE_TOOL_VERSION}.jar my-sbe-messages.xml ---- -* *[C{plus}{plus}]* Fix field precedence check issue https://github.com/aeron-io/simple-binary-encoding/issues/1031[#1031]. (https://github.com/aeron-io/simple-binary-encoding/pull/1033[#1033]) -* *[C{plus}{plus}]* respect the package override option for C{plus}{plus} codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) -* *[C#]* respect the package override option for C# codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) -* *[Go]* Fix warning about used args in GolangFlyweightGenerator. -* *[Rust]* Updated code generator to resolve Issue https://github.com/aeron-io/simple-binary-encoding/issues/1028[#1028]. (https://github.com/aeron-io/simple-binary-encoding/pull/1037[#1037]) -* *[Java]* Prevent collision when field name is 'value'. -* *[Java]* Preserve byte order throughout IR transformations. -* *[C{plus}{plus}]* Integrate std::span support for flyweight API. (https://github.com/aeron-io/simple-binary-encoding/pull/1038[#1038], https://github.com/aeron-io/simple-binary-encoding/pull/1027[#1027]) -* *[Rust]* generate message schema level info in lib.rs. (https://github.com/aeron-io/simple-binary-encoding/pull/1019[#1019]) +* **[C{plus}{plus}]** Fix field precedence check issue https://github.com/aeron-io/simple-binary-encoding/issues/1031[#1031]. (https://github.com/aeron-io/simple-binary-encoding/pull/1033[#1033]) +* **[C{plus}{plus}]** respect the package override option for C{plus}{plus} codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) +* **[C#]** respect the package override option for C# codecs and DTOs. (https://github.com/aeron-io/simple-binary-encoding/pull/1024[#1024]) +* **[Go]** Fix warning about used args in GolangFlyweightGenerator. +* **[Rust]** Updated code generator to resolve Issue https://github.com/aeron-io/simple-binary-encoding/issues/1028[#1028]. (https://github.com/aeron-io/simple-binary-encoding/pull/1037[#1037]) +* **[Java]** Prevent collision when field name is 'value'. +* **[Java]** Preserve byte order throughout IR transformations. +* **[C{plus}{plus}]** Integrate std::span support for flyweight API. (https://github.com/aeron-io/simple-binary-encoding/pull/1038[#1038], https://github.com/aeron-io/simple-binary-encoding/pull/1027[#1027]) +* **[Rust]** generate message schema level info in lib.rs. (https://github.com/aeron-io/simple-binary-encoding/pull/1019[#1019]) * Upgrade to `Gradle` 8.11.1. * Upgrade to `Checkstyle` 10.21.0. * Upgrade to `ByteBuddy` 1.15.11. @@ -131,21 +143,21 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.33.2 (2024-11-08) -* *[Rust]* Help decoding multiple messages using rust by resolving https://github.com/aeron-io/simple-binary-encoding/issues/987[#987]. -* *[Go]* SBE implementation in Go using flyweights. -* *[Java]* DTOs respect the optional package field in the schema definition. -* *[Java]* Fix bug in DTO `decodeFrom` signature. +* **[Rust]** Help decoding multiple messages using rust by resolving https://github.com/aeron-io/simple-binary-encoding/issues/987[#987]. +* **[Go]** SBE implementation in Go using flyweights. +* **[Java]** DTOs respect the optional package field in the schema definition. +* **[Java]** Fix bug in DTO `decodeFrom` signature. == 1.33.1 (2024-09-23) -* *[Java]* Fix #1012 DTO char array setter visibility. -* *[Rust]* Indicate the anonymous lifetime in set's Display impl (https://github.com/aeron-io/simple-binary-encoding/pull/1014[#1014]). -* *[Java]* Style consistency and add JavadocVariable Checkstyle test. -* *[Java]* Use version catalogs. -* *[Java]* Upgrade to JUnit 5.13.0. -* *[Java]* Upgrade to Gradle 8.10.1. -* *[Java]* Upgrade to Shadow 8.3.2. -* *[Java]* Upgrade to Checkstyle 10.18.1. +* **[Java]** Fix #1012 DTO char array setter visibility. +* **[Rust]** Indicate the anonymous lifetime in set's Display impl (https://github.com/aeron-io/simple-binary-encoding/pull/1014[#1014]). +* **[Java]** Style consistency and add JavadocVariable Checkstyle test. +* **[Java]** Use version catalogs. +* **[Java]** Upgrade to JUnit 5.13.0. +* **[Java]** Upgrade to Gradle 8.10.1. +* **[Java]** Upgrade to Shadow 8.3.2. +* **[Java]** Upgrade to Checkstyle 10.18.1. == 1.33.0 (2024-08-24) @@ -155,62 +167,62 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru === Changelog -* *[CI]* Execute tests using `ubuntu-24.04` and `macos-latest`. -* *[Java]* Upgrade to Agrona 1.23.0. -* *[Java]* Upgrade to Gradle 8.10. -* *[Java]* Upgrade to Shadow 8.3.0. -* *[Java]* Upgrade to Mockito 5.12.0. +* **[CI]** Execute tests using `ubuntu-24.04` and `macos-latest`. +* **[Java]** Upgrade to Agrona 1.23.0. +* **[Java]** Upgrade to Gradle 8.10. +* **[Java]** Upgrade to Shadow 8.3.0. +* **[Java]** Upgrade to Mockito 5.12.0. == 1.32.2 (2024-08-23) -* *[Rust]* Generate imports in alphabetical order. #997 -* *[Rust]* Make Rust crate version configurable. #996 -* *[C]* fix compilation error in C string view functions. #1010 -* *[Java]* Upgrade to JUnit 5.11.0. +* **[Rust]** Generate imports in alphabetical order. #997 +* **[Rust]** Make Rust crate version configurable. #996 +* **[C]** fix compilation error in C string view functions. #1010 +* **[Java]** Upgrade to JUnit 5.11.0. == 1.32.1 (2024-08-05) -* *[Java]* Upgrade to Agrona 1.22.0. -* *[Java]* Upgrade to Hamcrest 3.0. +* **[Java]** Upgrade to Agrona 1.22.0. +* **[Java]** Upgrade to Hamcrest 3.0. == 1.32.0 (2024-08-02) * [C#,C{plus}{plus},Java] Generate DTOs for non-perf-sensitive usecases. #957 * [C{plus}{plus}, C#] Only generate range validation code when specifying a range smaller than the associate type. -* *[C#]* Fix ToString() to avoid state changes on message. #992 -* *[C]* Add a #define for each template id. #1006 +* **[C#]** Fix ToString() to avoid state changes on message. #992 +* **[C]** Add a #define for each template id. #1006 * [Java, C#, C{plus}{plus}] Check enum value for language specific keywords and apply `sbe.keyword.append.token` when appropriate. #1009 #1008 == 1.31.0 (2024-04-03) -* *[Java]* Remove unused initialOffset member from generated codecs. -* *[Java]* Check for being in a composite when generating array access methods based on version. -* *[Java]* Captured types in IR should be for the minimum version used in a schema. https://github.com/aeron-io/simple-binary-encoding/pull/967[#967]. -* *[C{plus}{plus}]* Provide access to acting block length of repeating group via the sbeActingBlockLength() method. Issue #968. -* *[C{plus}{plus}]* message header members constexpr https://github.com/aeron-io/simple-binary-encoding/pull/971[#971]. -* *[C{plus}{plus}]* Code tidy up and address Issue #970. -* *[Java]* Cope with optional sets not being present when pretty printing decoders for debugging. https://github.com/aeron-io/simple-binary-encoding/pull/977[#977]. -* *[C{plus}{plus}]* small test fix https://github.com/aeron-io/simple-binary-encoding/pull/980[#980]. -* *[Rust]* Updated RustGenerator.generatePrimitiveOptionalDecoder() https://github.com/aeron-io/simple-binary-encoding/pull/981[#981]. -* *[Rust]* Take slices by reference https://github.com/aeron-io/simple-binary-encoding/pull/979[#979]. -* *[Rust]* updated code generator to prevent rust warning for "ambiguous glob re-exports" https://github.com/aeron-io/simple-binary-encoding/pull/982[#982]. -* *[Go]* Handle mixed case enums and BitSets. Fixes #983. -* *[Java]* Use `BYTE_ORDER` constant instead of accessing `java.nio.ByteOrder` directly. +* **[Java]** Remove unused initialOffset member from generated codecs. +* **[Java]** Check for being in a composite when generating array access methods based on version. +* **[Java]** Captured types in IR should be for the minimum version used in a schema. https://github.com/aeron-io/simple-binary-encoding/pull/967[#967]. +* **[C{plus}{plus}]** Provide access to acting block length of repeating group via the sbeActingBlockLength() method. Issue #968. +* **[C{plus}{plus}]** message header members constexpr https://github.com/aeron-io/simple-binary-encoding/pull/971[#971]. +* **[C{plus}{plus}]** Code tidy up and address Issue #970. +* **[Java]** Cope with optional sets not being present when pretty printing decoders for debugging. https://github.com/aeron-io/simple-binary-encoding/pull/977[#977]. +* **[C{plus}{plus}]** small test fix https://github.com/aeron-io/simple-binary-encoding/pull/980[#980]. +* **[Rust]** Updated RustGenerator.generatePrimitiveOptionalDecoder() https://github.com/aeron-io/simple-binary-encoding/pull/981[#981]. +* **[Rust]** Take slices by reference https://github.com/aeron-io/simple-binary-encoding/pull/979[#979]. +* **[Rust]** updated code generator to prevent rust warning for "ambiguous glob re-exports" https://github.com/aeron-io/simple-binary-encoding/pull/982[#982]. +* **[Go]** Handle mixed case enums and BitSets. Fixes #983. +* **[Java]** Use `BYTE_ORDER` constant instead of accessing `java.nio.ByteOrder` directly. * Upgrade .NET SDK to 8.0.201 (https://github.com/aeron-io/simple-binary-encoding/pull/978[#978]). -* *[Java]* Upgrade to Agrona 1.21.1. -* *[Java]* Upgrade to ASM 9.7. -* *[Java]* Upgrade to JUnit 5.10.2. -* *[Java]* Upgrade to Versions 0.51.0. +* **[Java]** Upgrade to Agrona 1.21.1. +* **[Java]** Upgrade to ASM 9.7. +* **[Java]** Upgrade to JUnit 5.10.2. +* **[Java]** Upgrade to Versions 0.51.0. == 1.30.0 (2023-12-06) * [Java, C{plus}{plus}, C#] Add support to https://github.com/aeron-io/simple-binary-encoding/wiki/Safe-Flyweight-Usage[check the safe usage of flyweights (w.r.t. field access order)]. https://github.com/aeron-io/simple-binary-encoding/pull/948[#948]. -* *[C#]* Fix invalid code generated when using some length types for var data https://github.com/aeron-io/simple-binary-encoding/issues/955[#955] -* *[Java]* Support valueRef with camelCase enum type identifiers https://github.com/aeron-io/simple-binary-encoding/pull/963[#963] -* *[Rust]* update how "use declarations" are generated, now deriving Defaults for enums https://github.com/aeron-io/simple-binary-encoding/pull/952[#952] -* *[C{plus}{plus}]* Rely on NAN from limits rather than pulling in cmath (https://github.com/aeron-io/simple-binary-encoding/issues/956) -* *[Java]* Fix javadoc link for JDK 21 GA -* *[Java]* Expose actingVersion https://github.com/aeron-io/simple-binary-encoding/pull/953[#953] +* **[C#]** Fix invalid code generated when using some length types for var data https://github.com/aeron-io/simple-binary-encoding/issues/955[#955] +* **[Java]** Support valueRef with camelCase enum type identifiers https://github.com/aeron-io/simple-binary-encoding/pull/963[#963] +* **[Rust]** update how "use declarations" are generated, now deriving Defaults for enums https://github.com/aeron-io/simple-binary-encoding/pull/952[#952] +* **[C{plus}{plus}]** Rely on NAN from limits rather than pulling in cmath (https://github.com/aeron-io/simple-binary-encoding/issues/956) +* **[Java]** Fix javadoc link for JDK 21 GA +* **[Java]** Expose actingVersion https://github.com/aeron-io/simple-binary-encoding/pull/953[#953] * Upgrade Agrona to 1.20.0 * Upgrade to ASM 9.6 * Upgrade to JMH 1.27 @@ -219,10 +231,10 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.29.0 (2023-07-21) -* *[Rust]* Add derive Copy Clone traits for decoders (PR #940). -* *[Rust]* Fix clippy lint (PR #941). -* *[Rust]* Fix array syntax error (PR #946). -* *[Rust]* Improve rust performance (PR #944). +* **[Rust]** Add derive Copy Clone traits for decoders (PR #940). +* **[Rust]** Fix clippy lint (PR #941). +* **[Rust]** Fix array syntax error (PR #946). +* **[Rust]** Improve rust performance (PR #944). * JsonPrinter remove trailing garbage after non-printable char (PR #950). * Upgrade to Agrona 1.19.0. * Upgrade to versions 0.47.0. @@ -248,17 +260,17 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.28.0 (2023-03-29) * Added semantic version as a static public member. PR #931. -* *[Rust]* Nested composite name should not be based on field name. PR #922. -* *[C/C{plus}{plus}]* Prevent clashing defines in C/C{plus}{plus} codecs when multiple generated schemas are used. Issue #884. -* *[C#]* Compare `PrimitiveValue` with doubles in the same way as Java by the raw bits, so NaN and Infinity are correctly handled. +* **[Rust]** Nested composite name should not be based on field name. PR #922. +* **[C/C{plus}{plus}]** Prevent clashing defines in C/C{plus}{plus} codecs when multiple generated schemas are used. Issue #884. +* **[C#]** Compare `PrimitiveValue` with doubles in the same way as Java by the raw bits, so NaN and Infinity are correctly handled. * Add CodeQL workflow. -* *[C#]* Add `ToString` for `PrimitiveType` -* *[C{plus}{plus}]* Pass by reference rather than value when streaming to a string. -* *[C{plus}{plus}]* Address duplicate guard issues. -* *[Java]* More efficient attribute parsing in XML with a more precise error message. -* *[Java]* Validate IR file for decoding is not greater than Integer.MAX_VALUE. -* *[C/C{plus}{plus}]* Move check for existing `SBE_BOUNDS_CHECK_EXPECT` define to outer condition to capture all platforms. -* *[Java]* Print warnings for undersize header fields. +* **[C#]** Add `ToString` for `PrimitiveType` +* **[C{plus}{plus}]** Pass by reference rather than value when streaming to a string. +* **[C{plus}{plus}]** Address duplicate guard issues. +* **[Java]** More efficient attribute parsing in XML with a more precise error message. +* **[Java]** Validate IR file for decoding is not greater than Integer.MAX_VALUE. +* **[C/C{plus}{plus}]** Move check for existing `SBE_BOUNDS_CHECK_EXPECT` define to outer condition to capture all platforms. +* **[Java]** Print warnings for undersize header fields. * Upgrade to Agrona 1.18.0. * Upgrade to Mockito 4.11.0. * Upgrade to Junit 5.9.2. @@ -268,10 +280,10 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.27.0 (2022-10-11) -* *[Java]* Add preview support for package override on types from SBE 2.0. https://github.com/aeron-io/simple-binary-encoding/pull/904[#904], https://github.com/aeron-io/simple-binary-encoding/pull/915[#915]. +* **[Java]** Add preview support for package override on types from SBE 2.0. https://github.com/aeron-io/simple-binary-encoding/pull/904[#904], https://github.com/aeron-io/simple-binary-encoding/pull/915[#915]. * Add support for transforming a schema to generate code for older versions when checking compatibility. -* *[Java]* Support binary var data in `JsonPrinter`. https://github.com/aeron-io/simple-binary-encoding/pull/914[#914]. -* *[Java]* Qualify methods with name `yield` to avoid warning in Java 17. https://github.com/aeron-io/simple-binary-encoding/pull/910[#910]. +* **[Java]** Support binary var data in `JsonPrinter`. https://github.com/aeron-io/simple-binary-encoding/pull/914[#914]. +* **[Java]** Qualify methods with name `yield` to avoid warning in Java 17. https://github.com/aeron-io/simple-binary-encoding/pull/910[#910]. * Carry down the the `sinceVersion` value into composite types to make parsing OTF easier. https://github.com/aeron-io/simple-binary-encoding/issues/908[Issue #908]. * Set the size for constant encoded data type to be zero in IR. * Upgrade to Google Test 1.21.1. @@ -282,12 +294,12 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.26.0 (2022-07-11) -* *[Java]* Provide raw access to type for bitset. https://github.com/aeron-io/simple-binary-encoding/issues/893[Issue #893]. -* *[C{plus}{plus}]* Generate `skip` function with loop rather than lambda to avoid compilation errors on some compilers. https://github.com/aeron-io/simple-binary-encoding/issues/903[Issue #903]. +* **[Java]** Provide raw access to type for bitset. https://github.com/aeron-io/simple-binary-encoding/issues/893[Issue #893]. +* **[C{plus}{plus}]** Generate `skip` function with loop rather than lambda to avoid compilation errors on some compilers. https://github.com/aeron-io/simple-binary-encoding/issues/903[Issue #903]. * Check `sinceVersion` is valid on elements against schema version. https://github.com/aeron-io/simple-binary-encoding/issues/902[Issue #902]. -* *[Rust]* Fix generated comparator when value is `NaN`. https://github.com/aeron-io/simple-binary-encoding/pull/896[#896]. -* *[Rust]* Fix resource leak in Rust generator running in Java SBE compiler. -* *[Java]* Generate `@SuppressWarnings` annotation on enums types. https://github.com/aeron-io/simple-binary-encoding/issues/894[Issue #894]. +* **[Rust]** Fix generated comparator when value is `NaN`. https://github.com/aeron-io/simple-binary-encoding/pull/896[#896]. +* **[Rust]** Fix resource leak in Rust generator running in Java SBE compiler. +* **[Java]** Generate `@SuppressWarnings` annotation on enums types. https://github.com/aeron-io/simple-binary-encoding/issues/894[Issue #894]. * Upgrade to Mockito 4.6.1. * Upgrade to Agrona 1.16.0. @@ -300,10 +312,10 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.25.2 (2022-03-18) -* *[Java]* Calling `toString()` on decoder should not disturb repeating group. https://github.com/aeron-io/simple-binary-encoding/pull/892[#892]. -* *[All]* Generate `NULL_VALUE` for enums based on correct type. https://github.com/aeron-io/simple-binary-encoding/issues/889[Issue #889]. -* *[C{plus}{plus}]* Check for version before outputting to stream for composites and bitsets. https://github.com/aeron-io/simple-binary-encoding/pull/888[#888]. -* *[Java]* Charset handling improvements for more efficient string decoding. https://github.com/aeron-io/simple-binary-encoding/pull/887[#887]. +* **[Java]** Calling `toString()` on decoder should not disturb repeating group. https://github.com/aeron-io/simple-binary-encoding/pull/892[#892]. +* **[All]** Generate `NULL_VALUE` for enums based on correct type. https://github.com/aeron-io/simple-binary-encoding/issues/889[Issue #889]. +* **[C{plus}{plus}]** Check for version before outputting to stream for composites and bitsets. https://github.com/aeron-io/simple-binary-encoding/pull/888[#888]. +* **[Java]** Charset handling improvements for more efficient string decoding. https://github.com/aeron-io/simple-binary-encoding/pull/887[#887]. * Add descriptions to schema for IR. * Set warnings as errors in build and clean up existing warnings. * Add ability to set the error stream in `ParserOptions`. @@ -324,11 +336,11 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.25.0 (2021-11-17) -* *[C#]* Add support for wrapping `ArraySegment` in `DirectBuffer`. https://github.com/aeron-io/simple-binary-encoding/pull/878[#878]. -* *[Java]* Add `@Deprecated` annotation to message codecs that have been marked as deprecated in SBE schema. https://github.com/aeron-io/simple-binary-encoding/pull/876[#876]. -* *[C{plus}{plus}]* Only generate necessary macros and includes for enum types. -* *[Rust]* Reinstate improved Rust codec generation. -* *[Java]* Add `sbeSkip` and `sbeDecodedLength` methods to codecs. https://github.com/aeron-io/simple-binary-encoding/pull/865[#865]. +* **[C#]** Add support for wrapping `ArraySegment` in `DirectBuffer`. https://github.com/aeron-io/simple-binary-encoding/pull/878[#878]. +* **[Java]** Add `@Deprecated` annotation to message codecs that have been marked as deprecated in SBE schema. https://github.com/aeron-io/simple-binary-encoding/pull/876[#876]. +* **[C{plus}{plus}]** Only generate necessary macros and includes for enum types. +* **[Rust]** Reinstate improved Rust codec generation. +* **[Java]** Add `sbeSkip` and `sbeDecodedLength` methods to codecs. https://github.com/aeron-io/simple-binary-encoding/pull/865[#865]. * Upgrade to JUnit 5.8.1. * Upgrade to Shadow 7.1.0. * Upgrade to Mockito 4.0.0. @@ -339,9 +351,9 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.24.0 (2021-08-06) -* *[Java]* Improve efficiency of encoding `CharSequence` when ASCII character encoding is used. -* *[Java]* Check that IR codecs are regenerated on codec change. -* *[Java/C{plus}{plus}/C]* Add `sbeRewind` to decoders so they can rewind to the beginning of a message and begin decoding again. +* **[Java]** Improve efficiency of encoding `CharSequence` when ASCII character encoding is used. +* **[Java]** Check that IR codecs are regenerated on codec change. +* **[Java/C{plus}{plus}/C]** Add `sbeRewind` to decoders so they can rewind to the beginning of a message and begin decoding again. * Upgrade to Google Test 1.11.0 * Upgrade to ByteBuddy 1.11.3 * Upgrade to Mockito 3.11.2. @@ -350,10 +362,10 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.23.0 (2021-06-13) -* *[C#]* Add `ToString()` method to generated codecs. https://github.com/aeron-io/simple-binary-encoding/pull/853[#853]. -* *[C#]* Add more string read and write methods to codecs. https://github.com/aeron-io/simple-binary-encoding/pull/845[#845]. -* *[Go]* Fix tokens passed when generating composites. https://github.com/aeron-io/simple-binary-encoding/pull/850[#850]. -* *[C/C{plus}{plus}]* Add Clang 12 to the matrix build. +* **[C#]** Add `ToString()` method to generated codecs. https://github.com/aeron-io/simple-binary-encoding/pull/853[#853]. +* **[C#]** Add more string read and write methods to codecs. https://github.com/aeron-io/simple-binary-encoding/pull/845[#845]. +* **[Go]** Fix tokens passed when generating composites. https://github.com/aeron-io/simple-binary-encoding/pull/850[#850]. +* **[C/C{plus}{plus}]** Add Clang 12 to the matrix build. * Upgrade to Versions 0.39.0. * Upgrade to JUnit 5.7.2. * Upgrade to Mockito 3.11.1. @@ -365,15 +377,15 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.22.0 (2021-04-16) -* *[C#]* Convert benchmarks to use DotNetBenchmark. https://github.com/aeron-io/agrona/pull/841[#841]. -* *[C#]* Help compiler to inline `DirectBuffer.CheckLimit` for better performance. https://github.com/aeron-io/simple-binary-encoding/pull/840[#840]. +* **[C#]** Convert benchmarks to use DotNetBenchmark. https://github.com/aeron-io/agrona/pull/841[#841]. +* **[C#]** Help compiler to inline `DirectBuffer.CheckLimit` for better performance. https://github.com/aeron-io/simple-binary-encoding/pull/840[#840]. * Add Java 17-ea to the build matrix. * Test with CME FixBinary version 9. -* *[C{plus}{plus}]* Capture `actingBlockLength` and use it for prettying printing output in version aware codecs. https://github.com/aeron-io/simple-binary-encoding/issues/839[Issue #839]. -* *[C{plus}{plus}]* Remove invalid use of `noexcept` on `resetCountToIndex`. https://github.com/aeron-io/simple-binary-encoding/issues/838[Issue #838]. -* *[Java]* Generate a `wrapAndApplyHeader` method for decoders to verify template then apply acting version and offset. -* *[C{plus}{plus}]* Clean up and improve samples. -* *[C{plus}{plus}]* Pass elements by reference rather than value in `forEach` for more efficient skip operations. +* **[C{plus}{plus}]** Capture `actingBlockLength` and use it for prettying printing output in version aware codecs. https://github.com/aeron-io/simple-binary-encoding/issues/839[Issue #839]. +* **[C{plus}{plus}]** Remove invalid use of `noexcept` on `resetCountToIndex`. https://github.com/aeron-io/simple-binary-encoding/issues/838[Issue #838]. +* **[Java]** Generate a `wrapAndApplyHeader` method for decoders to verify template then apply acting version and offset. +* **[C{plus}{plus}]** Clean up and improve samples. +* **[C{plus}{plus}]** Pass elements by reference rather than value in `forEach` for more efficient skip operations. * Upgrade to Version 0.38.0. * Upgrade to JMH 1.29. * Upgrade to JUnit 5.7.1. @@ -383,10 +395,10 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.21.0 (2021-01-15) -* *[Java]* Generate metadata methods to groups for min and max count values. https://github.com/aeron-io/simple-binary-encoding/pull/834[#834]. -* *[Java]* Declare generated classes as final to allow for better optimisation and increased performance. -* *[C{plus}{plus}]* Null terminate constant char arrays to avoid warnings. https://github.com/aeron-io/simple-binary-encoding/issues/832[Issue #832]. -* *[C{plus}{plus}]* Add support for decoding unknown enum values from later versions by enabling `sbe.decode.unknown.enum.values` and provide access to raw values. +* **[Java]** Generate metadata methods to groups for min and max count values. https://github.com/aeron-io/simple-binary-encoding/pull/834[#834]. +* **[Java]** Declare generated classes as final to allow for better optimisation and increased performance. +* **[C{plus}{plus}]** Null terminate constant char arrays to avoid warnings. https://github.com/aeron-io/simple-binary-encoding/issues/832[Issue #832]. +* **[C{plus}{plus}]** Add support for decoding unknown enum values from later versions by enabling `sbe.decode.unknown.enum.values` and provide access to raw values. * Clean up warnings in bash scripts. * Upgrade to Checkstyle 8.39. * Upgrade to Mockito 3.7.0. @@ -394,14 +406,14 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.20.4 (2020-12-22) * Add parsing of CME iLink order protocol to tests. -* *[C{plus}{plus}]* Generate literal marked up for correct type when shifting for bitsets using `uint64`. https://github.com/aeron-io/simple-binary-encoding/pull/829[#829]. -* *[Java]* Generate `@return` in javadoc for bitset values. https://github.com/aeron-io/simple-binary-encoding/issues/828[Issue #828]. -* *[Java]* Escape basic HTML characters for javadoc. https://github.com/aeron-io/simple-binary-encoding/issues/826[Issue #826]. -* *[Go]* Fix decoding into struct with pre-allocated slices. https://github.com/aeron-io/simple-binary-encoding/pull/825[#825]. -* *[C{plus}{plus}]* Fix spelling of `_cplusplus` macro. https://github.com/aeron-io/simple-binary-encoding/issues/823[Issue #821]. -* *[C#]* Fix repeating group encode overflow. https://github.com/aeron-io/simple-binary-encoding/pull/823[#823]. -* *[C]* Fix argument order for wrap_and_apply_header methods. https://github.com/aeron-io/simple-binary-encoding/pull/821[#821]. -* *[Java]* Generate bulk methods for fixed length `uint8` arrays. https://github.com/aeron-io/simple-binary-encoding/pull/819[#819]. +* **[C{plus}{plus}]** Generate literal marked up for correct type when shifting for bitsets using `uint64`. https://github.com/aeron-io/simple-binary-encoding/pull/829[#829]. +* **[Java]** Generate `@return` in javadoc for bitset values. https://github.com/aeron-io/simple-binary-encoding/issues/828[Issue #828]. +* **[Java]** Escape basic HTML characters for javadoc. https://github.com/aeron-io/simple-binary-encoding/issues/826[Issue #826]. +* **[Go]** Fix decoding into struct with pre-allocated slices. https://github.com/aeron-io/simple-binary-encoding/pull/825[#825]. +* **[C{plus}{plus}]** Fix spelling of `_cplusplus` macro. https://github.com/aeron-io/simple-binary-encoding/issues/823[Issue #821]. +* **[C#]** Fix repeating group encode overflow. https://github.com/aeron-io/simple-binary-encoding/pull/823[#823]. +* **[C]** Fix argument order for wrap_and_apply_header methods. https://github.com/aeron-io/simple-binary-encoding/pull/821[#821]. +* **[Java]** Generate bulk methods for fixed length `uint8` arrays. https://github.com/aeron-io/simple-binary-encoding/pull/819[#819]. * Add Java 16 EA to the build matrix. * Upgrade to JMH 1.27. * Upgrade to Checkstyle 8.38. @@ -614,10 +626,10 @@ $ java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dsbe.generate.ir=tru == 1.13.0 (2019-08-02) -* *[C#]* Add system property to allow squashing of namespace generation. https://github.com/aeron-io/simple-binary-encoding/pull/702[#702]. -* *[C{plus}{plus}]* Use `*[nodiscard]*` attribute where applicable. https://github.com/aeron-io/simple-binary-encoding/pull/700[#700]. -* *[C#]* Use ThrowHelper and simplify bounds checks to improve inlining. https://github.com/aeron-io/simple-binary-encoding/pull/695[#695]. -* *[Java]* Javadoc to `MetaAttribute` generation. +* **[C#]** Add system property to allow squashing of namespace generation. https://github.com/aeron-io/simple-binary-encoding/pull/702[#702]. +* **[C{plus}{plus}]** Use `**[nodiscard]**` attribute where applicable. https://github.com/aeron-io/simple-binary-encoding/pull/700[#700]. +* **[C#]** Use ThrowHelper and simplify bounds checks to improve inlining. https://github.com/aeron-io/simple-binary-encoding/pull/695[#695]. +* **[Java]** Javadoc to `MetaAttribute` generation. * Upgrade to Agrona 1.0.6. * Upgrade to javadoc-links 3.8.1. * Upgrade to Checkstyle 8.23. From fdea523263b140581a2d2d0421f263cb25eabc49 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:20:58 +0100 Subject: [PATCH 711/805] 1.37.0 released. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 7991f09416..bf50e910e6 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.37.0-SNAPSHOT +1.37.0 From 002af637b0b9a9e64ea82a50ac2cdf92363cb3d1 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Thu, 25 Dec 2025 23:21:08 +0100 Subject: [PATCH 712/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index bf50e910e6..860bd0396d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.37.0 +1.38.0-SNAPSHOT From b0882e7f58dfdd16af8bcd96c0f55620bdf4d4f7 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 6 Jan 2026 14:40:32 +0100 Subject: [PATCH 713/805] [Java] Ensure Java code generation for precedence checks always produces the same code without re-orderings. --- .../common/FieldPrecedenceModel.java | 31 +++++--- .../java/JavaGeneratorDeterminismTest.java | 79 +++++++++++++++++++ 2 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorDeterminismTest.java diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java index cad644fedf..e9c8dcc1f9 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/common/FieldPrecedenceModel.java @@ -45,12 +45,12 @@ public final class FieldPrecedenceModel private final CodecInteraction.CodecInteractionFactory interactionFactory = new CodecInteraction.CodecInteractionFactory(groupPathsByField, topLevelBlockFields); private final Map> transitionsByInteraction = new LinkedHashMap<>(); - private final Map> transitionsByState = new HashMap<>(); + private final Map> transitionsByState = new TreeMap<>(); private final TreeMap versionWrappedStates = new TreeMap<>(); private final State notWrappedState = allocateState("NOT_WRAPPED"); private final String generatedRepresentationClassName; private State encoderWrappedState; - private Set terminalEncoderStates; + private SortedSet terminalEncoderStates; private FieldPrecedenceModel(final String generatedRepresentationClassName) { @@ -135,9 +135,7 @@ public void forEachTerminalEncoderState(final Consumer consumer) */ public void forEachStateOrderedByStateNumber(final Consumer consumer) { - transitionsByState.keySet().stream() - .sorted(Comparator.comparingInt((s) -> s.number)) - .forEach(consumer); + transitionsByState.keySet().forEach(consumer); } /** @@ -273,7 +271,7 @@ private void findTransitions( // Last writer (highest version) wins when there are multiple versions encoderWrappedState = versionWrappedState; - terminalEncoderStates = transitionCollector.exitStates(); + terminalEncoderStates = new TreeSet<>(transitionCollector.exitStates()); }); } @@ -459,7 +457,7 @@ public void onVarData(final Token token) private final class TransitionCollector implements SchemaConsumer { private final String statePrefix; - private final HashSet currentStates; + private final Set currentStates; private final State blockState; private final Predicate filter; @@ -470,7 +468,7 @@ private TransitionCollector( final Predicate filter) { this.statePrefix = statePrefix; - this.currentStates = new HashSet<>(fromStates); + this.currentStates = new TreeSet<>(fromStates); this.blockState = blockState; this.filter = filter; @@ -585,7 +583,7 @@ private Set exitStates() /** * A state in which a codec may reside. */ - public static final class State + public static final class State implements Comparable { private final int number; private final String name; @@ -615,6 +613,19 @@ public String name() return name; } + /** + * {@inheritDoc}. + */ + public int compareTo(final State other) + { + final int result = Integer.compare(number, other.number); + if (0 != result) + { + return result; + } + return name.compareTo(other.name); + } + /** * {@inheritDoc} */ @@ -642,7 +653,7 @@ private TransitionGroup( final State to) { this.interaction = interaction; - this.from = new HashSet<>(from); + this.from = new TreeSet<>(from); this.to = to; } diff --git a/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorDeterminismTest.java b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorDeterminismTest.java new file mode 100644 index 0000000000..2f093c6ff1 --- /dev/null +++ b/sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/JavaGeneratorDeterminismTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2013-2025 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package uk.co.real_logic.sbe.generation.java; + +import org.agrona.DirectBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.generation.StringWriterOutputManager; +import org.junit.jupiter.api.Test; +import uk.co.real_logic.sbe.Tests; +import uk.co.real_logic.sbe.generation.common.PrecedenceChecks; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.xml.IrGenerator; +import uk.co.real_logic.sbe.xml.MessageSchema; +import uk.co.real_logic.sbe.xml.ParserOptions; + +import java.io.InputStream; +import java.util.Map; +import java.util.TreeMap; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static uk.co.real_logic.sbe.xml.XmlSchemaParser.parse; + +/** + * Tests that generated code is deterministic when precedence checks are enabled. + */ +class JavaGeneratorDeterminismTest +{ + private static final String BUFFER_NAME = MutableDirectBuffer.class.getName(); + private static final String READ_ONLY_BUFFER_NAME = DirectBuffer.class.getName(); + + @Test + void shouldGenerateDeterministicOutputWithPrecedenceChecks() throws Exception + { + final Map firstGeneration = generateWithPrecedenceChecks(); + final Map secondGeneration = generateWithPrecedenceChecks(); + + assertEquals(firstGeneration.keySet(), secondGeneration.keySet()); + + for (final String fileName : firstGeneration.keySet()) + { + final CharSequence firstSource = firstGeneration.get(fileName); + final CharSequence secondSource = secondGeneration.get(fileName); + assertEquals(firstSource, secondSource); + } + } + + private Map generateWithPrecedenceChecks() throws Exception + { + try (InputStream in = Tests.getLocalResource("field-order-check-schema.xml")) + { + final ParserOptions options = ParserOptions.builder().stopOnError(true).build(); + final MessageSchema schema = parse(in, options); + final IrGenerator irg = new IrGenerator(); + final Ir ir = irg.generate(schema); + final StringWriterOutputManager outputManager = new StringWriterOutputManager(); + outputManager.setPackageName(ir.applicableNamespace()); + final PrecedenceChecks.Context context = new PrecedenceChecks.Context() + .shouldGeneratePrecedenceChecks(true); + final PrecedenceChecks precedenceChecks = PrecedenceChecks.newInstance(context); + final JavaGenerator generator = new JavaGenerator( + ir, BUFFER_NAME, READ_ONLY_BUFFER_NAME, false, false, false, false, precedenceChecks, outputManager); + generator.generate(); + return new TreeMap<>(outputManager.getSources()); + } + } +} From ba8751caf0d4dc373e140b42abab53d9b3813f68 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:22:51 +0100 Subject: [PATCH 714/805] [Java] Update to `Shadow` 9.3.1. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d85c88eafd..57b225fb25 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ json = "20251224" junit = "6.0.1" mockito = "5.21.0" plexus = "3.3.0" -shadow = "9.3.0" +shadow = "9.3.1" versions = "0.53.0" [libraries] From 3fc0169a2fe24236f873f96830dbb1f8a7401dbf Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:23:04 +0100 Subject: [PATCH 715/805] [Java] Update to `JUnit` 6.0.2. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 57b225fb25..f5fc18e4e6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ httpcore = "4.4.14" jqwik = "1.9.3" jmh = "1.37" json = "20251224" -junit = "6.0.1" +junit = "6.0.2" mockito = "5.21.0" plexus = "3.3.0" shadow = "9.3.1" From c091c873bb932b775ae62550d0376968164afbb2 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Tue, 13 Jan 2026 12:24:45 +0100 Subject: [PATCH 716/805] [Doc] Update release notes. --- CHANGELOG.adoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 79db065ce0..897cda1814 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,10 @@ = Changelog +== 1.37.1 (2026-01-13) +* **[Java]** Ensure Java code generation for precedence checks always produces the same code without re-orderings. +* **[Java]** Upgrade to `Shadow` 9.3.1. +* **[Java]** Upgrade to `JUnit` 6.0.2. + == 1.37.0 (2025-12-25) * **[C]** Implement `--sanitise-build` support. From 2e78afe5addbc5f701e2d7f4528a8444bf25dd5b Mon Sep 17 00:00:00 2001 From: Dan Shearer Date: Tue, 13 Jan 2026 13:53:14 +0000 Subject: [PATCH 717/805] 1.37.1 release --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 860bd0396d..9cf86ad0ff 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.38.0-SNAPSHOT +1.37.1 From f8bdee5730959d41f41a28b2b02d90fca0beeac7 Mon Sep 17 00:00:00 2001 From: Dan Shearer Date: Tue, 13 Jan 2026 13:55:17 +0000 Subject: [PATCH 718/805] post release bump --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 9cf86ad0ff..860bd0396d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.37.1 +1.38.0-SNAPSHOT From d8232557dff8ca3002500df7fc72e2ac8a945f76 Mon Sep 17 00:00:00 2001 From: Dmytro Vyazelenko <696855+vyazelenko@users.noreply.github.com> Date: Mon, 19 Jan 2026 09:58:23 +0100 Subject: [PATCH 719/805] [Java] Upgrade to `Gradle` 9.3.0. --- gradle/wrapper/gradle-wrapper.jar | Bin 45633 -> 46175 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f8e1ee3125fe0768e9a76ee977ac089eb657005e..61285a659d17295f1de7c53e24fdf13ad755c379 100644 GIT binary patch delta 37058 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 NNswbwE82Y!{{uvZmpcFe delta 36446 zcmX6^V`C&-vs}csZQHhO+qRPlC+5U9H`>^?ZJQfwgS*drznnkN)qSd~s&`I*^d0`F zvqc0b{9s1P{qci@fbDj_o)SGZcGOth)FdL8OL)J_BV5J0Bg-Q#0m~a{rympvN!T0C zf*?`EI!3lL^X~80-SxBgn+G;u?F#5HaR;_dDD93ojdlBorJ;?Za5f{_E|uh#06r>^ zY+5|x5bua2nd4?pEqL{ATr-RDb>V^WUGMavPGn{?6EUfrVFqeUqtZa!Iee#Qll5`Z7ED@F=0&DnLuUlzG z21;z=*DT?UdaTs!;LD}w3u8Q@*l2p|?=Gf$}v71vIS2OcFN#*+Vg$V%{n^RTp1=nrWz$&^+rv-HGl8O`D z&J4~UF)9^WbknNUst(V88s$JJ4ml^5)M%*=S|VJ)5>*dFE(T}iZa!8{)oEK3L+=g9 zVWg@xdP($nI8`RO^*DoB{F;oy{7ebsF$cER5_M?n>N7-I;z_2)iD&P=!&C#UjcxQw z$^t-|@b3_qG~-qrv_`%GI=(%JE{aZ=kV*WmC8X4r&vt3GNE=A=vBMf!a%cJ0N>eZ{ zxUrh3%oD>7wP8%?cK3LQmQ^jJ^joB9(6SOcajnlHwx(^-h zm?aY2KWq7tXvqs#bSAfwPiy%a6{FjVKO(V06@kCl1bq zEgQX9a(z|bm-rAH?Y+I@q}ijgG?b*kS>9Btgz@Q(j(qbTyj^id40Bt@x39wW`4sSr zt5Zxdv7qO8&erf~%H0r*Oo}ivAe_m&nALj{lc|p7ZH&SXd+bTc0!h@3L8&p^Aaqn9 zciN$gum8rgxH*o=C!&6))g$8K>i~Bo-K1QBkaXq-;XwP&0z1IO;SqM&#qieXeqij6 z;&B@7N0epS&mQZ%5d#>?J)7VbxpuAT3R?Ze#k zs6$;!M3+;Qh>u8oz0c-U)*8hpUbrBJ^BuwE%_A*qD6uAmxWy%%H&DeVT%#|7{8z=p0SQ3PQj``SJ zCOR{SfrbsZfsB*2D>64ScPlJK6S!M038ub;r&nWnC2pGY+z?|P)vXhHgNIhPC|%_a z%aluo0WYGjzN@FcM`HuJTNl~(?=$Sc=~kA6M;(IE-JDLbWu_^jw(^4JrW4&_Fy zaZC}&GxUK=dKp?Ubk*=bT!{<13hMm$_N^I|PlgZrBqj$*SC9dk)a?~FG|&PV%&=m- z9j#m3b)Be#$SCZM*pP-HemT<6t1pm*$y7UJ%kJ-|jd~a@G=9cEx&nk~>zQM_FE@%m z%H2miDn$y?8Rg9=1Fl`C`DeIK2)_RA7}kE5JAfEipj5oZ2vDZg+d=bC&ryAZXRkVs zTVj&C#*M4iR!|2ZUBjq4DbAYY_+}blzLl;t^0_;NWaW-l#%5aF0xd!XO3UtF-|3vU z`g#AxmRh6iF12|?5`^iq+7asw)F8K$>%~8jbTVr}t zj~4ipd4oOt1lg|RP3M+3?*^rE1E0jwJv>_PEa9Etlv}u8dSSrHUE-u9h365> zh~HpnZz?6X`x;klw<=+pnf)@xCX-{0X>>`lt5}h9Nr-7D$!Om#q2Oh9?S0WV#5nbu zkEr8X@_&MQMT~O{!;tO6i(;{0o^g7EVoW>*$5ws$Br7^OmW1gXy`c*L;&J(mq)_hr z7XnZiC$#$G;Udj(Uf6Q13&2kohN4d#D#cHU|3i%J686=Ow0XaY*Cr*73Mg>xzRMgd-Ra^;(#gGxi+9Osx$W+ zdtcw1K*BTjTDq}oNUpU+j1<<9IVKcM1{?mnUYTvo!|X+LV`D*@8eCEzRH6!+eQr5x zW4i(#292HQ->?5VZou%CUFGMuZy-oe0husJ5r-ZCkqSo#5*vk2vf{|XrRy+)Qvbn* z&SYa2#D;V_tcLG_$Yktc$;t{VY-{4UUfH!qyS!{rSix>zbd)q&Tb=h-u(JWk|5z35 zU8eD$zGSd7QWfc$%)ZZkzUy3Z{k$9d3jmu976-4@@AfNwT-%Kx$U~|StE0yvga?K= z(`EoTA)4kyHTooMn5-RY+fzWwlB{`XEc{pEcJo=mOwV z7ciKK8^uBme0PDg^)yyd+a7!q!L*qgVkqS z1sZ>xko}h4nuL<)Ct(#(H77D05dZ-!LDBpcTPUDQUG{BhpPldA$D z;Iocs%8g;0$CrdPN>k1oM_8m2UC`Z@%t@`zE9y)2pw2ln<9dCVRh3747F{(U%NFE( z)PwdMR6Vmj;ECDP@(GN=bu|#e=|}+ug^9vAF*yPidjVsMp+zv)+VJ{A%*Wei@$Cl& zXaqN|W_+Vvxl(mzF#OkqZAAMHz8~E1BXbm@>(}5B1jX{iw)day@IcXlGUxso zC4hwRKo0pmHJ3LvgA4O{=Ts3L8~PRu50C2iM7fTIAU~*|s_m#!8_UIsNRfcva&t(R zEllPL-UR#2-bB&q#9^0gGr7^E#f(1(;&&fniGjb4=5MG7K#6=!G{D!&+wtEc@eE?< zco*G2bA|d*6o|~*zH8wL{JkafaJ|HUqA6!cZ7D05sKGJDK0RY|lm$;L zv`)Clv4ak|Nx0LX^N%Ig>i7j#vF+85h_2~OQn zn8m(~zvErL&)v97SB(HMj}of;JZYW4eeV}GK$8Y~f=W(>oTlv%W#=x@TtU>v(H#V)f+n%pHFfSQ zCIOzuwv!DmG?HZ_wR?orW2Zgaj6?(s*z}5-ku!!b}wM&Ofo8TDWxNO(Qv== z&{tJ>DBa$Ce&A9Ie&x6G`%>oot;wsc;C3R_xVGT-$1vJfDL>%s1ES~g!1z6`zD0aK z(~N5;#dD6=Yo_X(w9LZ^h%-z6G@I{4|LEeFHYM`VFG{h_4Du2Ab$65IqKXlOhukbF zjLt}w;&{SR^8!%Xt&|Z!?Gz-0-p*45`!hosHZlffg4@H{W?Slp{S_`+e}5v2S?7w( zUY`qo2|cy94dlLroiPTOAwb&ryK+4+>{|20kaEAKQR(-8wawB!&5+y?WbTN`4)Ez% zDxpVBsf_XQ08egbW5wNuMw@C!o+0`0qEmqom4w!K|{KmKAOdrm30Ay*3VA#BVy#L9p|)sbtW@nJ=ZtF~rJ za&>-VXNK-0=jPLu@@gkL*AK%S?@|d({l@+gPI#O z3q}q}boAWP*R*y_YbIru2#DzEL(Dvtd*A(U!BUj9oTU@C0{LF^`{$ly=el0c814YR zl@A!b)b)H7-YVESyK0U$Hy38$R~KgFZZzN%tmm@n)zXjtft9=wnjK+4glnLk+{*t0 z0a%v_=M5^i;-7Hxo~bj9_36^6+9Lh6gLTL2KSC@ydo)bX17p3W0=1Kh;r$#+s6=M8PmMFu&o%(Y}V4*?HEPbOp0~w)vey-x9uUeQS=03H?rq3d^z_Z;YP_nsh4R31ET_^tqS17VZ^=sT%BYl;!p7bB=T6q@E&b)qRYUj?;s7kP z*rPi#1=K%=5y9HQt$f9~5H!b1qx*Ez%yQm$jITM!ccedZe`z%xG@$7fzuu4u1AOD4 ztOXp-zmPwi^w87l6Nbq3l${AM3rTF@xD_3|TwXS8izrA+1io%$h zxt6R{IC80fM!j2#&A@eqfi(&xC_)t{!&*Y5e_>syTgijW>p9R#zt4b7qAu0WVDEnF z(Q87qK2gu<4XXUel4oN@{>2w45Q?V!_A{~(6^goxXEbK$&Q$6H;y;v`i2tkvWs$i9 zFj7-ps5!qYJA>O>r@5$(i%XGPN!1|{CB22qwG8~O>mYB?4gIIW<@FKTw321Md=p5% zwSyfmk@f_w<^1tG;Z5Vd|2q?J_>H2z_vZD`jQ>M<%GKYH3*22|$#b!|67%Zk!hWu{ z8(W7KQmCvk^fe62wTtG0XIS^2R6ETaz}j9aZPIyA!P>hJ>jVx6bZ~I6Fqm>i`<0Vq zj=X#AVjt7o&nzbiWz7Ro5H8Y=7Jc(DIw++>8zK6rN{S`wRiu^F?q#nNY+Okdn@sH8 zheEx@q8cr}ajak*mb~2R7KW$Cf8#psw|j@OcGF6U28Nx)p5y4n#>95^MGbcj7^e?n z>2i{{NG<5wVBhMSqq*eW^LxrZOW)=j$kMX+xw^UaL=K%p6XDmv3a&RNjL4^l1D}J! zLB5m6hqLDpoQ9=Q^GN|RyA5ePy$~yEZ!)Xk<^mWRZlB>~?D}GDNh2jTNqaWXz`Mli z+a&LIC7cMij2{Z}bTr+5i=W5<-qqP}GtmtN5p9-*s^8Gzm>MHU74Kr$WSX7$(qO7W z8N5qV#-+yMHRV>aVugl4NCc({1w}BzeX783jA#z-7VJHgZt*;*!f>}txyCOJ7M?W9 z3B^oRwpkNZYgcy1SMyIg7Ot+={1daj^!(It&SLJ~xd{j*T)}EkI1-Kkw(g{$U}vC& zs8=+GXT^A&*1Jxsc>);4Enf_Dr_rnp2XBL@GA-mWjT9@~R>s&lDrTP?)zH4x=Q z$}Xqyk$1Rxnz`u_b)n6eMc?T9La;<&zOw8K>6HT{LP@?NIx561k*}w)%lIF>u>}r? zmj6ixGT{Ff7(5Upl@ee9iOOEF>lYUp`h>_RF}PYqtXh*wvKrV?@6=k3om}U3%2jMa z<(=pYW;V@ZFXCx@C67YLJZ>doK<=|euI2H{pFG5Gvq39x*A9-1?K_>&h$rPFe->fO zwu3NBr76f-NYn$8B&0eeA~%U5SsmV;fP0&Vk+%wEdN_PHzgGc@UdPcTl4T1HEj!9J z*8>c8W>ISid+_fq7 zcUvl1H4n3|hE@Y;)bhvkSKsGxGz$*5AJr1$n}2rJ6S__Amam-)t_=&qXV1Y^6wdPr zn`8UgJ*{lT{L<}R1Mn`JHs-Zycg#a+PQ;h9fUK;whY09%`$txgu?hTk;-%f0Z&!hbrq|BwF_EEkm=#79E_a6}PC@w2 zT3$aB8g_rTDjdGqJ3JJ>s9xS1PIT&6FSU4RthDfob6n$Va z&tVP&l$o4<*f)$^38}H~EaG2ZX#AS9U3&@M>XQ$VMvTmcO z9}$62i+<6#60R=s9IAg}fFDj+dxn@tQl!^qI?ZLfC_U8IU4-ALbo7lI*t$lb=09OU za4@wCvmSqRFl+wR%lLm$9+BswSBlyEi9%Va zDF$Qstq*L03y&J^SnG7Wao63Y-O<1M5Jo+&z?(OhYhX#fg^BB&1=6o|y< zi&A0+l6wAeBuJ=Zu2L*e5S*+^Ja|4fBYN<0g-ylGTr(a-JGHrNHeEu3ftTGK{v)BpoLI z){J6JSrpB!7V0ec?Cju6NkGMum#7iHIlT7fP379_eNQICLE%L{B_mutHQM z5#<8IMMy&0ITA6k31l9AP#uYGxjr}OC?yjnZT`xfG$O|jnaNszvSew+HxCpzjmj%U1IniG zoeF&>D%;2EYZJMx^qecg+Ixt1mkN9cRvmoX$88(O&BOo*fTTv_n~F=mNammbKW>P3 z78k*wKqg=_O^S4Cq5M+wn+2uh1&lbX8TQ)yFzFF zLPT-w@%)?aQqt8k8iy2dpY=r)6dWn&_l1Pz?F_JdE!XCotC!jB?ow*M6`Oe&d&og^P8Wz_(~g%ABiPj2dy^w zI*lfi8ewt9-v}-PzK0n8cF+TCppcP%D{0d$)PbwH`@DnUd6I^?YxiGQKQ*=ddHvJ% z=tK5F){K0oRGer=y!=`}Ku~RSD#&m!l@l#VEk_?yl!b&dr7XcMxH_d(xr!I4%9VD6G20A(9X)m$%>Q7V2OfnWE<>^EFIO zvjbw1xtVX0;Xg?v-R9_bwO*xD4DOE38TO`~>~prF;+Lo((GapvVO`VG;LAM)waxx@ zhpClgW_rvwI3GG<;VY$+K@OAD;p{meS#99uv*p^k2!ddt0hmVatrbavej@HS=w)C6 zaR_5*U2m^jO*ASqr}3xQRM1t?&00bkTIsFoC$ExKFvdIet5$FOxN9~Fc@5}GXgV|J z`Qko5x3{+&LYp8so@SQZa^O5N$`lsVu*j#7`sZU%v@t`?7qra?PtPu}r7BE_KbgRW zkr>k1Wsx=60s2g%rRp+ibT#KB)u%cN+S{0!Me?LWMJ3`I|s0Q)viU!(=*$s zQKZI#qOJiZHe`8OW9Gx*mJ}?isskWy;A%Q#4R>a4vzRnp31#a6)C5)`ep#!0b`8`M z`qXhlyAt-QJy6tQslmX2f$JI`sw4IUr)A=x^PI&ApwEfvh;-IqoJA7`gT$Q+G=(d0b#u?#on4l1;Nhkv9(IyLZ?=GD zZ`kwe+f$f&itE7d^Rz2t85lo7%H}gHHR#okzpWX(2c*j%e7ZC z-Ayn*9XP-~K!830C)vV#WI32nB?iM^(`p@MO%uBCC5`vR2JN35)I2~x(p|!Rgs+Fo zfV?vDLM8|94je3Z3a=b6Io*hxN^Mg|dbaHcD2d@q4}Zv$jcLQRC&4Yv`Qel8y&p4s zfMIS08uXF_UzVLo+Zkl^X0%Fl#IdGtl1TWR$@DDJr(Fh^@H46^FQe%_8#nM-TFf2n zw9q`QPABf#Q(0E3%oVhS*{eoj^uuY<#ItNvuBF_)YBS<;k!qBnPUNEBO}TU>YtDE8 zbE~mYyEFpsb~&B zWKksvM&?v?Q!N%c7XwNp_3#2lV}m9jv%pR5jO0oEBwq3kl>85y?pkQ^j=(kCmU`YGw{|xGGwk2+~sPMn*J0iT9%i9YX_NRcBmrKnI=k|TN zoM@T(e41ti_L;6Ok9^jMt=7s6^CKf=!v}M8f=~fR-%S%#CB`Oia4Uzge*iP$kL1a#ZnY#- zOAJSOMAFstC#HrKhi}$I}Eet0?VQ3fSVxaZT_4nDZ|r?<(!6jsD3)@Pj~0#mTo9(G9iKNxurA?c!6%8(kLp zBW01MP|KCz%Bm-KplgvmN&J?nQ*7MU{XUu>3)u^{A3Ya&cFG)L4*-+E&9eygME4g} zdMGRl0}L%TfB!i=W2gF=d}S3pAM|(Zv@l7=x6mzghN;tX~6wT*R>-}-8L%YetL?v!ExrO`cYyicx8oFA*{YxP%r=W!j`8nAGFe^>XFAhbtW1f3&^BrvbR^}=cR}|Fa`g$9^TEF? z8sbZzD;Nq{9&DL8h(2``KC8&kUQW^Jm1xn8Xjp|s)!I6!D}W>=c4#v3TzCkM{XYBs z1pCFZnzorHBZEz0nbyrm6Kq-*=J;cyN{-*ILB_NwR=Ks6HQrER(;@NDUeiplFz#l} z@HdcO+exTm&$mLuB+b-%=#T><8@?}qn4;#^2%EuK4m#_J$e98tg-a$d+;;Jt8CsnW z0u4e7uh`keGC+_`W$$PmJIX9PZ^9Axj|BW@BFfP%h^_`J4|At-wkX=hDr_HBjt~6V z%r;uD?}YB6g!n`JF0hfC5YD|<>jUH&nw<_~44 zBV3rD2tUpB(C)~SAaM^1SQucrrS6tUV<`F=nWt~)F#yu(W?o@uEEe-)rk$>#-YlyT z8t^ndVTJ6`L)_2A5DcxPl3MFNI#>k%6JuD71|agSEPK zwGdypG$Z1cENa6xJ|9?|o3M<|AY$wa8 z^85Lrh+VDk31Q<%!NQzdKCU0D(1%@}JL6QRJ6Ws{ICT6xHHJ(50Z&}3&JuKpKx zPJyNQO`~q8wr7~?r(eW-eEstR^r=A|%=@7{5e9xqYd%8j=l|42Bf4R<5U_9GRG|L1 z%@6X50G1k?YzW)k6T`}}LYksqgpm4T!NrB0xG7rBP7nL!RFLWk_YGSUf`bWnB_mgY zc{$VWGhHo@FaCa@3L(<|U_7{0zd76bL@GC(+Wwrj!^Yi4V3D%g>`^ ziCT9#N$rKuqh1ie6*o6t9oMIgZmKTC8PslE0j^z_!2lDmYciqvdQC z?qb7t49g)oT{*qcR)+$b#9-$u+SVdGs+nNRtf+tM6B8)}7sq>&hgIA%$s^^81fKN| zdo(?mXlFaqNY89DhChe4_`||Nyn|j77s<7QmOd95VM{(xO%F{C*Y*>BO46tg)eD)M zYTTCw@nD=g%_5z?gFNfhMp$s*)s(A@5$J=~R09}wW)Z5@_7o&K+gf#7Kl z+TwmUrkdFcx1!bW$|%(VCe-Oqqjn3Skvc3>*T)Ty+vH%Tjci}iP^B9oyh~|A11qKDpyte94^g`x+6c>Lg)2t z9)17q(U6`t66zS;qgCC-m47LQu_gFs23O!L5=t^9D@@W~>YC?{ev=bCisM8C@9D}N z!tEr+{q?>wt}GD+(7$OI_Z$d{D9;ojNLufmScAYtWXj4PlOnM*sZM2FuA=aS6Ob#oM#)U<|t;(yP-s(ft7s)Se$UC6Cp56Fcw6vF!0BV zFmSN{X^GugA_q~6ZT^p4K>A~?{?baGa{`tmBJoI*di|#2r@fNb@z^0a`6xTb}x;%a`_4f zbM>64HQuyO-Ar}g8-)EOFmeQt?t`kC_eDDzD?)`Mlh=s{akvnzd4)EnI^mj!f@{#+ z$$owRk0rI;!xN(X3$(QUZ}&5j{;y#WKngX?0CVL&hXo-d{|z#C&~Rgc(zQU7vVIk@ zNP)Oic`zz^aG}e#9mO=qMN^Zlq*_D(lwfZgB^YEJ-V2qH9lEm-Vgv7=E^pS%kJpP0 z&u^xDNH1>w9~O7SnKDgeywP!_?C}UBDVAXzzZctL8~h|NL7>eN>GQ)$r9yk@X&KODhKyWIs$B{npjPhav69-W6wMnz zQ7tzHZUt*+IG!RGV|G+^Mqa_v+ur*IK(%*&Rm*Q`0nCj+wDW_VLc_6mvzMrXe0}t- zX{J(oueT?L#ZII}M=J_IAFvo-kdUpUv&!!4BOL8ntNlVoCp$=d4Cs%kKQEyg6}{De z?0Jv%I8#KoG(kh0-mpDthm?mOc;z*G-wFOReFMwkh$D>YAKLOzr0Zk*@^kNop7t8X zPvY+ue26_pSnEiwK1Qh4->L6N-%a6~Gc~FO|0~|qGcj@YziCJD|JpFFxGn&3IjvA% z!RsYe}l`1P~1J3n{)W+T1nj_9>RAVfbB3Cf&~RsHa5~kegw=D55rq0Vc!}nS_G^X z-7w)kusRmex=Wxl#=dvU`2*Oem8;aNmdYmCA6fl9^VxrDE55~Z7jvmFCn`G+o+ii* zH(}M*3ToH>#mDg>v>*nHnldvI@hM@0UPMI&PfWy@@9U+(FJDcHEJ4`D&L}lAsGP)E zA~=lwgWZ)en4Lk50P`an(uL|L{Q;HNf{k1dOT5utr>?CTmPGJ{vq9I_p zI7GiWE$s;gljYa-<6c*Og3(I1)X`iQ710+5;V$0aI5n-8Kh7XOkb1jIb+Sok15we* zI<$mQi$}cTF`uQs33U^1@7npu>zDq~*N;I@jD|^LLhek<*1(GY{b(2S%D(IWYCQ7) zHMW%$0Ps7a3M2W;3QS{(?uU}i5}JI6$-I|9$z}Ax3;Z4?W3q( ziQge`a1y9qzQ0oqzWn$>mWe-=^}OA=_3?Rd!TC*eQ}e~i{n5t_IWJMbk~cEmlt0$D zo*{bt5KYb+RG3}28|O+f!;+n-_z?5hW{4&r0LWFjZo|~nR#8exUpM8#gM)|zhBUmK(iav|2lF0vVJxWBq;66 z>;d8;0}6pTG>5KJ#1R+w4bF;)CgRDd4pEJ&kn^nJ*K%tAY5%)Nq<%Dy3#p*D`wes< zO#}JtxTRD5X#~QP;R1|d-`~5sx>`o!su})q9I25NTHQNRWkb)s@)7}yvqW9T6qc%o zs-4cwtxlz%;|#z9`*(;DfS11i`v3-*Nw|v6yPHZ&qx=2OqnJ|Lp`&-rOtop6Sk{Qc zgU_e@?nV&Q01#E8A2le7P1Gag*?Z_HS6^Fu2g#z?B+$6`(H@`+1_z350ka~DW(NvK z>locfpm2Y2?1x*3NaA0D7yfy1eqoeUN;DYkJx`wD9&s(4!H&b&1}Qnm601|yoMB05 zghVOhhm4x#8_9(OtxXlO=u)-76lal?R zQr&=4sYO<83F)jbLX5X8MKsUbCFU4r9Pz-+S$nt5-WF+GEUb8R0fLhw0L;?Gvk~`d zRXkpqUJBO7IycAutgx5klOZEak?tfB9QgLptN1#(1^H6*0E@sUOj~7MU9s`H@ySKO z`KQ?7vVV2RO~cjEO$T7@_vPScLuBd z4!5#;-gNPERB@{-oLG7Xpq1OYVqUkL(vv`aROWFrL|W;JGBVd6j7DB>>BL<>p(Sqz zlCXZ>BO&Jxde}*LPOs4N3W|Xt&mr(u=z2-&H9lWOrg6<&#XVfOlJ`k@`=1M`L+zRf z`Y!JX5Qm|GGMGho*R`sO&{0Az_as7M7#@aXwF~z!?$EVtA!5E0^}Cs~WY;Mq8>W>1 zXE$myl+u&U7k99p_?=|`$$qr}e0;va_YzTHZ`;{TmKvNzZ|Wf{Xb>(>k#`w#Zi&qO zZgXr?=-jmcUn{8te+J{e-;B=kHm>n12`)nfF#fwg`0!!IWV|uiT%Ts<;$mWA64T09 zk2a)Pq~Gl zXUG8Y*+w5`9u5^IjCEXRns)GQ@RDw&U6_&!GUDy9wEd9*e}u!I@Jpe@-=nnki-ki5 zIBwmG2a!;N9HHY2++A=D@925ChoU*LaU8Ydj^ddbaoM|1QGp4_{)NI}r6R)7K&H&h z*+30oP4q&JRi>`9!x*3~?b{@COYodaa&!ot)59NO zT-w0adcmd7%Z^($GGI56xZoJ0GMrh{E;P18F!5yvuMvFOPYQ?{rbe|fkv?@m68NKt z>91eBU9EI-J(brr(gW;zj-`LSLM${UWcrW>67g|-WuQYAg;hGHX735Hsar)sk6UiJ z6U@}FJfdC5{;A7MKxgy;sRc4bteJ*~xSBr|SVR8s_Ev}p*Ti9EXCkT#t^)q7Heq^4N9bv|5 zzZFns^NMma_Zb=!`_I+%|whQ!T#BNEc1w(HvuB_fylfDDKj=uxd^puqK zkc5TAovWy1Z0GU}?&!XlSng21kKMo@{f16q4$n76M+6yIrsOPjY>y0n_{~ z@m+3TA>TAunKrvEXHrwEE+8Kk9UMw8bT3px9;Y6uY106lzuRrKEZ8hdxNq%qkJ<;U zU8Fn1yHBXUdxHye;IVS9F4O#E;~?9AY%O1HsKQWd9WjC z%V3t9wjY>8@=V`AxDtO)U9HrTWt$4Ws8#O6`T<>KRQ4i4I)Sawa4E-UdT~Y<|#)bY^?iZ||K@YjmBbZ15FF*CwcY=g1EwrS9y7_d+JQ(2fVtI(Y2wB5|Y z;hD`a;M_(HHeE}hwC%j+BT$a{+acpRhnPW)$Mhkm2ph!>{+cO!mE4}LRf1!?`owz9 z57a@L+SM^L>Rh#}qQ--zprB3RJtRM=GP|f%uy+a&+qi>yve?4DOJ12Wp@B-2oo1CA z=n5<-b$(qYQs^)IhGD`yAid;9%M~VkRB9Vf&V{YDqSc07zaGqmUIvaddU~@qPmq10;bIjOeoDDW%Ab=VTXu}UhEasG``&tO%H0{&jw0B;E_$2P#{OjY<~-aB%G)7L=Y(;8D3zoe{ZEs^e>3t!GH zxN?vLt;}FJD6fi4ZDFsGh^M8-XwU}9e-s8hpupkzCp>QeH5B372 zwCFq|Iavp7fE6T<$gxh69!u!X9G(&h!}<92t9CncWXFXs-1bCzcXJLNca%eEypb_m zw7;DK=g?+gIcY~(vVGM0Qh$gOjnE#;%M`})s2?;Q>*yG?;MXJ)pnC&H>*JR=&2&lM zgi_Pse*df!0=NH6xHvZTMt%qg-=G1&EZ9WQX_KOb#Zd8EYDi~STC)JFj*ZbYRfo{u za>n6nj3e-2uUNlRozK{oGq6vWZ*6lM;Py6o;j1@Ok4z)^|I{}{@Ra2iLoN@zYAjLN z!@Vv2Rx^+#U689#yMRy1&X0+eI@9Y|!LD3e7k;KEY&TIC|O={*lXTlxe?A>6? z`4mN_%8OTDfOVj?#>i}eWNHVyH+Da>99@J$m`{iNxFOnHI=9~ib(>yoQ|@(pHQ+Mr z4>GJHy5Nad1)1F+Cdg`{?TeE6zgX`qtu)s}SuZKz=i*ox>H|<)n1q8l-y8Qt;a2Q* zJ4(umEJ4eEW=q$PySokKeRQ$_*EUmyyjlzLQ%v}|h4aNFrJb}lc?`r7q{Q|hxAN4| zOe@@<;Pn)xkK;Ac5!?{?a

      7tC7>U!@*Y>ktUh~^HLQztiG@$Zw6=)_k#hPU1+)xIanu%l0g zhtq7m08uTk$H{p%6)lRt1I~q+$g;Q0(@2Be0YA2Bwsg0S0BsBhWo(XRkzC-IP7K{Z z#n3dx8UtKJy4y!{A8YV6&oV@TUn(g6H`w1bckNf2)sm7{fejYmd8!2SvKfJYr(Wq= zf+HMYavQle_ld^;I16KyHqpgB4FG^d?G6&K0Ohl$g7PAf zBzX2XK}+xUSJ$)a9G)a!mG@K%CHxDI$s*5=H zim9)|2iES&w36E>OJ70VTIbiKVas2&n-geMv zL~sf-I~_KH7iBELeMK{u+<)hMfMVC1Q)xy6EYpQb`mc3fbQ}9(Do?_#`+RY@Xr0KrPHi;tb ze1Q<(!Ic@>y@$_J^|fbQ3Yq-SO1w*+%S^~QgJ%3241LQP-iCg*O*k>o0Q%u_WeC8J zjjk9fK`jQlQj{#DXmazhL(b+|L=nxdL+3xu-^cFA(y;dvDF!i+##|D{>V57WUcHu| z=mivL2NuM+@y2@$G%5<{p4veX6Tv!>R9;UipPGZIocvczH)1o)0brJ3D0x3c24OwpInx;MbH+r(3UGeh?;YRKg&VJvS#Tr$`G zJQ8s4Ts5(7&lAjVTFHSYD^*QtdPXToga2-~+0(`OhG)6mF97GKsp=En7RSBLm-a|y zs*aq7$pyjpKOWa&Cl(yd{Xy`{ndyU%vCHf$JA&nOSOS!HOR5GG+t(XVPD6PasuHr; zQv4OS^PxbR`W4a*SzGBl-eIs)?}J{Gu3knr812Le*1CaTDY7<-gYF$8#dPVQWjNId zLd-O}=`C}1WuDhEbK;AxZI^l580-d>*-i`L=GCe_5O4ZKd@5<_NQ^8@&>wAQOjUS+ z^Gye)oX7m|LA@M#_-v^8aTlNWW0W72h*`tb2*9}6%LvTM7OkMIlD9v&-FpgkOzT!S5ZG@|Cgrzt|qlTSPEbDG(Om8^DJNt=;XI~#$`13R-Yzf`) zVqrKN1iaNd;Qxq7{(ezQJ_?3P4iriQ!-7Q456GJN>_B=-1!tNjZ)=*52Zs1kw%4gd ziu!d4L+8k&yg6wqCpXTqY!E;J#|%bvt&ff}V>E+E=Q0fJ&AW(ut7P(Ww>PZfatk-w z6La(Q-!0`+?eqRi#7_JfkEw@28f_gqH{74*-iX|c=oA1eJlwcP)`?1@&}1B(nD3p< zGzzZMGnEn|N+Jq1NKpZSPPJDKE5BCZc8UjWW)&dgfj3wtqk>_B(tf6s_3amgLn!I> zc`tsSq_2(uU4tRvwTM*Hz~vEsqaFgbyE=&@)V3FZf~t+c+Bw)uW}mi*0YM_gZ(7Yr z;UHjBbEte;w%cEwOtsXh%|GsU&~ir|BJoD0@nN{&X=+VcpjurbYCV)yN&|DU8GZ5C zT1@nV`qUPMe|bwfyv1?l1|ha1!atvbN^6Vj9;!wQz{BH zG1@SXH@tjb_YZ{S^mjN|emopFv2AI*EWh^T9FlL%j$A(abJL7od)MXUZFV8*nt3-S zMphZXH#Vxuzy|wu5|hfi4vjEQ;e{tyW&twBTP6BDgRr6hqUI#F(W`pK=*EPd z!>JrlqvGv(AIK6&zS)b90sf@+5E~ZZH8QF!+M9YdT+*{!zNjJtJ{W;c#d$MB5U_dn zybx|!p7pr~%lw*CZo>E=*N|q288d$^%=GTO(VW?TykAX7FECoW30ObG{;E*%fpKgg zos^+gP#(5bR7(SfWHD#y;?8pL%e=?yeQrSHwplh)+eVa2KbKXP1)!}@W7&$!m3Kcy zcnFffQtd#^#xgcyV4<4J^k-!$uYVw!`i=BL#KL}W>yVO0W|Du^>!`+Ktj|8-N(0@7 zNfH=jF_ymV3K@;i)cEho&^R`Vo?WJx_-G_UQ1MvY^hxYE^CtY3W2`YZ4i>|%ebFl0 z#NWzs)d-_qUTThmo{mM+*h=E59S#K7o>h!VLRaZ`;TW*U|v@a3T z`pqoOCLl&I6;f#lH=rSrmsM|R!I~ZZO>MdkS=p|F5IKewOfa*z3qxX+(cv6?TsEhBD^HK$l}Bpt^r1pGzWyBKti*8Z$*u*Kf)=eKaVy(mQHfoA-j z^fMJ<&n#A`dYxt`Uu7hjV+89trJrpGpkpvxa>Eq;Z4h&@B&8l7vZ3IS0I1^#N>(+W=#u1&Ev}XriaYIg_adw7_ojYR= zj?K9DAloDEL?<<3!&C^ix2+J#|W!33!x7U^$sW%P++rC^`&sd{+_k zetT1u=gnL9Xn;YKDW<3yY!+YbTYFvVhzlliM=@cODr7HeWowEIJH+%GRd3znbw1K)JmH<76g*aMABHZD7egd}R!QiN}9vV39funGz~Z4kgm>%et(iEg$gV8sKPi%jwG=(@5Qi zkbqA*F{Pa9tfxl0l;&!Fdam5C6MihWEutwMp?d3v7>SkoOCvhk02#YTA(+TABEiem zDATfeG8;3K_6G=k+<#v5FdfeiNb7>m&qkH6-c13BC%ij7NA2IV7Y>*(HFwKSs-mIE zI#Us>PKq)oQ9%G<^I^_Z<%6X1XHI9&b^?sX%^pmpN}H?}A#6<_LEYVzc`>3;&Ts`-TW8UZaRQU5b7x~)mH_P1j_1{77-^Xt*ANj`b%fHjx z89s>J_JDFldpx6lF3~4IY;q{xV=#Bw8k$AQGR4DIkgmx&$N^0^*tx(}*kgiKg(cab zr{$JD9%hP~m$#x)qORkZLGx+oA|NdY+5S=8K6@kQVBejNak=S67h|eD&>kpQi`#BA z84NV;$%P?M6xtXQtOJq^qwDt6YE#6iKymGPuOgc#ciS_ZTIl2F=PoZzLZ4<$Q)@D9(tUkm^Kab}Kfb3TG%s&u7{-J^XZL$Aro_Hf7CtmiFP$FqV3`hJv^|tq9<&>P*GwuIk?VY+r3%4!Hux;+JZQHhO+qP}n zwz;XwN1TL6==jxx-OZuhH!)bOVA&*SyILZmVsqDy%l@g_=q#nXOM2>8ODp6qg>{^el#w^m(wn+S1=mN~*hEoB zH!hjd^!msGz7(^&$1~jJ5!B`39mF#=?nA$A947np;QO7@%gkNBA1QHab?Uj~?n)0w z!6mZh&ZLr7IkuZ@TE*N@OW^8N9~@JlsLJ`F1y0Kl_@ZJK<9=|%DtmP!zm|CE9dE4v zd;Ca!L50L$dk@1b?3U8HNJ|u0`k{ZdIsPu+JRHs&Nwv}c#OPo+0YlJolYUI73pH^# zOZ-ceLIT@Mf#68C<8dngK$P69=e7_(MK^u5~za!0zJj(1x$*EmsxHQG;qkJJ) zoa|dNE79X)%PI$3mN<@Ub?lbDp7OQrP+VJpypw|7?hFh*(eb16b|SPGPXEQ5(5GjE zMW2x3=l)q!c}IJsh;O-*yVUFRWc|Kle2Sgx^L@eup{~R#XHs3`k*ypcWMTY1d};s8 zK$W0#YQU}X)JT0>!q#_r-cfbY7?wLFJ|ncb6a>Q3 z!jAkDEopx382G7h)_sUlzSh3NKaS)0~HuG~MuYBR9QJNdxvYtP@SrZ(7PS;U?D)r#yO^lDu`G#1Fy7JUt;sxPAM8dBwI zGKDST4sPoC1VztxIjr)t~L-9a;e}YYu%2Q*1oIp*68+ikq}IqU~;qJ=TNeOcQkY zxX0jUiO>RRUIjVU#yn4f+YKXed)9-T6l~ArOnIWqf^s3*(aQ_@NPDbMBw;RkJNCz4 zhJwxqDAb?=)Q*WFEsC;t2Z;EROtSY8jO%kH-It3+is|I7Ms;?u?HxqPe2o5IHKLQU z2R{cvVK#&YD}n6vC^9v+meb1dD#a20eJ251-wbl~oyY}M3ocqwEW($!35n^TG+nb= zv;eg`F&IOEKlZTsSssiMOoo4i_=eFAzLTDG01ZU2P}@QF+SOjtFgsMJqub%Tatj<0 zLho>eV@aL*fz`^hsS5N*qera6x z+KS=YNTJ%aWw)(lzDKmD2MPF z$(>>aZ5~F_ttmI$3{}BA_;sV4E84s&p%Q6kgJmThd@=G7;rVk}-Kd4teU`Ab=`EOX|RPq#R~L<1D8l_xVg!s64hrLKoE3R}Zdy45I^~KUc@jJ8 z1q~?`I_yoPR9lrBvWuv@MfhpGp&aQdjGASstti9up@V^J*K;FzWQjYE>6)5oluUU4N+S;*mf# z9Nqq9l~8epbO>AvpYHp}kHl~+U3mj0WT!PAaDYaBEn>zkA1Pp=#Jvy-Z4IEjj!gMH!+Peh6gxsb}21m#2>{0Y*)6aQ^iN{eu<%Rz@aCUO?F`NYEJ>c3_M!6azZva zcI(r^l6&J{CTWmiD_IOjsl5uEib9=xuQ&n_A8RBSv%(3RM9CksqE8v}48}Znw-4rD zlQ1vg>X-X*hg?#ftesb|el7{JRxUplAc>+Xm5)LH!ICx)csQBSsN3e}lCQBvQ4Pam zTor=Tebb=I94STsdF2^gCNz%Ha7T#+x0BHcgu>7au2oie7_i=5vLChtR>Kv_I^JP0 zoN(fnglq2{$Q-Oux2{ZM>b7nnaT!$uebC?-{4ma*m>j$=L9Gy!YWyo5bf5!@VlT*A z+i3*=jRBV|jhkOEu2F*NRkh?szZItR>G{3YJ*8@jd}@now$cjYKYbSc9MF9$GI3 zslbxZIS(wycYiPfsj}$9Xlhb{^>Hl*d*5f1f$EQ5U{5t(&5pAoNlxWc7P<(pVWA(X zlh1w2wL4j8KwxJVK!qKw=is@%VNA7?m$6J~Q2jW8ii= z9-FG@CkTEgd}l;q;i3KVnFne#jn60OPq<^@Pa_lp|PSHNDA3 z!u6>~+D0_?;8<<$zolG6vIzUNKVpk8MNlr7b2Eh6ws@H0>7u0}%M2^QNvEWhydb%elD} zU^c~i!#FfjaI2Gvm(mH-Y#Cv@K?I(DZ|&=x?o_u+d*aFAg4uTtNTjiLM4Hdk(gEBx z+}|Y}rB40*wCito?UYES*q$gW8KweZl=_R@P_MxK}aIKA2Mu)^br<80DT>a}|$+0l&b zuhSxGg!j{-rJGsy@BU?98ByBapwQtg7z5EOXI#0_V5&{?YY@d1rwvnpxEa4C>no_D z=Xe)3nSmE)E&#dEPrDkX+peHTDybbpfOc}SwkJqX#Lm0TK$Q0@bl$}j`!h$sJE0dS zV=~~T{WuB~<8%!Wd4cn>hJq4*7AS2+escHN+h3atoEXr>RRkqn3D{^r-GgDM=}J4T z>#Knl-5MaHljb~OA`zP_vPU8xnu<=cnLK}hgG!&d3Q^lW8QTL|+*m-i6ly1qsQXjQ zA(f?(LAPwSwhyQ5l5>;4H%mg^JgP9LPA`W>pE_ADCAP}^*<+Z-VV(vCv9p90Dq(rX znAU9WPz0GA&TtaUG7SYFC7JI-yDI~WFxH;>AWGx?L&~jgl-nPj31BG}9SDcilxkYG z(lQSVSyzR?n=pLib0h3e#c@aIr*nAT_DG8R0qYGZXnw88?u=_MD!PbW>7Cr%+UzjX zD7y5ra;B;DA}!j_+~;KD1zf034<|agl2u=Z#?aJ1XV~r2RWQU0^7ML&) zrM{ohI;_X8Sux$++DZl{o`3fq&yxYo`latbxZp|0H!|i`=Ads4%ASYr$E!9-w@CER zAChHptbr--W0B<z_hh%}n6jk#0^G#OMq8}rl_TS3wp zppRb#M3SBs-WF20#xxg4yO@2NJNAnNo8&;E`M7{~9Z*Q|hwH?9#JuOf&@io|>?#m5_-@Q1341O> zIV`d2-x623S+^5cLSJ9pwqaze-i=2IN_veD8`-=L2<4DKj_NPUL|Y+4uz9fIQ4P`D zpL~3_@^Z)32a$Gj*febS)sHS_W$l|A=HOlE!XCovMgS_&E+qaL#|YT+85#G=k-N(z z4v;oO;2VkPN|X)Jg-|a{xOqMDH~^j*d9(Nzd6xtaz{fYeq~brBO9`wZTM{-tlL>20 z8`Pg)G5l_nBUrkrw2EULs_5){9SXs9z>AIu9H|*dbG|u#TbO3Rl#HW9vZ!rP$j?!j zKV+g&?aBpf?fMX%t$U0+BZC=kWl8n6Fe{ex!teOJ$6dlP_%B(l_=m%d8e3AU!DW%G zmta}v-rET?{MAi5By?~Mp{$VL_GoUF*N*crThB|+nLyG#Ploe)XJocR>NYPh`hisA z5T)#oJ7pa9QE2GhoN2N}c|G}UAM?vw5IyXL6X(j5 zm5-)F$uaW-kH{_KJ%70a-d%`tyY@*6aENXsQ?YbO=8TWmEu0Lc5^M1@h6nG_!HrV1 zeQsDVM)XTO_5Pzf!P^w?;ys`(Re>*;TNxB#UHwZyki=f~3O$J<_$h1Z?tPH^U58q5 z7ykCJr>7bY!8C3$M8!SdYX(c`YLqy2mNgAnO9CyYs!@+WqSUJlIWA7$ct&M{MMhA$ z!uSb`)ud***&3C%EvS&@nwbpBP^n`CrnS_!Cy3D_YXU+k!&LoNuvCSyJO(#nkwx!0 zU^1J5^O!2PN?DA$Xcq=Ukr%oCPLjxc>s8Vf6}RsV`VVBJeOG){Sk*DQB(2JcG4i3!{T*c=EVX;d^On8H_wBkFha7eLI#2_01$MjlF@oJ~X@- z@%43blZqAJQ^)U~#o=ITyY_?JIK&j*Xn?|(q%4OkU!s3F9o3H2fEZPQ@hmbNl3*%! zln`aT!}b!iGMT1z)5AzokG7v=29b}T5L->~6FPCf72KiRDOeRkpshu`t_oSLXu%nw zy~r_jRomBZZvsiyCx|cqrwV9Y7h`qa2}QTwfq-TQ(z3QV1XURdS65e|ejy})+z{vn znY8%m`!HeNKF6JEG>ip8^(*Z21p32~{(Aj+M{hNuNt@%Kadoi!VG=+3ehuyq+Rne3 zAiDJ0UWYq_8xSdJ4L|=0exooblmkb5>=`__UkTVjC?oVl0fuHYh8eMlO(>jrur$WG zn!}%aeB^JSSpNSy$#+L#)#}uX4V?YHf%WYjfDXRA*O|uH9R-|B&&D?(N;s5I!{57q zMJWMtq1Q*aqM!GAQ-oJLsiHM+$q$gX0@)c#7$#qGzakv!O7$BBQBzWS+i4uYO?R(O zjEmLPkEUGvCgxP>Kk;#u!A?~k?U+&LH59JdgEnCA07}5^lA&*n2>Tp)!GV;fEwEqf z-bg9DFRsWqoK8@JJrJyS&jA?0`BSGIX6LjbW7>lYDjec1d6J+885P=Qj$x?^R5ZfI z%`j->BBZF6=+3q<$4UQkLJ8L4pbA^FRW2Hj8xd}UdkB6_+C#|p6dOpOUA3;>+0JY< zsZ&N$@iaqSuo-ltBX9Ud4Cy^{<2W!XXY5_6tMC2qq5QKmF+!&sg`6ZnVlgwC@Dxp~ zJvac%D^&OZz?3w;CuknGopDaVo-nxcHVXcJ0-KLBl29O2&w>ks<(qrUbbd=V}*`T&&KYD{)X*i317I z!}QdS4q|t$S3&`%lBu5qV4vvxJ%%^E(*`qRZY;1Ji;AApE<#?=j5IOCV9sS8iJxya zYgQuGE-TQm-&3{DXzFzfLVztJ>MP$`O%2ZRKteFx=dF+r2rJQ+Q zIfd3mN#z*%nCz;lkeWp6YEn2gMmTx+5Rxj=F%RrHQHhFL@8MaFb6h@=- zER0~&3EaU(3v(xW+SN|4h-{)s+!ZrX<(}8fbX3$YEs@o(Xo6PvB;cMzFU`o$6{>2V zJ27PmHhUOjs98e@bUTFe<2dkoh#ytz$m>6)zEHrLVcS%lxBfH5dZ0a zG`*D49~9L8Ku9qFC^7457W;1m7zoV6cL=|>I{}fJ$WLF}uP5;naXY*}cW=2fwKn=D zW-=j~+m-DBxXH@G5;URNtQK|78BO|29%1x!Y|fR&gD9JTy`L^ZYhMIKmU@*3F3sVS zOAZ7_h)cT@P2W#~M;zp@HI~HgCDEyyJcKk&wQKZB?49Ey@ z>T0=Z0}jDbQ&B6XwxBff8iDS^&{~So{(2y+H&|yaX^;D z>REd>IB6HLm@!9N;v3s@d6+!wvC&ZzSL+$ZB%R9Ik|UE<1amX@rF;Tg3|Ed;`YC~`)$ zRfa^%W+sCw_Fs8DKmHO$;5O;8m4|($FBGn;bA)tA`7F0i6c1~E>C7~xK7I%KCkU0lU#S#ski82vRVXzL96J-@ zv~~_M7Q(Vt0=y1m?5DmPs9tqfv`I2KMND(63{Lq_rxPrDe02n`adNzOV0ViTbRI5! zJp7sTT<>0g=1bqaiFFwAf@ZB2^YHGLy zhe>I3Vr*)Z%=6{6Q}*edm~_(Mox9Pnt6X?D_9;|o@v43Nh$-#U)BZH#U##q;Bknl% zgs4zLF)og@tT6tb*H+|HQeDc(5()Kch(4+? z`45&DL>pbAH|6P02m`_`Ie`ZTK?a-OO91Eto%#nEiTwhjbh&eVLXqslFsBF(m6*i_ zndXw4Vu|3eR32gAJH0<3oy^H-vUbv#3Ug6m7vP_OX=9$1iF!&+Q>AM7hcwl=3@{Mt zIOA~T(KkS>O$kX$gurPDK=?=z3{X2mg}h2BUWZYqEn!QNl`U!d@s=@5o5DJ4vLcN) zhS;jDcmZF8Z4N)e4tjv!VeD{v?F~K(^8>nD09Q}!*+yQB2twjvOv7*Nc(p`-;s>WO zkp*98Aad;BM%YF12NS#jc03MGg>b#X*9FVR1E;Ljm#p&CEnTYmOPt0W8KjaIAvSG0%v^{Pfi@ z?oJ+v?M6JXYjF}rYB4EKpWJ}VLCT(uZzkXWvCQZ!^Q=vWBv7v{TzmVZaHVAo&W?)_ zCzI(D2bq?9aRx_f3Wf4 zy0(%bC3$!==_UpnmQKi5o~-vYZjGB>3d%$y6?>%3obZRWSSlTU8o#5PxNC_O+N`$i z^I5dHO8MJ3t03$+bk*zY7TphHpPDXM!VE2riPbi-$WN6>vRSiU zSspDHBy>2LN`+VJ*^u5jy2&D)^WEYt-X$VO&Ao2jQ_E^)63$~2XpjThMQ0^faKTcc zce}*JABdrRHh$D7Q7r#*!lMZo>t5`u%SokmR?FwxrQ}E#N0~Tm>1Ep-`tY90WE(P! zTG9SX_V(!Nk`0m@FLXRmD;9!e(6Vx!)5l6Bn`=dl>^0Y7`ALa{trte_XJMed;R_(QF`{wS=sm^K*x9z83W#DZaq7l+ASX0u?J9_L=&6Qn%tNrYx9;v zD_~m)os^fMmyS`iOi{vU!z^E>+|X&bQM0(s%N)23VB`BqH1>R7m0WmjdqKSnJO!S6 zeU0`NauKDbpcpdW%bcTZHL-|;o7VOqM&OnfduhYu`zqsvr%g{nWb5VQ#~uqYsJ3Xr zYsL>*MVW!l=!Jsx=gQRaxOU1z>hY-3)Mx*zzWc+0n?3~{H4&AjGY!h`w7t?L3fx39 zr-)i0H*VC13f205_Ku^-qdEJCqONIbg>uY)WyVhW!)u#uknTy(1l}3ysp;$`jMs}R z-96k>(r5ML_I!?oPaHrP8na| zbEcLfSm^tzw#>Vf`|mW!$PbfgbhlM!GCDlpEkLDrEf!h|=cfbZ1KOk&l8lcgNIr@$ z!gXv7-kOs+9ZP)!R?ZCJ&t!(1^?1U=Hk>1NQFvq+aZf3-D}07JWLB7E5FH#tUHV^# zI*&G5uceep-SK$0>3O@#J)5N01q-Q9(_kDI>8@wZE6)bxpAu^8TXJj=bm!<{P}0D#E4UoSJ&Il+gum31NthOTBi z-5y+AhuXRW;<&lZTi3ANU7hd40Tqf}(g1XczNZgJThzc^I)P{<=0G2!X-ctmCWhM z5eW7y+_77ySMZh1NXQr z7}4(s-n~T)5GFrfQvrxtwh$T)5& zwtHYND}!?|M7)|4TYyQG`hP-T$-C)cMIDpq)>~q580c#>kAx6rH{RbSoxz8@9@P0b zvWp=ELZvtMGvwLRu2aCQk>oY2W&g!~IE4cYkzze~jqaqEo`Ai{0b@1ptC@piGq|GN zqBvRmaC5nf7p?NA3FneTstq+5DpDEJzxXhs@)`@&;x*ido%))CYJBtw2iHWuqa!yZ3@Y@(uy;dj}z5M8K@ADQ4sVKk_( zBGe3wWgcKPl%nT=%h&<6fhg34S7;@ckWc?q|6vX^1zrxz4KIGN0?!Zcga>i49a`~Fh=uF{*svQpZR>i z4HzbGwMxUz2xC?AnQng=yuC^maD4dPH;**Mw#)qd{EJm(tcyi%V`^rO*H@T1JH{`E4t^K+ zZoR=qnp2f~bD=rvpWzOco~il|&EFauE#u#!5sk%at4#u%W~9yLWk9Ko1H7}@Dwy8f zMnK<2TZ}(liaONwoYiLQSV=@uSj+sH?kdI3j87N7UPnue*|R2(uUi}E%e!l{*(ohu z?Ao=`ChMi!I&ICO+U4)5{}Omhv+F%2RhMgavk*W)L24 zf0xsEXBFd41mG35KW-iS@b1BxuN4=B`%PfYSA$kZhk{39nPNFQ;@O| zhC8y+^9(DE5!6{QFeKQ=kJ`yGv9yp07%U^!9-o@rE?4~fw-O~~WAGr#yIxGLm#gUF z(fz!TAMd7fF8d6=fllP+h4$2Rm38@<()mJezJx$-XLfUh$RKWbz(V;{1s=KSD zBxuk(l-;ZmAiLNLf;pkhY>^uxr-%I=$l1#}`x|i=Qh+%N-P`fa6AkQluz)WcG=>mG zE3E$SWmD1~C(r_InLV98eV98iUIb25Dm14{UqFTe%6tT#&~55s?ZWYH4lN_T=RGMU zer|uwX$up2ImRHL3o?NkM%o$4$lQaNoj2~dTzpPGbDtPvl<7oFR<)W}$P@)b;N+A4R4Y{GKGvR>{xOncqX6VkX6^ZVoI=_q<<=v z;Xu93guoA7t0}^@%4dW1j!HjEPcZeZEmNiW$`iT@jhS1hZGj_I_d&y?mUA+{SVdtU zFo30_*{lz1h0F2nBSC0$ejG8sSizgS)&goSC{ZG(nO+HYVh&6<0QdIeXod;Moo{kk z#DTLe+O0BZ;3MS3C<_hJ0y^=HLqf}*|2Q#YlvWStT-rZOiJg@ZRK+hvL_s55Z9cX= zLkuXcj?^wFbL$ipyJc~)yiLl93oTi#w+tz8K6d$($v&ca9dcu^{wJ($z5 zNgU9H7JnU+kNuk`OZg^uZ{dyZQJ5WHI)$@zk5;B=d0vcA)@g0ucE!l1K~h(fQqOU3YfJwJoGGZcVoE#bB*)~t zX`adyMKh}CNt?2K0k{p>&`q5hAyu{Xj$z7LPlKyPB&m5hq=jotu~UTB~sYkcC@kmLrapY z{RfE1)i}}8y5`xz^#NJ5TU7_KC!4^?A9(8|ai`2?=4}Ua&lD7;EI2Uo-!%$St5;P+ z@Ez@r?osda@*%DkR_Yq}xPqLf*<=7d5)L(kl0$7QEaNGLI0x!mn2eb@=QsjxfNG2I zl-JZ%;ijN2NYrTO-v=X*RcqV>9?EjYO|Aj73S{*;&>-ji@p4QcYKYs(eE82C$mvL= zzRx)FkX`|^$^|U^(4vH+uQ+VYh1Y_{DWOj!PkvE$$}SZ$J-$*XD-&5 zDVUyF{0tk(;l6qSN-6b^8?YO|I%?6Owcj;zm10Y}LQT~v-%kUkuv?efiZ&u2prRPx_0`GME!(d1z_c}&7qwRDa(e99?s31_mJ&W(VWBbLol zat>%Da{7hrIAM|fWvL$w0jhflw@n&Au{zUqs9!#=jsIY%I>Ej4Hw)Yl!794CC9&&1 zg6a;wXrz_&U$sr@^lH3x)G{_-mt{?DYDDy{w}{S~`U(abpKGaK-c9U>)~S{XvaG<& zAU6pe8_D!vTsu=hDU?Pn$;g#?(5gnptVJHjrkH>9fIC<4ocXj=oyKCUod)j$7?`DyuYG%h4sx72k*KSu!eT?X_kDJ*9jQ0$PC(g=Id-y8;3PnrN_& z@^%MOay|e=M6DtzBooJqOs{hzJq_oARWFfz-cf%)chbm^C;n+1P9b)(&{GRdS)z{) zV1+OGFM!w1z=yF;q9eOVbcB8?$4|Xbe2+fOObtdE)e3E}`g#)yqZoMXfaZuw1m3<< zDedrkduu>-(1U74$ycjDd!QDp@v7yG-t6fBFQ360_GOnt~8H^j3aB{;4DEl=; zCZ2d<~leGB9FQcpCh?YBzCXv3Bw zvf;~{u2YHMm3`<%@VMn4NkXBpb2;Pew!v^IOC1T*$%2Ma;A8DVy z2)Mne++Y2$Y_YypiwPo3kY36%()brp8WcobxE&XhIE%sVhH@;=PJ*LqEm9>7iyfX5 z^X6Ry9~34!#$M$*Zu2G_OO>YVX(lZtf-fTo`U=x0BOLCJ#)goHJPgN2VIw4b+@z|B z2U3O_v0G@;#()v(I4VO)dDtb*}90PXzKR6t+i>l&?cp-P&y@ArHp+m9!jdVCbrZN zIFCClC#yr$sQP;~pClh2IO=>6AV*33tubh+8W`csgJKy2(ON;xX)2SZ_W zZw_6?j5eBd#1;vtW`0k!0`CYOwBW8H&#CGw&~SuUS8c`D;A6Q`>$&XLeZkklJbY_O z-b#$c;a-s583$3;?{so~SDd!NVa=@{;Z|+!;_K%pt^A3tFynS?AS>ARlNmW?4Zj>b zpm;P6%+Zm}gEu63$3Z0Hm>0!CDAJh6##>%r@pe4c5U*aIt;9yuRXuRk>+;O;mtsD@ z@!0U^VAR3IE~ddR`LVbRtDvF_)ggRa;GOD_7Rda^yz=Zaxr1O8+Y(JL{TQu>x;gzT z`;j=xcAS~>(u*#ddhsC1l^dfAUuD``c#3a&KT&eCAo{)T|Bx9CFRgd|4bRb$ z_@WWQrr&BRtoMWDE0gF2iv5DgkN6@qV{Gk~x%oi;?)JrTe{N~;h(#+^i3}th9vj*z z`+@GW>nQGu32sp&e`&uFa!l3UlYhK5N@wO+5dDaA8jZ(tYp5N5hAlk=xF9ELK{SRC zX1yeKIqeSx_^si*zBvV`QL10fhkyI+n1jTCkr(~0;lJj^3j}MwmL9P-D_bUh0RD4Q zQAWSanEYjQZ=n7k6c+xMN##ElTP?q=?*A?Ul~nV|u*1{44DoTo7JGRyNg$yi_C*4FOF*Wx*O@GaOI>~iaKHb^#k zi2%qI?O7QHO_u=jZ1>kjA=HaX?_G>1Gt?;8-bs-(r3kiwF(KeDl{Yr|1Nn6M;t?}+*c^dX9ov?7C+tgD>y={r-lv@s6fC(c6Cpyu_#{%vR{xM7k740 zM~lbDFj(R#y9cEChe1-H9og-c3Bg%?-bfNSKSGkY=|JF*n`8G&HC0J=KueKIsI<>& zhMp1&CE}nKB5}kd9oBWvp~oTi_k?NL!y$OG29g^r!Pjgd6x{h>$N{d1lrcUBqn(6y z{(^7|yZ{dx<1c3LMOCI0H_4y?#CEBNF**uYfpEgX$EguZm|g}(l~d7>uND?|33((& z)s{s~v9+usuY@r7q(9+(y`gVs-~oH(zTdL4Wq_u&bBO=jpR?uZ%?zi1wSo5Q_P~Yi z;|v(3D+{=M16gGC$=+HqDs_Usii;Ta#?yv>T^>3K4};@ggk*p0>dy(_X=!J=05bel zdw>`|QvJy{*>i2VJj~dG+mG}JV(86G+dBDMaO>Qiy?ksoQ3azR&Xq%C$WL_2UGNLG;Mvg?=KKQk)K=Tk=qz?mHlS zDPT~-uL;#P&tuiQ|8rKqs~64of=OnC5m>3~zt>xDju%ce1a3el9*YwFI%Po|eF7oz z6%kD|H7%F&Q&}4ZwQf?s>#Z44blVY_J}=@r)oEf5Z)H1#rRiU~X$A1+C^Q`Qy7y2v zAQ5nyzis<0XFB&y65#4g1L54Y@~EtYkS(Xqpecu&i)#S<-{xA5`?{-!Ki;}2ajACn zwM(}x5ayYZzkpUR7}oM@OSm(iM+MR~ipXmuMvLtegb<6Ct3Ue&1VtgNtdVdnx%B~o zQE$BPY0XQIj3F&BkYy|4qQ5SV_4v(n=qoU*3^NKB8uhTXf*Yi5tg*Z6O|J*WO?kp( z52T$J03b`~SGhKn$iS&`Dl`(ttTYQ@A8P4h&#jigkTnLc`1bqldE3^R@5)YCFb0pI z=S0DdWpG>#jrXPn1MwD%q>gaq!15YAV=NL9TNWFc2f?2knvI%N+t4b6uCHB9`d=QON+*FjcDyb(1sv~C-s*`i5H2lL`Mx^7pRd_dRjZ=R`Rw`Svs+H{hw5RkX8(e5 zn<8MnUj8hfVdDi>Zg`Wx)ShQE_dolCY((ClronP`Lgf}WlgE_nlCoo>hldH?aYT9|>dfd!EUb6_t>um>)*Vh&#_mdT56X}MkTZP`2EUAnm8;e($i!ME@!Ar-V(-g1k&uJ#n z1K{#~kQv;b0L@u$t-5B*W&@YKCU18~UkKYbru?P3sY^D3IP~^$DiN<1Ig87ej~#$n zp8@u-%$=1txaNq-zx$7?C&@Snrtj>c=*Gz!wPIt zMv*~B53&d3`3B~1zsCUoT_)_#ciF`6k;)w>zt+;W8p*t;@5HL0MUb6mFc`O{Ah4j9 zLUEMgeT@bNy|(u0?Wvy_xmf(U*Y&s4Tqo?LS)OB7(muzJS8)IDtG1q;7R_{6^-xBZ zGlHqxB3j`ndcVg|-IXk0A)0XC;+Qk0=Gzleo7d-0LKCoIl*d4!J7-(P%SM~o1E zcqE;7RbxYi3O)bqZ$}3w&)-42)Z=!cEjehQbi!|r!Fn6M!L2h&YUkDKV{at4akuxP z_9m(z)UNw;cg-V13V!pgiH4itvfoU!&YOPe{SAfp~_sg}PN~_(pzhuKnVNn<1_--9eJkn@)pE(^^VIX^(HgRoioDeP>3~ul%J> zK~y&@bL>pW%gP)c{Xmhx5bnHvEY7upKBksY!`Cqtvu0%ak6d#I_LT!?kgHGLzh&y( z`I9KQaIB}lH4OM}YFN#5@;%yCl$C=3*D=%F81Wz`j(-_F#-+QmFVZ%ws|osX5Vy}m zU4cdxVL|3N9PS|Sy(Ue>iU94lw9!S}{@7n4eFc^$={X?s9*5}jsHbR>x{GmWyxci~2we!*|3{4Z$SxtXQgD0HpJR=C70Hs@?St<9IG{hJ~mfT;VxNkw8@v|-ZQCNYv6a{*n zYVrG^k@Ee6aI)(d6KLqe;)gtKEkcEYd%o$w0-Bp(aggpUNb<)xq6cFiL?%7)Rd(1o zC2+-9f9b8QFbQBBByOTlDgm8501m-YwnMIP`iH5We?$!WhWB`4M9XHim|LP%i$51m zXYc^j^&$YQ1%G1BK+|h}sN=ubJmf@=wkZZUx?lAApsUw_idqZeet2VQ3xDLqAwG}#Ri-i1(evd?Nc%eKm{)O2z7xu1))i|z9S6j3|MdTl9dTZ zq}y*n_Ahxo1y+s!ok3jh_7%^&V~5Jy0mw!_0mk#2r?Nn=hlnb|g2?~lk2s=Hh`?KX zo-g-rm|YL+Ks(7k4&h{J_Vvv#WU}dr(CtVEXopPyV8n{avoE)w!(Q&z#M+onG@@iM z;N$8tN0&!4H-kzY0e(A-tG2PtCh%id@O5R2=90HtQc_F}E*qMione%XlmfRR*h3Uw zm)ldFl@)a3j};ru7FqVMnA6UT(yGzJ{TLKu?8=dSj0E9Z{MJ~R?#c8=~foW3_)P*i@25k<7uMxPt#k;w!I=E-iB*-;W&wKGa+Mc~r3#SV}sBHHt z6m++ygn)m(egZ4b*MP(lXXJ=tyE8JFK$4Ca#m&yKE7FK>RZ~Z1fB1|@9Zbh@J$6I{ zL2T6L?{}Xe8G`mrqGURGCFi3m+e#CR=#F4UGcGr<;)AG&@N;H`wlpa>%1gRPaBStt z{-}Lkvk6o8PvmeFe+Yf{-*EH$s~iXV!KIO79a!R70KIlcv?_>NU7l(k*sT~-!a1FA zz{&LX5O@nDai4VhKWICrCeflTytZxIwr$(CZJf4k+qTWqwr$%y?e26^m4};3UT#(1 z_WlEF*2Fgk!ROS%Hk6S^H$#j8Z$dIpIN4oNqHG1TC_m&=Qd_u7y3kT^O7p8#LVal1 zhYEk}eG+hBH}1!<3UxT%jJr8?ch0}ZCwTN?gyo!L$}m^*3@oFbAvJ2o!%SLac0(#k z%49>q@?z~V<#N(YweW6~?2nG+Wq+Q>9>E5IU<=~Z@&sGO7-aH&ZOd9AQc~#w6Gbh> z1vHmRl|}<{Z^;g7MLjzvw76%fqY`*FRav^pMX%{`CrB)fS$PfaS8;W-J<|uw3j@T7 zBu8^a5@mpt~DHtzfcJ!vhgleYu;oQSO=hQg1suO0l*QZSnpG zyfeVWh04kJX1m=OO$6_BiP_&hddbJ0M;Uimi#xF(J>rlqgN?{FHIVEZ$n1Z!E;v={m6D z6}>ISsq2V=^lVogqQ}6BO$ysiyw)-t8z}Was&qriZXereQrbKgUTx?N7h4zTWZ}BX zl^R{Q@)aF^WU3A}@hWq)XexJy%Hg{^VWa*PXmv?z7FDchr%rQGmseMf+>MRZ(8Dz< zmqm4IRg_a1AC?vM{)*vFf}U^{|2;6I^*bdms2*!cV{^Zg55GA5en=3*$@dfTB^kY7^cbC`O$p08 zxI3J8Y&ng7+1i!v{3h$%!9OJ{JLo6^`ixLoNV&3AKHowzgMKUD2vQ#Qxz+K?0X?ni zVz|R6A2V+3mA1{m5gIfOoO&0+C7eVenLYm($>*>UjNF)@3k$@^@ zB>(l=X3TSD?E|R;Zc)9u2N@vWfn80&^|6JX$ZQAjMfm;jDBf)RdA-fOzf557XUPxw z2V{%e&W@*4jL(**F(3^G;NDhCoFX60dkm#!V7ou*2$qs znwOqeJFWH9r|!N_S5^ikxC&KxLgr6nlP+D-DZT$QZYL4MOIs7E1?9Lat9c0Ry7bkC zPX5xEF7)gy=!Do2Y6?>qF|uoEuldEm2g~^oOhDA^IrcX(CG&Q8jPsQH~CookquyaFW>I!yOq1>P;gat3? z2|lsyJNM0pJP801->Yg$G`Mdf;e)F2slP?Q;))=>`oHM&S|X4a&qV6%E!Kh?BNr+l97>2AD* zohK(Cbu|&R3bVM(7@$AfYnrD|!dH$*kkB0$;PmKExITD4sdvCqKI#i;_bG35Qoxrk zAPlVcUS z0@N7H(0W4HC+L+N=u2lJ+9G|qJY`eeB%(P5XYxXloUDpVYSG6U@&;*!?+W53O#kb5 zwsj;%E#3+i1aVlx1QhJ`XR&bU3SjlU3kfBpkvM3<)6;RO9y>rugA#a-qr&VD4uSr= z2pTnfm74Z1@Gp@l?>GDw>eJO)zhg(2) zs^CGFcND9qkmRk$See6Q&m7 zf-w_%eAuTi5Lm0{&9HYh8v^!xxLfx`EM#?V0x|x1*1D2Q9t#z$qR ztBX>gxAQWmO8G`tkDx-3m7xd|FJp4@b2Sg}{kH}w3m1?~j+USECjdQ$R-QN<=gr06 zHJMgz9R-x(r!GV_i_V#u_GYQZ2##1?7nbU7$FZ-w;+S!T_GA8msVti?>1lIgfOl== zX(OAmnw{DdRi2TWybQybMm$>Vz!)Y>VpbRu{$VRZ1m)gkPyBA*P4U6t8I-d5lB9>; zc>Qr%LAP*oz8eYa?z&scZpD(Xxh;(Q%5>l}7tdzR5SZ472}!zy=o3K};14f-W8jFb z#P}d}@}VM+sWavfeL2tJY>U6Th|#6KNyO)8rHZHxMMCkou>W$DRvN=_`wj6%X@&2N zT&GN%X4}}yJ<-3_mas+%b-OW0nslPM_XpGKXRi*h67OziV?Op`-WSOE0Xz_Wl~8SN zUeNfEgVN4deOr^;sHpH!g&4uq5&fJ=LUX12UsZCPth^6v{yYr4 zx9bSuVRw=7bL1veIG!5))H7k9BkUn)YLFxD&<8BOqdCyQPrqyaH{DKMbOby{M5j+Y zNa)WlZ7t@JJW0xO6lBqTKa&U4|6nQ}LB_c}#uPVS~8 zcp&X{sI4$2*1M3YyNEL`(ep{EKSVF}Mx7S5NDYhsXu%@%Ue1#f06dqpvf1IL9{1f4 zeRc6(%q=cII9i`NyYb|qcFum{KAu$i_>83_s4Bk3o-MJK@~SzA4%s>@RE7CIG@2ZH zT;*Gu;nChg5}~LEbsh87{8vvfeHv|nr=6hIqGWLxeJfGG87ItkYXp;3wg*0iZPy8)jer zW&zF+U40t~q;Vv|i`XB#^vqRKRJ^ulxmjJ|#D&|fRaDgaDRokB+xmRfhi8L5=-zw% z$l5(5Q4AJ6);-4L`xm4Sc<7MaYr8)oIU)N+vl+-!GG=dl*ar$zp*$z^$az`KW@D#% z*&;h%T=xV19sSug#xvdi!~0yBj_+XqoQlx@A&5=3Pv-WR^bdr8!>>XDXofo9_GfiK z6i#l1H=)L*>LuQBYK!hCv4^pb56JF?0AuXJ=k@F*Ob-~`>=$C76B6X&AZfj}X$#Pq z?FS85q0Mk=*B%Co@;Cx&gIw)|$#al&02l-^+?#bn7wJuT`-c!b=>~ZKlCC+NbnPUH zo6%y`=ZqkRfFW?{16xs&)$cQF78Bo26RXw!Sdw@Yc@3&0UZi`bl#@jU48&v3{E z1`2A_A;%-GoZ{7p&INQGg(uar3Z};(zVwigRRRIhL>sNWgls#jU=a|Q@T3p6;XDK1 zX@o+W2Qub+I13=4#PRk4_!FuP?F&CdV-dGR3{&$7n+BTVQE3KSp+JO0{_1sT@cf*_ zY*;vO^)-dF`ah!f_ZH6AdH;CB2C;Et>gd4dG|3zPvvk;L3L`dq_PVq6<8g^4KkRn^ zQTS7hSiN09Smif;MUO7*#bOjh=**{|%?$vz2Ve8O)*!BX@+3b)&RgcUVhRxW3~uc2 zc;o$Ngu#*LY+>X$#KvKQZ*wq7{%)S@&rHre>$Uqu^hf*VxdDU&%^yS9(V6k1Ev&|< z@jD}iMogqtXEE~A)W`Lk41d6@i7V+YezPL^l{b%EH2~)Ji%nq?0rC{wP5&}iZ@WV? z5vy6u4RYgRN-sAc7!Z`%E&y{E!#s{VGVnv-zw!oHFpas->s-Ju&*R$aq^~NlmcriKmCN@n?{rTcJ`0Inxr$cyO6Eon%MjIw3#8kZ2HuEO{Anstu zdtdh^M+h(3-)neq8Y+yrc9AjmnIS<8X0xCjRn zb^I}*E?DY@bdji?(E|$?oFW6)}y%1Om=VpINPIRx(EHSD}Y`PI%G0p(7(dX zHN2RzvKdYY0J!fY^bkNT@_$Exq@6G0PpwNR0@Xhy&o2>BQBrj32jK>17WOt z5A|?n79~2n(tVBH07~-v_67*ralsgJ+sOX^RsgZU0j4(WBC8rPOukr*xDK%IRN#4l zXtc3L2EJzoj*)&|di;?S$C~*v8TPy4iSGwuPAqcgZvt9i0sn&gO#|0|Vlt2CNzMe7 znHn2lf}h{nU1mTFfFS)PqacH7Tz*KcVgOo2sB+swO*%WSA0D%4Ob52$WI2FzHvWuk zaJxd$@DVHk;AZd>Q&QU_x#2xBit@{G+-nquzNUa84sLfkbjf=qwVQ{-Op+B+j)i`k zhkixiw^M9K9EyORVm@CCob?4h!VA{bf3p+XL2Q9_GxF{L3Q((%jDBa;cK^oN^T#mf ziS@8y`ZFBCY>Wn?}R`zSI-Spn59y#~38zo%ZTh*IO^{(0#}zmZrh zh!y~{k>yRDPn%oxp0i}^s%45Y&ajehop|5LdEerE5 zlj^1}u;qHwrbru@G=6`M@rDbaHW9+aD(j9B6q&n5rK8f-8aF>ur3%%C+F~*p%AeH& zwVrcr5w(hX-%C<`krAM<`AU{66i_!h_S1WgA9ypvI8Nk#nJd*Y9YDXxI3W7%;>il= z+vk%j1xZ>d$a`FNB=B1t_tg1*T%CDZ;NSz zcx`wUB;<<^RIA6uyTNBJ`7932`V3sat$g3k^>xD`!^1uEH+Bf$ue-~yQGY7#16K*o z>Ghyns?Bd`0~H)|^;Cmq4brZjORld^G?c{R8)4o1is+B91cm+*6YncSrvE4i?`b#T zD~3QicL;>%8g@#-MUhz4cb-tTjUT1_GT8Fe{2G?LSa_x`yM9*UfnFqE>&e7gC83qoilCrl7P7U8`t7rR8+)7At^MuV^=D7tr#+C?$G z?-ffCV{RBL_Bb~|@xAANGh02ZZR@P6&0Y*L>7Yxt+fuBzYZt;yo58`EQt9=r9n@`g zE8f3I#;`XWN|jm^(;6yfAxxg;gIT<408uvWQ@D-LElY(A*xJQdf8?nK955KQ&Qg2K zI`y-zdV&KoXxBTjq$uby2Jv6LNeq94k3*Ea-PWMT5b@G@jNGGGZZRFTf%j^{4y+@O zF0ihp>1YUi;#vNF`-t)v4uLOwa|z>bGS>vWZzzo(|6h#V;Mr*C{N+f?YDbHo{Z<># zM)SW;N88q0-KvzfI85@`?Qk@c!@F}99dRg!XOP^6c{Yr_Du%?zH^7W8=kO zobsT|j29<;?*=9z!uN^=*=V50N-E5JY8$+!g)zZS=rD;UpaWbhDzv%^7|4E)aowEg z9Ox87iX&7)*-* zB{&G72Wy0gRZ2h|{G~7~$Y34tlSeNWVMi(raLkbhT9Qi+xElT5V@a+kFk^i!+h>fa zGD^k$)f~`;Djg8KA|liYrAuFuOhXbygZS}I#Y)LbT-GY< z`blFsim%Raawpfp_jLqJo$Lh=fA=ot`Xw{fv5}gz0-c)y2nrf7fEOgu^nX(&2`S)0 z8oi?$0XnP@zNDOnBh+)(t&Z3jxCNln>>0EMl7xIr=O1jfw{tuSB#bS^ejY3qiEkJo zm#QB{8kI7NmR%P)nJ-e7)oT(lNO3Z5EeHMGIfO5{n5F$9?yKW24LNkbF(8FXPF<#c+}1BKey}#SLx%aw~5^)IRAm`qW z$wi|r6h_L3R+MdXNrsfTno?$cF1Lt{Som(E7vek07HS(hbted;X6=!Rk~Km_x|u7lC{sKxf20Ib4^36x#3wB97|i(>D+x!!q$(idSYLs6QOKKc)DO2uJa-Xzv40e72 zkW&v~bV(&T0cjTP^F)~RpeZ_5>m5`6o*Ihke7rB-i+s+RypG2xFbT(XoGvOfhfW0t z8RZD+!qY90dL}x^1vbv)zR^$IrBB4t*u)U|N>f0cvgA^T)iI$Sao|2tfRhy$+?_>| zCM@aiJ}TD(A)B*ii(BJdMhAvHp-10-}M!7K(6poHkFH| zv#TDiC<#5yNJUSm-@PUBH3*d)$0)SP+>xOUlujI=m~1ie>qx4<8ZS_K>oNUwcX?R- zS^LpEcYXc>pb&z4)o0jH&&(t(dVBZ9BSfXSJQs1bTk2TcrV?4RpNL!Pa%t6sjp^@^bZrQYf?jZD za!NR*kG{90>SC!E?6OZ9uvFU^$TcMAk>hk_q*#A8uFuFfLbR|d0r{2(R$in5UUek& zc~rRlG3_yL_A@62oITi1_{9#E{i0dd8`cy6YUMDa8=lkD6_aEq=#*M!ne<(}re!oZ z8%*>Bv@KbaBxK6*QMC0LGxW-&mqx^W#2y7riH=-4<9=w;+*FRAAP~^FW2B#M07pls zE7P;_z*@npNl8Xx;~3OB%;{67IL-XJ<5=xn{z0!vLy`q8aByw+rLK6RI)!qQ6mKe> z=dOy?JFxEIPglp!rd=%&6}n@G_<9&N&%;089hX0iR!MewO&jqHFR&fWtENQC_fJB>h`HsV-l&9 zJZguU=lnF>!H6(uCRmwYNW1Y}s;=Y`4DTlKB5$y=d35!tv&t1C%2(H>mbavKFmqs8 zM1H0PUa_Cfsj?e|%yqmkRId#hj%>x4MYWpkP|+oE;p)yrra*L!;%~L&;XHB$K^lg}pGUs9fok*w=9(h=!?wKgsKi(8!^PGeMPFboRw9VE4KNjI?Nr#;dD zEys!4wCTFvt%PVOP1Klp*^d^2T#Xt&_eQ6XNn#U|D`wUt>o%O%3!1|eMY&OH=SMR0 z_nJKfq*w3zT+L+F%YA`*;&<}xyA;-McO-lU#bBIpLHA{x<+X{w(keU{jSIh)0ELePO9IRbqjdG|DYfLp$Ao6iVT2yhXO*;C z+qmi(6m}dh@zfY;E=T-$P+OROqtExHM(ZHd^A;mXqSm|kkkH}(E&oWJ_RQeAxK43q zFH>1UAEa6eYB0XU*JPLNXewD+R=Tq2sNx^nRgzhd)pN{UT+X5rexN5l>JgJDD7&at zL(-NqECTq$y0e|k9Xl~CtV%)2XX1wG`E+9JiwK4hOz%#3r#|nB90`kSTF2Otg|*1` zv(3_{@UA(0;Ie#k$uL7-%~8mTXLIX6Y~$t|ERj@p#JYz#^AV<7C@R5UDZi6fohXXPE1zyH87{Ldc4^EUam4 z4#TTsxf-OA69a^W~y7K`UUvyU;Yz`1*Vs<+PjgT51)v=sU@|Y_&?mZiOKd^)OvJ?*6vQO6X6c#UAx~ z58)_;*EIgFl-Uj~P>0Qa1o3Va(oIsQF7h50Ucm&|>a!0r?GZi5G-~d8Awm!$As;ff%TM57cZi-ci%|e;yuZ z(^&EE4<3J>!c}N4SJqV=r;By%h*+*_m2uI<HAQc=?k%!g zp?AQ~;Ym=uD}p<0AzwbE+E@gK-R+CP{@IgIh!PcD)qwbrmnQSsj(?tL=Y*cFK=(q! z&8uR3p%tCW;492}(8w0t_xFlBJ{{9fnEpM8e}*}wlX%=#9>#ZNaDz8>A|$6CB*xKu zSLs?x+!(#Q9D#rG_Q+!J&FVJIGVsgV3h^}*=oU;8LxZDvlzpGX8q(eGJv3PsR<%l`E58g)UXTFr^h$$}_Cqw*2}(_!eU^J~M5dkVc3biVls8*WlQl|tDs7oavDZ&+(L@8#b6;8hrH!bwdg+MP=TLJWwwpwbT z^@|j(DiwrK(872J@~E0hs*b=eq1z=W{K}Z}yD*V#n#C8Yzac88)S_8Z8z%84t~*La ze&n+dsrjp3W)*spYb&N9lBz(M$gLU|xEULs2y(U5DN@kWmBBFm5JlLW`n*LUh>J4i zH8f)URdH#Om#!OmSt=3F{wbUg^3|Znr|xZ ziwrDC0_;b1n)Dddt;qfm?(@z4brb(JRedmQkbMW=aEd1%gU>S7|ste@= zDK)huEX)0jI)vicLK;N@4l=w_J+(KM?i=HQ4|1g}>h1FLeW)yo9?ZX-3p0VuL(VvY zhqC(?T&BKLf~UInK^%XJ z9&CfWpm48C@>k_{ zlYNuex_{|iJiUyBWjy~VwwBt}Wq&GFd0BLmNC4BY9ss@p<(Z0#p@{f0-BLnv& zj2%SwnPIzr&vV9sxA-Bma$O}BqKZAD%MJr6$`Z+I;+JvZ{1)wjEC$C1sQVZW+u*@N z1a232C}OZSbR;J$Y*(tgc<9(F;}#&_|EHGY-u}xGk7y@0j&j#zN6l}EIG;qlybXyJ z4Ajam)7aA

  19. eiA2GR@p!BxfkB$9OMKXKst*+I> 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 AyZ`_I literal 0 HcmV?d00001 From 56d7d3b2534c07c9a8b6329e02c156d33933c383 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Fri, 9 Sep 2022 09:42:30 +0100 Subject: [PATCH 124/805] [Java] Upgrade to Mockito 4.8.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 478167dfeb..ec7122c49c 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ def toolchainLauncher = javaToolchains.launcherFor { def checkstyleVersion = '9.3' def hamcrestVersion = '2.2' -def mockitoVersion = '4.7.0' +def mockitoVersion = '4.8.0' def junitVersion = '5.9.0' def jmhVersion = '1.35' def agronaVersion = '1.16.0' From e39a15d521880c65adabf0fc9504fca0986968cc Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 14 Sep 2022 17:14:35 +0100 Subject: [PATCH 125/805] [Java] Upgrade to Agrona 1.17.0. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ec7122c49c..60938e413c 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.8.0' def junitVersion = '5.9.0' def jmhVersion = '1.35' -def agronaVersion = '1.16.0' +def agronaVersion = '1.17.0' def agronaVersionRange = '[1.15.2,2.0[' // allow any release >= 1.15.2 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' From 6275f894b3a0298c67c902eefd39a6aa36845f81 Mon Sep 17 00:00:00 2001 From: mjpt777 Date: Wed, 14 Sep 2022 18:56:54 +0100 Subject: [PATCH 126/805] [Java] Upgrade to Agrona 1.17.1. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 60938e413c..582bed2752 100644 --- a/build.gradle +++ b/build.gradle @@ -47,8 +47,8 @@ def hamcrestVersion = '2.2' def mockitoVersion = '4.8.0' def junitVersion = '5.9.0' def jmhVersion = '1.35' -def agronaVersion = '1.17.0' -def agronaVersionRange = '[1.15.2,2.0[' // allow any release >= 1.15.2 and < 2.0.0 +def agronaVersion = '1.17.1' +def agronaVersionRange = '[1.17.1,2.0[' // allow any release >= 1.17.1 and < 2.0.0 def sbeGroup = 'uk.co.real-logic' def sbeVersion = file('version.txt').text.trim() From c23992114334f0e12d8a7da95ade4c19c0faa537 Mon Sep 17 00:00:00 2001 From: Michael Barker Date: Thu, 15 Sep 2022 13:45:45 +1200 Subject: [PATCH 127/805] [Java] Add support for transforming the schema to generate code for older versions. --- .gitignore | 2 + .../java/uk/co/real_logic/sbe/SbeTool.java | 32 ++++- .../sbe/xml/IdKeyedSchemaTransformer.java | 42 ++++++ .../co/real_logic/sbe/xml/MessageSchema.java | 34 ++++- .../real_logic/sbe/xml/SchemaTransformer.java | 35 +++++ .../sbe/xml/SchemaTransformerFactory.java | 88 ++++++++++++ .../xml/SinceVersionSchemaTransformer.java | 70 ++++++++++ ...onTransformedSchemaJavaGenerationTest.java | 73 ++++++++++ .../sbe/xml/SchemaTransformerFactoryTest.java | 67 +++++++++ .../SinceVersionSchemaTransformerTest.java | 132 ++++++++++++++++++ .../resources/since-version-filter-schema.xml | 118 ++++++++++++++++ 11 files changed, 687 insertions(+), 6 deletions(-) create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/IdKeyedSchemaTransformer.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformer.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactory.java create mode 100644 sbe-tool/src/main/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformer.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/generation/java/SinceVersionTransformedSchemaJavaGenerationTest.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SchemaTransformerFactoryTest.java create mode 100644 sbe-tool/src/test/java/uk/co/real_logic/sbe/xml/SinceVersionSchemaTransformerTest.java create mode 100644 sbe-tool/src/test/resources/since-version-filter-schema.xml diff --git a/.gitignore b/.gitignore index c7dcc86189..117022a886 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,5 @@ rust/Cargo.lock # Mac .DS_Store /sbe-tool/src/main/golang/uk_co_real_logic_sbe_ir_generated/ + +/generated/ diff --git a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java index 340de63f8f..cacf53a187 100644 --- a/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java +++ b/sbe-tool/src/main/java/uk/co/real_logic/sbe/SbeTool.java @@ -18,12 +18,20 @@ import org.agrona.DirectBuffer; import org.agrona.MutableDirectBuffer; import org.xml.sax.InputSource; -import uk.co.real_logic.sbe.generation.*; -import uk.co.real_logic.sbe.ir.*; +import uk.co.real_logic.sbe.generation.CodeGenerator; +import uk.co.real_logic.sbe.generation.TargetCodeGenerator; +import uk.co.real_logic.sbe.generation.TargetCodeGeneratorLoader; +import uk.co.real_logic.sbe.ir.Ir; +import uk.co.real_logic.sbe.ir.IrDecoder; +import uk.co.real_logic.sbe.ir.IrEncoder; import uk.co.real_logic.sbe.xml.*; -import java.io.*; -import java.nio.file.*; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; /** * A tool for running the SBE parser, validator, and code generator. @@ -176,6 +184,17 @@ public class SbeTool */ public static final String DECODE_UNKNOWN_ENUM_VALUES = "sbe.decode.unknown.enum.values"; + /** + * Configuration option used to manage sinceVersion based transformations. When set, parsed schemas will be + * transformed to discard messages and types higher than the specified version. This can be useful when needing + * to generate older versions of a schema to do version compatibility testing. + *

    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