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