IDE perf tests for Kotlin/Native projects

Issue #MMPP-201
This commit is contained in:
Dmitriy Dolovov
2020-02-21 19:23:55 +07:00
parent f5e6001d82
commit ca3c72c143
31 changed files with 1143 additions and 70 deletions
@@ -11,7 +11,6 @@ import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.ide.highlighter.ModuleFileType
import com.intellij.ide.startup.impl.StartupManagerImpl
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.application.ApplicationManager
@@ -20,26 +19,23 @@ import com.intellij.openapi.editor.EditorFactory
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.module.ModuleTypeId
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.project.impl.ProjectImpl
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.startup.StartupManager
import com.intellij.openapi.vcs.changes.ChangeListManager
import com.intellij.openapi.vcs.changes.ChangeListManagerImpl
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.testFramework.*
import com.intellij.testFramework.EditorTestUtil
import com.intellij.testFramework.RunAll
import com.intellij.testFramework.TestDataProvider
import com.intellij.testFramework.UsefulTestCase
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
import com.intellij.util.ArrayUtilRt
import com.intellij.util.ThrowableRunnable
@@ -51,7 +47,6 @@ import org.jetbrains.kotlin.idea.framework.KotlinSdkType
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.invalidateLibraryCache
import org.jetbrains.kotlin.idea.testFramework.*
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches
@@ -98,11 +93,15 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
}
}
protected fun warmUpProject(stats: Stats) {
val project = perfOpenHelloWorld(stats, WARM_UP)
protected fun warmUpProject(stats: Stats, vararg filesToHighlight: String, openProject: () -> Project) {
assertTrue(filesToHighlight.isNotEmpty())
val project = openProject()
try {
val perfHighlightFile = perfHighlightFile(project, "src/HelloMain.kt", stats, WARM_UP)
assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty())
filesToHighlight.forEach {
val perfHighlightFile = perfHighlightFile(project, it, stats, WARM_UP)
assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty())
}
} finally {
closeProject(project)
myApplication.setDataProvider(null)
@@ -130,22 +129,12 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName
}
protected fun perfOpenKotlinProjectFast(stats: Stats) =
perfOpenKotlinProject(stats, fast = true)
protected fun perfOpenKotlinProject(stats: Stats, fast: Boolean = false) {
myProject = innerPerfOpenProject("kotlin", stats = stats, path = "../perfTestProject", note = "", fast = fast)
}
protected fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project =
innerPerfOpenProject("helloKotlin", stats, note, path = "idea/testData/perfTest/helloKotlin", simpleModule = true)
protected fun innerPerfOpenProject(
protected fun perfOpenProject(
name: String,
stats: Stats,
note: String,
path: String,
simpleModule: Boolean = false,
openAction: ProjectOpenAction,
fast: Boolean = false
): Project {
val projectPath = File(path).canonicalPath
@@ -154,7 +143,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
val warmUpIterations = if (fast) 0 else 5
val iterations = if (fast) 1 else 5
val projectManagerEx = ProjectManagerEx.getInstanceEx()
var lastProject: Project? = null
var counter = 0
@@ -166,27 +154,10 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
iterations(iterations)
checkStability(!fast)
test {
val project = if (!simpleModule) {
val project = loadProjectWithName(name = name, path = path)
assertNotNull("project $name at $path is not loaded", project)
val projectRootManager = ProjectRootManager.getInstance(project!!)
runWriteAction {
with(projectRootManager) {
projectSdk = jdk18
}
}
assertTrue("project $name at $path is not opened", projectManagerEx.openProject(project))
project
} else {
val project = projectManagerEx.loadAndOpenProject(projectPath)!!
initKotlinProject(project, projectPath, name)
project
}
(project as ProjectImpl).registerComponentImplementation(
FileEditorManager::class.java,
FileEditorManagerImpl::class.java
val project = openAction.openProject(
projectPath = path,
projectName = name,
jdk = jdk18
)
dispatchAllInvocationEvents()
@@ -537,27 +508,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
}
}
private fun initKotlinProject(
project: Project,
projectPath: String,
name: String
) {
val modulePath = "$projectPath/$name${ModuleFileType.DOT_DEFAULT_EXTENSION}"
val projectFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(projectPath))!!
val srcFile = projectFile.findChild("src")!!
val module = runWriteAction {
val projectRootManager = ProjectRootManager.getInstance(project)
with(projectRootManager) {
projectSdk = jdk18
}
val moduleManager = ModuleManager.getInstance(project)
val module = moduleManager.newModule(modulePath, ModuleTypeId.JAVA_MODULE)
PsiTestUtil.addSourceRoot(module, srcFile)
module
}
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, jdk18)
}
protected fun perfHighlightFile(name: String, stats: Stats): List<HighlightInfo> =
perfHighlightFile(project(), name, stats)
@@ -0,0 +1,229 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.perf
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.rootManager
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.gradle.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME
import org.jetbrains.kotlin.ide.konan.NativeLibraryKind
import org.jetbrains.kotlin.idea.caches.project.isMPPModule
import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.parseIDELibraryName
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.framework.detectLibraryKind
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.GRADLE_PROJECT
import org.jetbrains.kotlin.idea.testFramework.logMessage
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.library.KOTLIN_STDLIB_NAME
import org.jetbrains.kotlin.platform.konan.isNative
import java.io.File
class PerformanceNativeProjectsTest : AbstractPerformanceProjectsTest() {
companion object {
private const val GRADLE_VERSION = "6.0.1"
private const val KOTLIN_PLUGIN_VERSION = "1.4.0-dev-3273" // TODO: use 1.4-M1 when it's published
private var warmedUp: Boolean = false
}
override fun setUp() {
super.setUp()
// warm up: open simple small project
if (!warmedUp) {
val projectTemplate = "HelloWorld"
val enableCommonizer = true
val projectName = "${projectName(projectTemplate, enableCommonizer)}-$WARM_UP"
// don't share this stats instance with another one used in "Hello World" test
Stats(projectName).use { stats ->
warmUpProject(stats, "src/iosX64Main/kotlin/HelloMain.kt") {
perfOpenTemplateGradleProject(stats, projectTemplate, enableCommonizer, WARM_UP)
}
}
warmedUp = true
}
}
fun testHelloWorldProjectWithCommonizer() = doTestHighlighting(
"HelloWorld",
true,
"src/iosX64Main/kotlin/HelloMain.kt",
"src/iosX64Main/kotlin/HelloMain2.kt",
"src/iosX64Main/kotlin/HelloMain3.kt",
"src/iosX64Test/kotlin/HelloTest.kt",
"src/iosX64Test/kotlin/HelloTest2.kt",
"src/iosX64Test/kotlin/HelloTest3.kt"
)
fun testHelloWorldProjectWithoutCommonizer() = doTestHighlighting(
"HelloWorld",
false,
"src/iosX64Main/kotlin/HelloMain.kt",
"src/iosX64Main/kotlin/HelloMain2.kt",
"src/iosX64Main/kotlin/HelloMain3.kt",
"src/iosX64Test/kotlin/HelloTest.kt",
"src/iosX64Test/kotlin/HelloTest2.kt",
"src/iosX64Test/kotlin/HelloTest3.kt"
)
fun testCvsParserProjectWithCommonizer() = doTestHighlighting(
"CsvParser",
true,
"src/iosX64Main/kotlin/CsvParser.kt",
"src/iosX64Main/kotlin/CsvParser2.kt",
"src/iosX64Main/kotlin/CsvParser3.kt"
)
fun testCvsParserProjectWithoutCommonizer() = doTestHighlighting(
"CsvParser",
false,
"src/iosX64Main/kotlin/CsvParser.kt",
"src/iosX64Main/kotlin/CsvParser2.kt",
"src/iosX64Main/kotlin/CsvParser3.kt"
)
fun testUIKitAppProjectWithCommonizer() = doTestHighlighting(
"UIKitApp",
true,
"src/iosX64Main/kotlin/UIKitApp.kt",
"src/iosX64Main/kotlin/UIKitApp2.kt",
"src/iosX64Main/kotlin/UIKitApp3.kt"
)
fun testUIKitAppProjectWithoutCommonizer() = doTestHighlighting(
"UIKitApp",
false,
"src/iosX64Main/kotlin/UIKitApp.kt",
"src/iosX64Main/kotlin/UIKitApp2.kt",
"src/iosX64Main/kotlin/UIKitApp3.kt"
)
private fun doTestHighlighting(
templateName: String,
enableCommonizer: Boolean,
vararg filesToHighlight: String
) {
assertTrue(filesToHighlight.isNotEmpty())
val projectName = projectName(templateName, enableCommonizer)
tcSuite(projectName) {
Stats(projectName).use { stats ->
myProject = perfOpenTemplateGradleProject(stats, templateName, enableCommonizer)
// highlight
filesToHighlight.forEach { perfHighlightFile(it, stats) }
}
}
}
private fun perfOpenTemplateGradleProject(
stats: Stats,
templateName: String,
enableCommonizer: Boolean,
note: String = ""
): Project {
val templateRoot = File("idea/testData/perfTest/native/").resolve(templateName)
val projectRoot = FileUtil.createTempDirectory("project", "", false)
templateRoot.walkTopDown()
.filter { it.isFile }
.forEach { source ->
val destination = projectRoot.resolve(source.relativeTo(templateRoot))
val filename = source.name
if (filename == "build.gradle.kts" || filename == "gradle-wrapper.properties" || filename == "gradle.properties") {
val text = source.readText()
.replace("{{kotlin_plugin_version}}", KOTLIN_PLUGIN_VERSION)
.replace("{{gradle_version}}", GRADLE_VERSION)
.replace("{{disable_commonizer}}", (!enableCommonizer).toString())
destination.parentFile.mkdirs()
destination.writeText(text)
} else {
source.copyTo(destination)
}
}
val projectName = projectName(templateName, enableCommonizer, separator = '-')
val project = perfOpenProject(
name = projectName,
stats = stats,
note = note,
path = projectRoot.absolutePath,
openAction = GRADLE_PROJECT
)
runProjectSanityChecks(project)
return project
}
// goal: make sure that the project imported from Gradle is valid
private fun runProjectSanityChecks(project: Project) {
val nativeModules: Map<Module, Set<String>> = runReadAction {
project.allModules().mapNotNull { module ->
val facetSettings = KotlinFacet.get(module)?.configuration?.settings ?: return@mapNotNull null
if (!facetSettings.isMPPModule || !facetSettings.targetPlatform.isNative()) return@mapNotNull null
// workaround to skip top-level common test module, which in fact does not get any Kotlin/Native KLIB libraries
// but accidentally gets Kotlin facet with Native platform
if (module.name == "${project.name}.$COMMON_TEST_SOURCE_SET_NAME") return@mapNotNull null
val nativeLibraries = module.rootManager.orderEntries
.asSequence()
.filterIsInstance<LibraryOrderEntry>()
.mapNotNull { it.library }
.filter { library ->
val libraryKind = detectLibraryKind(library.getFiles(OrderRootType.CLASSES))
libraryKind == NativeLibraryKind
// TODO: remove this check for CommonLibraryKind when detection of K/N KLIBs in
// org.jetbrains.kotlin.ide.konan.KotlinNativePluginUtilKt.isKonanLibraryRoot
// is correctly implemented
|| libraryKind == CommonLibraryKind
}
.mapNotNull inner@{ library ->
val libraryNameParts = parseIDELibraryName(library.name.orEmpty()) ?: return@inner null
val (_, pureLibraryName, platformPart) = libraryNameParts
pureLibraryName + if (platformPart != null) " [$platformPart]" else ""
}
.toSet()
module to nativeLibraries
}.toMap()
}
assertTrue("No Native modules found in project $project", nativeModules.isNotEmpty())
nativeModules.forEach { (module, nativeLibraries) ->
assertTrue(
"$KOTLIN_STDLIB_NAME not found for for Native module $module in project $project",
KOTLIN_STDLIB_NAME in nativeLibraries
)
assertTrue(
"No Native libraries except for $KOTLIN_STDLIB_NAME for Native module $module in project $project",
(nativeLibraries - KOTLIN_STDLIB_NAME).isNotEmpty()
)
logMessage { "$module has ${nativeLibraries.size} native libraries" }
}
}
private fun projectName(templateName: String, enableCommonizer: Boolean, separator: Char = ' ') =
"$templateName project ${if (enableCommonizer) "with" else "without"} commonizer".replace(' ', separator)
}
@@ -14,11 +14,14 @@ import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker
import org.jetbrains.kotlin.idea.highlighter.KotlinPsiCheckerAndHighlightingUpdater
import org.jetbrains.kotlin.idea.perf.Stats.Companion.TEST_KEY
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
import org.jetbrains.kotlin.idea.testFramework.Fixture
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.EXISTING_IDEA_PROJECT
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.SIMPLE_JAVA_MODULE
import java.util.concurrent.atomic.AtomicLong
import kotlin.test.assertNotEquals
@@ -53,8 +56,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
super.setUp()
// warm up: open simple small project
if (!warmedUp) {
warmUpProject(hwStats)
warmUpProject(hwStats, "src/HelloMain.kt") { perfOpenHelloWorld(hwStats, WARM_UP) }
warmedUp = true
}
}
@@ -207,6 +209,28 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
}
}
private fun perfOpenKotlinProjectFast(stats: Stats) = perfOpenKotlinProject(stats, fast = true)
private fun perfOpenKotlinProject(stats: Stats, fast: Boolean = false) {
myProject = perfOpenProject(
name = "kotlin",
stats = stats,
note = "",
path = "../perfTestProject",
openAction = EXISTING_IDEA_PROJECT,
fast = fast
)
}
private fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project =
perfOpenProject(
name = "helloKotlin",
stats = stats,
note = note,
path = "idea/testData/perfTest/helloKotlin",
openAction = SIMPLE_JAVA_MODULE
)
private fun perfScriptDependenciesBuildGradleKts(it: Stats) {
perfScriptDependencies("build.gradle.kts", stats = it)
}
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.testFramework
import com.intellij.ide.highlighter.ModuleFileType
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.module.ModuleTypeId
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.testFramework.PsiTestUtil
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import java.io.File
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
enum class ProjectOpenAction {
SIMPLE_JAVA_MODULE {
override fun openProject(projectPath: String, projectName: String, jdk: Sdk): Project {
val project = ProjectManagerEx.getInstanceEx().loadAndOpenProject(projectPath)!!
val modulePath = "$projectPath/$name${ModuleFileType.DOT_DEFAULT_EXTENSION}"
val projectFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(projectPath))!!
val srcFile = projectFile.findChild("src")!!
val module = runWriteAction {
ProjectRootManager.getInstance(project).projectSdk = jdk
val module = ModuleManager.getInstance(project).newModule(modulePath, ModuleTypeId.JAVA_MODULE)
PsiTestUtil.addSourceRoot(module, srcFile)
module
}
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, jdk)
return project
}
},
EXISTING_IDEA_PROJECT {
override fun openProject(projectPath: String, projectName: String, jdk: Sdk): Project {
val projectManagerEx = ProjectManagerEx.getInstanceEx()
val project = loadProjectWithName(projectPath, projectName)
assertNotNull(project, "project $projectName at $projectPath is not loaded")
runWriteAction {
ProjectRootManager.getInstance(project).projectSdk = jdk
}
assertTrue(projectManagerEx.openProject(project), "project $projectName at $projectPath is not opened")
return project
}
},
GRADLE_PROJECT {
override fun openProject(projectPath: String, projectName: String, jdk: Sdk): Project {
val project = ProjectManagerEx.getInstanceEx().loadAndOpenProject(projectPath)!!
runWriteAction {
ProjectRootManager.getInstance(project).projectSdk = jdk
}
refreshGradleProject(projectPath, project)
return project
}
};
abstract fun openProject(projectPath: String, projectName: String, jdk: Sdk): Project
}
+4
View File
@@ -0,0 +1,4 @@
build
.idea
.gradle
gradlew*
@@ -0,0 +1,15 @@
plugins {
kotlin("multiplatform") version "{{kotlin_plugin_version}}"
}
repositories {
mavenCentral()
maven("https://dl.bintray.com/kotlin/kotlin-dev")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
}
kotlin {
ios() {
compilations["main"].enableEndorsedLibs = true
}
}
@@ -0,0 +1,2 @@
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation={{disable_commonizer}}
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-{{gradle_version}}-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -0,0 +1,7 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven("https://dl.bintray.com/kotlin/kotlin-dev")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.allocArray
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toKString
import kotlinx.cli.ArgParser
import kotlinx.cli.ArgType
import kotlinx.cli.required
import platform.posix.fclose
import platform.posix.fgets
import platform.posix.fopen
import platform.posix.perror
import kotlin.collections.set
private fun parseLine(line: String, separator: Char) : List<String> {
val result = mutableListOf<String>()
val builder = StringBuilder()
var quotes = 0
for (ch in line) {
when {
ch == '\"' -> {
quotes++
builder.append(ch)
}
(ch == '\n') || (ch == '\r') -> {}
(ch == separator) && (quotes % 2 == 0) -> {
result.add(builder.toString())
builder.setLength(0)
}
else -> builder.append(ch)
}
}
return result
}
fun main(args: Array<String>) {
val argParser = ArgParser("csvparser")
val fileName by argParser.argument(ArgType.String, description = "CSV file")
val column by argParser.option(ArgType.Int, description = "Column to parse").required()
val count by argParser.option(ArgType.Int, description = "Count of lines to parse").required()
argParser.parse(args)
val file = fopen(fileName, "r")
if (file == null) {
perror("cannot open input file $fileName")
return
}
val keyValue = mutableMapOf<String, Int>()
try {
memScoped {
val bufferLength = 64 * 1024
val buffer = allocArray<ByteVar>(bufferLength)
for (i in 1..count) {
val nextLine = fgets(buffer, bufferLength, file)?.toKString()
if (nextLine == null || nextLine.isEmpty()) break
val records = parseLine(nextLine, ',')
val key = records[column]
val current = keyValue[key] ?: 0
keyValue[key] = current + 1
}
}
} finally {
fclose(file)
}
keyValue.forEach {
println("${it.key} -> ${it.value}")
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.allocArray
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toKString
import kotlinx.cli.ArgParser
import kotlinx.cli.ArgType
import kotlinx.cli.required
import platform.posix.fclose
import platform.posix.fgets
import platform.posix.fopen
import platform.posix.perror
import kotlin.collections.set
private fun parseLine(line: String, separator: Char) : List<String> {
val result = mutableListOf<String>()
val builder = StringBuilder()
var quotes = 0
for (ch in line) {
when {
ch == '\"' -> {
quotes++
builder.append(ch)
}
(ch == '\n') || (ch == '\r') -> {}
(ch == separator) && (quotes % 2 == 0) -> {
result.add(builder.toString())
builder.setLength(0)
}
else -> builder.append(ch)
}
}
return result
}
fun main(args: Array<String>) {
val argParser = ArgParser("csvparser")
val fileName by argParser.argument(ArgType.String, description = "CSV file")
val column by argParser.option(ArgType.Int, description = "Column to parse").required()
val count by argParser.option(ArgType.Int, description = "Count of lines to parse").required()
argParser.parse(args)
val file = fopen(fileName, "r")
if (file == null) {
perror("cannot open input file $fileName")
return
}
val keyValue = mutableMapOf<String, Int>()
try {
memScoped {
val bufferLength = 64 * 1024
val buffer = allocArray<ByteVar>(bufferLength)
for (i in 1..count) {
val nextLine = fgets(buffer, bufferLength, file)?.toKString()
if (nextLine == null || nextLine.isEmpty()) break
val records = parseLine(nextLine, ',')
val key = records[column]
val current = keyValue[key] ?: 0
keyValue[key] = current + 1
}
}
} finally {
fclose(file)
}
keyValue.forEach {
println("${it.key} -> ${it.value}")
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.allocArray
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toKString
import kotlinx.cli.ArgParser
import kotlinx.cli.ArgType
import kotlinx.cli.required
import platform.posix.fclose
import platform.posix.fgets
import platform.posix.fopen
import platform.posix.perror
import kotlin.collections.set
private fun parseLine(line: String, separator: Char) : List<String> {
val result = mutableListOf<String>()
val builder = StringBuilder()
var quotes = 0
for (ch in line) {
when {
ch == '\"' -> {
quotes++
builder.append(ch)
}
(ch == '\n') || (ch == '\r') -> {}
(ch == separator) && (quotes % 2 == 0) -> {
result.add(builder.toString())
builder.setLength(0)
}
else -> builder.append(ch)
}
}
return result
}
fun main(args: Array<String>) {
val argParser = ArgParser("csvparser")
val fileName by argParser.argument(ArgType.String, description = "CSV file")
val column by argParser.option(ArgType.Int, description = "Column to parse").required()
val count by argParser.option(ArgType.Int, description = "Count of lines to parse").required()
argParser.parse(args)
val file = fopen(fileName, "r")
if (file == null) {
perror("cannot open input file $fileName")
return
}
val keyValue = mutableMapOf<String, Int>()
try {
memScoped {
val bufferLength = 64 * 1024
val buffer = allocArray<ByteVar>(bufferLength)
for (i in 1..count) {
val nextLine = fgets(buffer, bufferLength, file)?.toKString()
if (nextLine == null || nextLine.isEmpty()) break
val records = parseLine(nextLine, ',')
val key = records[column]
val current = keyValue[key] ?: 0
keyValue[key] = current + 1
}
}
} finally {
fclose(file)
}
keyValue.forEach {
println("${it.key} -> ${it.value}")
}
}
+4
View File
@@ -0,0 +1,4 @@
build
.idea
.gradle
gradlew*
@@ -0,0 +1,13 @@
plugins {
kotlin("multiplatform") version "{{kotlin_plugin_version}}"
}
repositories {
mavenCentral()
maven("https://dl.bintray.com/kotlin/kotlin-dev")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
}
kotlin {
ios()
}
@@ -0,0 +1,2 @@
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation={{disable_commonizer}}
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-{{gradle_version}}-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -0,0 +1,7 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven("https://dl.bintray.com/kotlin/kotlin-dev")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
}
}
@@ -0,0 +1,4 @@
fun main(args: Array<String>) {
println("Hello World!")
}
@@ -0,0 +1,4 @@
fun main(args: Array<String>) {
println("Hello World!")
}
@@ -0,0 +1,4 @@
fun main(args: Array<String>) {
println("Hello World!")
}
@@ -0,0 +1,11 @@
import kotlin.test.Test
import kotlin.test.assertTrue
private const val GREETING = "Hello, Kotlin/Native!"
class HelloTest {
@Test
fun testHello() {
assertTrue("Kotlin/Native" in GREETING)
}
}
@@ -0,0 +1,11 @@
import kotlin.test.Test
import kotlin.test.assertTrue
private const val GREETING = "Hello, Kotlin/Native!"
class HelloTest2 {
@Test
fun testHello() {
assertTrue("Kotlin/Native" in GREETING)
}
}
@@ -0,0 +1,11 @@
import kotlin.test.Test
import kotlin.test.assertTrue
private const val GREETING = "Hello, Kotlin/Native!"
class HelloTest3 {
@Test
fun testHello() {
assertTrue("Kotlin/Native" in GREETING)
}
}
+4
View File
@@ -0,0 +1,4 @@
build
.idea
.gradle
gradlew*
+13
View File
@@ -0,0 +1,13 @@
plugins {
kotlin("multiplatform") version "{{kotlin_plugin_version}}"
}
repositories {
mavenCentral()
maven("https://dl.bintray.com/kotlin/kotlin-dev")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
}
kotlin {
ios()
}
@@ -0,0 +1,2 @@
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation={{disable_commonizer}}
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-{{gradle_version}}-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -0,0 +1,7 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven("https://dl.bintray.com/kotlin/kotlin-dev")
maven("https://dl.bintray.com/kotlin/kotlin-eap")
}
}
@@ -0,0 +1,140 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
import kotlinx.cinterop.ExportObjCClass
import kotlinx.cinterop.ObjCAction
import kotlinx.cinterop.ObjCOutlet
import kotlinx.cinterop.autoreleasepool
import kotlinx.cinterop.cstr
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toCValues
import kotlinx.cinterop.useContents
import platform.CoreGraphics.CGPointMake
import platform.CoreGraphics.CGRectMake
import platform.Foundation.NSCoder
import platform.Foundation.NSSelectorFromString
import platform.Foundation.NSStringFromClass
import platform.UIKit.NSTextAlignmentCenter
import platform.UIKit.UIApplication
import platform.UIKit.UIApplicationDelegateProtocol
import platform.UIKit.UIApplicationDelegateProtocolMeta
import platform.UIKit.UIApplicationMain
import platform.UIKit.UIButton
import platform.UIKit.UIColor
import platform.UIKit.UIControlEventTouchUpInside
import platform.UIKit.UIControlStateNormal
import platform.UIKit.UIFont
import platform.UIKit.UILabel
import platform.UIKit.UIResponder
import platform.UIKit.UIResponderMeta
import platform.UIKit.UIScreen
import platform.UIKit.UIView
import platform.UIKit.UIViewController
import platform.UIKit.UIWindow
import platform.UIKit.addSubview
import platform.UIKit.backgroundColor
import platform.UIKit.font
import platform.UIKit.heightAnchor
import platform.UIKit.leadingAnchor
import platform.UIKit.setFrame
import platform.UIKit.topAnchor
import platform.UIKit.translatesAutoresizingMaskIntoConstraints
import platform.UIKit.widthAnchor
fun main(args: Array<String>) {
memScoped {
val argc = args.size + 1
val argv = (arrayOf("konan") + args).map { it.cstr.ptr }.toCValues()
autoreleasepool {
UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate))
}
}
}
private class AppDelegate : UIResponder, UIApplicationDelegateProtocol {
companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta {}
@OverrideInit
constructor() : super()
private var _window: UIWindow? = null
override fun window() = _window
override fun setWindow(window: UIWindow?) {
_window = window
}
override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map<Any?, *>?): Boolean {
window = UIWindow(frame = UIScreen.mainScreen.bounds)
window!!.rootViewController = ViewController()
window!!.makeKeyAndVisible()
return true
}
}
@ExportObjCClass
private class ViewController : UIViewController {
@OverrideInit
constructor() : super(nibName = null, bundle = null)
@OverrideInit
constructor(coder: NSCoder) : super(coder)
@ObjCOutlet
lateinit var label: UILabel
@ObjCOutlet
lateinit var button: UIButton
var pressed = 0
@ObjCAction
fun buttonPressed() {
label.text = "Hello #${pressed++} from Konan!"
println("Button pressed")
}
override fun viewDidLoad() {
super.viewDidLoad()
val (width, height) = UIScreen.mainScreen.bounds.useContents {
this.size.width to this.size.height
}
val header = UIView().apply {
backgroundColor = UIColor.lightGrayColor
view.addSubview(this)
translatesAutoresizingMaskIntoConstraints = false
leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
topAnchor.constraintEqualToAnchor(view.topAnchor).active = true
widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true
heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true
}
label = UILabel().apply {
setFrame(CGRectMake(x = 10.0, y = 10.0, width = width - 100.0, height = 40.0))
center = CGPointMake(x = width / 2, y = 40.0 )
textAlignment = NSTextAlignmentCenter
text = "Press OK"
header.addSubview(this)
}
button = UIButton().apply {
setFrame(CGRectMake(x = 10.0, y = height - 100.0, width = width - 100.0, height = 40.0))
center = CGPointMake(x = width / 2, y = height / 2)
backgroundColor = UIColor.blueColor
setTitle("OK", forState = UIControlStateNormal)
font = UIFont.fontWithName(fontName = font.fontName, size = 28.0)!!
layer.borderWidth = 1.0
layer.borderColor = UIColor.colorWithRed(0x47 / 255.0, 0x43 / 255.0, 0x70 / 255.0, 1.0).CGColor
layer.masksToBounds = true
addTarget(target = this@ViewController, action = NSSelectorFromString("buttonPressed"),
forControlEvents = UIControlEventTouchUpInside)
header.addSubview(this)
}
}
}
@@ -0,0 +1,140 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
import kotlinx.cinterop.ExportObjCClass
import kotlinx.cinterop.ObjCAction
import kotlinx.cinterop.ObjCOutlet
import kotlinx.cinterop.autoreleasepool
import kotlinx.cinterop.cstr
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toCValues
import kotlinx.cinterop.useContents
import platform.CoreGraphics.CGPointMake
import platform.CoreGraphics.CGRectMake
import platform.Foundation.NSCoder
import platform.Foundation.NSSelectorFromString
import platform.Foundation.NSStringFromClass
import platform.UIKit.NSTextAlignmentCenter
import platform.UIKit.UIApplication
import platform.UIKit.UIApplicationDelegateProtocol
import platform.UIKit.UIApplicationDelegateProtocolMeta
import platform.UIKit.UIApplicationMain
import platform.UIKit.UIButton
import platform.UIKit.UIColor
import platform.UIKit.UIControlEventTouchUpInside
import platform.UIKit.UIControlStateNormal
import platform.UIKit.UIFont
import platform.UIKit.UILabel
import platform.UIKit.UIResponder
import platform.UIKit.UIResponderMeta
import platform.UIKit.UIScreen
import platform.UIKit.UIView
import platform.UIKit.UIViewController
import platform.UIKit.UIWindow
import platform.UIKit.addSubview
import platform.UIKit.backgroundColor
import platform.UIKit.font
import platform.UIKit.heightAnchor
import platform.UIKit.leadingAnchor
import platform.UIKit.setFrame
import platform.UIKit.topAnchor
import platform.UIKit.translatesAutoresizingMaskIntoConstraints
import platform.UIKit.widthAnchor
fun main(args: Array<String>) {
memScoped {
val argc = args.size + 1
val argv = (arrayOf("konan") + args).map { it.cstr.ptr }.toCValues()
autoreleasepool {
UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate))
}
}
}
private class AppDelegate : UIResponder, UIApplicationDelegateProtocol {
companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta {}
@OverrideInit
constructor() : super()
private var _window: UIWindow? = null
override fun window() = _window
override fun setWindow(window: UIWindow?) {
_window = window
}
override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map<Any?, *>?): Boolean {
window = UIWindow(frame = UIScreen.mainScreen.bounds)
window!!.rootViewController = ViewController()
window!!.makeKeyAndVisible()
return true
}
}
@ExportObjCClass
private class ViewController : UIViewController {
@OverrideInit
constructor() : super(nibName = null, bundle = null)
@OverrideInit
constructor(coder: NSCoder) : super(coder)
@ObjCOutlet
lateinit var label: UILabel
@ObjCOutlet
lateinit var button: UIButton
var pressed = 0
@ObjCAction
fun buttonPressed() {
label.text = "Hello #${pressed++} from Konan!"
println("Button pressed")
}
override fun viewDidLoad() {
super.viewDidLoad()
val (width, height) = UIScreen.mainScreen.bounds.useContents {
this.size.width to this.size.height
}
val header = UIView().apply {
backgroundColor = UIColor.lightGrayColor
view.addSubview(this)
translatesAutoresizingMaskIntoConstraints = false
leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
topAnchor.constraintEqualToAnchor(view.topAnchor).active = true
widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true
heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true
}
label = UILabel().apply {
setFrame(CGRectMake(x = 10.0, y = 10.0, width = width - 100.0, height = 40.0))
center = CGPointMake(x = width / 2, y = 40.0 )
textAlignment = NSTextAlignmentCenter
text = "Press OK"
header.addSubview(this)
}
button = UIButton().apply {
setFrame(CGRectMake(x = 10.0, y = height - 100.0, width = width - 100.0, height = 40.0))
center = CGPointMake(x = width / 2, y = height / 2)
backgroundColor = UIColor.blueColor
setTitle("OK", forState = UIControlStateNormal)
font = UIFont.fontWithName(fontName = font.fontName, size = 28.0)!!
layer.borderWidth = 1.0
layer.borderColor = UIColor.colorWithRed(0x47 / 255.0, 0x43 / 255.0, 0x70 / 255.0, 1.0).CGColor
layer.masksToBounds = true
addTarget(target = this@ViewController, action = NSSelectorFromString("buttonPressed"),
forControlEvents = UIControlEventTouchUpInside)
header.addSubview(this)
}
}
}
@@ -0,0 +1,140 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
import kotlinx.cinterop.ExportObjCClass
import kotlinx.cinterop.ObjCAction
import kotlinx.cinterop.ObjCOutlet
import kotlinx.cinterop.autoreleasepool
import kotlinx.cinterop.cstr
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.toCValues
import kotlinx.cinterop.useContents
import platform.CoreGraphics.CGPointMake
import platform.CoreGraphics.CGRectMake
import platform.Foundation.NSCoder
import platform.Foundation.NSSelectorFromString
import platform.Foundation.NSStringFromClass
import platform.UIKit.NSTextAlignmentCenter
import platform.UIKit.UIApplication
import platform.UIKit.UIApplicationDelegateProtocol
import platform.UIKit.UIApplicationDelegateProtocolMeta
import platform.UIKit.UIApplicationMain
import platform.UIKit.UIButton
import platform.UIKit.UIColor
import platform.UIKit.UIControlEventTouchUpInside
import platform.UIKit.UIControlStateNormal
import platform.UIKit.UIFont
import platform.UIKit.UILabel
import platform.UIKit.UIResponder
import platform.UIKit.UIResponderMeta
import platform.UIKit.UIScreen
import platform.UIKit.UIView
import platform.UIKit.UIViewController
import platform.UIKit.UIWindow
import platform.UIKit.addSubview
import platform.UIKit.backgroundColor
import platform.UIKit.font
import platform.UIKit.heightAnchor
import platform.UIKit.leadingAnchor
import platform.UIKit.setFrame
import platform.UIKit.topAnchor
import platform.UIKit.translatesAutoresizingMaskIntoConstraints
import platform.UIKit.widthAnchor
fun main(args: Array<String>) {
memScoped {
val argc = args.size + 1
val argv = (arrayOf("konan") + args).map { it.cstr.ptr }.toCValues()
autoreleasepool {
UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate))
}
}
}
private class AppDelegate : UIResponder, UIApplicationDelegateProtocol {
companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta {}
@OverrideInit
constructor() : super()
private var _window: UIWindow? = null
override fun window() = _window
override fun setWindow(window: UIWindow?) {
_window = window
}
override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map<Any?, *>?): Boolean {
window = UIWindow(frame = UIScreen.mainScreen.bounds)
window!!.rootViewController = ViewController()
window!!.makeKeyAndVisible()
return true
}
}
@ExportObjCClass
private class ViewController : UIViewController {
@OverrideInit
constructor() : super(nibName = null, bundle = null)
@OverrideInit
constructor(coder: NSCoder) : super(coder)
@ObjCOutlet
lateinit var label: UILabel
@ObjCOutlet
lateinit var button: UIButton
var pressed = 0
@ObjCAction
fun buttonPressed() {
label.text = "Hello #${pressed++} from Konan!"
println("Button pressed")
}
override fun viewDidLoad() {
super.viewDidLoad()
val (width, height) = UIScreen.mainScreen.bounds.useContents {
this.size.width to this.size.height
}
val header = UIView().apply {
backgroundColor = UIColor.lightGrayColor
view.addSubview(this)
translatesAutoresizingMaskIntoConstraints = false
leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
topAnchor.constraintEqualToAnchor(view.topAnchor).active = true
widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true
heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true
}
label = UILabel().apply {
setFrame(CGRectMake(x = 10.0, y = 10.0, width = width - 100.0, height = 40.0))
center = CGPointMake(x = width / 2, y = 40.0 )
textAlignment = NSTextAlignmentCenter
text = "Press OK"
header.addSubview(this)
}
button = UIButton().apply {
setFrame(CGRectMake(x = 10.0, y = height - 100.0, width = width - 100.0, height = 40.0))
center = CGPointMake(x = width / 2, y = height / 2)
backgroundColor = UIColor.blueColor
setTitle("OK", forState = UIControlStateNormal)
font = UIFont.fontWithName(fontName = font.fontName, size = 28.0)!!
layer.borderWidth = 1.0
layer.borderColor = UIColor.colorWithRed(0x47 / 255.0, 0x43 / 255.0, 0x70 / 255.0, 1.0).CGColor
layer.masksToBounds = true
addTarget(target = this@ViewController, action = NSSelectorFromString("buttonPressed"),
forControlEvents = UIControlEventTouchUpInside)
header.addSubview(this)
}
}
}