private void ImplementMemoryVectorReadMethod(VectorTypeModel typeModel) { string invocation; if (typeModel.ItemTypeModel.ClrType == typeof(byte)) { invocation = nameof(InputBuffer.ReadByteMemoryBlock); if (typeModel.IsReadOnly) { invocation = nameof(InputBuffer.ReadByteReadOnlyMemoryBlock); } } else { string methodName = nameof(InputBuffer.ReadMemoryBlock); if (typeModel.IsReadOnly) { methodName = nameof(InputBuffer.ReadReadOnlyMemoryBlock); } invocation = $"{methodName}<{CSharpHelpers.GetCompilableTypeName(typeModel.ItemTypeModel.ClrType)}>"; } string body = $"memory.{invocation}(offset, {typeModel.ItemTypeModel.InlineSize})"; // Greedy deserialize has the invariant that we no longer touch the // original buffer. This means a memory copy here. if (this.options.GreedyDeserialize) { body = $"{body}.ToArray().AsMemory()"; } this.GenerateMethodDefinition(typeModel.ClrType, $"return {body};"); }
private void ImplementArrayVectorReadMethod(VectorTypeModel typeModel) { var itemTypeModel = typeModel.ItemTypeModel; string statement; if (itemTypeModel is ScalarTypeModel scalarModel && scalarModel.NativelyReadableFromMemory) { // Memory is faster in situations where we can get away with it. statement = $"memory.{nameof(InputBuffer.ReadMemoryBlock)}<{CSharpHelpers.GetCompilableTypeName(itemTypeModel.ClrType)}>(offset, {itemTypeModel.InlineSize}).ToArray()"; }
private void ImplementMemoryVectorInlineWriteMethod(VectorTypeModel vectorModel) { var type = vectorModel.ClrType; var itemTypeModel = vectorModel.ItemTypeModel; string writerMethodName = $"{nameof(SpanWriter.WriteReadOnlyMemoryBlock)}<{CSharpHelpers.GetCompilableTypeName(itemTypeModel.ClrType)}>"; if (itemTypeModel.ClrType == typeof(byte)) { // Optimization: when we're writing bytes we don't have to change types. writerMethodName = nameof(SpanWriter.WriteReadOnlyByteMemoryBlock); } string body = $"writer.{writerMethodName}(span, item, originalOffset, {itemTypeModel.Alignment}, {itemTypeModel.InlineSize}, context);"; this.GenerateSerializeMethod(type, body); }
private void ImplementListVectorReadMethod(VectorTypeModel typeModel) { string body = this.CreateFlatBufferVector(typeModel); if (this.options.PreallocateVectors) { // We just call .ToList(). Noe that when full greedy mode is on, these items will be // greedily initialized as we traverse the list. Otherwise, they'll be allocated lazily. body += $".{nameof(SerializationHelpers.FlatBufferVectorToList)}()"; if (!this.options.GenerateMutableObjects) { // Finally, if we're not in the business of making mutable objects, then convert the list to read only. body += ".AsReadOnly()"; } } this.GenerateMethodDefinition(typeModel.ClrType, $"return {body};"); }
private void ImplementListVectorInlineWriteMethod(VectorTypeModel vectorModel) { var type = vectorModel.ClrType; var itemTypeModel = vectorModel.ItemTypeModel; string propertyName = vectorModel.LengthPropertyName; string body = $@" int count = item.{propertyName}; int vectorOffset = context.{nameof(SerializationContext.AllocateVector)}({itemTypeModel.Alignment}, count, {vectorModel.PaddedMemberInlineSize}); writer.{nameof(SpanWriter.WriteUOffset)}(span, originalOffset, vectorOffset, context); writer.{nameof(SpanWriter.WriteInt)}(span, count, vectorOffset, context); vectorOffset += sizeof(int); for (int i = 0; i < count; ++i) {{ var current = item[i]; {CSharpHelpers.GetNonNullCheckInvocation(itemTypeModel, "current")}; {this.GetSerializeInvocation(itemTypeModel.ClrType, "current", "vectorOffset")} vectorOffset += {vectorModel.PaddedMemberInlineSize}; }}"; this.GenerateSerializeMethod(type, body); }
/// <summary> /// Gets the max size of the vector itself, not the uoffset_t as part of the containing table. /// </summary> private void ImplementVectorGetMaxSizeMethod(VectorTypeModel vectorModel) { var itemModel = vectorModel.ItemTypeModel; string body; // count of items + padding(uoffset_t); int fixedSize = sizeof(uint) + SerializationHelpers.GetMaxPadding(sizeof(uint)); string lengthProperty = $"item.{vectorModel.LengthPropertyName}"; // Constant size items. We can reduce these reasonably well. if (itemModel.IsFixedSize) { body = $"return {fixedSize} + {SerializationHelpers.GetMaxPadding(itemModel.Alignment)} + ({vectorModel.PaddedMemberInlineSize} * {lengthProperty});"; } else if (itemModel.SchemaType == FlatBufferSchemaType.Table || itemModel.SchemaType == FlatBufferSchemaType.String) { Debug.Assert(itemModel.Alignment == sizeof(uint)); Debug.Assert(itemModel.InlineSize == sizeof(uint)); body = $@" int length = {lengthProperty}; int runningSum = {fixedSize} + {SerializationHelpers.GetMaxPadding(itemModel.Alignment)} + ({vectorModel.PaddedMemberInlineSize} * length); for (int i = 0; i < length; ++i) {{ var itemTemp = item[i]; {CSharpHelpers.GetNonNullCheckInvocation(itemModel, "itemTemp")}; runningSum += {this.InvokeGetMaxSizeMethod(itemModel, "itemTemp")}; }} return runningSum;"; } else { throw new NotImplementedException("Vector.GetMaxSize is not implemented for schema type of " + itemModel.SchemaType); } this.GenerateGetMaxSizeMethod(vectorModel.ClrType, body); }
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); }