[CLI] argumentsToStrings: Add 'compactArgumentValues' option

Passing 'false' will pass Array or List based arguments multiple times
instead of using the Delimiter.

eg:
compactArgumentValues = true:
"-cp", "library1;library2;library3"

compactArgumentValues = false:
"-cp", "library1", "-cp", -"library2", "-cp", "library3"

Using compactArgumentValues = false can be beneficial
when the many compiler arguments are held in memory.
In this case the raw arguments can intern individual string values, which
is highly effective when the arguments refer to files on disk.

KTIJ-24976
This commit is contained in:
Sebastian Sellmair
2023-04-04 14:43:24 +02:00
committed by Space Team
parent fb66764c4d
commit 082a38216d
2 changed files with 42 additions and 19 deletions
@@ -17,14 +17,20 @@ import kotlin.reflect.full.memberProperties
@Suppress("UNCHECKED_CAST")
@JvmOverloads
fun CommonToolArguments.toArgumentStrings(useShortNames: Boolean = false): List<String> {
fun CommonToolArguments.toArgumentStrings(shortArgumentKeys: Boolean = false, compactArgumentValues: Boolean = true): List<String> {
return toArgumentStrings(
this, this::class as KClass<CommonToolArguments>, useShortNames = useShortNames
this, this::class as KClass<CommonToolArguments>,
shortArgumentKeys = shortArgumentKeys,
compactArgumentValues = compactArgumentValues
)
}
@PublishedApi
internal fun <T : CommonToolArguments> toArgumentStrings(thisArguments: T, type: KClass<T>, useShortNames: Boolean): List<String> {
internal fun <T : CommonToolArguments> toArgumentStrings(
thisArguments: T, type: KClass<T>,
shortArgumentKeys: Boolean,
compactArgumentValues: Boolean
): List<String> {
val defaultArguments = type.newArgumentsInstance()
val result = mutableListOf<String>()
type.memberProperties.forEach { property ->
@@ -41,15 +47,15 @@ internal fun <T : CommonToolArguments> toArgumentStrings(thisArguments: T, type:
property.returnType.classifier == Boolean::class -> listOf(rawPropertyValue?.toString() ?: false.toString())
(property.returnType.classifier as? KClass<*>)?.java?.isArray == true ->
getArgumentStringValue(argumentAnnotation, rawPropertyValue as Array<*>?)
getArgumentStringValue(argumentAnnotation, rawPropertyValue as Array<*>?, compactArgumentValues)
property.returnType.classifier == List::class ->
getArgumentStringValue(argumentAnnotation, (rawPropertyValue as List<*>?)?.toTypedArray())
getArgumentStringValue(argumentAnnotation, (rawPropertyValue as List<*>?)?.toTypedArray(), compactArgumentValues)
else -> listOf(rawPropertyValue.toString())
}
val argumentName = if (useShortNames && argumentAnnotation.shortName.isNotEmpty()) argumentAnnotation.shortName
val argumentName = if (shortArgumentKeys && argumentAnnotation.shortName.isNotEmpty()) argumentAnnotation.shortName
else argumentAnnotation.value
argumentStringValues.forEach { argumentStringValue ->
@@ -77,10 +83,10 @@ internal fun <T : CommonToolArguments> toArgumentStrings(thisArguments: T, type:
return result
}
private fun getArgumentStringValue(argumentAnnotation: Argument, values: Array<*>?): List<String> {
private fun getArgumentStringValue(argumentAnnotation: Argument, values: Array<*>?, compactArgumentValues: Boolean): List<String> {
if (values.isNullOrEmpty()) return emptyList()
val delimiter = argumentAnnotation.resolvedDelimiter
return if (delimiter.isNullOrEmpty()) values.map { it.toString() }
return if (delimiter.isNullOrEmpty() || !compactArgumentValues) values.map { it.toString() }
else listOf(values.joinToString(delimiter))
}
@@ -25,14 +25,28 @@ class CompilerArgumentParsingTest {
@ParameterizedTest
@MethodSource("parameters")
fun `test - parsing random compiler arguments`(type: KClass<out CommonToolArguments>, seed: Int, useShortNames: Boolean) {
fun `test - parsing random compiler arguments`(
type: KClass<out CommonToolArguments>,
seed: Int,
shortArgumentKeys: Boolean,
compactArgumentValues: Boolean
) {
val constructor = type.constructors.find { it.parameters.isEmpty() } ?: error("Missing empty constructor on $type")
val arguments = constructor.call()
arguments.fillRandomValues(Random(seed))
val argumentsAsStrings = arguments.toArgumentStrings(useShortNames)
val argumentsAsStrings = arguments.toArgumentStrings(
shortArgumentKeys = shortArgumentKeys,
compactArgumentValues = compactArgumentValues
)
val parsedArguments = parseCommandLineArguments(type, argumentsAsStrings)
assertEqualArguments(arguments, parsedArguments)
assertEquals(argumentsAsStrings, parsedArguments.toArgumentStrings(useShortNames))
assertEquals(
argumentsAsStrings,
parsedArguments.toArgumentStrings(
shortArgumentKeys = shortArgumentKeys,
compactArgumentValues = compactArgumentValues
)
)
}
companion object {
@@ -40,12 +54,15 @@ class CompilerArgumentParsingTest {
fun parameters(): List<Arguments> = getCompilerArgumentImplementations()
.flatMap { clazz ->
listOf(1002, 2803, 2411).flatMap { seed ->
listOf(true, false).map { useShortNames ->
Arguments.of(
Named.of("${clazz.simpleName}", clazz),
Named.of("seed: $seed", seed),
Named.of("useShortNames: $useShortNames", useShortNames)
)
listOf(true, false).flatMap { shortArgumentKeys ->
listOf(true, false).map { compactArgumentValues ->
Arguments.of(
Named.of("${clazz.simpleName}", clazz),
Named.of("seed: $seed", seed),
Named.of("shortArgumentKeys: $shortArgumentKeys", shortArgumentKeys),
Named.of("compactArgumentValues: $compactArgumentValues", compactArgumentValues)
)
}
}
}
}
@@ -96,14 +113,14 @@ private fun Random.randomString() = nextBytes(nextInt(8, 12)).let { data ->
private fun Random.randomBoolean() = nextBoolean()
private fun Random.randomStringArray(): Array<String> {
val size = nextInt(1, 5)
val size = nextInt(5, 10)
return Array(size) {
randomString()
}
}
private fun Random.randomList(elementType: KType): List<Any>? {
val size = nextInt(1, 5)
val size = nextInt(5, 10)
return List(size) {
randomValue(elementType) ?: return null
}