optimized special cases for COMBINE (sum, product, min, max) by up to 34 x

pull/95/head
jmoenig 2021-03-02 10:55:45 +01:00
rodzic b8e90ad0b7
commit cc01cd6733
3 zmienionych plików z 70 dodań i 2 usunięć

Wyświetl plik

@ -3,11 +3,15 @@
## in development:
* **Notable Changes:**
* optimized special cases for COMBINE (sum, product, min, max) by up to 34 x
* custom block label parts inside the prototype (in the block editor) are now displayed the same as in block instances
* variadic ring inputs are now arranged vertically (e.g. the reporter rings in PIPE)
* changed zebra-coloring for yellow custom block prototypes (in the block editor) so the hat block changes the shade, not the prototype
* improved layout and rendering of (+) buttons in custom block prototypes
### 2021-03-02
* threads: optimized special cases for COMBINE (sum, product, min, max) by up to 34 x
### 2021-03-01
* byob: improved layout and rendering of (+) buttons in custom block prototypes
* byob: display custom block label parts in the prototype (in the block editor) the same as in block instances

Wyświetl plik

@ -9,7 +9,7 @@
<script src="src/symbols.js?version=2020-10-07"></script>
<script src="src/widgets.js?version=2021-01-05"></script>
<script src="src/blocks.js?version=2021-02-27"></script>
<script src="src/threads.js?version=2021-02-23"></script>
<script src="src/threads.js?version=2021-03-02"></script>
<script src="src/objects.js?version=2021-02-23"></script>
<script src="src/gui.js?version=2021-02-27"></script>
<script src="src/paint.js?version=2020-05-17"></script>

Wyświetl plik

@ -61,7 +61,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy, Map,
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph, BLACK,
TableFrameMorph, ColorSlotMorph, isSnapObject, newCanvas, Symbol, SVG_Costume*/
modules.threads = '2021-February-23';
modules.threads = '2021-March-02';
var ThreadManager;
var Process;
@ -2899,6 +2899,14 @@ Process.prototype.reportCombine = function (list, reporter) {
}
if (list.isLinked) {
if (this.context.accumulator === null) {
// check for special cases to speed up
if (this.canRunOptimizedForCombine(reporter)) {
return this.reportListAggregation(
list,
reporter.expression.selector
);
}
// initialize the accumulator
this.context.accumulator = {
source : list.cdr(),
idx : 1,
@ -2919,6 +2927,14 @@ Process.prototype.reportCombine = function (list, reporter) {
next = this.context.accumulator.source.at(1);
} else { // arrayed
if (this.context.accumulator === null) {
// check for special cases to speed up
if (this.canRunOptimizedForCombine(reporter)) {
return this.reportListAggregation(
list,
reporter.expression.selector
);
}
// initialize the accumulator
this.context.accumulator = {
idx : 1,
target : list.at(1)
@ -2946,6 +2962,54 @@ Process.prototype.reportCombine = function (list, reporter) {
this.evaluate(reporter, new List(parms));
};
Process.prototype.reportListAggregation = function (list, selector) {
// private - used by reportCombine to optimize certain commutative
// operations such as sum, product, min, max hyperized all at once
var len = list.length(),
result, i;
if (len === 0) {
return 0;
}
result = list.at(1);
if (len > 1) {
for (i = 2; i <= len; i += 1) {
result = this[selector](result, list.at(i));
}
}
return result;
};
Process.prototype.canRunOptimizedForCombine = function (aContext) {
// private - used by reportCombine to check for optimizable
// special cases
var op = aContext.expression.selector,
eligible;
if (!op) {
return false;
}
eligible = ['reportSum', 'reportProduct', 'reportMin', 'reportMax'];
if (!contains(eligible, op)) {
return false;
}
// scan the expression's inputs, we can assume there are exactly two,
// because we're only looking at eligible selectors. Make sure none is
// a non-empty input slot or a variable getter whose name doesn't
// correspond to an input of the context.
// make sure the context has either no or exactly two inputs.
if (aContext.inputs.length === 0) {
return aContext.expression.inputs().every(each => each.bindingID);
}
if (aContext.inputs.length !== 2) {
return false;
}
return aContext.expression.inputs().every(each =>
each.selector === 'reportGetVar' &&
contains(aContext.inputs, each.blockSpec)
);
};
// Process interpolated primitives
Process.prototype.doWait = function (secs) {