Skip to content

Commit

Permalink
Add specialized filter expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
Anand Thakker authored and jfirebaugh committed Jan 3, 2018
1 parent 2d0336e commit fe1ca76
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 2 deletions.
148 changes: 148 additions & 0 deletions src/style-spec/expression/definitions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,20 @@ function gt(ctx, [a, b]) { return a.evaluate(ctx) > b.evaluate(ctx); }
function lteq(ctx, [a, b]) { return a.evaluate(ctx) <= b.evaluate(ctx); }
function gteq(ctx, [a, b]) { return a.evaluate(ctx) >= b.evaluate(ctx); }

function binarySearch(v, a, i, j) {
while (i <= j) {
const m = (i + j) >> 1;
if (a[m] === v)
return true;
if (a[m] > v)
j = m - 1;
else
i = m + 1;
}
return false;
}


CompoundExpression.register(expressions, {
'error': [
ErrorType,
Expand Down Expand Up @@ -315,6 +329,140 @@ CompoundExpression.register(expressions, {
varargs(NumberType),
(ctx, args) => Math.max(...args.map(arg => arg.evaluate(ctx)))
],
'filter-==': [
BooleanType,
[StringType, ValueType],
function (ctx) {
return ctx.properties()[this.args[0].value] === this.args[1].value;
}
],
'filter-id-==': [
BooleanType,
[ValueType],
function (ctx) {
return ctx.id() === this.args[0].value;
}
],
'filter-type-==': [
BooleanType,
[StringType],
function (ctx) {
return ctx.geometryType() === this.args[0].value;
}
],
'filter-<': [
BooleanType,
[StringType, ValueType],
function (ctx) {
const v = ctx.properties()[this.args[0].value];
const b = this.args[1];
return typeof v === typeof b.value && v < b.value;
}
],
'filter-id-<': [
BooleanType,
[ValueType],
function (ctx) {
const v = ctx.id();
const b = this.args[0];
return typeof v === typeof b.value && v < b.value;
}
],
'filter->': [
BooleanType,
[StringType, ValueType],
function (ctx) {
const v = ctx.properties()[this.args[0].value];
const b = this.args[1];
return typeof v === typeof b.value && v > b.value;
}
],
'filter-id->': [
BooleanType,
[ValueType],
function (ctx) {
const v = ctx.id();
const b = this.args[0];
return typeof v === typeof b.value && v > b.value;
}
],
'filter-<=': [
BooleanType,
[StringType, ValueType],
function (ctx) {
const v = ctx.properties()[this.args[0].value];
const b = this.args[1];
return typeof v === typeof b.value && v <= b.value;
}
],
'filter-id-<=': [
BooleanType,
[ValueType],
function (ctx) {
const v = ctx.id();
const b = this.args[0];
return typeof v === typeof b.value && v <= b.value;
}
],
'filter->=': [
BooleanType,
[StringType, ValueType],
function (ctx) {
const v = ctx.properties()[this.args[0].value];
const b = this.args[1];
return typeof v === typeof b.value && v >= b.value;
}
],
'filter-id->=': [
BooleanType,
[ValueType],
function (ctx) {
const v = ctx.id();
const b = this.args[0];
return typeof v === typeof b.value && v >= b.value;
}
],
'filter-has': [
BooleanType,
[ValueType],
function (ctx) { return this.args[0].value in ctx.properties(); }
],
'filter-has-id': [
BooleanType,
[],
(ctx) => ctx.id() !== null
],
'filter-type-in': [
BooleanType,
[array(StringType)],
function (ctx) { return this.args[0].value.indexOf(ctx.geometryType()) >= 0; }
],
'filter-id-in': [
BooleanType,
[array(ValueType)],
function (ctx) { return this.args[0].value.indexOf(ctx.id()) >= 0; }
],
'filter-in-small': [
BooleanType,
[StringType, array(ValueType)],
function (ctx) {
// assumes this.args[1] is an array Literal
const value = ctx.properties()[this.args[0].value];
const array = this.args[1].value;
return array.indexOf(value) >= 0;
}
],
'filter-in-large': [
BooleanType,
[StringType, array(ValueType)],
function (ctx) {
// assumes this.args[1] is a array Literal with values
// sorted in ascending order and of a single type
const value = ctx.properties()[this.args[0].value];
const array = this.args[1].value;
return binarySearch(value, array, 0, array.length - 1);
}
],
'>': {
type: BooleanType,
overloads: [
Expand Down
2 changes: 2 additions & 0 deletions src/style-spec/expression/is_constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ function isFeatureConstant(e: Expression) {
e.name === 'id'
) {
return false;
} else if (e.name.startsWith('filter-')) {
return false;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/style-spec/feature_filter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ function compileInOp(property, values) {
const left = JSON.stringify(values.sort(compare));
const right = compilePropertyReference(property);

if (values.length <= 200) return `${left}.indexOf(${right}) !== -1`;
if (values.length <= 200 || values.some(v => typeof v !== typeof values[0])) return `${left}.indexOf(${right}) !== -1`;

return `${'function(v, a, i, j) {' +
'while (i <= j) { var m = (i + j) >> 1;' +
Expand Down
18 changes: 17 additions & 1 deletion test/unit/style-spec/feature_filter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,23 @@ test('in, multiple', (t) => {
});

test('in, large_multiple', (t) => {
const f = filter(['in', 'foo'].concat(Array.apply(null, {length: 2000}).map(Number.call, Number)));
const values = Array.apply(null, {length: 2000}).map(Number.call, Number);
values.reverse();
const f = filter(['in', 'foo'].concat(values));
t.equal(f({zoom: 0}, {properties: {foo: 0}}), true);
t.equal(f({zoom: 0}, {properties: {foo: 1}}), true);
t.equal(f({zoom: 0}, {properties: {foo: 1999}}), true);
t.equal(f({zoom: 0}, {properties: {foo: 2000}}), false);
t.end();
});

test('in, large_multiple, heterogeneous', (t) => {
const values = Array.apply(null, {length: 2000}).map(Number.call, Number);
values.push('a');
values.unshift('b');
const f = filter(['in', 'foo'].concat(values));
t.equal(f({zoom: 0}, {properties: {foo: 'b'}}), true);
t.equal(f({zoom: 0}, {properties: {foo: 'a'}}), true);
t.equal(f({zoom: 0}, {properties: {foo: 0}}), true);
t.equal(f({zoom: 0}, {properties: {foo: 1}}), true);
t.equal(f({zoom: 0}, {properties: {foo: 1999}}), true);
Expand Down

0 comments on commit fe1ca76

Please sign in to comment.