11package kotlinx.benchmark.integration
22
3+ @OptIn(ExperimentalStdlibApi ::class )
34class AnnotationsSpecifier {
4- private var isMeasurementSpecified: Boolean = false
5- private var iterations: Int? = null
6- private var time: Int? = null
7- private var timeUnit: String? = null
5+ private val classAnnotations = mutableListOf<Annotation >()
6+ private val propertyAnnotations = mutableListOf<AnnotatedMember >()
7+ private val functionAnnotations = mutableListOf<AnnotatedMember >()
88
99 fun measurement (iterations : Int , time : Int , timeUnit : String ) {
10- isMeasurementSpecified = true
11- this .iterations = iterations
12- this .time = time
13- this .timeUnit = timeUnit
10+ classAnnotations.add(
11+ Annotation (" @Measurement" , listOf (iterations, time, timeUnit))
12+ )
1413 }
1514
16- fun replacementForLine (line : String ): String {
15+ fun outputTimeUnit (timeUnit : String ) {
16+ classAnnotations.add(
17+ Annotation (" @OutputTimeUnit" , listOf (timeUnit))
18+ )
19+ }
20+
21+ fun benchmarkMode (mode : String ) {
22+ classAnnotations.add(
23+ Annotation (" @BenchmarkMode" , listOf (mode))
24+ )
25+ }
26+
27+ fun benchmark (functionName : String ) {
28+ functionAnnotations.add(
29+ AnnotatedMember (functionName, Annotation (" @Benchmark" ))
30+ )
31+ }
32+
33+ fun setup (functionName : String ) {
34+ functionAnnotations.add(
35+ AnnotatedMember (functionName, Annotation (" @Setup" ))
36+ )
37+ }
38+
39+ fun teardown (functionName : String ) {
40+ functionAnnotations.add(
41+ AnnotatedMember (functionName, Annotation (" @TearDown" ))
42+ )
43+ }
44+
45+ fun param (propertyName : String , vararg values : String ) {
46+ require(values.all { ' \" ' !in it }) { " TODO: Support param values that contain '\" '." }
47+
48+ propertyAnnotations.add(
49+ AnnotatedMember (propertyName, Annotation (" @Param" , values.map { " \" $it \" " }))
50+ )
51+ }
52+
53+ fun annotationsForProperty (line : String ): List <String > {
54+ val annotations = mutableListOf<String >()
55+ for ((propertyName, annotation) in propertyAnnotations) {
56+ val regex = Regex (" \\ s*(public|private|protected|internal)?\\ s*(final|open)?\\ s*(val|var)\\ s+${Regex .escape(propertyName)} " )
57+ if (regex.matchesAt(line, 0 )) {
58+ check(! annotation.isUsed)
59+ annotation.isUsed = true
60+ annotations.add(annotation.toCode())
61+ }
62+ }
63+ return annotations
64+ }
65+
66+ fun annotationsForFunction (line : String ): List <String > {
67+ val annotations = mutableListOf<String >()
68+ for ((functionName, annotation) in functionAnnotations) {
69+ val regex = Regex (" \\ s*(public|private|protected|internal)?\\ s*(final|open)?\\ s*fun\\ s+${Regex .escape(functionName)} \\ (" )
70+ if (regex.matchesAt(line, 0 )) {
71+ check(! annotation.isUsed)
72+ annotation.isUsed = true
73+ annotations.add(annotation.toCode())
74+ }
75+ }
76+ return annotations
77+ }
78+
79+ fun replaceClassAnnotation (line : String ): String {
1780 val trimmedLine = line.trimStart()
1881 val prefix = line.substring(0 , line.length - trimmedLine.length)
19- return when {
20- isMeasurementSpecified && trimmedLine.startsWith(" @Measurement" ) ->
21- " $prefix @Measurement($iterations , $time , $timeUnit )"
22- else ->
23- line
82+ for (annotation in classAnnotations) {
83+ if (trimmedLine.startsWith(annotation.name)) {
84+ check(! annotation.isUsed)
85+ annotation.isUsed = true
86+ return prefix + annotation.toCode()
87+ }
2488 }
89+ return line
90+ }
91+
92+ fun checkAllAnnotationsAreUsed () {
93+ classAnnotations.forEach { check(it.isUsed) { " Unused class annotation: $it " } }
94+ propertyAnnotations.forEach { check(it.annotation.isUsed) { " Unused property annotation: $it " } }
95+ functionAnnotations.forEach { check(it.annotation.isUsed) { " Unused function annotation: $it " } }
2596 }
97+ }
98+
99+ private data class AnnotatedMember (
100+ val memberName : String ,
101+ val annotation : Annotation
102+ )
103+
104+ private data class Annotation (
105+ val name : String ,
106+ val arguments : List <Any ?> = emptyList(),
107+ var isUsed : Boolean = false
108+ ) {
109+ fun toCode (): String =
110+ " $name${if (arguments.isEmpty()) " " else arguments.joinToString(" , " , " (" , " )" )} "
26111}
0 commit comments