perf(cpu): Optimized multiFilter string manipulations

This commit is contained in:
yairm210 2025-09-07 22:40:14 +03:00
parent 4754ac3040
commit c0674dc39f

View File

@ -5,11 +5,14 @@ import yairm210.purity.annotations.Readonly
import yairm210.purity.annotations.Pure
object MultiFilter {
private const val andPrefix = "{"
private const val andPrefixChar = '{'
private const val andPrefix = andPrefixChar.toString()
private const val andSeparator = "} {"
private const val andSuffix = "}"
private const val andSuffixChar = '}'
private const val andSuffix = andSuffixChar.toString()
private const val notPrefix = "non-["
private const val notSuffix = "]"
private const val notSuffixChar = ']'
private const val notSuffix = notSuffixChar.toString()
/**
* Implements `and` and `not` logic on top of a [filterFunction].
@ -27,12 +30,12 @@ object MultiFilter {
@Readonly filterFunction: (String) -> Boolean,
forUniqueValidityTests: Boolean = false
): Boolean {
if (input.hasSurrounding(andPrefix, andSuffix) && input.contains(andSeparator))
return input.removeSurrounding(andPrefix, andSuffix).split(andSeparator)
if (isAnd(input))
return getAndFilters(input)
.all { multiFilter(it, filterFunction, forUniqueValidityTests) }
if (input.hasSurrounding(notPrefix, notSuffix)) {
if (isNot(input)) {
//same as `return multiFilter() == forUniqueValidityTests`, but clearer
val internalResult = multiFilter(input.removeSurrounding(notPrefix, notSuffix), filterFunction, forUniqueValidityTests)
val internalResult = multiFilter(getNotFilter(input), filterFunction, forUniqueValidityTests)
return if (forUniqueValidityTests) internalResult else !internalResult
}
return filterFunction(input)
@ -40,19 +43,19 @@ object MultiFilter {
@Pure
fun getAllSingleFilters(input: String): Sequence<String> = when {
input.hasSurrounding(andPrefix, andSuffix) && input.contains(andSeparator) -> {
isAnd(input) -> {
// Resolve "AND" filters
@LocalState val filters = input.removeSurrounding(andPrefix, andSuffix)
.splitToSequence(andSeparator)
@LocalState val filters = getAndFilters(input)
filters.flatMap { getAllSingleFilters(it) }
}
input.hasSurrounding(notPrefix, notSuffix) ->
isNot(input) ->
// Simply remove "non" syntax
getAllSingleFilters(input.removeSurrounding(notPrefix, notSuffix))
getAllSingleFilters(getNotFilter(input))
else -> sequenceOf(input)
}
@Pure
fun String.hasSurrounding(prefix: String, suffix: String) =
startsWith(prefix) && endsWith(suffix)
@Pure fun isAnd(input: String) = input.startsWith(andPrefixChar) && input.endsWith(andSuffixChar) && input.contains(andSeparator)
@Pure fun getAndFilters(input: String) = input.removeSurrounding(andPrefix, andSuffix).splitToSequence(andSeparator)
@Pure fun isNot(input: String) = input.endsWith(notSuffixChar) && input.startsWith(notPrefix)
@Pure fun getNotFilter(input: String) = input.removeSurrounding(notPrefix, notSuffix)
}