forked from MapComplete/MapComplete
Fix: improve optimization; add tests
This commit is contained in:
parent
78238dccc7
commit
595503cfc3
3 changed files with 47 additions and 8 deletions
|
@ -233,6 +233,15 @@ export class And extends TagsFilter {
|
||||||
return And.construct(newAnds)
|
return And.construct(newAnds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* const raw = {"and": [{"or":["leisure=playground","playground!=forest"]},{"or":["leisure=playground","playground!=forest"]}]}
|
||||||
|
* const parsed = TagUtils.Tag(raw)
|
||||||
|
* parsed.optimize().asJson() // => {"or":["leisure=playground","playground!=forest"]}
|
||||||
|
*
|
||||||
|
* const raw = {"and": [{"and":["advertising=screen"]}, {"and":["advertising~*"]}]}]
|
||||||
|
* const parsed = TagUtils.Tag(raw)
|
||||||
|
* parsed.optimize().asJson() // => "advertising=screen"
|
||||||
|
*/
|
||||||
optimize(): TagsFilter | boolean {
|
optimize(): TagsFilter | boolean {
|
||||||
if (this.and.length === 0) {
|
if (this.and.length === 0) {
|
||||||
return true
|
return true
|
||||||
|
@ -294,9 +303,17 @@ export class And extends TagsFilter {
|
||||||
optimized.splice(i, 1)
|
optimized.splice(i, 1)
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
} else if (v !== opt.value) {
|
} else {
|
||||||
// detected an internal conflict
|
if (!v.match(opt.value)) {
|
||||||
return false
|
// We _know_ that for the key of the RegexTag `opt`, the value will be `v`.
|
||||||
|
// As such, if `opt.value` cannot match `v`, we detected an internal conflict and can fail
|
||||||
|
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
// Another tag already provided a _stricter_ value then this regex, so we can remove this one!
|
||||||
|
optimized.splice(i, 1)
|
||||||
|
i--
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -374,10 +391,13 @@ export class And extends TagsFilter {
|
||||||
const elements = containedOr.or.filter(
|
const elements = containedOr.or.filter(
|
||||||
(candidate) => !commonValues.some((cv) => cv.shadows(candidate))
|
(candidate) => !commonValues.some((cv) => cv.shadows(candidate))
|
||||||
)
|
)
|
||||||
newOrs.push(Or.construct(elements))
|
if (elements.length > 0) {
|
||||||
|
newOrs.push(Or.construct(elements))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newOrs.length > 0) {
|
||||||
|
commonValues.push(And.construct(newOrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
commonValues.push(And.construct(newOrs))
|
|
||||||
const result = new Or(commonValues).optimize()
|
const result = new Or(commonValues).optimize()
|
||||||
if (result === false) {
|
if (result === false) {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -162,6 +162,12 @@ export class Or extends TagsFilter {
|
||||||
return Or.construct(newOrs)
|
return Or.construct(newOrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* const raw = {"or": [{"and":["leisure=playground","playground!=forest"]},{"and":["leisure=playground","playground!=forest"]}]}
|
||||||
|
* const parsed = TagUtils.Tag(raw)
|
||||||
|
* parsed.optimize().asJson() // => {"and":["leisure=playground","playground!=forest"]}
|
||||||
|
*
|
||||||
|
*/
|
||||||
optimize(): TagsFilter | boolean {
|
optimize(): TagsFilter | boolean {
|
||||||
if (this.or.length === 0) {
|
if (this.or.length === 0) {
|
||||||
return false
|
return false
|
||||||
|
@ -241,16 +247,21 @@ export class Or extends TagsFilter {
|
||||||
const elements = containedAnd.and.filter(
|
const elements = containedAnd.and.filter(
|
||||||
(candidate) => !commonValues.some((cv) => cv.shadows(candidate))
|
(candidate) => !commonValues.some((cv) => cv.shadows(candidate))
|
||||||
)
|
)
|
||||||
|
if (elements.length == 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
newAnds.push(And.construct(elements))
|
newAnds.push(And.construct(elements))
|
||||||
}
|
}
|
||||||
|
if (newAnds.length > 0) {
|
||||||
|
commonValues.push(Or.construct(newAnds))
|
||||||
|
}
|
||||||
|
|
||||||
commonValues.push(Or.construct(newAnds))
|
|
||||||
const result = new And(commonValues).optimize()
|
const result = new And(commonValues).optimize()
|
||||||
if (result === true) {
|
if (result === true) {
|
||||||
return true
|
return true
|
||||||
} else if (result === false) {
|
} else if (result === false) {
|
||||||
// neutral element: skip
|
// neutral element: skip
|
||||||
} else {
|
} else if (commonValues.length > 0) {
|
||||||
newOrs.push(And.construct(commonValues))
|
newOrs.push(And.construct(commonValues))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,6 +325,14 @@ export class TagUtils {
|
||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static optimzeJson(json: TagConfigJson): TagConfigJson | boolean {
|
||||||
|
const optimized = TagUtils.Tag(json).optimize()
|
||||||
|
if (optimized === true || optimized === false) {
|
||||||
|
return optimized
|
||||||
|
}
|
||||||
|
return optimized.asJson()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given multiple tagsfilters which can be used as answer, will take the tags with the same keys together as set.
|
* Given multiple tagsfilters which can be used as answer, will take the tags with the same keys together as set.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Reference in a new issue