diff --git a/src/idl_gen_csharp.cpp b/src/idl_gen_csharp.cpp index cfa51bc117e..a8c807514b3 100644 --- a/src/idl_gen_csharp.cpp +++ b/src/idl_gen_csharp.cpp @@ -43,6 +43,20 @@ class CSharpGenerator : public BaseGenerator { int length; }; + // Check if a struct (or any of its nested structs) contains array fields. + // Used to decide whether Create/Pack methods need Span overloads. + bool StructHasArrayFields(const StructDef& struct_def) const { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto& field = **it; + if (IsArray(field.value.type)) return true; + if (IsStruct(field.value.type) && + StructHasArrayFields(*field.value.type.struct_def)) + return true; + } + return false; + } + public: CSharpGenerator(const Parser& parser, const std::string& path, const std::string& file_name) @@ -536,9 +550,11 @@ class CSharpGenerator : public BaseGenerator { } // Recursively generate arguments for a constructor, to deal with nested - // structs. + // structs. When use_span is true, array parameters use Span instead of + // T[] or T[,] for zero-allocation struct creation. void GenStructArgs(const StructDef& struct_def, std::string* code_ptr, - const char* nameprefix, size_t array_count = 0) const { + const char* nameprefix, size_t array_count = 0, + bool use_span = false) const { std::string& code = *code_ptr; for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { @@ -553,17 +569,21 @@ class CSharpGenerator : public BaseGenerator { // a nested struct, prefix the name with the field name. GenStructArgs(*field_type.struct_def, code_ptr, (nameprefix + (EscapeKeyword(field.name) + "_")).c_str(), - array_cnt); + array_cnt, use_span); } else { code += ", "; - code += GenTypeBasic(type); - if (field.IsScalarOptional()) { - code += "?"; - } - if (array_cnt > 0) { - code += "["; - for (size_t i = 1; i < array_cnt; i++) code += ","; - code += "]"; + if (use_span && array_cnt > 0) { + code += "ReadOnlySpan<" + GenTypeBasic(type) + ">"; + } else { + code += GenTypeBasic(type); + if (field.IsScalarOptional()) { + code += "?"; + } + if (array_cnt > 0) { + code += "["; + for (size_t i = 1; i < array_cnt; i++) code += ","; + code += "]"; + } } code += " "; code += nameprefix; @@ -574,10 +594,12 @@ class CSharpGenerator : public BaseGenerator { // Recusively generate struct construction statements of the form: // builder.putType(name); - // and insert manual padding. + // and insert manual padding. When use_span is true, multi-dimensional array + // accesses use flat indexing (e.g. [i*N+j]) instead of [i,j]. void GenStructBody(const StructDef& struct_def, std::string* code_ptr, const char* nameprefix, size_t index = 0, - bool in_array = false) const { + bool in_array = false, bool use_span = false, + std::vector array_dims = {}) const { std::string& code = *code_ptr; std::string indent((index + 1) * 2, ' '); code += indent + " builder.Prep("; @@ -594,21 +616,23 @@ class CSharpGenerator : public BaseGenerator { if (IsStruct(field_type)) { GenStructBody(*field_type.struct_def, code_ptr, (nameprefix + (field.name + "_")).c_str(), index, - in_array); + in_array, use_span, array_dims); } else { const auto& type = IsArray(field_type) ? field_type.VectorType() : field_type; const auto index_var = "_idx" + NumToString(index); + auto current_dims = array_dims; if (IsArray(field_type)) { code += indent + " for (int " + index_var + " = "; code += NumToString(field_type.fixed_length); code += "; " + index_var + " > 0; " + index_var + "--) {\n"; in_array = true; + current_dims.push_back(field_type.fixed_length); } if (IsStruct(type)) { GenStructBody(*field_type.struct_def, code_ptr, (nameprefix + (field.name + "_")).c_str(), index + 1, - in_array); + in_array, use_span, current_dims); } else { code += IsArray(field_type) ? " " : ""; code += indent + " builder.Put"; @@ -619,9 +643,24 @@ class CSharpGenerator : public BaseGenerator { size_t array_cnt = index + (IsArray(field_type) ? 1 : 0); if (array_cnt > 0) { code += "["; - for (size_t i = 0; in_array && i < array_cnt; i++) { - code += "_idx" + NumToString(i) + "-1"; - if (i != (array_cnt - 1)) code += ","; + if (use_span && in_array && array_cnt > 1) { + // Flat indexing for Span: [(_idx0-1)*stride + (_idx1-1)] + for (size_t i = 0; i < array_cnt; i++) { + if (i > 0) code += " + "; + code += "(_idx" + NumToString(i) + "-1)"; + int stride = 1; + for (size_t j = i + 1; j < current_dims.size(); j++) { + stride *= current_dims[j]; + } + if (stride > 1) { + code += "*" + NumToString(stride); + } + } + } else { + for (size_t i = 0; in_array && i < array_cnt; i++) { + code += "_idx" + NumToString(i) + "-1"; + if (i != (array_cnt - 1)) code += ","; + } } code += "]"; } @@ -1374,7 +1413,22 @@ class CSharpGenerator : public BaseGenerator { flatbuffers::FieldDef* key_field = nullptr; if (struct_def.fixed) { struct_has_create = true; - // create a struct constructor function + const bool has_arrays = StructHasArrayFields(struct_def); + if (has_arrays) { + // Span version: array params become Span, multi-dim uses flat index + code += "#if ENABLE_SPAN_T\n"; + code += " public static " + GenOffsetType(struct_def) + " "; + code += "Create"; + code += struct_def.name + "(FlatBufferBuilder builder"; + GenStructArgs(struct_def, code_ptr, "", 0, true); + code += ") {\n"; + GenStructBody(struct_def, code_ptr, "", 0, false, true); + code += " return "; + code += GenOffsetConstruct(struct_def, "builder.Offset"); + code += ";\n }\n"; + code += "#else\n"; + } + // Original version (also the only version when no arrays) code += " public static " + GenOffsetType(struct_def) + " "; code += "Create"; code += struct_def.name + "(FlatBufferBuilder builder"; @@ -1384,6 +1438,9 @@ class CSharpGenerator : public BaseGenerator { code += " return "; code += GenOffsetConstruct(struct_def, "builder.Offset"); code += ";\n }\n"; + if (has_arrays) { + code += "#endif\n"; + } } else { // Generate a method that creates a table in one go. This is only possible // when the table has no struct fields, since those have to be created @@ -2365,6 +2422,73 @@ class CSharpGenerator : public BaseGenerator { code += " }\n"; } + // Generate one pack declaration: either flat (for Span) or multi-dim. + void GenPackDeclArray(std::string& code, const std::string& name, + const Type& field_type, + const std::vector& array_lengths, + const std::vector& array_only_lengths, + bool flat) const { + code += " var " + name + " = "; + code += "new " + GenTypeBasic(field_type) + "["; + if (flat) { + int total = 1; + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + total *= array_only_lengths[i].length; + } + code += NumToString(total); + } else { + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + if (i != 0) code += ","; + code += NumToString(array_only_lengths[i].length); + } + } + code += "];\n"; + code += " "; + // initialize array + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + auto idx = "idx" + NumToString(i); + code += "for (var " + idx + " = 0; " + idx + " < " + + NumToString(array_only_lengths[i].length) + "; ++" + idx + + ") {"; + } + if (flat) { + // flat indexing: name[idx0*d1 + idx1] + code += name + "["; + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + if (i > 0) code += " + "; + code += "idx" + NumToString(i); + int stride = 1; + for (size_t j = i + 1; j < array_only_lengths.size(); ++j) { + stride *= array_only_lengths[j].length; + } + if (stride > 1) code += "*" + NumToString(stride); + } + code += "]"; + } else { + // multi-dim indexing: name[idx0,idx1] + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + auto idx = "idx" + NumToString(i); + if (i == 0) { + code += name + "[" + idx; + } else { + code += "," + idx; + } + } + code += "]"; + } + code += " = _o"; + for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) { + code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel); + if (array_lengths[i].length <= 0) continue; + code += "[idx" + NumToString(j++) + "]"; + } + code += ";"; + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + code += "}"; + } + code += "\n"; + } + void GenStructPackDecl_ObjectAPI( const StructDef& struct_def, std::string* code_ptr, std::vector& array_lengths) const { @@ -2394,50 +2518,25 @@ class CSharpGenerator : public BaseGenerator { for (size_t i = 0; i < array_lengths.size(); ++i) { name += "_" + array_lengths[i].name; } - code += " var " + name + " = "; - if (array_only_lengths.size() > 0) { - code += "new " + GenTypeBasic(field_type) + "["; - for (size_t i = 0; i < array_only_lengths.size(); ++i) { - if (i != 0) { - code += ","; - } - code += NumToString(array_only_lengths[i].length); - } - code += "];\n"; - code += " "; - // initialize array - for (size_t i = 0; i < array_only_lengths.size(); ++i) { - auto idx = "idx" + NumToString(i); - code += "for (var " + idx + " = 0; " + idx + " < " + - NumToString(array_only_lengths[i].length) + "; ++" + idx + - ") {"; - } - for (size_t i = 0; i < array_only_lengths.size(); ++i) { - auto idx = "idx" + NumToString(i); - if (i == 0) { - code += name + "[" + idx; - } else { - code += "," + idx; - } - } - code += "] = _o"; - for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) { - code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel); - if (array_lengths[i].length <= 0) continue; - code += "[idx" + NumToString(j++) + "]"; - } - code += ";"; - for (size_t i = 0; i < array_only_lengths.size(); ++i) { - code += "}"; - } + if (array_only_lengths.size() > 1) { + // Multi-dim case: needs flat arrays for Span, multi-dim for legacy + code += "#if ENABLE_SPAN_T\n"; + GenPackDeclArray(code, name, field_type, array_lengths, + array_only_lengths, true); + code += "#else\n"; + GenPackDeclArray(code, name, field_type, array_lengths, + array_only_lengths, false); + code += "#endif\n"; + } else if (array_only_lengths.size() == 1) { + GenPackDeclArray(code, name, field_type, array_lengths, + array_only_lengths, false); } else { - code += "_o"; + code += " var " + name + " = _o"; for (size_t i = 0; i < array_lengths.size(); ++i) { code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel); } - code += ";"; + code += ";\n"; } - code += "\n"; } array_lengths.pop_back(); } diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs index d5774571c86..49386626820 100644 --- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs +++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs @@ -398,22 +398,32 @@ public void TestFixedLenghtArrays() float a; int[] b = new int[15]; sbyte c; - int[,] d_a = new int[2, 2]; TestEnum[] d_b = new TestEnum[2]; - TestEnum[,] d_c = new TestEnum[2, 2]; - long[,] d_d = new long[2, 2]; int e; long[] f = new long[2]; a = 0.5f; for (int i = 0; i < 15; i++) b[i] = i; c = 1; + d_b[0] = TestEnum.B; + d_b[1] = TestEnum.C; + e = 2; + f[0] = -1; + f[1] = 1; + +#if ENABLE_SPAN_T + // Flat arrays for Span parameters + int[] d_a = new int[] { 1, 2, 3, 4 }; + TestEnum[] d_c = new TestEnum[] { TestEnum.A, TestEnum.B, TestEnum.C, TestEnum.B }; + long[] d_d = new long[] { -1, 1, -2, 2 }; +#else + int[,] d_a = new int[2, 2]; + TestEnum[,] d_c = new TestEnum[2, 2]; + long[,] d_d = new long[2, 2]; d_a[0, 0] = 1; d_a[0, 1] = 2; d_a[1, 0] = 3; d_a[1, 1] = 4; - d_b[0] = TestEnum.B; - d_b[1] = TestEnum.C; d_c[0, 0] = TestEnum.A; d_c[0, 1] = TestEnum.B; d_c[1, 0] = TestEnum.C; @@ -422,9 +432,7 @@ public void TestFixedLenghtArrays() d_d[0, 1] = 1; d_d[1, 0] = -2; d_d[1, 1] = 2; - e = 2; - f[0] = -1; - f[1] = 1; +#endif Offset arrayOffset = ArrayStruct.CreateArrayStruct( builder, a, b, c, d_a, d_b, d_c, d_d, e, f); diff --git a/tests/FlatBuffers.Test/FlatBuffersFixedLengthArrayTests.cs b/tests/FlatBuffers.Test/FlatBuffersFixedLengthArrayTests.cs index 1c9a8f327d0..95fc87d3ea2 100644 --- a/tests/FlatBuffers.Test/FlatBuffersFixedLengthArrayTests.cs +++ b/tests/FlatBuffers.Test/FlatBuffersFixedLengthArrayTests.cs @@ -109,10 +109,11 @@ public void FixedLengthArray_GetBytesSpanEquality_ReturnTrue() var intE = 999; var longArray = new long[] { 5000L, 6000L }; - var nestedInts = new int[2, 2] { { 10, 20 }, { 30, 40 } }; + // Flat arrays for Span parameters + var nestedInts = new int[] { 10, 20, 30, 40 }; var nestedEnumB = new TestEnum[] { TestEnum.A, TestEnum.B }; - var nestedEnums = new TestEnum[2, 2] { { TestEnum.A, TestEnum.B }, { TestEnum.C, TestEnum.A } }; - var nestedLongs = new long[2, 2] { { 100L, 200L }, { 300L, 400L } }; + var nestedEnums = new TestEnum[] { TestEnum.A, TestEnum.B, TestEnum.C, TestEnum.A }; + var nestedLongs = new long[] { 100L, 200L, 300L, 400L }; var structOffset = ArrayStruct.CreateArrayStruct(builder, floatA, intArray, byteC, nestedInts, nestedEnumB, nestedEnums, nestedLongs, intE, longArray); @@ -132,28 +133,54 @@ public void FixedLengthArray_GetBytesSpanEquality_ReturnTrue() Assert.IsTrue(arrayStruct.GetBBytes().SequenceEqual(intArray)); Assert.IsTrue(arrayStruct.GetFBytes().SequenceEqual(longArray)); - - // Test nested struct arrays + + // Test nested struct arrays via individual element access for (int i = 0; i < 2; i++) { var nestedStruct = arrayStruct.D(i); - + var nestedIntSpan = nestedStruct.GetABytes(); - var expectedNestedInts = new int[] { nestedInts[i, 0], nestedInts[i, 1] }; + var expectedNestedInts = new int[] { nestedInts[i * 2], nestedInts[i * 2 + 1] }; Assert.IsTrue(nestedIntSpan.SequenceEqual(expectedNestedInts)); - + Assert.AreEqual(nestedEnumB[i], nestedStruct.B); - + var nestedEnumSpan = nestedStruct.GetCBytes(); - var expectedNestedEnums = new TestEnum[] { nestedEnums[i, 0], nestedEnums[i, 1] }; + var expectedNestedEnums = new TestEnum[] { nestedEnums[i * 2], nestedEnums[i * 2 + 1] }; Assert.IsTrue(nestedEnumSpan.SequenceEqual(expectedNestedEnums)); - + var nestedLongSpan = nestedStruct.GetDBytes(); - var expectedNestedLongs = new long[] { nestedLongs[i, 0], nestedLongs[i, 1] }; + var expectedNestedLongs = new long[] { nestedLongs[i * 2], nestedLongs[i * 2 + 1] }; Assert.IsTrue(nestedLongSpan.SequenceEqual(expectedNestedLongs)); } } -#endif + + [FlatBuffersTestMethod] + public void FixedLengthArray_CreateWithStackalloc_ReturnTrue() + { + var builder = new FlatBufferBuilder(1024); + + // Demonstrate zero-allocation struct creation with stackalloc + Span a = stackalloc int[] { 7, 8 }; + Span c = stackalloc TestEnum[] { TestEnum.B, TestEnum.C }; + Span d = stackalloc long[] { 42L, 43L }; + + var structOffset = NestedStruct.CreateNestedStruct(builder, a, TestEnum.A, c, d); + builder.Finish(structOffset.Value); + + var buffer = builder.DataBuffer; + var nestedStruct = new NestedStruct(); + nestedStruct.__assign(buffer.Length - builder.Offset, buffer); + + Assert.AreEqual(7, nestedStruct.A(0)); + Assert.AreEqual(8, nestedStruct.A(1)); + Assert.AreEqual(TestEnum.A, nestedStruct.B); + Assert.AreEqual(TestEnum.B, nestedStruct.C(0)); + Assert.AreEqual(TestEnum.C, nestedStruct.C(1)); + Assert.AreEqual(42L, nestedStruct.D(0)); + Assert.AreEqual(43L, nestedStruct.D(1)); + } +#endif #if !ENABLE_SPAN_T [FlatBuffersTestMethod] diff --git a/tests/MyGame/Example/ArrayStruct.cs b/tests/MyGame/Example/ArrayStruct.cs index bb601d173b8..6225568ada6 100644 --- a/tests/MyGame/Example/ArrayStruct.cs +++ b/tests/MyGame/Example/ArrayStruct.cs @@ -40,6 +40,37 @@ public struct ArrayStruct : IFlatbufferObject #endif public void MutateF(int j, long f) { __p.bb.PutLong(__p.bb_pos + 144 + j * 8, f); } +#if ENABLE_SPAN_T + public static Offset CreateArrayStruct(FlatBufferBuilder builder, float A, ReadOnlySpan B, sbyte C, ReadOnlySpan d_A, ReadOnlySpan d_B, ReadOnlySpan d_C, ReadOnlySpan d_D, int E, ReadOnlySpan F) { + builder.Prep(8, 160); + for (int _idx0 = 2; _idx0 > 0; _idx0--) { + builder.PutLong(F[_idx0-1]); + } + builder.Pad(4); + builder.PutInt(E); + for (int _idx0 = 2; _idx0 > 0; _idx0--) { + builder.Prep(8, 32); + for (int _idx1 = 2; _idx1 > 0; _idx1--) { + builder.PutLong(d_D[(_idx0-1)*2 + (_idx1-1)]); + } + builder.Pad(5); + for (int _idx1 = 2; _idx1 > 0; _idx1--) { + builder.PutSbyte((sbyte)d_C[(_idx0-1)*2 + (_idx1-1)]); + } + builder.PutSbyte((sbyte)d_B[_idx0-1]); + for (int _idx1 = 2; _idx1 > 0; _idx1--) { + builder.PutInt(d_A[(_idx0-1)*2 + (_idx1-1)]); + } + } + builder.Pad(7); + builder.PutSbyte(C); + for (int _idx0 = 15; _idx0 > 0; _idx0--) { + builder.PutInt(B[_idx0-1]); + } + builder.PutFloat(A); + return new Offset(builder.Offset); + } +#else public static Offset CreateArrayStruct(FlatBufferBuilder builder, float A, int[] B, sbyte C, int[,] d_A, MyGame.Example.TestEnum[] d_B, MyGame.Example.TestEnum[,] d_C, long[,] d_D, int E, long[] F) { builder.Prep(8, 160); for (int _idx0 = 2; _idx0 > 0; _idx0--) { @@ -69,6 +100,7 @@ public struct ArrayStruct : IFlatbufferObject builder.PutFloat(A); return new Offset(builder.Offset); } +#endif public ArrayStructT UnPack() { var _o = new ArrayStructT(); this.UnPackTo(_o); @@ -88,14 +120,29 @@ public void UnPackTo(ArrayStructT _o) { public static Offset Pack(FlatBufferBuilder builder, ArrayStructT _o) { if (_o == null) return default(Offset); var _b = _o.B; +#if ENABLE_SPAN_T + var _d_a = new int[4]; + for (var idx0 = 0; idx0 < 2; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_d_a[idx0*2 + idx1] = _o.D[idx0].A[idx1];}} +#else var _d_a = new int[2,2]; for (var idx0 = 0; idx0 < 2; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_d_a[idx0,idx1] = _o.D[idx0].A[idx1];}} +#endif var _d_b = new MyGame.Example.TestEnum[2]; for (var idx0 = 0; idx0 < 2; ++idx0) {_d_b[idx0] = _o.D[idx0].B;} +#if ENABLE_SPAN_T + var _d_c = new MyGame.Example.TestEnum[4]; + for (var idx0 = 0; idx0 < 2; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_d_c[idx0*2 + idx1] = _o.D[idx0].C[idx1];}} +#else var _d_c = new MyGame.Example.TestEnum[2,2]; for (var idx0 = 0; idx0 < 2; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_d_c[idx0,idx1] = _o.D[idx0].C[idx1];}} +#endif +#if ENABLE_SPAN_T + var _d_d = new long[4]; + for (var idx0 = 0; idx0 < 2; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_d_d[idx0*2 + idx1] = _o.D[idx0].D[idx1];}} +#else var _d_d = new long[2,2]; for (var idx0 = 0; idx0 < 2; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_d_d[idx0,idx1] = _o.D[idx0].D[idx1];}} +#endif var _f = _o.F; return CreateArrayStruct( builder, diff --git a/tests/MyGame/Example/LargeArrayStruct.cs b/tests/MyGame/Example/LargeArrayStruct.cs index 3a38b02a0f2..2940d8e537a 100644 --- a/tests/MyGame/Example/LargeArrayStruct.cs +++ b/tests/MyGame/Example/LargeArrayStruct.cs @@ -50,6 +50,38 @@ public struct LargeArrayStruct : IFlatbufferObject #endif public void MutateH(int j, MyGame.Example.TestEnum h) { __p.bb.PutSbyte(__p.bb_pos + 2432 + j * 1, (sbyte)h); } +#if ENABLE_SPAN_T + public static Offset CreateLargeArrayStruct(FlatBufferBuilder builder, ReadOnlySpan D, ReadOnlySpan E, ReadOnlySpan F, ReadOnlySpan g_A, ReadOnlySpan g_B, ReadOnlySpan g_C, ReadOnlySpan g_D, ReadOnlySpan H) { + builder.Prep(8, 2496); + for (int _idx0 = 64; _idx0 > 0; _idx0--) { + builder.PutSbyte((sbyte)H[_idx0-1]); + } + for (int _idx0 = 64; _idx0 > 0; _idx0--) { + builder.Prep(8, 32); + for (int _idx1 = 2; _idx1 > 0; _idx1--) { + builder.PutLong(g_D[(_idx0-1)*2 + (_idx1-1)]); + } + builder.Pad(5); + for (int _idx1 = 2; _idx1 > 0; _idx1--) { + builder.PutSbyte((sbyte)g_C[(_idx0-1)*2 + (_idx1-1)]); + } + builder.PutSbyte((sbyte)g_B[_idx0-1]); + for (int _idx1 = 2; _idx1 > 0; _idx1--) { + builder.PutInt(g_A[(_idx0-1)*2 + (_idx1-1)]); + } + } + for (int _idx0 = 64; _idx0 > 0; _idx0--) { + builder.PutBool(F[_idx0-1]); + } + for (int _idx0 = 64; _idx0 > 0; _idx0--) { + builder.PutFloat(E[_idx0-1]); + } + for (int _idx0 = 64; _idx0 > 0; _idx0--) { + builder.PutByte(D[_idx0-1]); + } + return new Offset(builder.Offset); + } +#else public static Offset CreateLargeArrayStruct(FlatBufferBuilder builder, byte[] D, float[] E, bool[] F, int[,] g_A, MyGame.Example.TestEnum[] g_B, MyGame.Example.TestEnum[,] g_C, long[,] g_D, MyGame.Example.TestEnum[] H) { builder.Prep(8, 2496); for (int _idx0 = 64; _idx0 > 0; _idx0--) { @@ -80,6 +112,7 @@ public struct LargeArrayStruct : IFlatbufferObject } return new Offset(builder.Offset); } +#endif public LargeArrayStructT UnPack() { var _o = new LargeArrayStructT(); this.UnPackTo(_o); @@ -102,14 +135,29 @@ public void UnPackTo(LargeArrayStructT _o) { var _d = _o.D; var _e = _o.E; var _f = _o.F; +#if ENABLE_SPAN_T + var _g_a = new int[128]; + for (var idx0 = 0; idx0 < 64; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_g_a[idx0*2 + idx1] = _o.G[idx0].A[idx1];}} +#else var _g_a = new int[64,2]; for (var idx0 = 0; idx0 < 64; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_g_a[idx0,idx1] = _o.G[idx0].A[idx1];}} +#endif var _g_b = new MyGame.Example.TestEnum[64]; for (var idx0 = 0; idx0 < 64; ++idx0) {_g_b[idx0] = _o.G[idx0].B;} +#if ENABLE_SPAN_T + var _g_c = new MyGame.Example.TestEnum[128]; + for (var idx0 = 0; idx0 < 64; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_g_c[idx0*2 + idx1] = _o.G[idx0].C[idx1];}} +#else var _g_c = new MyGame.Example.TestEnum[64,2]; for (var idx0 = 0; idx0 < 64; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_g_c[idx0,idx1] = _o.G[idx0].C[idx1];}} +#endif +#if ENABLE_SPAN_T + var _g_d = new long[128]; + for (var idx0 = 0; idx0 < 64; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_g_d[idx0*2 + idx1] = _o.G[idx0].D[idx1];}} +#else var _g_d = new long[64,2]; for (var idx0 = 0; idx0 < 64; ++idx0) {for (var idx1 = 0; idx1 < 2; ++idx1) {_g_d[idx0,idx1] = _o.G[idx0].D[idx1];}} +#endif var _h = _o.H; return CreateLargeArrayStruct( builder, diff --git a/tests/MyGame/Example/NestedStruct.cs b/tests/MyGame/Example/NestedStruct.cs index 84e70d0b0eb..911b70aaadd 100644 --- a/tests/MyGame/Example/NestedStruct.cs +++ b/tests/MyGame/Example/NestedStruct.cs @@ -43,6 +43,23 @@ public struct NestedStruct : IFlatbufferObject #endif public void MutateD(int j, long d) { __p.bb.PutLong(__p.bb_pos + 16 + j * 8, d); } +#if ENABLE_SPAN_T + public static Offset CreateNestedStruct(FlatBufferBuilder builder, ReadOnlySpan A, MyGame.Example.TestEnum B, ReadOnlySpan C, ReadOnlySpan D) { + builder.Prep(8, 32); + for (int _idx0 = 2; _idx0 > 0; _idx0--) { + builder.PutLong(D[_idx0-1]); + } + builder.Pad(5); + for (int _idx0 = 2; _idx0 > 0; _idx0--) { + builder.PutSbyte((sbyte)C[_idx0-1]); + } + builder.PutSbyte((sbyte)B); + for (int _idx0 = 2; _idx0 > 0; _idx0--) { + builder.PutInt(A[_idx0-1]); + } + return new Offset(builder.Offset); + } +#else public static Offset CreateNestedStruct(FlatBufferBuilder builder, int[] A, MyGame.Example.TestEnum B, MyGame.Example.TestEnum[] C, long[] D) { builder.Prep(8, 32); for (int _idx0 = 2; _idx0 > 0; _idx0--) { @@ -58,6 +75,7 @@ public struct NestedStruct : IFlatbufferObject } return new Offset(builder.Offset); } +#endif public NestedStructT UnPack() { var _o = new NestedStructT(); this.UnPackTo(_o);