<%
const {
    className,
    members,
    size,
    usedTypes
} = locals

const StructArrayLayoutClass = className;
-%>
/**
 * Implementation of the StructArray layout:
<%
for (const member of members) {
-%>
 * [<%=member.offset%>]: <%=member.type%>[<%=member.components%>]
<%
}
-%>
 *
 * @private
 */
class <%=StructArrayLayoutClass%> extends StructArray {
<%
for (const type of usedTypes) {
-%>
    <%=type.toLowerCase()%>: <%=type%>Array;
<%
}
-%>

    _refreshViews() {
<%
for (const type of usedTypes) {
-%>
        this.<%=type.toLowerCase()%> = new <%=type%>Array(this.arrayBuffer);
<%
}
-%>
    }

<%
// prep for emplaceBack: collect type sizes and count the number of arguments
// we'll need
const bytesPerElement = size;
const usedTypeSizes = [];
const argNames = [];
const argNamesTyped = [];
for (const member of members) {
    if (usedTypeSizes.indexOf(member.size) < 0) {
        usedTypeSizes.push(member.size);
    }
    for (let c = 0; c < member.components; c++) {
        // arguments v0, v1, v2, ... are, in order, the components of
        // member 0, then the components of member 1, etc.
        const name = `v${argNames.length}`;
        argNames.push(name);
        argNamesTyped.push(`${name}: number`);
    }
}
-%>
    emplaceBack(<%=argNamesTyped.join(', ')%>) {
        const i = this.length;
        this.resize(i + 1);
        return this.emplace(i, <%=argNames.join(', ')%>);
    }

    emplace(i: number, <%=argNamesTyped.join(', ')%>) {
<%
{
for (const size of usedTypeSizes) {
-%>
        const o<%=size.toFixed(0)%> = i * <%=(bytesPerElement / size).toFixed(0)%>;
<%
}

let argIndex = 0;
for (const member of members) {
    for (let c = 0; c < member.components; c++) {
        // The index for `member` component `c` into the appropriate type array is:
        // this.{TYPE}[o{SIZE} + MEMBER_OFFSET + {c}] = v{X}
        // where MEMBER_OFFSET = ROUND(member.offset / size) is the per-element
        // offset of this member into the array
        const index = `o${member.size.toFixed(0)} + ${(member.offset / member.size + c).toFixed(0)}`;
-%>
        this.<%=member.view%>[<%=index%>] = v<%=argIndex++%>;
<%
    }
}
}
-%>
        return i;
    }
-%>
}

<%=StructArrayLayoutClass%>.prototype.bytesPerElement = <%= size %>;
register('<%=StructArrayLayoutClass%>', <%=StructArrayLayoutClass%>);
