perf: primitive array fast paths

This commit is contained in:
cha0s 2024-12-05 07:09:00 -06:00
parent f82e336849
commit 86063aae5a

View File

@ -5,6 +5,19 @@ const ArrayProperty = {
return [];
},
define(receiver, key, blueprint) {
let isPrimitiveType = false;
switch (blueprint.element.type) {
case 'bool':
case 'int8': case 'uint8':
case 'int16': case 'uint16':
case 'int32': case 'uint32':
case 'float32': case 'float64':
case 'string': {
isPrimitiveType = true;
break;
}
}
const privateKey = `$$${key}`;
let coalescing = true;
let coalesced;
@ -42,6 +55,9 @@ const ArrayProperty = {
}
const api = {
[Symbol.iterator]: () => {
if (isPrimitiveType) {
return receiver[privateKey].values();
}
const protocol = toJSON().values();
return {
next: () => {
@ -61,8 +77,20 @@ const ArrayProperty = {
},
merge(value) {
coalescing = true;
for (const elementKey in value) {
receiver[key].setAt(elementKey, value[elementKey]);
if (isPrimitiveType) {
const change = {};
for (const elementKey in value) {
receiver[privateKey][elementKey] = value[elementKey];
change[elementKey] = value[elementKey];
}
if (receiver.markChange) {
receiver[privateKey].markChange(change);
}
}
else {
for (const elementKey in value) {
receiver[key].setAt(elementKey, value[elementKey]);
}
}
flushCoalesced();
},
@ -70,21 +98,28 @@ const ArrayProperty = {
const elementBlueprint = blueprint.element;
let wasCoalescing = coalescing;
coalescing = true;
if (!(index in receiver[privateKey])) {
Properties[elementBlueprint.type].define(
receiver[privateKey],
index,
elementBlueprint,
);
if (isPrimitiveType) {
receiver[privateKey][index] = value;
if (receiver.markChange) {
receiver[privateKey].markChange({[index]: value});
}
}
else {
if (!(index in receiver[privateKey])) {
Properties[elementBlueprint.type].define(
receiver[privateKey],
index,
elementBlueprint,
);
}
receiver[privateKey][index] = value;
}
receiver[privateKey][index] = value;
if (!wasCoalescing) {
flushCoalesced();
}
},
toJSON,
};
Object.defineProperties(
receiver,
{
@ -94,8 +129,21 @@ const ArrayProperty = {
return api;
},
set(value) {
coalescing = true;
this[privateKey].length = 0;
// fast paths
if (isPrimitiveType) {
coalescing = false;
const change = {};
for (const elementKey in value) {
this[privateKey][elementKey] = value[elementKey];
change[elementKey] = value[elementKey];
}
if (receiver.markChange) {
receiver[privateKey].markChange(change);
}
return;
}
coalescing = true;
for (const elementKey in value) {
this[key].setAt(elementKey, value[elementKey]);
}