private (string prepareBlock, string serializeBlock) GetStandardSerializeBlocks(int index, TableMemberModel memberModel)
        {
            string valueVariableName  = $"index{index}Value";
            string offsetVariableName = $"index{index}Offset";

            string condition = $"if ({valueVariableName} != {CSharpHelpers.GetDefaultValueToken(memberModel)})";

            if (memberModel.ItemTypeModel is VectorTypeModel vector && vector.IsMemoryVector)
            {
                // Memory is a struct and can't be null, and 0-length vectors are valid.
                // Therefore, we just need to omit the conditional check entirely.
                condition = string.Empty;
            }

            string prepareBlock =
                $@"
                    var {valueVariableName} = item.{memberModel.PropertyInfo.Name};
                    int {offsetVariableName} = 0;
                    {condition} 
                    {{
                            currentOffset += {CSharpHelpers.GetFullMethodName(ReflectedMethods.SerializationHelpers_GetAlignmentErrorMethod)}(currentOffset, {memberModel.ItemTypeModel.Alignment});
                            {offsetVariableName} = currentOffset;
                            vtable.{nameof(VTableBuilder.SetOffset)}({index}, currentOffset - tableStart);
                            currentOffset += {memberModel.ItemTypeModel.InlineSize};
                    }}";

            string serializeBlock =
                $@"
                    if ({offsetVariableName} != 0)
                    {{
                        {this.GetSerializeInvocation(memberModel.ItemTypeModel.ClrType, valueVariableName, offsetVariableName)}
                    }}";

            return(prepareBlock, serializeBlock);
        }
Esempio n. 2
0
        /// <summary>
        /// Generates a special property getter for union types. This stems from
        /// the fact that unions occupy two spots in the table's vtable to deserialize one
        /// logical field. This means that the logic to read them must also be special.
        /// </summary>
        private GeneratedProperty CreateUnionTableGetter(TableMemberModel memberModel, int index)
        {
            Type           propertyType = memberModel.ItemTypeModel.ClrType;
            string         defaultValue = CSharpHelpers.GetDefaultValueToken(memberModel);
            UnionTypeModel unionModel   = (UnionTypeModel)memberModel.ItemTypeModel;

            GeneratedProperty generatedProperty = new GeneratedProperty(this.options, index, memberModel.PropertyInfo);

            // Start by generating switch cases. The codegen'ed union types have
            // well-defined constructors for each constituent type, so this .ctor
            // will always be available.
            List <string> switchCases = new List <string>();

            for (int i = 0; i < unionModel.UnionElementTypeModel.Length; ++i)
            {
                var    unionMember            = unionModel.UnionElementTypeModel[i];
                int    unionIndex             = i + 1;
                string structOffsetAdjustment = string.Empty;
                if (unionMember.SchemaType == FlatBufferSchemaType.Struct)
                {
                    structOffsetAdjustment = $"offsetLocation += buffer.{nameof(InputBuffer.ReadUOffset)}(offsetLocation);";
                }

                string @case =
                    $@"
                    case {unionIndex}:
                        {structOffsetAdjustment}
                        return new {CSharpHelpers.GetCompilableTypeName(unionModel.ClrType)}({this.GetReadInvocation(unionMember.ClrType, "buffer", "offsetLocation")});
";
                switchCases.Add(@case);
            }


            generatedProperty.ReadValueMethodDefinition =
                $@"
                    [MethodImpl(MethodImplOptions.AggressiveInlining)]
                    private static {CSharpHelpers.GetCompilableTypeName(propertyType)} {generatedProperty.ReadValueMethodName}(InputBuffer buffer, int offset)
                    {{
                        int discriminatorLocation = buffer.{nameof(InputBuffer.GetAbsoluteTableFieldLocation)}(offset, {index});
                        int offsetLocation = buffer.{nameof(InputBuffer.GetAbsoluteTableFieldLocation)}(offset, {index + 1});
                            
                        if (discriminatorLocation == 0) {{
                            return {defaultValue};
                        }}
                        else {{
                            byte discriminator = buffer.{nameof(InputBuffer.ReadByte)}(discriminatorLocation);
                            if (discriminator == 0 && offsetLocation != 0)
                                throw new System.IO.InvalidDataException(""FlatBuffer union had discriminator set but no offset."");
                            switch (discriminator)
                            {{
                                {string.Join("\r\n", switchCases)}
                                default:
                                    return {defaultValue};
                            }}
                        }}
                    }}
";
            return(generatedProperty);
        }
Esempio n. 3
0
        /// <summary>
        /// Generates a standard getter for a normal vtable entry.
        /// </summary>
        private GeneratedProperty CreateStandardTableProperty(TableMemberModel memberModel, int index)
        {
            Type              propertyType = memberModel.ItemTypeModel.ClrType;
            string            defaultValue = CSharpHelpers.GetDefaultValueToken(memberModel);
            GeneratedProperty property     = new GeneratedProperty(this.options, index, memberModel.PropertyInfo);

            property.ReadValueMethodDefinition =
                $@"
                    [MethodImpl(MethodImplOptions.AggressiveInlining)]
                    private static {CSharpHelpers.GetCompilableTypeName(propertyType)} {property.ReadValueMethodName}(InputBuffer buffer, int offset)
                    {{
                        int absoluteLocation = buffer.{nameof(InputBuffer.GetAbsoluteTableFieldLocation)}(offset, {index});
                        if (absoluteLocation == 0) {{
                            return {defaultValue};
                        }}
                        else {{
                            return {this.GetReadInvocation(propertyType, "buffer", "absoluteLocation")};
                        }}
                    }}
";

            return(property);
        }
        private (string prepareBlock, string serializeBlock) GetStandardSerializeBlocks(int index, TableMemberModel memberModel)
        {
            string valueVariableName  = $"index{index}Value";
            string offsetVariableName = $"index{index}Offset";

            string condition = $"if ({valueVariableName} != {CSharpHelpers.GetDefaultValueToken(memberModel)})";

            if ((memberModel.ItemTypeModel is VectorTypeModel vector && vector.IsMemoryVector) || memberModel.IsKey)
            {
                // 1) Memory is a struct and can't be null, and 0-length vectors are valid.
                //    Therefore, we just need to omit the conditional check entirely.

                // 2) For sorted vector keys, we must include the value since some other
                //    libraries cannot do binary search with omitted keys.
                condition = string.Empty;
            }

            string keyCheckMethodCall = string.Empty;

            if (memberModel.IsKey)
            {
                keyCheckMethodCall = $"{nameof(SortedVectorHelpers)}.{nameof(SortedVectorHelpers.EnsureKeyNonNull)}({valueVariableName});";
            }

            string prepareBlock =
                $@"
                    var {valueVariableName} = item.{memberModel.PropertyInfo.Name};
                    int {offsetVariableName} = 0;
                    {keyCheckMethodCall}
                    {condition} 
                    {{
                            currentOffset += {CSharpHelpers.GetFullMethodName(ReflectedMethods.SerializationHelpers_GetAlignmentErrorMethod)}(currentOffset, {memberModel.ItemTypeModel.Alignment});
                            {offsetVariableName} = currentOffset;
                            vtable.{nameof(VTableBuilder.SetOffset)}({index}, currentOffset - tableStart);
                            currentOffset += {memberModel.ItemTypeModel.InlineSize};
                    }}";

            string sortInvocation = string.Empty;

            if (memberModel.IsSortedVector)
            {
                VectorTypeModel  vectorModel = (VectorTypeModel)memberModel.ItemTypeModel;
                TableTypeModel   tableModel  = (TableTypeModel)vectorModel.ItemTypeModel;
                TableMemberModel keyMember   = tableModel.IndexToMemberMap.Single(x => x.Value.PropertyInfo == tableModel.KeyProperty).Value;

                var    builtInType = BuiltInType.BuiltInTypes[keyMember.ItemTypeModel.ClrType];
                string inlineSize  = builtInType.TypeModel.SchemaType == FlatBufferSchemaType.Scalar ? builtInType.TypeModel.InlineSize.ToString() : "null";

                sortInvocation = $"{nameof(SortedVectorHelpers)}.{nameof(SortedVectorHelpers.SortVector)}(" +
                                 $"span, {offsetVariableName}, {keyMember.Index}, {inlineSize}, {CSharpHelpers.GetCompilableTypeName(builtInType.SpanComparerType)}.Instance);";
            }

            string serializeBlock =
                $@"
                    if ({offsetVariableName} != 0)
                    {{
                        {this.GetSerializeInvocation(memberModel.ItemTypeModel.ClrType, valueVariableName, offsetVariableName)}
                        {sortInvocation}
                    }}";

            return(prepareBlock, serializeBlock);
        }