public CppTypeVisitorResult Visit(CppArrayType t, Qualifiers q) { // has inner type this.TypeBuilder.Append($"Array[]"); this.DbgBuilder.Append(t.DbgDescription + " "); this.QualifierBuilder.Append(q.ToString("g") + " "); return(null); }
// Add a field to the type. Returns the offset of the field in the type public int AddField(CppField field, int alignmentBytes = 0) { // Unions and enums always have an offset of zero // An empty struct has a Size (bits) of 8 so the first field must also be set to zero offset field.Offset = ComplexValueType == ComplexValueType.Struct ? (Fields.Any()? Size : 0) : 0; // If we just came out of a bitfield, move to the next byte if necessary if (field.BitfieldSize == 0 && field.Offset % 8 != 0) { field.Offset = (field.Offset / 8) * 8 + 8; } // A 2, 4 or 8-byte value etc. must be aligned on an equivalent boundary // The same goes for the first entry in a struct, union or array // This block searches depth-first for the first field or element in any child types to find the required alignment boundary // https://en.wikipedia.org/wiki/Data_structure_alignment if (field.BitfieldSize == 0) { var firstSimpleType = field.Type; var foundType = false; while (!foundType) { var simpleType = firstSimpleType switch { CppAlias alias => alias.ElementType, CppComplexType { ComplexValueType : ComplexValueType.Struct } complex => complex.Fields.FirstOrDefault().Value?.First().Type, CppArrayType array => array.ElementType, _ => firstSimpleType }; if (simpleType == firstSimpleType) { foundType = true; } firstSimpleType = simpleType; } // Empty classes shall always have sizeof() >= 1 and alignment doesn't matter // Empty classes will be returned as null by the above code (complex? null conditional operator) // https://www.stroustrup.com/bs_faq2.html#sizeof-empty if (firstSimpleType != null) { if (field.OffsetBytes % firstSimpleType.SizeBytes != 0) { field.Offset += (firstSimpleType.SizeBytes - field.OffsetBytes % firstSimpleType.SizeBytes) * 8; } } } // Respect alignment directives if (alignmentBytes > 0 && field.OffsetBytes % alignmentBytes != 0) { field.Offset += (alignmentBytes - field.OffsetBytes % alignmentBytes) * 8; } if (field.Type.AlignmentBytes > 0 && field.OffsetBytes % field.Type.AlignmentBytes != 0) { field.Offset += (field.Type.AlignmentBytes - field.OffsetBytes % field.Type.AlignmentBytes) * 8; } if (Fields.ContainsKey(field.Offset)) { Fields[field.Offset].Add(field); } else { Fields.Add(field.Offset, new List <CppField> { field }); } // Update type size. This lazy evaluation only works if there are no value type forward declarations in the type // Union size is the size of the largest element in the union if (ComplexValueType == ComplexValueType.Union) { if (field.Size > Size) { Size = field.Size; } } // For structs we look for the last item and add the size; adding the sizes without offsets might fail because of alignment padding if (ComplexValueType == ComplexValueType.Struct) { Size = field.Offset + field.Size; } return(Size); }