Fix: improve optimization; add tests

This commit is contained in:
Pieter Vander Vennet 2023-11-30 00:30:46 +01:00
parent 78238dccc7
commit 595503cfc3
3 changed files with 47 additions and 8 deletions

View file

@ -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

View file

@ -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))
} }
} }

View file

@ -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.
* *