Пример #1
0
        internal static string GetDefaultValueToken(TableMemberModel memberModel)
        {
            var itemTypeModel = memberModel.ItemTypeModel;
            var clrType       = itemTypeModel.ClrType;

            string defaultValue = $"default({GetCompilableTypeName(memberModel.ItemTypeModel.ClrType)})";

            if (memberModel.HasDefaultValue)
            {
                if (BuiltInType.BuiltInScalars.TryGetValue(clrType, out IBuiltInScalarType builtInType))
                {
                    return(builtInType.FormatObject(memberModel.DefaultValue));
                }
                else if (clrType.IsEnum)
                {
                    return($"{CSharpHelpers.GetCompilableTypeName(clrType)}.{memberModel.DefaultValue}");
                }
                else
                {
                    throw new InvalidOperationException("Unexpected default value type: " + clrType.FullName);
                }
            }

            return(defaultValue);
        }
Пример #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);
        }
Пример #3
0
    public override Type OnInitialize()
    {
        FlatSharpInternal.Assert(
            this.ClrType.IsGenericType && this.ClrType.GetGenericTypeDefinition() == typeof(IIndexedVector <,>),
            $"Indexed vectors must be of type IIndexedVector. Type = {this.GetCompilableTypeName()}.");

        Type keyType   = this.ClrType.GetGenericArguments()[0];
        Type valueType = this.ClrType.GetGenericArguments()[1];

        this.keyTypeModel   = this.typeModelContainer.CreateTypeModel(keyType);
        this.valueTypeModel = this.typeModelContainer.CreateTypeModel(valueType);

        if (this.valueTypeModel.SchemaType != FlatBufferSchemaType.Table)
        {
            throw new InvalidFlatBufferDefinitionException(
                      $"Indexed vector values must be flatbuffer tables. Type = '{this.valueTypeModel.GetCompilableTypeName()}'");
        }

        if (!this.valueTypeModel.TryGetTableKeyMember(out TableMemberModel? tempKeyMemberModel))
        {
            throw new InvalidFlatBufferDefinitionException(
                      $"Indexed vector values must have a property with the key attribute defined. Table = '{this.valueTypeModel.GetCompilableTypeName()}'");
        }
        else
        {
            this.keyMemberModel = tempKeyMemberModel;
        }

        if (!this.keyMemberModel.ItemTypeModel.TryGetSpanComparerType(out _))
        {
            throw new InvalidFlatBufferDefinitionException(
                      $"FlatSharp indexed vector keys must supply a span comparer. KeyType = '{this.keyMemberModel.ItemTypeModel.GetCompilableTypeName()}'.");
        }

        if (keyMemberModel.ItemTypeModel.ClrType != this.keyTypeModel.ClrType)
        {
            throw new InvalidFlatBufferDefinitionException(
                      $"FlatSharp indexed vector keys must have the same type as the key of the value. KeyType = {this.keyTypeModel.GetCompilableTypeName()}, Value Key Type = '{this.valueTypeModel.GetCompilableTypeName()}'.");
        }

        return(valueType);
    }
Пример #4
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)
            {
                // 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);
        }
        private (string prepareBlock, string serializeBlock) GetUnionSerializeBlocks(int index, TableMemberModel memberModel)
        {
            UnionTypeModel unionModel = (UnionTypeModel)memberModel.ItemTypeModel;

            string valueVariableName = $"index{index}Value";
            string discriminatorOffsetVariableName = $"index{index}DiscriminatorOffset";
            string valueOffsetVariableName         = $"index{index}ValueOffset";
            string discriminatorValueVariableName  = $"index{index}Discriminator";

            string prepareBlock =
                $@"
                    var {valueVariableName} = item.{memberModel.PropertyInfo.Name};
                    int {discriminatorOffsetVariableName} = 0;
                    int {valueOffsetVariableName} = 0;
                    byte {discriminatorValueVariableName} = 0;

                    if ({valueVariableName} != null && {valueVariableName}.Discriminator != 0)
                    {{
                            {discriminatorValueVariableName} = {valueVariableName}.Discriminator;
                            {discriminatorOffsetVariableName} = currentOffset;
                            vtable.{nameof(VTableBuilder.SetOffset)}({index}, currentOffset - tableStart);
                            currentOffset++;

                            currentOffset += {CSharpHelpers.GetFullMethodName(ReflectedMethods.SerializationHelpers_GetAlignmentErrorMethod)}(currentOffset, sizeof(uint));
                            {valueOffsetVariableName} = currentOffset;
                            vtable.{nameof(VTableBuilder.SetOffset)}({index + 1}, currentOffset - tableStart);
                            currentOffset += sizeof(uint);
                    }}";

            List <string> switchCases = new List <string>();

            for (int i = 0; i < unionModel.UnionElementTypeModel.Length; ++i)
            {
                var elementModel = unionModel.UnionElementTypeModel[i];
                var unionIndex   = i + 1;

                string structAdjustment = string.Empty;
                if (elementModel.SchemaType == FlatBufferSchemaType.Struct)
                {
                    // Structs are generally written in-line, with the exception of unions.
                    // So, we need to do the normal allocate space dance here, since we're writing
                    // a pointer to a struct.
                    structAdjustment =
                        $@"
                        var writeOffset = context.{nameof(SerializationContext.AllocateSpace)}({elementModel.InlineSize}, {elementModel.Alignment});
                        writer.{nameof(SpanWriter.WriteUOffset)}(span, {valueOffsetVariableName}, writeOffset, context);
                        {valueOffsetVariableName} = writeOffset;";
                }

                string @case =
                    $@"
                    case {unionIndex}:
                    {{
                        {structAdjustment}
                        {this.GetSerializeInvocation(elementModel.ClrType, $"{valueVariableName}.Item{unionIndex}", valueOffsetVariableName)}
                    }}
                        break;";

                switchCases.Add(@case);
            }

            string serializeBlock =
                $@"
                    if ({discriminatorOffsetVariableName} != 0)
                    {{
                        {this.GetSerializeInvocation(typeof(byte), discriminatorValueVariableName, discriminatorOffsetVariableName)}
                        switch ({discriminatorValueVariableName})
                        {{
                            {string.Join("\r\n", switchCases)}
                            default: throw new InvalidOperationException(""Unexpected"");
                        }}
                    }}";

            return(prepareBlock, serializeBlock);
        }
Пример #7
0
        internal static string GetDefaultValueToken(TableMemberModel memberModel)
        {
            var itemTypeModel = memberModel.ItemTypeModel;
            var clrType       = itemTypeModel.ClrType;

            string defaultValue = $"default({GetCompilableTypeName(memberModel.ItemTypeModel.ClrType)})";

            if (memberModel.HasDefaultValue)
            {
                string literalSpecifier    = string.Empty;
                string cast                = string.Empty;
                string defaultValueLiteral = memberModel.DefaultValue.ToString();

                if (clrType == typeof(bool))
                {
                    // Bool.ToString() returns 'True', which is not the right keyword.
                    defaultValueLiteral = defaultValueLiteral.ToLower();
                }
                else if (clrType == typeof(sbyte))
                {
                    cast = "(sbyte)";
                }
                else if (clrType == typeof(byte))
                {
                    cast = "(byte)";
                }
                else if (clrType == typeof(short))
                {
                    cast = "(short)";
                }
                else if (clrType == typeof(ushort))
                {
                    cast = "(ushort)";
                }
                else if (clrType == typeof(float))
                {
                    literalSpecifier = "f";
                }
                else if (clrType == typeof(uint))
                {
                    literalSpecifier = "u";
                }
                else if (clrType == typeof(int))
                {
                    // shouldn't need this one, but let's be thorough.
                    cast = "(int)";
                }
                else if (clrType == typeof(double))
                {
                    literalSpecifier = "d";
                }
                else if (clrType == typeof(long))
                {
                    literalSpecifier = "L";
                }
                else if (clrType == typeof(ulong))
                {
                    literalSpecifier = "ul";
                }
                else if (clrType.IsEnum)
                {
                    defaultValueLiteral = $"{CSharpHelpers.GetCompilableTypeName(clrType)}.{defaultValueLiteral}";
                }
                else
                {
                    throw new InvalidOperationException("Unexpected default value type: " + clrType.FullName);
                }

                defaultValue = $"{cast}{defaultValueLiteral}{literalSpecifier}";
            }

            return(defaultValue);
        }
Пример #8
0
 public override void AdjustTableMember(TableMemberModel source)
 {
     // Force the vector to be sorted.
     source.IsSortedVector = true;
 }
Пример #9
0
 internal IndexedVectorTypeModel(Type vectorType, TypeModelContainer provider) : base(vectorType, provider)
 {
     this.keyTypeModel   = null !;
     this.valueTypeModel = null !;
     this.keyMemberModel = null !;
 }
 public void AdjustTableMember(TableMemberModel source) => this.underlyingModel.AdjustTableMember(source);
Пример #11
0
 public virtual void AdjustTableMember(TableMemberModel source)
 {
 }
        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);
        }