Skip to content

Commit

Permalink
Code-generation for "non-transferred members" of StructArray.
Browse files Browse the repository at this point in the history
Allows users of a transferred StructArray to add information to it without resizing/modifying the underlying ArrayBuffer.
  • Loading branch information
ChrisLoer committed Aug 20, 2018
1 parent 4e34548 commit 15fffa9
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 80 deletions.
10 changes: 7 additions & 3 deletions build/generate-struct-arrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ function normalizeMembers(members, usedTypes) {
// - If necessary, write the StructArrayLayout_* class for the given layout
// - If `includeStructAccessors`, write the fancy subclass
// - Add an entry for `name` in the array type registry
function createStructArrayType(name: string, layout: StructArrayLayout, includeStructAccessors: boolean = false) {
function createStructArrayType(name: string,
layout: StructArrayLayout,
includeStructAccessors: boolean = false,
nonTransferredMembers?: Array<string>) {
const hasAnchorPoint = layout.members.some(m => m.name === 'anchorPointX');

// create the underlying StructArrayLayout class exists
Expand All @@ -68,7 +71,8 @@ function createStructArrayType(name: string, layout: StructArrayLayout, includeS
usedTypes,
hasAnchorPoint,
layoutClass,
includeStructAccessors
includeStructAccessors,
nonTransferredMembers
});
} else {
arrayTypeEntries.add(`${layoutClass} as ${arrayClass}`);
Expand Down Expand Up @@ -163,7 +167,7 @@ createStructArrayType(`collision_box_layout`, collisionBoxLayout);
createStructArrayType(`collision_circle_layout`, collisionCircleLayout);
createStructArrayType(`collision_vertex`, collisionVertexAttributes);
createStructArrayType('placed_symbol', placement, true);
createStructArrayType('symbol_instance', symbolInstance, true);
createStructArrayType('symbol_instance', symbolInstance, true, ['crossTileID']);
createStructArrayType('glyph_offset', glyphOffset, true);
createStructArrayType('symbol_line_vertex', lineVertex, true);

Expand Down
150 changes: 74 additions & 76 deletions src/data/array_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,67 @@ StructArrayLayout2i2ui3ul3ui2f2ub40.prototype.bytesPerElement = 40;
register('StructArrayLayout2i2ui3ul3ui2f2ub40', StructArrayLayout2i2ui3ul3ui2f2ub40);


/**
* Implementation of the StructArray layout:
* [0]: Int16[4]
* [8]: Uint16[9]
*
* @private
*/
class StructArrayLayout4i9ui26 extends StructArray {
uint8: Uint8Array;
int16: Int16Array;
uint16: Uint16Array;

_refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
}

emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number) {
const i = this.length;
this.resize(i + 1);
const o2 = i * 13;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
this.int16[o2 + 2] = v2;
this.int16[o2 + 3] = v3;
this.uint16[o2 + 4] = v4;
this.uint16[o2 + 5] = v5;
this.uint16[o2 + 6] = v6;
this.uint16[o2 + 7] = v7;
this.uint16[o2 + 8] = v8;
this.uint16[o2 + 9] = v9;
this.uint16[o2 + 10] = v10;
this.uint16[o2 + 11] = v11;
this.uint16[o2 + 12] = v12;
return i;
}

emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number) {
const o2 = i * 13;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
this.int16[o2 + 2] = v2;
this.int16[o2 + 3] = v3;
this.uint16[o2 + 4] = v4;
this.uint16[o2 + 5] = v5;
this.uint16[o2 + 6] = v6;
this.uint16[o2 + 7] = v7;
this.uint16[o2 + 8] = v8;
this.uint16[o2 + 9] = v9;
this.uint16[o2 + 10] = v10;
this.uint16[o2 + 11] = v11;
this.uint16[o2 + 12] = v12;
return i;
}
}

StructArrayLayout4i9ui26.prototype.bytesPerElement = 26;
register('StructArrayLayout4i9ui26', StructArrayLayout4i9ui26);


/**
* Implementation of the StructArray layout:
* [0]: Float32[1]
Expand Down Expand Up @@ -732,6 +793,11 @@ class StructArrayLayout1ui2 extends StructArray {
return i;
}

emplace(i: number, v0: number) {
const o2 = i * 1;
this.uint16[o2 + 0] = v0;
return i;
}
}

StructArrayLayout1ui2.prototype.bytesPerElement = 2;
Expand Down Expand Up @@ -814,70 +880,6 @@ StructArrayLayout4f16.prototype.bytesPerElement = 16;
register('StructArrayLayout4f16', StructArrayLayout4f16);


/**
* Implementation of the StructArray layout:
* [0]: Int16[4]
* [8]: Uint8[9]
*
* @private
*/
class StructArrayLayout4i9ul26 extends StructArray {
uint8: Uint8Array;
int16: Int16Array;
uint16: Uint16Array;

_refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
}

emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number,
v5: number, v6: number, v7: number, v8: number, v9: number,
v10: number, v11: number, v12: number) {
const i = this.length;
this.resize(i + 1);
const o2 = i * 13;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
this.int16[o2 + 2] = v2;
this.int16[o2 + 3] = v3;
this.uint16[o2 + 4] = v4;
this.uint16[o2 + 5] = v5;
this.uint16[o2 + 6] = v6;
this.uint16[o2 + 7] = v7;
this.uint16[o2 + 8] = v8;
this.uint16[o2 + 9] = v9;
this.uint16[o2 + 10] = v10;
this.uint16[o2 + 11] = v11;
this.uint16[o2 + 12] = v12;
return i;
}

emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number,
v5: number, v6: number, v7: number, v8: number, v9: number,
v10: number, v11: number, v12: number) {
const o2 = i * 13;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
this.int16[o2 + 2] = v2;
this.int16[o2 + 3] = v3;
this.uint16[o2 + 4] = v4;
this.uint16[o2 + 5] = v5;
this.uint16[o2 + 6] = v6;
this.uint16[o2 + 7] = v7;
this.uint16[o2 + 8] = v8;
this.uint16[o2 + 9] = v9;
this.uint16[o2 + 10] = v10;
this.uint16[o2 + 11] = v11;
this.uint16[o2 + 12] = v12;
return i;
}
}

StructArrayLayout4i9ul26.prototype.bytesPerElement = 26;
register('StructArrayLayout4i9ul26', StructArrayLayout4i9ul26);

class CollisionBoxStruct extends Struct {
_structArray: CollisionBoxArray;
anchorPointX: number;
Expand Down Expand Up @@ -1020,16 +1022,16 @@ class SymbolInstanceStruct extends Struct {
numGlyphVertices: number;
numVerticalGlyphVertices: number;
numIconVertices: number;

crossTileIDs: Array<number>;
index: number;

constructor(structArray: StructArray, index: number, crossTileIDs: Array<number>) {
constructor(structArray: StructArray,
index: number,
crossTileIDs: Array<number>) {
super(structArray, index);
this.crossTileIDs = crossTileIDs;
this.index = index;
}

get anchorX() { return this._structArray.int16[this._pos2 + 0]; }
set anchorX(x) { this._structArray.int16[this._pos2 + 0] = x; }
get anchorY() { return this._structArray.int16[this._pos2 + 1]; }
Expand Down Expand Up @@ -1068,23 +1070,18 @@ export type SymbolInstance = SymbolInstanceStruct;
/**
* @private
*/
export class SymbolInstanceArray extends StructArrayLayout4i9ul26 {
export class SymbolInstanceArray extends StructArrayLayout4i9ui26 {
crossTileIDs: Array<number>;

constructor() {
super();
this.crossTileIDs = [];
}

_refreshViews() {
super._refreshViews();
_initializeNonTransferables() {
this.crossTileIDs = [];
for (let i = 0; i < this.length; i++) {
this.crossTileIDs.push(0);
}
}

/**
* Return the PlacedSymbolStruct at the given location in the array.
* Return the SymbolInstanceStruct at the given location in the array.
* @param {number} index The index of the element.
*/
get(index: number): SymbolInstanceStruct {
Expand Down Expand Up @@ -1208,6 +1205,7 @@ export {
StructArrayLayout2i2i2i12,
StructArrayLayout2ub4,
StructArrayLayout2i2ui3ul3ui2f2ub40,
StructArrayLayout4i9ui26,
StructArrayLayout1f4,
StructArrayLayout3i6,
StructArrayLayout1ul2ui8,
Expand Down
10 changes: 10 additions & 0 deletions src/util/struct_array.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ class StructArray {
structArray.length = input.length;
structArray.capacity = input.arrayBuffer.byteLength / structArray.bytesPerElement;
structArray._refreshViews();
structArray._initializeNonTransferables();

return structArray;
}

Expand Down Expand Up @@ -188,6 +190,14 @@ class StructArray {
_refreshViews() {
throw new Error('_refreshViews() must be implemented by each concrete StructArray layout');
}

/**
* Create arrays of non-transferrable items to be access in parallel with
* the TypedArray items
*/
_initializeNonTransferables() {
// No-op unless implementation overrides
}
}

/**
Expand Down
51 changes: 50 additions & 1 deletion src/util/struct_array.js.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const {
usedTypes,
hasAnchorPoint,
layoutClass,
includeStructAccessors
includeStructAccessors,
nonTransferredMembers
} = locals
const StructTypeClass = arrayClass.replace('Array', 'Struct');
Expand Down Expand Up @@ -37,6 +38,23 @@ class <%=StructTypeClass%> extends Struct {
<% }
if (hasAnchorPoint) { -%>
anchorPoint: Point;
<% }
if (nonTransferredMembers) {
// non-transferred member declarations
for (const name of nonTransferredMembers) {-%>
<%=name%>s: Array<number>;
<% } -%>
index: number;
constructor(structArray: StructArray,
index: number,
<%-nonTransferredMembers.map(name => `${name}s: Array<number>`).join(',\n')%>) {
super(structArray, index);
<% for (const name of nonTransferredMembers) {-%>
this.<%=name%>s = <%=name%>s;
<% } -%>
this.index = index;
}
<% } -%>
<%
for (const {name, member, component} of components) {
Expand All @@ -55,6 +73,14 @@ if (hasAnchorPoint) {
get anchorPoint() { return new Point(this.anchorPointX, this.anchorPointY); }
<%
}
if (nonTransferredMembers) {
// non-transferred member declarations
for (const name of nonTransferredMembers) {
-%>
get <%=name%>() { return this.<%=name%>s[this.index]; }
set <%=name%>(x) { this.<%=name%>s[this.index] = x; }
<% }
}
-%>
}
Expand All @@ -70,6 +96,25 @@ export type <%=StructTypeClass.replace('Struct', '')%> = <%=StructTypeClass%>;
* @private
*/
export class <%=StructArrayClass%> extends <%=StructArrayLayoutClass%> {
<% if (nonTransferredMembers) {
// non-transferred member declarations
for (const name of nonTransferredMembers) {
-%>
<%=name%>s: Array<number>;
<% } -%>
_initializeNonTransferables() {
<% for (const name of nonTransferredMembers) {
-%>
this.<%=name%>s = [];
for (let i = 0; i < this.length; i++) {
this.<%=name%>s.push(0);
}
<% } -%>
}
<% }
-%>
<%
if (StructArrayClass === 'GlyphOffsetArray' || StructArrayClass === 'SymbolLineVertexArray') {
// component getters
Expand Down Expand Up @@ -98,7 +143,11 @@ if (includeStructAccessors) {
*/
get(index: number): <%=StructTypeClass%> {
assert(!this.isTransferred);
<% if (nonTransferredMembers) {-%>
return new <%=StructTypeClass%>(this, index, <%-nonTransferredMembers.map(name => `this.${name}s`).join(',')%>);
<% } else {-%>
return new <%=StructTypeClass%>(this, index);
<% }-%>
}
<%
}
Expand Down

0 comments on commit 15fffa9

Please sign in to comment.