From 71b8089f337c1933cd4a77df0ef3e17083cd3895 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Fri, 26 Aug 2022 11:26:51 +0200 Subject: [PATCH] Native: remove samples that are not used in tests --- kotlin-native/samples/README.md | 3 - kotlin-native/samples/gitchurn/README.md | 16 - .../samples/gitchurn/build.gradle.kts | 41 -- .../samples/gitchurn/gradle.properties | 2 - .../src/gitChurnMain/kotlin/GitChurn.kt | 92 ---- .../src/gitChurnMain/kotlin/GitCommit.kt | 33 -- .../src/gitChurnMain/kotlin/GitDiff.kt | 45 -- .../src/gitChurnMain/kotlin/GitRemote.kt | 16 - .../src/gitChurnMain/kotlin/GitRepository.kt | 63 --- .../src/gitChurnMain/kotlin/GitTree.kt | 50 -- .../gitchurn/src/gitChurnMain/kotlin/git.kt | 33 -- .../src/nativeInterop/cinterop/libgit2.def | 5 - kotlin-native/samples/gtk/README.md | 40 -- kotlin-native/samples/gtk/build.gradle.kts | 70 --- kotlin-native/samples/gtk/gradle.properties | 3 - .../samples/gtk/src/gtkMain/kotlin/Main.kt | 56 -- .../gtk/src/nativeInterop/cinterop/gtk3.def | 9 - .../samples/python_extension/README.md | 114 ---- .../samples/python_extension/build.bat | 15 - .../samples/python_extension/build.sh | 23 - .../src/main/c/kotlin_bridge.c | 145 ------ .../src/main/kotlin/Server.kt | 14 - .../python_extension/src/main/python/main.py | 22 - .../python_extension/src/main/python/setup.py | 34 -- kotlin-native/samples/settings.gradle.kts | 5 - kotlin-native/samples/simd/build.gradle.kts | 11 - .../simd/src/macosX64Main/kotlin/simd.kt | 54 -- kotlin-native/samples/tetris/README.md | 32 -- kotlin-native/samples/tetris/build.gradle.kts | 119 ----- .../samples/tetris/gradle.properties | 2 - .../tetris/src/nativeInterop/cinterop/sdl.def | 9 - .../tetris/src/tetrisMain/kotlin/Config.kt | 42 -- .../src/tetrisMain/kotlin/SDL_Visualizer.kt | 486 ----------------- .../tetris/src/tetrisMain/kotlin/Tetris.kt | 491 ------------------ .../tetris/src/tetrisMain/kotlin/main.kt | 21 - .../src/tetrisMain/resources/Info.plist | 77 --- .../tetris/src/tetrisMain/resources/Tetris.rc | 23 - .../src/tetrisMain/resources/config.txt | 3 - .../src/tetrisMain/resources/tetris_all.bmp | Bin 112374 -> 0 bytes kotlin-native/samples/torch/README.md | 48 -- kotlin-native/samples/torch/build.gradle.kts | 62 --- kotlin-native/samples/torch/downloadMNIST.sh | 17 - kotlin-native/samples/torch/downloadTorch.sh | 32 -- kotlin-native/samples/torch/gradle.properties | 2 - .../src/nativeInterop/cinterop/torch.def | 1 - .../src/torchMain/kotlin/ClassifierDemo.kt | 81 --- .../torch/src/torchMain/kotlin/Dataset.kt | 104 ---- .../torch/src/torchMain/kotlin/Disposable.kt | 42 -- .../torch/src/torchMain/kotlin/Modules.kt | 212 -------- .../torch/src/torchMain/kotlin/SmallDemos.kt | 62 --- .../torch/src/torchMain/kotlin/Tensors.kt | 164 ------ .../samples/weather_function/.gitignore | 16 - .../weather_function/function/Dockerfile | 32 -- .../function/build.gradle.kts | 24 - .../weather_function/function/cjson.def | 6 - .../weather_function/function/curl.def | 5 - .../function/settings.gradle.kts | 19 - .../org/example/weather_func/Weather.kt | 19 - .../kotlin/org/example/weather_func/curl.kt | 94 ---- .../kotlin/org/example/weather_func/events.kt | 36 -- .../kotlin/org/example/weather_func/json.kt | 167 ------ .../kotlin/org/example/weather_func/main.kt | 123 ----- .../samples/weather_function/readme.md | 32 -- .../samples/weather_function/weather.yml | 9 - kotlin-native/samples/zephyr/CMakeLists.txt | 23 - kotlin-native/samples/zephyr/build.bat | 55 -- kotlin-native/samples/zephyr/build.sh | 71 --- .../c_interop/platforms/stm32f4_disco.bat | 36 -- .../c_interop/platforms/stm32f4_disco.def | 10 - .../c_interop/platforms/stm32f4_disco.sh | 36 -- kotlin-native/samples/zephyr/prj.conf | 5 - kotlin-native/samples/zephyr/src/main.kt | 28 - 72 files changed, 3992 deletions(-) delete mode 100644 kotlin-native/samples/gitchurn/README.md delete mode 100644 kotlin-native/samples/gitchurn/build.gradle.kts delete mode 100644 kotlin-native/samples/gitchurn/gradle.properties delete mode 100644 kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitChurn.kt delete mode 100644 kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitCommit.kt delete mode 100644 kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitDiff.kt delete mode 100644 kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRemote.kt delete mode 100644 kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRepository.kt delete mode 100644 kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitTree.kt delete mode 100644 kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/git.kt delete mode 100644 kotlin-native/samples/gitchurn/src/nativeInterop/cinterop/libgit2.def delete mode 100644 kotlin-native/samples/gtk/README.md delete mode 100644 kotlin-native/samples/gtk/build.gradle.kts delete mode 100644 kotlin-native/samples/gtk/gradle.properties delete mode 100644 kotlin-native/samples/gtk/src/gtkMain/kotlin/Main.kt delete mode 100644 kotlin-native/samples/gtk/src/nativeInterop/cinterop/gtk3.def delete mode 100644 kotlin-native/samples/python_extension/README.md delete mode 100644 kotlin-native/samples/python_extension/build.bat delete mode 100755 kotlin-native/samples/python_extension/build.sh delete mode 100644 kotlin-native/samples/python_extension/src/main/c/kotlin_bridge.c delete mode 100644 kotlin-native/samples/python_extension/src/main/kotlin/Server.kt delete mode 100644 kotlin-native/samples/python_extension/src/main/python/main.py delete mode 100644 kotlin-native/samples/python_extension/src/main/python/setup.py delete mode 100644 kotlin-native/samples/simd/build.gradle.kts delete mode 100644 kotlin-native/samples/simd/src/macosX64Main/kotlin/simd.kt delete mode 100644 kotlin-native/samples/tetris/README.md delete mode 100644 kotlin-native/samples/tetris/build.gradle.kts delete mode 100644 kotlin-native/samples/tetris/gradle.properties delete mode 100644 kotlin-native/samples/tetris/src/nativeInterop/cinterop/sdl.def delete mode 100644 kotlin-native/samples/tetris/src/tetrisMain/kotlin/Config.kt delete mode 100644 kotlin-native/samples/tetris/src/tetrisMain/kotlin/SDL_Visualizer.kt delete mode 100644 kotlin-native/samples/tetris/src/tetrisMain/kotlin/Tetris.kt delete mode 100644 kotlin-native/samples/tetris/src/tetrisMain/kotlin/main.kt delete mode 100644 kotlin-native/samples/tetris/src/tetrisMain/resources/Info.plist delete mode 100644 kotlin-native/samples/tetris/src/tetrisMain/resources/Tetris.rc delete mode 100644 kotlin-native/samples/tetris/src/tetrisMain/resources/config.txt delete mode 100644 kotlin-native/samples/tetris/src/tetrisMain/resources/tetris_all.bmp delete mode 100644 kotlin-native/samples/torch/README.md delete mode 100644 kotlin-native/samples/torch/build.gradle.kts delete mode 100755 kotlin-native/samples/torch/downloadMNIST.sh delete mode 100755 kotlin-native/samples/torch/downloadTorch.sh delete mode 100644 kotlin-native/samples/torch/gradle.properties delete mode 100644 kotlin-native/samples/torch/src/nativeInterop/cinterop/torch.def delete mode 100644 kotlin-native/samples/torch/src/torchMain/kotlin/ClassifierDemo.kt delete mode 100644 kotlin-native/samples/torch/src/torchMain/kotlin/Dataset.kt delete mode 100644 kotlin-native/samples/torch/src/torchMain/kotlin/Disposable.kt delete mode 100644 kotlin-native/samples/torch/src/torchMain/kotlin/Modules.kt delete mode 100644 kotlin-native/samples/torch/src/torchMain/kotlin/SmallDemos.kt delete mode 100644 kotlin-native/samples/torch/src/torchMain/kotlin/Tensors.kt delete mode 100644 kotlin-native/samples/weather_function/.gitignore delete mode 100644 kotlin-native/samples/weather_function/function/Dockerfile delete mode 100644 kotlin-native/samples/weather_function/function/build.gradle.kts delete mode 100644 kotlin-native/samples/weather_function/function/cjson.def delete mode 100644 kotlin-native/samples/weather_function/function/curl.def delete mode 100644 kotlin-native/samples/weather_function/function/settings.gradle.kts delete mode 100644 kotlin-native/samples/weather_function/function/src/main/kotlin/org/example/weather_func/Weather.kt delete mode 100644 kotlin-native/samples/weather_function/function/src/main/kotlin/org/example/weather_func/curl.kt delete mode 100644 kotlin-native/samples/weather_function/function/src/main/kotlin/org/example/weather_func/events.kt delete mode 100644 kotlin-native/samples/weather_function/function/src/main/kotlin/org/example/weather_func/json.kt delete mode 100644 kotlin-native/samples/weather_function/function/src/main/kotlin/org/example/weather_func/main.kt delete mode 100644 kotlin-native/samples/weather_function/readme.md delete mode 100644 kotlin-native/samples/weather_function/weather.yml delete mode 100644 kotlin-native/samples/zephyr/CMakeLists.txt delete mode 100644 kotlin-native/samples/zephyr/build.bat delete mode 100755 kotlin-native/samples/zephyr/build.sh delete mode 100644 kotlin-native/samples/zephyr/c_interop/platforms/stm32f4_disco.bat delete mode 100644 kotlin-native/samples/zephyr/c_interop/platforms/stm32f4_disco.def delete mode 100644 kotlin-native/samples/zephyr/c_interop/platforms/stm32f4_disco.sh delete mode 100644 kotlin-native/samples/zephyr/prj.conf delete mode 100644 kotlin-native/samples/zephyr/src/main.kt diff --git a/kotlin-native/samples/README.md b/kotlin-native/samples/README.md index 4fd6a3dfb58..551092059f1 100644 --- a/kotlin-native/samples/README.md +++ b/kotlin-native/samples/README.md @@ -13,8 +13,6 @@ More Kotlin Multiplatform Mobile samples can be found here: https://kotlinlang.o The samples that are in this directory mostly illustrate the other use cases for Kotlin/Native: * `csvparser` - simple CSV file parser and analyzer * `echoServer` - TCP/IP echo server - * `gitchurn` - program interoperating with `libgit2` for GIT repository analysis - * `gtk` - GTK3 interoperability example * `html5Canvas` - WebAssembly example * `libcurl` - using of FTP/HTTP/HTTPS client library `libcurl` * `nonBlockingEchoServer` - multi-client TCP/IP echo server using co-routines @@ -22,7 +20,6 @@ The samples that are in this directory mostly illustrate the other use cases for * `opengl` - OpenGL/GLUT teapot example * `python_extension` - Python extension written in Kotlin/Native * `tensorflow` - simple client for TensorFlow Machine Intelligence library - * `tetris` - Tetris game implementation (using SDL2 for rendering) * `uikit` - UIKit Objective-C interoperability example for iOS * `videoplayer` - SDL and FFMPEG-based video and audio player * `win32` - trivial Win32 GUI application diff --git a/kotlin-native/samples/gitchurn/README.md b/kotlin-native/samples/gitchurn/README.md deleted file mode 100644 index c17c130ecc5..00000000000 --- a/kotlin-native/samples/gitchurn/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# GIT frequency analyzer - -This example shows how one could perform statistics on Git repository. - -Install libgit2 development files. -For Debian-like Linux - use `apt-get install libgit2-dev`. -For Windows - `pacman -S mingw-w64-x86_64-libgit2` in MinGW64 console, if you do -not have MSYS2-MinGW64 installed - install it first as described in http://www.msys2.org - -To build use `../gradlew assemble`. - -To run use `../gradlew runReleaseExecutableGitChurn` or execute the program directly: - - ./build/bin/gitChurn/main/release/executable/gitchurn.kexe ../../ - -It will print most frequently modified (by number of commits) files in repository. diff --git a/kotlin-native/samples/gitchurn/build.gradle.kts b/kotlin-native/samples/gitchurn/build.gradle.kts deleted file mode 100644 index 825991898b3..00000000000 --- a/kotlin-native/samples/gitchurn/build.gradle.kts +++ /dev/null @@ -1,41 +0,0 @@ -plugins { - kotlin("multiplatform") -} - -val mingwPath = File(System.getenv("MINGW64_DIR") ?: "C:/msys64/mingw64") - -kotlin { - // Determine host preset. - val hostOs = System.getProperty("os.name") - val isMingwX64 = hostOs.startsWith("Windows") - - // Create a target for the host platform. - val hostTarget = when { - hostOs == "Mac OS X" -> macosX64("gitChurn") - hostOs == "Linux" -> linuxX64("gitChurn") - isMingwX64 -> mingwX64("gitChurn") - else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native $project.") - } - - hostTarget.apply { - binaries { - executable { - entryPoint = "sample.gitchurn.main" - if (isMingwX64) { - linkerOpts("-L${mingwPath.resolve("lib")}") - runTask?.environment("PATH" to mingwPath.resolve("bin")) - } - runTask?.args(rootProject.rootDir.resolve("..")) - } - } - compilations["main"].cinterops { - val libgit2 by creating { - when (preset) { - presets["macosX64"] -> includeDirs.headerFilterOnly("/opt/local/include", "/usr/local/include") - presets["linuxX64"] -> includeDirs.headerFilterOnly("/usr/include") - presets["mingwX64"] -> includeDirs.headerFilterOnly(mingwPath.resolve("include")) - } - } - } - } -} diff --git a/kotlin-native/samples/gitchurn/gradle.properties b/kotlin-native/samples/gitchurn/gradle.properties deleted file mode 100644 index 790a07d5124..00000000000 --- a/kotlin-native/samples/gitchurn/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -kotlin.code.style=official -kotlin.import.noCommonSourceSets=true diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitChurn.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitChurn.kt deleted file mode 100644 index 60410ba4148..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitChurn.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.git_time_t -import platform.posix.ctime -import platform.posix.time_tVar - -fun main(args: Array) { - if (args.isEmpty()) - return help() - - val workDir = args[0] - - val limit = if (args.size > 1) { - val limitRaw = args[1].toIntOrNull() - if (limitRaw == null || limitRaw <= 0) { - return help("Not a positive integer: $limitRaw") - } - limitRaw - } else - Int.MAX_VALUE - - try { - calculateChurn(workDir, limit) - } catch (e: GitException) { - help(e.message) - } -} - -private fun calculateChurn(workDir: String, limit: Int) { - println("Opening…") - val repository = git.repository(workDir) - val map = mutableMapOf() - var count = 0 - val commits = repository.commits() - val limited = commits.take(limit) - println("Calculating…") - limited.forEach { commit -> - if (count % 100 == 0) - println("Commit #$count [${commit.time.format()}]: ${commit.summary}") - - commit.parents.forEach { parent -> - val diff = commit.tree.diff(parent.tree) - diff.deltas().forEach { delta -> - val path = delta.newPath - val n = map[path] ?: 0 - map.put(path, n + 1) - } - diff.close() - parent.close() - } - commit.close() - count++ - } - println("Report:") - map.toList().sortedByDescending { it.second }.take(10).forEach { - println("File: ${it.first}") - println(" ${it.second}") - println() - } - - repository.close() - git.close() -} - -private fun git_time_t.format() = memScoped { - val commitTime = alloc() - commitTime.value = this@format - ctime(commitTime.ptr)!!.toKString().trim() -} - - -private fun printTree(commit: GitCommit) { - commit.tree.entries().forEach { entry -> - when (entry) { - is GitTreeEntry.File -> println(" ${entry.name}") - is GitTreeEntry.Folder -> println(" /${entry.name} (${entry.subtree.entries().size})") - } - } -} - -private fun help(errorMessage: String? = null) { - errorMessage?.let { - println("ERROR: $it") - } - println("./gitchurn.kexe []") -} diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitCommit.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitCommit.kt deleted file mode 100644 index 7b12183345f..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitCommit.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitCommit(val repository: GitRepository, val commit: CPointer) { - fun close() = git_commit_free(commit) - - val summary: String get() = git_commit_summary(commit)!!.toKString() - val time: git_time_t get() = git_commit_time(commit) - - val tree: GitTree get() = memScoped { - val treePtr = allocPointerTo() - git_commit_tree(treePtr.ptr, commit).errorCheck() - GitTree(repository, treePtr.value!!) - } - - val parents: List get() = memScoped { - val count = git_commit_parentcount(commit).toInt() - val result = ArrayList(count) - for (index in 0..count - 1) { - val commitPtr = allocPointerTo() - git_commit_parent(commitPtr.ptr, commit, index.toUInt()).errorCheck() - result.add(GitCommit(repository, commitPtr.value!!)) - } - result - } -} \ No newline at end of file diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitDiff.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitDiff.kt deleted file mode 100644 index b5d73643422..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitDiff.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitDiff(val repository: GitRepository, val handle: CPointer) { - fun deltas(): List { - val size = git_diff_num_deltas(handle).toInt() - val results = ArrayList(size) - for (index in 0..size - 1) { - val delta = git_diff_get_delta(handle, index.convert()) - results.add(GifDiffDelta(this, delta!!)) - } - return results - } - - fun close() { - git_diff_free(handle) - } - -} - -class GifDiffDelta(val diff: GitDiff, val handle: CPointer) { - - val status get() = handle.pointed.status - val newPath get() = handle.pointed.new_file.path!!.toKString() - val oldPath get() = handle.pointed.old_file.path!!.toKString() - - fun status(): String { - return when (status) { - GIT_DELTA_ADDED -> "A" - GIT_DELTA_DELETED -> "D" - GIT_DELTA_MODIFIED -> "M" - GIT_DELTA_RENAMED -> "R" - GIT_DELTA_COPIED -> "C" - else -> throw Exception("Unsupported delta status $status") - } - } - -} diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRemote.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRemote.kt deleted file mode 100644 index 18a65ee8772..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRemote.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitRemote(val repository: GitRepository, val handle: CPointer) { - fun close() = git_remote_free(handle) - - val url: String get() = git_remote_url(handle)!!.toKString() - val name: String = git_remote_name(handle)!!.toKString() -} \ No newline at end of file diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRepository.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRepository.kt deleted file mode 100644 index b10f23d37f6..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitRepository.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitRepository(val location: String) { - val arena = Arena() - val handle: CPointer = memScoped { - val loc = allocPointerTo() - git_repository_open(loc.ptr, location).errorCheck() - loc.value!! - } - - fun close() { - git_repository_free(handle) - arena.clear() - } - - fun remotes(): List = memScoped { - val remoteList = alloc() - git_remote_list(remoteList.ptr, handle).errorCheck() - val size = remoteList.count.toInt() - val list = ArrayList(size) - for (index in 0..size - 1) { - val array = remoteList.strings!! - val name = array[index]!!.toKString() - val remotePtr = allocPointerTo() - git_remote_lookup(remotePtr.ptr, handle, name).errorCheck() - list.add(GitRemote(this@GitRepository, remotePtr.value!!)) - } - list - } - - fun commits(): Sequence = memScoped { - val walkPtr = allocPointerTo() - git_revwalk_new(walkPtr.ptr, handle).errorCheck() - val walk = walkPtr.value - git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL or GIT_SORT_TIME) - git_revwalk_push_head(walk).errorCheck() - generateSequence { - memScoped { - val oid = alloc() - val result = git_revwalk_next(oid.ptr, walk) - - when (result) { - 0 -> { - val commitPtr = allocPointerTo() - git_commit_lookup(commitPtr.ptr, handle, oid.ptr).errorCheck() - val commit = commitPtr.value!! - GitCommit(this@GitRepository, commit) - } - GIT_ITEROVER -> null - else -> throw Exception("Unexpected result code $result") - } - } - } - } -} \ No newline at end of file diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitTree.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitTree.kt deleted file mode 100644 index 03d78325939..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/GitTree.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -class GitTree(val repository: GitRepository, val handle: CPointer) { - fun close() = git_tree_free(handle) - - fun entries(): List = memScoped { - val size = git_tree_entrycount(handle).toInt() - val entries = ArrayList(size) - for (index in 0..size - 1) { - val treeEntry = git_tree_entry_byindex(handle, index.convert())!! - val entryType = git_tree_entry_type(treeEntry) - val entry = when (entryType) { - GIT_OBJ_TREE -> memScoped { - val id = git_tree_entry_id(treeEntry) - val treePtr = allocPointerTo() - git_tree_lookup(treePtr.ptr, repository.handle, id) - GitTreeEntry.Folder(this@GitTree, treeEntry, treePtr.value!!) - } - GIT_OBJ_BLOB -> GitTreeEntry.File(this@GitTree, treeEntry) - else -> throw Exception("Unsupported entry type $entryType") - } - entries.add(entry) - } - entries - } - - fun diff(other: GitTree): GitDiff = memScoped { - val diffPtr = allocPointerTo() - git_diff_tree_to_tree(diffPtr.ptr, repository.handle, handle, other.handle, null).errorCheck() - GitDiff(repository, diffPtr.value!!) - } -} - -sealed class GitTreeEntry(val tree: GitTree, val handle: CPointer) { - val name: String get() = git_tree_entry_name(handle)!!.toKString() - - class Folder(tree: GitTree, handle: CPointer, val subtreeHandle: CPointer) : GitTreeEntry(tree, handle) { - val subtree = GitTree(tree.repository, subtreeHandle) - } - - class File(tree: GitTree, handle: CPointer) : GitTreeEntry(tree, handle) -} diff --git a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/git.kt b/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/git.kt deleted file mode 100644 index 5ecb1d6413c..00000000000 --- a/kotlin-native/samples/gitchurn/src/gitChurnMain/kotlin/git.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - */ - -package sample.gitchurn - -import kotlinx.cinterop.* -import libgit2.* - -object git { - init { - git_libgit2_init() - } - - fun close() { - git_libgit2_shutdown() - } - - fun repository(location: String): GitRepository { - return GitRepository(location) - } -} - -fun Int.errorCheck() { - if (this == 0) return - throw GitException() -} - -class GitException : Exception(run { - val err = giterr_last() - err!!.pointed.message!!.toKString() -}) \ No newline at end of file diff --git a/kotlin-native/samples/gitchurn/src/nativeInterop/cinterop/libgit2.def b/kotlin-native/samples/gitchurn/src/nativeInterop/cinterop/libgit2.def deleted file mode 100644 index 377332016f4..00000000000 --- a/kotlin-native/samples/gitchurn/src/nativeInterop/cinterop/libgit2.def +++ /dev/null @@ -1,5 +0,0 @@ -headers = git2.h -headerFilter = git2/** git2.h -linkerOpts.osx = -L/opt/local/lib -L/usr/local/lib -lgit2 -linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -lgit2 -linkerOpts.mingw = -lgit2 diff --git a/kotlin-native/samples/gtk/README.md b/kotlin-native/samples/gtk/README.md deleted file mode 100644 index c8817e84d38..00000000000 --- a/kotlin-native/samples/gtk/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# GTK application - -This example shows how one may use _Kotlin/Native_ to build GUI -applications with the GTK toolkit. - -To build use `../gradlew assemble`. - -Do not forget to install GTK3. See bellow. - -To run on Mac also install XQuartz X server (https://www.xquartz.org/), and then `../gradlew runReleaseExecutableGtk` or execute the program directly: - - ./build/bin/gtk/main/release/executable/gtk.kexe - -Dialog box with the button will be shown, and application will print message -and terminate on button click. - - -#### GTK3 Install - -on Mac use - - brew install gtk+3 - -or - - port install gtk3 - -on Debian flavours of Linux - - sudo apt-get install libgtk-3-dev - -on Fedora - - sudo dnf install gtk3-devel - -on Windows in MinGW64 console, if you do -not have MSYS2-MinGW64 installed - install it first as described in http://www.msys2.org - - pacman -S mingw-w64-x86_64-gtk3 - pacman -S mingw-w64-x86_64-harfbuzz diff --git a/kotlin-native/samples/gtk/build.gradle.kts b/kotlin-native/samples/gtk/build.gradle.kts deleted file mode 100644 index 4b5df719236..00000000000 --- a/kotlin-native/samples/gtk/build.gradle.kts +++ /dev/null @@ -1,70 +0,0 @@ -plugins { - kotlin("multiplatform") -} - -val mingwPath = File(System.getenv("MINGW64_DIR") ?: "C:/msys64/mingw64") - -kotlin { - // Determine host preset. - val hostOs = System.getProperty("os.name") - val isMingwX64 = hostOs.startsWith("Windows") - - // Create a target for the host platform. - val hostTarget = when { - hostOs == "Mac OS X" -> macosX64("gtk") - hostOs == "Linux" -> linuxX64("gtk") - isMingwX64 -> mingwX64("gtk") - else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native $project.") - } - - hostTarget.apply { - binaries { - executable { - entryPoint = "sample.gtk.main" - if (isMingwX64) { - linkerOpts("-L${mingwPath.resolve("lib")}") - runTask?.environment("PATH" to mingwPath.resolve("bin")) - } - } - } - compilations["main"].cinterops { - val gtk3 by creating { - when (preset) { - presets["macosX64"], presets["linuxX64"] -> { - listOf("/opt/local/include", "/usr/include", "/usr/local/include").forEach { - includeDirs( - "$it/atk-1.0", - "$it/gdk-pixbuf-2.0", - "$it/cairo", - "$it/harfbuzz", - "$it/pango-1.0", - "$it/gtk-3.0", - "$it/glib-2.0" - ) - } - - includeDirs( - "/opt/local/lib/glib-2.0/include", - "/usr/lib/x86_64-linux-gnu/glib-2.0/include", - "/usr/local/lib/glib-2.0/include" - ) - } - presets["mingwX64"] -> { - listOf( - "include/atk-1.0", - "include/gdk-pixbuf-2.0", - "include/cairo", - "include/pango-1.0", - "include/gtk-3.0", - "include/glib-2.0", - "include/harfbuzz", - "lib/glib-2.0/include" - ).forEach { - includeDirs(mingwPath.resolve(it)) - } - } - } - } - } - } -} \ No newline at end of file diff --git a/kotlin-native/samples/gtk/gradle.properties b/kotlin-native/samples/gtk/gradle.properties deleted file mode 100644 index f833920c5d7..00000000000 --- a/kotlin-native/samples/gtk/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -kotlin.native.jvmArgs=-Xmx8g -kotlin.code.style=official -kotlin.import.noCommonSourceSets=true diff --git a/kotlin-native/samples/gtk/src/gtkMain/kotlin/Main.kt b/kotlin-native/samples/gtk/src/gtkMain/kotlin/Main.kt deleted file mode 100644 index c09de4f268a..00000000000 --- a/kotlin-native/samples/gtk/src/gtkMain/kotlin/Main.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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. - */ - -package sample.gtk - -import kotlinx.cinterop.* -import gtk3.* - -// Note that all callback parameters must be primitive types or nullable C pointers. -fun > g_signal_connect(obj: CPointer<*>, actionName: String, - action: CPointer, data: gpointer? = null, connect_flags: GConnectFlags = 0u) { - g_signal_connect_data(obj.reinterpret(), actionName, action.reinterpret(), - data = data, destroy_data = null, connect_flags = connect_flags) - -} - -fun activate(app: CPointer?, user_data: gpointer?) { - val windowWidget = gtk_application_window_new(app)!! - val window = windowWidget.reinterpret() - gtk_window_set_title(window, "Window") - gtk_window_set_default_size(window, 200, 200) - - val button_box = gtk_button_box_new( - GtkOrientation.GTK_ORIENTATION_HORIZONTAL)!! - gtk_container_add(window.reinterpret(), button_box) - - val button = gtk_button_new_with_label("Konan говорит: click me!")!! - g_signal_connect(button, "clicked", - staticCFunction { _: CPointer?, _: gpointer? -> println("Hi Kotlin") - }) - g_signal_connect(button, "clicked", - staticCFunction { widget: CPointer? -> - gtk_widget_destroy(widget) - }, - window, G_CONNECT_SWAPPED) - gtk_container_add (button_box.reinterpret(), button) - - gtk_widget_show_all(windowWidget) -} - -fun gtkMain(args: Array): Int { - val app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE)!! - g_signal_connect(app, "activate", staticCFunction(::activate)) - val status = memScoped { - g_application_run(app.reinterpret(), - args.size, args.map { it.cstr.ptr }.toCValues()) - } - g_object_unref(app) - return status -} - -fun main(args: Array) { - gtkMain(args) -} diff --git a/kotlin-native/samples/gtk/src/nativeInterop/cinterop/gtk3.def b/kotlin-native/samples/gtk/src/nativeInterop/cinterop/gtk3.def deleted file mode 100644 index 51c5e6f6d23..00000000000 --- a/kotlin-native/samples/gtk/src/nativeInterop/cinterop/gtk3.def +++ /dev/null @@ -1,9 +0,0 @@ -headers = gtk/gtk.h -headerFilter = gtk/* gobject/* gio/* -compilerOpts.osx = -I/usr/local/include/gtk-3.0 -I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include \ --I/usr/local/include/pango-1.0 -I/usr/local/include/cairo -I/usr/local/include -I/usr/local/include/gdk-pixbuf-2.0 \ --I/usr/local/include/atk-1.0 -compilerOpts.linux = -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/local/lib/glib-2.0/include -I/usr/lib64/glib-2.0/include -linkerOpts.osx = -L/opt/local/lib -L/usr/local/lib -lglib-2.0 -lgdk-3.0 -lgtk-3 -lgio-2.0 -lgobject-2.0 -linkerOpts.linux = -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu -lglib-2.0 -lgdk-3 -lgtk-3 -lgio-2.0 -lgobject-2.0 -linkerOpts.mingw = -lglib-2.0 -lgdk-3 -lgtk-3 -lgio-2.0 -lgobject-2.0 diff --git a/kotlin-native/samples/python_extension/README.md b/kotlin-native/samples/python_extension/README.md deleted file mode 100644 index 8ae6b7d5dc3..00000000000 --- a/kotlin-native/samples/python_extension/README.md +++ /dev/null @@ -1,114 +0,0 @@ -# C to Kotlin/Native interoperability example - -This example shows how to use Kotlin/Native programs from other execution environments, such as Python. -Python has C native interface, which could be used to organize a bridge with the -Kotlin/Native application. File `kotlin_bridge.c` contains translation code between Kotlin and Python -lands. This demo works on Linux, Windows (64-bit) or macOS hosts. - -To build and run the sample do the following: - -* Install Python with development headers, i.e. on Linux - ``` - sudo apt install python-dev - ``` - -* Run `build.sh`, it will ask for superuser password to install Python extension. - Use build.bat on Windows. -* On macOS copy Kotlin binary to extension's directory and change install name with - `install_name_tool` tool, i.e. - ``` - sudo cp ./build/libserver.dylib /Library/Python/2.7/site-packages/ - sudo install_name_tool /Library/Python/2.7/site-packages/kotlin_bridge.so \ - -change libserver.dylib @loader_path/libserver.dylib - ``` -* On Linux copy Kotlin binary in some place where libraries could be loaded from, i.e. - ``` - cp ./build/libserver.so /usr/local/lib/ - ldconfig - ``` - or modify dynamic loader search path with - ``` - export LD_LIBRARY_PATH=`pwd` - ``` - -* run Python code using Kotlin functionality with - ``` - python src/main/python/main.py - ``` -* it will show you result of using several Kotlin/Native APIs, accepting and returning both objects and - primitive types - - The example works as following. Kotlin/Native API is implemented in `Server.kt`, and we run Kotlin/Native compiler - with `-produce dynamic` option. Compiler produces two artifacts: `server_api.h` which is C language API - to all public functions and classes available in the application. `libserver.dylib` or `libserver.so` or `server.dll` - shared object contains C bridge to all above APIs. - - This C bridge looks like a C struct, reflecting all scopes in program, with operations available. For example, - for class Server -```c_cpp - class Server(val prefix: String) { - fun greet(session: Session) = "$prefix: Hello from Kotlin/Native in ${session}" - fun concat(session: Session, a: String, b: String) = "$prefix: $a $b in ${session}" - fun add(session: Session, a: Int, b: Int) = a + b + session.number - } -``` - following C API is produced -```c_cpp - typedef struct { - server_KNativePtr pinned; - } server_kref_demo_Session; - typedef struct { - server_KNativePtr pinned; - } server_kref_demo_Server; - - typedef struct { - /* Service functions. */ - void (*DisposeStablePointer)(server_KNativePtr ptr); - void (*DisposeString)(const char* string); - server_KBoolean (*IsInstance)(server_KNativePtr ref, const server_KType* type); - - /* User functions. */ - struct { - struct { - struct { - server_KType* (*_type)(void); - server_kref_demo_Session (*Session)(const char* name, server_KInt number); - } Session; - struct { - server_KType* (*_type)(void); - server_kref_demo_Server (*Server)(const char* prefix); - const char* (*greet)(server_kref_demo_Server thiz, server_kref_demo_Session session); - const char* (*concat)(server_kref_demo_Server thiz, server_kref_demo_Session session, const char* a, const char* b); - server_KInt (*add)(server_kref_demo_Server thiz, server_kref_demo_Session session, server_KInt a, server_KInt b); - } Server; - } demo; - } kotlin; - } server_ExportedSymbols; - extern server_ExportedSymbols* server_symbols(void); -``` - - So every class instance is represented with a single element structure, encapsulating stable pointer to an instance. - Once no longer needed, `DisposeStablePointer()` with that stable pointer shall be called, and if value is not stored - somewhere else - it is disposed. For primitive types and `kotlin.String` smart bridges converting to C primitive types - or to C strings (which has to be manually freed with `DisposeString()`) are implemented. - - For example, running constructor of class Server taking a string will look like - - server_kref_demo_Server server = server_symbols()->kotlin.demo.Server.Server("the server"); - - And disposing no longer needed instance will look like - - server_symbols()->DisposeStablePointer(server.pinned); - - To make code easier readable, macro definitions like - - #define T_(name) server_kref_demo_ ## name - #define __ server_symbols()-> - - will transform above, overly verbose lines to more readable - - T_(Server) server = __ kotlin.demo.Server.Server("the server"); - - `_type()` function will return opaque type pointer, which could be checked with `IsInstance()` operation, like - - __ IsInstance(ref.pinned, __ kotlin.demo.Server._type()) diff --git a/kotlin-native/samples/python_extension/build.bat b/kotlin-native/samples/python_extension/build.bat deleted file mode 100644 index 2fcff0aa32c..00000000000 --- a/kotlin-native/samples/python_extension/build.bat +++ /dev/null @@ -1,15 +0,0 @@ -setlocal -set DIR=. - -if defined KONAN_HOME ( - set "PATH=%KONAN_HOME%\bin;%PATH%" -) else ( - set "PATH=..\..\dist\bin;..\..\bin;%PATH%" -) -kotlinc-native -p dynamic src/main/kotlin/Server.kt -o server - -rem Prepare MSVC build environment, and .lib file for linking with our .dll. -SET VS90COMNTOOLS=%VS140COMNTOOLS% -\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\lib.exe" /def:server.def /out:server.lib /machine:X64 - -python src/main/python/setup.py install diff --git a/kotlin-native/samples/python_extension/build.sh b/kotlin-native/samples/python_extension/build.sh deleted file mode 100755 index f091f2cda3d..00000000000 --- a/kotlin-native/samples/python_extension/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -DIR=$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd ) - -if [ -z "$KONAN_HOME" ]; then - PATH="$DIR/../../dist/bin:$DIR/../../bin:$PATH" -else - PATH="$KONAN_HOME/bin:$PATH" -fi - -KONAN_USER_DIR=${KONAN_DATA_DIR:-"$HOME/.konan"} -KONAN_DEPS="$KONAN_USER_DIR/dependencies" - -# python3 shall work as well. -PYTHON=python - -mkdir -p $DIR/build -cd $DIR/build - -kotlinc-native -p dynamic $DIR/src/main/kotlin/Server.kt -o server - -cd $DIR -sudo -S $PYTHON ${DIR}/src/main/python/setup.py install diff --git a/kotlin-native/samples/python_extension/src/main/c/kotlin_bridge.c b/kotlin-native/samples/python_extension/src/main/c/kotlin_bridge.c deleted file mode 100644 index d010e9ff6fd..00000000000 --- a/kotlin-native/samples/python_extension/src/main/c/kotlin_bridge.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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. - */ - -#include - -#include "server_api.h" - -#define __ server_symbols()-> -#define T_(name) server_kref_demo_ ## name - -// Note, that as we cache this in the global, and Kotlin/Native object references -// are currently thread local, we make this global a TLS variable. -#ifdef _MSC_VER -#define TLSVAR __declspec(thread) -#else -#define TLSVAR __thread -#endif - -static TLSVAR server_kref_demo_Server server = { 0 }; - -static T_(Server) getServer(void) { - if (!server.pinned) { - server = __ kotlin.root.demo.Server.Server("the server"); - } - return server; -} - -static T_(Session) getSession(PyObject* args) { - T_(Session) result = { 0 }; - long long pinned; - if (PyArg_ParseTuple(args, "L", &pinned)) { - result.pinned = (void*)(uintptr_t)pinned; - } - return result; -} - -static PyObject* open_session(PyObject* self, PyObject* args) { - PyObject *result = NULL; - char* string_arg = NULL; - int int_arg = 0; - if (PyArg_ParseTuple(args, "is", &int_arg, &string_arg)) { - T_(Session) session = __ kotlin.root.demo.Session.Session(string_arg, int_arg); - result = Py_BuildValue("L", session.pinned); - } - return result; -} - -static PyObject* close_session(PyObject* self, PyObject* args) { - T_(Session) session = getSession(args); - __ DisposeStablePointer(session.pinned); - __ DisposeStablePointer(getServer().pinned); - server.pinned = 0; - return Py_BuildValue("L", 0); -} - -static PyObject* greet_server(PyObject* self, PyObject* args) { - T_(Server) server = getServer(); - T_(Session) session = getSession(args); - const char* string = __ kotlin.root.demo.Server.greet(server, session); - PyObject* result = Py_BuildValue("s", string); - __ DisposeString(string); - return result; -} - -static PyObject* concat_server(PyObject* self, PyObject* args) { - long long session_arg; - char* string_arg1 = NULL; - char* string_arg2 = NULL; - PyObject* result = NULL; - - if (PyArg_ParseTuple(args, "Lss", &session_arg, &string_arg1, &string_arg2)) { - T_(Server) server = getServer(); - T_(Session) session = { (void*)(uintptr_t)session_arg }; - const char* string = __ kotlin.root.demo.Server.concat(server, session, string_arg1, string_arg2); - result = Py_BuildValue("s", string); - __ DisposeString(string); - } else { - result = Py_BuildValue("s", NULL); - } - return result; -} - -static PyObject* add_server(PyObject* self, PyObject* args) { - long long session_arg; - int int_arg1 = 0; - int int_arg2 = 0; - PyObject* result = NULL; - - if (PyArg_ParseTuple(args, "Lii", &session_arg, &int_arg1, &int_arg2)) { - T_(Server) server = getServer(); - T_(Session) session = { (void*)(uintptr_t)session_arg }; - int sum = __ kotlin.root.demo.Server.add(server, session, int_arg1, int_arg2); - result = Py_BuildValue("i", sum); - } else { - result = Py_BuildValue("i", 0); - } - return result; -} - -static PyMethodDef kotlin_bridge_funcs[] = { - { "open_session", (PyCFunction)open_session, METH_VARARGS, "Opens a session" }, - { "close_session", (PyCFunction)close_session, METH_VARARGS, "Closes the session" }, - { "greet_server", (PyCFunction)greet_server, METH_VARARGS, "Greeting service" }, - { "concat_server", (PyCFunction)concat_server, METH_VARARGS, "Concatenation service" }, - { "add_server", (PyCFunction)add_server, METH_VARARGS, "Addition service" }, - { NULL } -}; - -#if PY_MAJOR_VERSION >= 3 - -struct module_state { - server_kref_demo_Server server; -}; - -static int kotlin_bridge_traverse(PyObject *m, visitproc visit, void *arg) { - return 0; -} - -static int kotlin_bridge_clear(PyObject *m) { - return 0; -} - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "kotlin_bridge", - NULL, - sizeof(struct module_state), - kotlin_bridge_funcs, - NULL, - kotlin_bridge_traverse, - kotlin_bridge_clear, - NULL -}; - -PyMODINIT_FUNC PyInit_kotlin_bridge(void) { - PyObject *module = PyModule_Create(&moduledef); - return module; -} -#else -void initkotlin_bridge(void) { - Py_InitModule3("kotlin_bridge", kotlin_bridge_funcs, "Kotlin/Native example module"); -} -#endif diff --git a/kotlin-native/samples/python_extension/src/main/kotlin/Server.kt b/kotlin-native/samples/python_extension/src/main/kotlin/Server.kt deleted file mode 100644 index ee137f8f94b..00000000000 --- a/kotlin-native/samples/python_extension/src/main/kotlin/Server.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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. - */ - -package demo - -class Session(val name: String, val number: Int) - -class Server(val prefix: String) { - fun greet(session: Session) = "$prefix: Hello from Kotlin/Native in ${session}" - fun concat(session: Session, a: String, b: String) = "$prefix: $a $b in ${session}" - fun add(session: Session, a: Int, b: Int) = a + b + session.number -} diff --git a/kotlin-native/samples/python_extension/src/main/python/main.py b/kotlin-native/samples/python_extension/src/main/python/main.py deleted file mode 100644 index bb7111128e5..00000000000 --- a/kotlin-native/samples/python_extension/src/main/python/main.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/python -# -# 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 kotlin_bridge - -session = kotlin_bridge.open_session(239, 'konan') - -message = kotlin_bridge.greet_server(session) -print("Greet '{}'".format(message)) - -message = kotlin_bridge.concat_server(session, "Coding", "fun") -print("Concat '{}'".format(message)) - -message = kotlin_bridge.add_server(session, 1, 60) -print("Sum '{}'".format(message)) - - -kotlin_bridge.close_session(session) - diff --git a/kotlin-native/samples/python_extension/src/main/python/setup.py b/kotlin-native/samples/python_extension/src/main/python/setup.py deleted file mode 100644 index e8030fd991b..00000000000 --- a/kotlin-native/samples/python_extension/src/main/python/setup.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python -# -# 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. -# - -from distutils.core import setup, Extension - -setup(name='kotlin_bridge', - version='1.0', - maintainer = 'JetBrains', - maintainer_email = 'info@jetbrains.com', - author = 'JetBrains', - author_email = 'info@jetbrains.com', - description = 'Kotlin/Native Python bridge', - long_description = 'Using Kotlin/Native from Python example', - - # data_files=[("/Library/Python/2.7/site-packages/", ['libserver.dylib'])], - - ext_modules=[ - Extension('kotlin_bridge', - include_dirs = ['./build'], - libraries = ['server'], - library_dirs = ['./build'], - depends = ['server_api.h'], - sources = ['src/main/c/kotlin_bridge.c'] - ) - ] -) - -# On macOS, after install you may want to copy libserver.dylib to Python's extension directory, -# and do something like -# sudo install_name_tool /Library/Python/2.7/site-packages/kotlin_bridge.so -change libserver.dylib @loader_path/libserver.dylib -# This way libserver.dylib could be loaded from extension's directory. \ No newline at end of file diff --git a/kotlin-native/samples/settings.gradle.kts b/kotlin-native/samples/settings.gradle.kts index ed5559953a3..e88a0ee28d7 100644 --- a/kotlin-native/samples/settings.gradle.kts +++ b/kotlin-native/samples/settings.gradle.kts @@ -19,12 +19,9 @@ if (isMacos || isLinux || isWindows) { include(":csvparser") include(":curl") include(":echoServer") - include(":gitchurn") include(":globalState") - include(":gtk") include(":html5Canvas") include(":libcurl") - include(":tetris") include(":videoplayer") include(":workers") include(":coverage") @@ -33,7 +30,6 @@ if (isMacos || isLinux || isWindows) { if (isMacos || isLinux) { include(":nonBlockingEchoServer") include(":tensorflow") - include(":torch") } if (isMacos) { @@ -41,7 +37,6 @@ if (isMacos) { include(":opengl") include(":uikit") include(":watchos") - include(":simd") } if (isWindows) { diff --git a/kotlin-native/samples/simd/build.gradle.kts b/kotlin-native/samples/simd/build.gradle.kts deleted file mode 100644 index ba008f6b994..00000000000 --- a/kotlin-native/samples/simd/build.gradle.kts +++ /dev/null @@ -1,11 +0,0 @@ -plugins { - kotlin("multiplatform") -} - -kotlin { - macosX64 { - binaries { - executable() - } - } -} \ No newline at end of file diff --git a/kotlin-native/samples/simd/src/macosX64Main/kotlin/simd.kt b/kotlin-native/samples/simd/src/macosX64Main/kotlin/simd.kt deleted file mode 100644 index 99d63bb55dd..00000000000 --- a/kotlin-native/samples/simd/src/macosX64Main/kotlin/simd.kt +++ /dev/null @@ -1,54 +0,0 @@ -import platform.Accelerate.* - -// Custom print -fun Vector128.toStringHex(): String { - return "0x" + (0 until 16).map { getUByteAt(it).toString(16) }.joinToString("") -} - -// Custom print -fun Vector128.toStringFloat(): String { - return "(${(0 until 4).map { getFloatAt(it).toString() }.joinToString(", ")})" -} - - -fun main() { - - // Accessors - val vf4 = vectorOf(1f, 3.162f, 10f, 31f) - println(vf4) - println(vf4.toStringFloat()) - println(vf4.toStringHex()) - println(vf4.getFloatAt(1)) - println(vf4.getIntAt(0)) - println(vf4.getByteAt(3)) - // Illegal access (out of bounds) - try { - println(vf4.getIntAt(4)) - println("FAILED") - } catch (e: IndexOutOfBoundsException) { - println("Handling $e") - } - - // Assignment and equality - var x1 = vectorOf(-1f, 0f, 0f, -7f) - val y1 = vectorOf(-1f, 0f, 0f, -7f) - var x2 = vectorOf(1f, 4f, 3f, 7f) - println("(x1 == y1) is ${(x1 == y1)}") - println("(x1.equals(y1)) is ${(x1.equals(y1))}") - println("(x1 == x2) is ${(x1 == x2)}") - x1 = x2 - println("Now (x1 == x1) is ${(x1 == x1)}") - - - // Using library function (MacOS Accelerate framework) - val sum = vS128Add(vectorOf(1,2,3,4), vectorOf(4,3,2,1)) - println(sum) - // More Accelerate framework - val q = vectorOf(1f, 9f, 25f, 49f) - val sq = vsqrtf(q) - println("vsqrtf$q = ${sq.toStringFloat()}") - val f4 = vectorOf(1f, 3.162f, 10f, 31f) - println("vlog10f($f4) = ${vlog10f(vf4).toStringFloat()}") - - -} diff --git a/kotlin-native/samples/tetris/README.md b/kotlin-native/samples/tetris/README.md deleted file mode 100644 index ca961c9f74e..00000000000 --- a/kotlin-native/samples/tetris/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Tetris game - -This example shows implementation of simple Tetris game using SDL -(Simple DirectMedia Layer) library for rendering. SDL allows easy development -of cross-platform game and multimedia applications. - -Install SDL2 development files (see https://www.libsdl.org/download-2.0.php). For Mac - -copy `SDL2.framework` to `$HOME/Library/Frameworks`. For Debian-like Linux - -use `apt-get install libsdl2-dev`. -For Windows - `pacman -S mingw-w64-x86_64-SDL2 mingw-w64-i686-SDL2` in MSYS2 console. If you do not have MSYS2 -installed - install it first as described in http://www.msys2.org - -To build Tetris application for your host platform use `../gradlew assemble`. - -Note that SDL2 must be installed on the host. - -Now you can run the game using `../gradlew runReleaseExecutableTetris` or directly with - - ./build/bin/tetris/main/release/executable/tetris.kexe - -During build process compilation script creates interoperability bindings to SDL2, using SDL C headers, -and then compiles an application with the produced bindings. - -To deploy executable to iPhone device take Info.plist, then use XCode and your own private signing identity. - -To run on Raspberry Pi one need to install SDL package with `apt-get install libsdl2-2.0.0` on the Pi. -Also GLES2 renderer is recommended (use `SDL_RENDER_DRIVER=opengles2 ./Tetris.kexe`). - -For Windows `set SDL_RENDER_DRIVER=software` may be needed on some machines. - -Note: There is a known issue with SDL2 library on Mac OS X 10.14 Mojave. Window may render black until -it is dragged. See https://bugzilla.libsdl.org/show_bug.cgi?id=4272 diff --git a/kotlin-native/samples/tetris/build.gradle.kts b/kotlin-native/samples/tetris/build.gradle.kts deleted file mode 100644 index 6b782129ac4..00000000000 --- a/kotlin-native/samples/tetris/build.gradle.kts +++ /dev/null @@ -1,119 +0,0 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget - -plugins { - kotlin("multiplatform") -} - -val kotlinNativeDataPath = System.getenv("KONAN_DATA_DIR")?.let { File(it) } - ?: File(System.getProperty("user.home")).resolve(".konan") -val mingw64Path = File(System.getenv("MINGW64_DIR") ?: "C:/msys64/mingw64") -val mingw32Path = File(System.getenv("MINGW32_DIR") ?: "C:/msys64/mingw32") - -kotlin { - val hostOs = System.getProperty("os.name") - if (hostOs == "Mac OS X") { - macosX64() - } - if (hostOs == "Linux") { - linuxX64() - } - if (hostOs.startsWith("Windows")) { - mingwX64() - mingwX86() - } - - targets.withType { - sourceSets["${targetName}Main"].apply { - kotlin.srcDir("src/tetrisMain/kotlin") - } - - binaries { - executable { - entryPoint = "sample.tetris.main" - - // Compile Windows Resources - if (preset == presets["mingwX64"] || preset == presets["mingwX86"]) { - val taskName = linkTaskName.replaceFirst("link", "windres") - val inFile = File("src/tetrisMain/resources/Tetris.rc") - val outFile = buildDir.resolve("processedResources/$taskName.res") - val windresTask = tasks.register(taskName) { - val llvmDir = when (preset) { - presets["mingwX86"] -> kotlinNativeDataPath.resolve( - "dependencies/msys2-mingw-w64-i686-2/bin") - presets["mingwX64"] -> kotlinNativeDataPath.resolve( - "dependencies/msys2-mingw-w64-x86_64-2/bin") - else -> throw GradleException("Unsupported presets") - }.toString() - inputs.file(inFile) - outputs.file(outFile) - commandLine("$llvmDir/windres", inFile, "-O", "coff", "-o", outFile) - environment("PATH", "$llvmDir;${System.getenv("PATH")}") - dependsOn(compilation.compileKotlinTask) - } - linkTask.dependsOn(windresTask) - linkerOpts(outFile.toString()) - } - - when (preset) { - presets["macosX64"] -> linkerOpts("-L/opt/local/lib", "-L/usr/local/lib", "-lSDL2") - presets["linuxX64"] -> linkerOpts("-L/usr/lib64", "-L/usr/lib/x86_64-linux-gnu", "-lSDL2") - presets["mingwX64"] -> linkerOpts( - "-L${mingw64Path.resolve("lib")}", - "-Wl,-Bstatic", - "-lstdc++", - "-static", - "-lSDL2", - "-limm32", - "-lole32", - "-loleaut32", - "-lversion", - "-lwinmm", - "-lsetupapi", - "-mwindows" - ) - presets["mingwX86"] -> linkerOpts( - "-L${mingw32Path.resolve("lib")}", - "-Wl,-Bstatic", - "-lstdc++", - "-static", - "-lSDL2", - "-limm32", - "-lole32", - "-loleaut32", - "-lversion", - "-lwinmm", - "-lsetupapi", - "-mwindows" - ) - } - - val distTaskName = linkTaskName.replaceFirst("link", "dist") - val distTask = tasks.register(distTaskName) { - from("src/tetrisMain/resources") - into(linkTask.outputFile.get().parentFile) - exclude("*.rc") - if (!konanTarget.family.isAppleFamily) { - exclude("*.plist") - } - dependsOn(linkTask) - } - tasks["assemble"].dependsOn(distTask) - - runTask?.workingDir(project.provider { outputDirectory }) - } - } - - compilations["main"].cinterops { - val sdl by creating { - when (preset) { - presets["macosX64"] -> includeDirs("/opt/local/include/SDL2", "/usr/local/include/SDL2") - presets["linuxX64"] -> includeDirs("/usr/include", "/usr/include/x86_64-linux-gnu", "/usr/include/SDL2") - presets["mingwX64"] -> includeDirs(mingw64Path.resolve("include/SDL2")) - presets["mingwX86"] -> includeDirs(mingw32Path.resolve("include/SDL2")) - } - } - } - - compilations["main"].enableEndorsedLibs = true - } -} \ No newline at end of file diff --git a/kotlin-native/samples/tetris/gradle.properties b/kotlin-native/samples/tetris/gradle.properties deleted file mode 100644 index 790a07d5124..00000000000 --- a/kotlin-native/samples/tetris/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -kotlin.code.style=official -kotlin.import.noCommonSourceSets=true diff --git a/kotlin-native/samples/tetris/src/nativeInterop/cinterop/sdl.def b/kotlin-native/samples/tetris/src/nativeInterop/cinterop/sdl.def deleted file mode 100644 index 10463bab759..00000000000 --- a/kotlin-native/samples/tetris/src/nativeInterop/cinterop/sdl.def +++ /dev/null @@ -1,9 +0,0 @@ -headers = SDL.h stdlib.h time.h -entryPoint = SDL_main - -headerFilter = SDL* stdlib.h time.h - -compilerOpts = -D_POSIX_SOURCE -compilerOpts.osx = -compilerOpts.linux = -D_REENTRANT -compilerOpts.ios = diff --git a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Config.kt b/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Config.kt deleted file mode 100644 index 6e4f9f59ff4..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Config.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -package sample.tetris - -import platform.posix.* -import kotlinx.cinterop.* - -object Config { - var width: Int = 10 - private set - var height: Int = 20 - private set - var startLevel = 0 - private set - - init { - val file = fopen("config.txt", "r") - if (file != null) { - try { - val buffer = ByteArray(2 * 1024) - while (true) { - val nextLine = fgets(buffer.refTo(0), buffer.size, file)?.toKString() - if (nextLine == null || nextLine.isEmpty()) break - val records = nextLine.split('=') - if (records.size != 2) continue - val key = records[0].trim() - val value = records[1].trim() - when (key) { - "width" -> width = value.toInt() - "height" -> height = value.toInt() - "startLevel" -> startLevel = value.toInt() - } - } - } finally { - fclose(file) - } - } - } -} \ No newline at end of file diff --git a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/SDL_Visualizer.kt b/kotlin-native/samples/tetris/src/tetrisMain/kotlin/SDL_Visualizer.kt deleted file mode 100644 index 8d582b531b3..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/SDL_Visualizer.kt +++ /dev/null @@ -1,486 +0,0 @@ -/* - * 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. - */ - -package sample.tetris - -import kotlinx.cinterop.* -import platform.posix.* -import sdl.* - -fun get_SDL_Error() = SDL_GetError()!!.toKString() - -fun sleep(millis: Int) { - SDL_Delay(millis.toUInt()) -} - -class SDL_Visualizer(val width: Int, val height: Int): GameFieldVisualizer, UserInput { - private val CELL_SIZE = 20 - private val COLORS = 10 - private val CELLS_WIDTH = COLORS * CELL_SIZE - private val CELLS_HEIGHT = 3 * CELL_SIZE - private val SYMBOL_SIZE = 21 - private val INFO_MARGIN = 10 - private val MARGIN = 2 - private val BORDER_WIDTH = 18 - private val INFO_SPACE_WIDTH = SYMBOL_SIZE * (2 + 8) - private val LINES_LABEL_WIDTH = 104 - private val SCORE_LABEL_WIDTH = 107 - private val LEVEL_LABEL_WIDTH = 103 - private val NEXT_LABEL_WIDTH = 85 - private val TETRISES_LABEL_WIDTH = 162 - - private var ratio: Float - - private fun stretch(value: Int) = (value.toFloat() * ratio + 0.5).toInt() - - inner class GamePadButtons(width: Int, height: Int, gamePadHeight: Int) { - val MOVE_BUTTON_SIZE = 50 - val ROTATE_BUTTON_SIZE = 80 - val BUTTONS_MARGIN = 25 - - val arena = Arena() - val leftRect: SDL_Rect - val rightRect: SDL_Rect - val downRect: SDL_Rect - val dropRect: SDL_Rect - val rotateRect: SDL_Rect - - init { - val moveButtonsWidth = 3 * MOVE_BUTTON_SIZE + 2 * BUTTONS_MARGIN + BUTTONS_MARGIN - val x = (width - moveButtonsWidth - ROTATE_BUTTON_SIZE) / 2 - MOVE_BUTTON_SIZE - val y2 = (gamePadHeight - 2 * MOVE_BUTTON_SIZE - BUTTONS_MARGIN) / 2 - leftRect = arena.alloc() - leftRect.w = MOVE_BUTTON_SIZE - leftRect.h = MOVE_BUTTON_SIZE - leftRect.x = x - leftRect.y = height - gamePadHeight + y2 + MOVE_BUTTON_SIZE + BUTTONS_MARGIN - - downRect = arena.alloc() - downRect.w = MOVE_BUTTON_SIZE - downRect.h = MOVE_BUTTON_SIZE - downRect.x = x + MOVE_BUTTON_SIZE + BUTTONS_MARGIN - downRect.y = leftRect.y - - dropRect = arena.alloc() - dropRect.w = MOVE_BUTTON_SIZE - dropRect.h = MOVE_BUTTON_SIZE - dropRect.x = downRect.x - dropRect.y = height - gamePadHeight + y2 - - rightRect = arena.alloc() - rightRect.w = MOVE_BUTTON_SIZE - rightRect.h = MOVE_BUTTON_SIZE - rightRect.x = x + 2 * MOVE_BUTTON_SIZE + 2 * BUTTONS_MARGIN - rightRect.y = height - gamePadHeight + y2 + MOVE_BUTTON_SIZE + BUTTONS_MARGIN - - rotateRect = arena.alloc() - rotateRect.w = ROTATE_BUTTON_SIZE - rotateRect.h = ROTATE_BUTTON_SIZE - rotateRect.x = x + moveButtonsWidth - rotateRect.y = height - gamePadHeight + y2 - BUTTONS_MARGIN - } - - fun getCommandAt(x: Int, y: Int): UserCommand? { - return when { - inside(leftRect, x, y) -> UserCommand.LEFT - inside(rightRect, x, y) -> UserCommand.RIGHT - inside(downRect, x, y) -> UserCommand.DOWN - inside(dropRect, x, y) -> UserCommand.DROP - inside(rotateRect, x, y) -> UserCommand.ROTATE - else -> null - } - } - - private fun inside(rect: SDL_Rect, x: Int, y: Int): Boolean { - return x >= stretch(rect.x) && x <= stretch(rect.x + rect.w) - && y >= stretch(rect.y) && y <= stretch(rect.y + rect.h) - } - - fun destroy() { - arena.clear() - } - } - - private val field: Field = Array(height) { ByteArray(width) } - private val nextPieceField: Field = Array(4) { ByteArray(4) } - private var linesCleared: Int = 0 - private var level: Int = 0 - private var score: Int = 0 - private var tetrises: Int = 0 - - private var displayWidth: Int = 0 - private var displayHeight: Int = 0 - private val fieldWidth: Int - private val fieldHeight: Int - private var windowX: Int - private var windowY: Int - private val window: CPointer - private val renderer: CPointer - private val texture: CPointer - private val gamePadButtons: GamePadButtons? - private val platform: String - - init { - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { - throw Error("SDL_Init Error: ${get_SDL_Error()}") - } - - platform = SDL_GetPlatform()!!.toKString() - - memScoped { - val displayMode = alloc() - if (SDL_GetCurrentDisplayMode(0, displayMode.ptr.reinterpret()) != 0) { - println("SDL_GetCurrentDisplayMode Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - displayWidth = displayMode.w - displayHeight = displayMode.h - } - fieldWidth = width * (CELL_SIZE + MARGIN) + MARGIN + BORDER_WIDTH * 2 - fieldHeight = height * (CELL_SIZE + MARGIN) + MARGIN + BORDER_WIDTH * 2 - var windowWidth = fieldWidth + INFO_SPACE_WIDTH - var windowHeight: Int - if (platform == "iOS") { - val gamePadHeight = (displayHeight * windowWidth - fieldHeight * displayWidth) / displayWidth - windowHeight = fieldHeight + gamePadHeight - gamePadButtons = GamePadButtons(windowWidth, windowHeight, gamePadHeight) - windowX = 0 - windowY = 0 - ratio = displayHeight.toFloat() / windowHeight - windowWidth = displayWidth - windowHeight = displayHeight - } else { - windowHeight = fieldHeight - gamePadButtons = null - windowX = (displayWidth - windowWidth) / 2 - windowY = (displayHeight - windowHeight) / 2 - ratio = 1.0f - } - val window = SDL_CreateWindow("Tetris", windowX, windowY, windowWidth, windowHeight, - SDL_WINDOW_SHOWN or SDL_WINDOW_ALLOW_HIGHDPI) - if (window == null) { - println("SDL_CreateWindow Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - this.window = window - - val renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED or SDL_RENDERER_PRESENTVSYNC) - if (renderer == null) { - SDL_DestroyWindow(window) - println("SDL_CreateRenderer Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - this.renderer = renderer - - memScoped { - val realWidth = alloc() - val realHeight = alloc() - SDL_GetRendererOutputSize(renderer, realWidth.ptr, realHeight.ptr) - if (platform != "iOS" && windowHeight != realHeight.value) { - println("DPI differs ${realWidth.value} x ${realHeight.value} vs $windowWidth x $windowHeight") - ratio = realHeight.value.toFloat() / windowHeight - } - } - - texture = loadImage(window, renderer, findFile("tetris_all.bmp")) - } - - private fun findFile(name: String): String { - memScoped { - val dirs = listOf(".", SDL_GetBasePath()?.toKString() ?: "/") - val statBuffer = alloc() - dirs.forEach { - val candidate = "$it/$name" - if (stat(candidate, statBuffer.ptr) == 0) return candidate - } - throw Error("name not found") - } - } - - private fun loadImage(win: CPointer, ren: CPointer, imagePath: String): CPointer { - val bmp = SDL_LoadBMP_RW(SDL_RWFromFile(imagePath, "rb"), 1); - if (bmp == null) { - SDL_DestroyRenderer(ren) - SDL_DestroyWindow(win) - println("SDL_LoadBMP_RW Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - - val tex = SDL_CreateTextureFromSurface(ren, bmp) - SDL_FreeSurface(bmp) - if (tex == null) { - SDL_DestroyRenderer(ren) - SDL_DestroyWindow(win) - println("SDL_CreateTextureFromSurface Error: ${get_SDL_Error()}") - SDL_Quit() - throw Error() - } - return tex - } - - override fun drawCell(x: Int, y: Int, cell: Byte) { - field[x][y] = cell - } - - override fun drawNextPieceCell(x: Int, y: Int, cell: Byte) { - nextPieceField[x][y] = cell - } - - override fun setInfo(linesCleared: Int, level: Int, score: Int, tetrises: Int) { - this.linesCleared = linesCleared - this.level = level - this.score = score - this.tetrises = tetrises - } - - override fun refresh() { - SDL_RenderClear(renderer) - drawField() - drawInfo() - drawNextPiece() - drawGamePad() - SDL_RenderPresent(renderer) - } - - private fun drawBorder(topLeftX: Int, topLeftY: Int, width: Int, height: Int) { - // Upper-left corner. - var srcX = CELLS_WIDTH - var srcY = 0 - var destX = topLeftX - var destY = topLeftY - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH + MARGIN, BORDER_WIDTH) - - // Upper margin. - srcX += BORDER_WIDTH + MARGIN - destX += BORDER_WIDTH + MARGIN - for (i in 0..width - 1) { - copyRect(srcX, srcY, destX, destY, CELL_SIZE + MARGIN, BORDER_WIDTH) - destX += CELL_SIZE + MARGIN - } - - // Upper-right corner. - srcX += CELL_SIZE + MARGIN - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH, BORDER_WIDTH + MARGIN) - - // Right margin. - srcY += BORDER_WIDTH + MARGIN - destY += BORDER_WIDTH + MARGIN - for (j in 0..height - 1) { - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH, CELL_SIZE + MARGIN) - destY += CELL_SIZE + MARGIN - } - - // Left margin. - srcX = CELLS_WIDTH - srcY = BORDER_WIDTH - destX = topLeftX - destY = topLeftY + BORDER_WIDTH - for (j in 0..height - 1) { - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH, CELL_SIZE + MARGIN) - destY += CELL_SIZE + MARGIN - } - - // Left-down corner. - srcY += CELL_SIZE + MARGIN - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH, BORDER_WIDTH + MARGIN) - - // Down marign. - srcX += BORDER_WIDTH - srcY += MARGIN - destX += BORDER_WIDTH - destY += MARGIN - for (i in 0..width - 1) { - copyRect(srcX, srcY, destX, destY, CELL_SIZE + MARGIN, BORDER_WIDTH) - destX += CELL_SIZE + MARGIN - - } - // Right-down corner. - srcX += CELL_SIZE + MARGIN - copyRect(srcX, srcY, destX, destY, BORDER_WIDTH + MARGIN, BORDER_WIDTH) - } - - private fun drawField() { - drawField(field = field, - topLeftX = 0, - topLeftY = 0, - width = width, - height = height) - } - - private fun drawNextPiece() { - drawInt(labelSrcX = LEVEL_LABEL_WIDTH, - labelSrcY = CELLS_HEIGHT + SYMBOL_SIZE, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(5), - labelWidth = NEXT_LABEL_WIDTH, - totalDigits = 0, - value = 0) - drawField(field = nextPieceField, - topLeftX = fieldWidth + SYMBOL_SIZE, - topLeftY = getInfoY(6), - width = 4, - height = 4) - } - - private fun drawField(field: Field, topLeftX: Int, topLeftY: Int, width: Int, height: Int) { - drawBorder(topLeftX = topLeftX, - topLeftY = topLeftY, - width = width, - height = height) - for (i in 0..height - 1) - for (j in 0..width - 1) { - val cell = field[i][j].toInt() - if (cell == 0) continue - copyRect(srcX = (level % COLORS) * CELL_SIZE, - srcY = (3 - cell) * CELL_SIZE, - destX = topLeftX + BORDER_WIDTH + MARGIN + j * (CELL_SIZE + MARGIN), - destY = topLeftY + BORDER_WIDTH + MARGIN + i * (CELL_SIZE + MARGIN), - width = CELL_SIZE, - height = CELL_SIZE) - } - } - - private fun drawInfo() { - drawInt(labelSrcX = LINES_LABEL_WIDTH, - labelSrcY = CELLS_HEIGHT, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(0), - labelWidth = SCORE_LABEL_WIDTH, - totalDigits = 6, - value = score) - drawInt(labelSrcX = 0, - labelSrcY = CELLS_HEIGHT, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(1), - labelWidth = LINES_LABEL_WIDTH, - totalDigits = 3, - value = linesCleared) - drawInt(labelSrcX = 0, - labelSrcY = CELLS_HEIGHT + SYMBOL_SIZE, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(2), - labelWidth = LEVEL_LABEL_WIDTH, - totalDigits = 2, - value = level) - drawInt(labelSrcX = 0, - labelSrcY = CELLS_HEIGHT + SYMBOL_SIZE * 2, - labelDestX = fieldWidth + SYMBOL_SIZE, - labelDestY = getInfoY(3), - labelWidth = TETRISES_LABEL_WIDTH, - totalDigits = 2, - value = tetrises) - } - - private fun getInfoY(line: Int): Int { - return SYMBOL_SIZE * (2 * line + 1) + INFO_MARGIN * line - } - - private fun drawInt(labelSrcX: Int, labelSrcY: Int, labelDestX: Int, labelDestY: Int, - labelWidth: Int, totalDigits: Int, value: Int) { - copyRect(srcX = labelSrcX, - srcY = labelSrcY, - destX = labelDestX, - destY = labelDestY, - width = labelWidth, - height = SYMBOL_SIZE) - val digits = IntArray(totalDigits) - var x = value - for (i in 0..totalDigits - 1) { - digits[totalDigits - 1 - i] = x % 10 - x = x / 10 - } - for (i in 0..totalDigits - 1) { - copyRect(srcX = digits[i] * SYMBOL_SIZE, - srcY = CELLS_HEIGHT + 3 * SYMBOL_SIZE, - destX = labelDestX + SYMBOL_SIZE + i * SYMBOL_SIZE, - destY = labelDestY + SYMBOL_SIZE, - width = SYMBOL_SIZE, - height = SYMBOL_SIZE) - } - } - - private fun drawGamePad() { - if (gamePadButtons == null) return - SDL_SetRenderDrawColor(renderer, 127, 127, 127, SDL_ALPHA_OPAQUE.toUByte()) - fillRect(gamePadButtons.leftRect) - fillRect(gamePadButtons.downRect) - fillRect(gamePadButtons.dropRect) - fillRect(gamePadButtons.rightRect) - fillRect(gamePadButtons.rotateRect) - SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE.toUByte()) - } - - private fun fillRect(rect: SDL_Rect) { - memScoped { - val stretchedRect = alloc() - stretchedRect.w = stretch(rect.w) - stretchedRect.h = stretch(rect.h) - stretchedRect.x = stretch(rect.x) - stretchedRect.y = stretch(rect.y) - SDL_RenderFillRect(renderer, stretchedRect.ptr.reinterpret()) - } - } - - private fun copyRect(srcX: Int, srcY: Int, destX: Int, destY: Int, width: Int, height: Int) { - memScoped { - val srcRect = alloc() - val destRect = alloc() - srcRect.w = width - srcRect.h = height - srcRect.x = srcX - srcRect.y = srcY - destRect.w = stretch(width) - destRect.h = stretch(height) - destRect.x = stretch(destX) - destRect.y = stretch(destY) - SDL_RenderCopy(renderer, texture, srcRect.ptr.reinterpret(), destRect.ptr.reinterpret()) - } - } - - override fun readCommands(): List { - val commands = mutableListOf() - memScoped { - val event = alloc() - while (SDL_PollEvent(event.ptr.reinterpret()) != 0) { - val eventType = event.type - when (eventType) { - SDL_QUIT -> commands.add(UserCommand.EXIT) - SDL_KEYDOWN -> { - val keyboardEvent = event.ptr.reinterpret().pointed - when (keyboardEvent.keysym.scancode) { - SDL_SCANCODE_LEFT -> commands.add(UserCommand.LEFT) - SDL_SCANCODE_RIGHT -> commands.add(UserCommand.RIGHT) - SDL_SCANCODE_DOWN -> commands.add(UserCommand.DOWN) - SDL_SCANCODE_Z, SDL_SCANCODE_SPACE -> commands.add(UserCommand.ROTATE) - SDL_SCANCODE_UP -> commands.add(UserCommand.DROP) - SDL_SCANCODE_ESCAPE -> commands.add(UserCommand.EXIT) - } - } - SDL_MOUSEBUTTONDOWN -> if (gamePadButtons != null) { - val mouseEvent = event.ptr.reinterpret().pointed - val x = mouseEvent.x - val y = mouseEvent.y - val command = gamePadButtons.getCommandAt(x, y) - if (command != null) - commands.add(command) - } - } - } - } - return commands - } - - fun destroy() { - SDL_DestroyTexture(texture) - SDL_DestroyRenderer(renderer) - SDL_DestroyWindow(window) - SDL_Quit() - gamePadButtons?.destroy() - } -} diff --git a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Tetris.kt b/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Tetris.kt deleted file mode 100644 index 0e26af76f4b..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/Tetris.kt +++ /dev/null @@ -1,491 +0,0 @@ -/* - * 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. - */ - -package sample.tetris - -import kotlinx.cinterop.* -import platform.posix.* - -typealias Field = Array - -enum class Move { - LEFT, - RIGHT, - DOWN, - ROTATE -} - -enum class PlacementResult(val linesCleared: Int = 0, val bonus: Int = 0) { - NOTHING, - GAMEOVER, - // For values of bonuses see https://tetris.wiki/Scoring - SINGLE(1, 40), - DOUBLE(2, 100), - TRIPLE(3, 300), - TETRIS(4, 1200) -} - -const val EMPTY: Byte = 0 -const val CELL1: Byte = 1 -const val CELL2: Byte = 2 -const val CELL3: Byte = 3 -const val BRICK: Byte = -1 - -class Point(var x: Int, var y: Int) - -operator fun Point.plus(other: Point): Point { - return Point(x + other.x, y + other.y) -} - -class PiecePosition(piece: Piece, private val origin: Point) { - private var p = piece.origin - val x get() = p.x + origin.x - val y get() = p.y + origin.y - - var state: Int get private set - val numberOfStates = piece.numberOfStates - - init { - state = 0 - } - - fun makeMove(move: Move) { - when (move) { - Move.LEFT -> --p.y - Move.RIGHT -> ++p.y - Move.DOWN -> ++p.x - Move.ROTATE -> state = (state + 1) % numberOfStates - } - } - - fun unMakeMove(move: Move) { - when (move) { - Move.LEFT -> ++p.y - Move.RIGHT -> --p.y - Move.DOWN -> --p.x - Move.ROTATE -> state = (state + numberOfStates - 1) % numberOfStates - } - } -} - -/* - * We use Nintendo Rotation System, right-handed version. - * See https://tetris.wiki/Nintendo_Rotation_System - */ -enum class Piece(private val origin_: Point, private vararg val states: Field) { - T(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL1, CELL1, CELL1), - byteArrayOf(EMPTY, CELL1, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL1, EMPTY), - byteArrayOf(CELL1, CELL1, EMPTY), - byteArrayOf(EMPTY, CELL1, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL1, EMPTY), - byteArrayOf(CELL1, CELL1, CELL1), - byteArrayOf(EMPTY, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL1, EMPTY), - byteArrayOf(EMPTY, CELL1, CELL1), - byteArrayOf(EMPTY, CELL1, EMPTY)) - ), - J(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL2, CELL2, CELL2), - byteArrayOf(EMPTY, EMPTY, CELL2)), - arrayOf( - byteArrayOf(EMPTY, CELL2, EMPTY), - byteArrayOf(EMPTY, CELL2, EMPTY), - byteArrayOf(CELL2, CELL2, EMPTY)), - arrayOf( - byteArrayOf(CELL2, EMPTY, EMPTY), - byteArrayOf(CELL2, CELL2, CELL2), - byteArrayOf(EMPTY, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL2, CELL2), - byteArrayOf(EMPTY, CELL2, EMPTY), - byteArrayOf(EMPTY, CELL2, EMPTY)) - ), - Z(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL3, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, CELL3)), - arrayOf( - byteArrayOf(EMPTY, EMPTY, CELL3), - byteArrayOf(EMPTY, CELL3, CELL3), - byteArrayOf(EMPTY, CELL3, EMPTY)) - ), - O(Point(0, -1), - arrayOf( - byteArrayOf(CELL1, CELL1), - byteArrayOf(CELL1, CELL1)) - ), - S(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(EMPTY, CELL2, CELL2), - byteArrayOf(CELL2, CELL2, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL2, EMPTY), - byteArrayOf(EMPTY, CELL2, CELL2), - byteArrayOf(EMPTY, EMPTY, CELL2)) - ), - L(Point(-1, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL3, CELL3, CELL3), - byteArrayOf(CELL3, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(CELL3, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, EMPTY, CELL3), - byteArrayOf(CELL3, CELL3, CELL3), - byteArrayOf(EMPTY, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, EMPTY), - byteArrayOf(EMPTY, CELL3, CELL3)) - ), - I(Point(-2, -2), - arrayOf( - byteArrayOf(EMPTY, EMPTY, EMPTY, EMPTY), - byteArrayOf(EMPTY, EMPTY, EMPTY, EMPTY), - byteArrayOf(CELL1, CELL1, CELL1, CELL1), - byteArrayOf(EMPTY, EMPTY, EMPTY, EMPTY)), - arrayOf( - byteArrayOf(EMPTY, EMPTY, CELL1, EMPTY), - byteArrayOf(EMPTY, EMPTY, CELL1, EMPTY), - byteArrayOf(EMPTY, EMPTY, CELL1, EMPTY), - byteArrayOf(EMPTY, EMPTY, CELL1, EMPTY)) - ); - - val origin get() = Point(origin_.x, origin_.y) - val numberOfStates: Int = states.size - - fun canBePlaced(field: Field, position: PiecePosition): Boolean { - val piece = states[position.state] - val x = position.x - val y = position.y - for (i in piece.indices) { - val pieceRow = piece[i] - val boardRow = field[x + i] - for (j in pieceRow.indices) { - if (pieceRow[j] != EMPTY && boardRow[y + j] != EMPTY) - return false - } - } - return true - } - - fun place(field: Field, position: PiecePosition) { - val piece = states[position.state] - val x = position.x - val y = position.y - for (i in piece.indices) { - val pieceRow = piece[i] - for (j in pieceRow.indices) { - if (pieceRow[j] != EMPTY) field[x + i][y + j] = pieceRow[j] - } - } - } - - fun unPlace(field: Field, position: PiecePosition) { - val piece = states[position.state] - val x = position.x - val y = position.y - for (i in piece.indices) { - val pieceRow = piece[i] - for (j in pieceRow.indices) { - if (pieceRow[j] != EMPTY) field[x + i][y + j] = EMPTY - } - } - } -} - -interface GameFieldVisualizer { - fun drawCell(x: Int, y: Int, cell: Byte) - fun drawNextPieceCell(x: Int, y: Int, cell: Byte) - fun setInfo(linesCleared: Int, level: Int, score: Int, tetrises: Int) - fun refresh() -} - -enum class UserCommand { - LEFT, - RIGHT, - DOWN, - DROP, - ROTATE, - EXIT -} - -interface UserInput { - fun readCommands(): List -} - -class GameField(val width: Int, val height: Int, val visualizer: GameFieldVisualizer) { - private val MARGIN = 4 - - private val field: Field - private val origin: Point - private val nextPieceField: Field - - init { - field = Array(height + MARGIN * 2) { ByteArray(width + MARGIN * 2) } - for (i in field.indices) { - val row = field[i] - for (j in row.indices) { - if (i >= (MARGIN + height) // Bottom (field is flipped over). - || (j < MARGIN) // Left - || (j >= MARGIN + width)) // Right - row[j] = BRICK - } - } - // Coordinates are relative to the central axis and top of the field. - origin = Point(MARGIN, MARGIN + (width + 1) / 2) - nextPieceField = Array(4) { ByteArray(4) } - } - - lateinit var currentPiece: Piece - lateinit var nextPiece: Piece - lateinit var currentPosition: PiecePosition - - fun reset() { - for (i in 0..height - 1) - for (j in 0..width - 1) - field[i + MARGIN][j + MARGIN] = 0 - srand(time(null).toUInt()) - nextPiece = getNextPiece(false) - switchCurrentPiece() - } - - private fun randInt() = (rand() and 32767) or ((rand() and 32767) shl 15) - - private fun getNextPiece(denyPrevious: Boolean): Piece { - val pieces = Piece.values() - if (!denyPrevious) - return pieces[randInt() % pieces.size] - while (true) { - val nextPiece = pieces[randInt() % pieces.size] - if (nextPiece != currentPiece) return nextPiece - } - } - - private fun switchCurrentPiece() { - currentPiece = nextPiece - nextPiece = getNextPiece(denyPrevious = true) // Forbid repeating the same piece for better distribution. - currentPosition = PiecePosition(currentPiece, origin) - } - - fun makeMove(move: Move): Boolean { - currentPosition.makeMove(move) - if (currentPiece.canBePlaced(field, currentPosition)) - return true - currentPosition.unMakeMove(move) - return false - } - - /** - * Places current piece at its current location. - */ - fun place(): PlacementResult { - currentPiece.place(field, currentPosition) - val linesCleared = clearLines() - if (isOutOfBorders()) return PlacementResult.GAMEOVER - switchCurrentPiece() - if (!currentPiece.canBePlaced(field, currentPosition)) - return PlacementResult.GAMEOVER - when (linesCleared) { - 1 -> return PlacementResult.SINGLE - 2 -> return PlacementResult.DOUBLE - 3 -> return PlacementResult.TRIPLE - 4 -> return PlacementResult.TETRIS - else -> return PlacementResult.NOTHING - } - } - - private fun clearLines(): Int { - val clearedLines = mutableListOf() - for (i in 0..height - 1) { - val row = field[i + MARGIN] - if ((0..width - 1).all { j -> row[j + MARGIN] != EMPTY }) { - clearedLines.add(i + MARGIN) - (0..width - 1).forEach { j -> row[j + MARGIN] = EMPTY } - } - } - if (clearedLines.size == 0) return 0 - draw(false) - visualizer.refresh() - sleep(500) - for (i in clearedLines) { - for (k in i - 1 downTo 1) - for (j in 0..width - 1) - field[k + 1][j + MARGIN] = field[k][j + MARGIN] - } - draw(false) - visualizer.refresh() - return clearedLines.size - } - - private fun isOutOfBorders(): Boolean { - for (i in 0..MARGIN - 1) - for (j in 0..width - 1) - if (field[i][j + MARGIN] != EMPTY) - return true - return false - } - - fun draw() { - draw(true) - drawNextPiece() - } - - private fun drawNextPiece() { - for (i in 0..3) - for (j in 0..3) - nextPieceField[i][j] = 0 - nextPiece.place(nextPieceField, PiecePosition(nextPiece, Point(1, 2))) - for (i in 0..3) - for (j in 0..3) - visualizer.drawNextPieceCell(i, j, nextPieceField[i][j]) - } - - private fun draw(drawCurrentPiece: Boolean) { - if (drawCurrentPiece) - currentPiece.place(field, currentPosition) - for (i in 0..height - 1) - for (j in 0..width - 1) - visualizer.drawCell(i, j, field[i + MARGIN][j + MARGIN]) - if (drawCurrentPiece) - currentPiece.unPlace(field, currentPosition) - } -} - -class Game(width: Int, height: Int, val visualizer: GameFieldVisualizer, val userInput: UserInput) { - private val field = GameField(width, height, visualizer) - - private var gameOver = true - private var startLevel = 0 - private var leveledUp = false - private var level = 0 - private var linesClearedAtCurrentLevel = 0 - private var linesCleared = 0 - private var tetrises = 0 - private var score = 0 - - /* - * For speed constants and level up thresholds see https://tetris.wiki/Tetris_(NES,_Nintendo) - */ - private val speeds = intArrayOf(48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) - private val levelUpThreshold - get() = - if (leveledUp) 10 - else minOf(startLevel * 10 + 10, maxOf(100, startLevel * 10 - 50)) - private val speed get() = if (level < 29) speeds[level] else 1 - - private var ticks = 0 - - fun startNewGame(level: Int) { - gameOver = false - startLevel = level - leveledUp = false - this.level = level - linesClearedAtCurrentLevel = 0 - linesCleared = 0 - tetrises = 0 - score = 0 - ticks = 0 - field.reset() - - visualizer.setInfo(linesCleared, level, score, tetrises) - field.draw() - visualizer.refresh() - - mainLoop() - } - - private fun placePiece() { - val placementResult = field.place() - ticks = 0 - when (placementResult) { - PlacementResult.NOTHING -> return - PlacementResult.GAMEOVER -> { - gameOver = true - return - } - else -> { - linesCleared += placementResult.linesCleared - linesClearedAtCurrentLevel += placementResult.linesCleared - score += placementResult.bonus * (level + 1) - if (placementResult == PlacementResult.TETRIS) - ++tetrises - val levelUpThreshold = levelUpThreshold - if (linesClearedAtCurrentLevel >= levelUpThreshold) { - ++level - linesClearedAtCurrentLevel -= levelUpThreshold - leveledUp = true - } - - visualizer.setInfo(linesCleared, level, score, tetrises) - } - } - } - - /* - * Number of additional gravity shifts before locking a piece landed on the ground. - * This is needed in order to let user to move a piece to the left/right before locking. - */ - private val LOCK_DELAY = 1 - - private fun mainLoop() { - var attemptsToLock = 0 - while (!gameOver) { - sleep(1000 / 60) // Refresh rate - 60 frames per second. - val commands = userInput.readCommands() - for (cmd in commands) { - val success: Boolean - when (cmd) { - UserCommand.EXIT -> return - UserCommand.LEFT -> success = field.makeMove(Move.LEFT) - UserCommand.RIGHT -> success = field.makeMove(Move.RIGHT) - UserCommand.ROTATE -> success = field.makeMove(Move.ROTATE) - UserCommand.DOWN -> { - success = field.makeMove(Move.DOWN) - if (!success) placePiece() - } - UserCommand.DROP -> { - while (field.makeMove(Move.DOWN)) { - } - success = true - placePiece() - } - } - if (success) { - field.draw() - visualizer.refresh() - } - } - ++ticks - if (ticks < speed) continue - if (!field.makeMove(Move.DOWN)) { - if (++attemptsToLock >= LOCK_DELAY) { - placePiece() - attemptsToLock = 0 - } - } - field.draw() - visualizer.refresh() - ticks -= speed - } - } - -} - diff --git a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/main.kt b/kotlin-native/samples/tetris/src/tetrisMain/kotlin/main.kt deleted file mode 100644 index 6548dcb6296..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/kotlin/main.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -package sample.tetris - -import kotlinx.cli.* - -fun main(args: Array) { - val argParser = ArgParser("tetris", useDefaultHelpShortName = false) - val level by argParser.option(ArgType.Int, shortName = "l", description = "Game level").default(Config.startLevel) - val width by argParser.option(ArgType.Int, shortName = "w", description = "Width of the game field").default(Config.width) - val height by argParser.option(ArgType.Int, shortName = "h", description = "Height of the game field").default(Config.height) - argParser.parse(args) - val visualizer = SDL_Visualizer(width, height) - val game = Game(width, height, visualizer, visualizer) - game.startNewGame(level) - - return -} \ No newline at end of file diff --git a/kotlin-native/samples/tetris/src/tetrisMain/resources/Info.plist b/kotlin-native/samples/tetris/src/tetrisMain/resources/Info.plist deleted file mode 100644 index da637bfe644..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/resources/Info.plist +++ /dev/null @@ -1,77 +0,0 @@ - - - - - BuildMachineOSBuild - 15G1212 - CFBundleDevelopmentRegion - en - CFBundleExecutable - tetris.kexe - CFBundleIdentifier - tetris.kexe - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - tetris.kexe - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSupportedPlatforms - - iPhoneOS - - CFBundleVersion - 1 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 14C89 - DTPlatformName - iphoneos - DTPlatformVersion - 10.2 - DTSDKBuild - 14C89 - DTSDKName - iphoneos10.2 - DTXcode - 0821 - DTXcodeBuild - 8C1002 - LSRequiresIPhoneOS - - MinimumOSVersion - 10.2 - UIDeviceFamily - - 1 - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - arm64 - - UIStatusBarHidden - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CFBundleIcons - - CFBundlePrimaryIcon - - CFBundleIconFiles - - Icon-60x2 - Icon-60 - - - - - diff --git a/kotlin-native/samples/tetris/src/tetrisMain/resources/Tetris.rc b/kotlin-native/samples/tetris/src/tetrisMain/resources/Tetris.rc deleted file mode 100644 index 6d1bcf075d3..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/resources/Tetris.rc +++ /dev/null @@ -1,23 +0,0 @@ -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "JetBrains LLC" - VALUE "FileDescription", "Tetris Demo Game" - VALUE "FileVersion", "1.0" - VALUE "InternalName", "Tetris" - VALUE "LegalCopyright", "©JetBrains" - VALUE "OriginalFilename", "Tetris.exe" - VALUE "ProductName", "Tetris for Windows" - VALUE "ProductVersion", "1.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/kotlin-native/samples/tetris/src/tetrisMain/resources/config.txt b/kotlin-native/samples/tetris/src/tetrisMain/resources/config.txt deleted file mode 100644 index da8f7d7d673..00000000000 --- a/kotlin-native/samples/tetris/src/tetrisMain/resources/config.txt +++ /dev/null @@ -1,3 +0,0 @@ -width = 10 -height = 30 -startLevel = 0 \ No newline at end of file diff --git a/kotlin-native/samples/tetris/src/tetrisMain/resources/tetris_all.bmp b/kotlin-native/samples/tetris/src/tetrisMain/resources/tetris_all.bmp deleted file mode 100644 index e5c57a6cc4f93c32f561f550d346116d38a34e96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112374 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 XXTAV41iUTS&IJo(8b})jU@JupoCt@_ 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 MhbSp22?`4SKekwD+5i9m diff --git a/kotlin-native/samples/torch/README.md b/kotlin-native/samples/torch/README.md deleted file mode 100644 index 7c0bf73a233..00000000000 --- a/kotlin-native/samples/torch/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Torch demo - -Trains a handwritten digit classifier using the [Torch](http://torch.ch) C backend. -Like other Torch clients, most prominently [PyTorch](http://pytorch.org), -this example is built on top of the -[ATen C API](https://github.com/pytorch/pytorch/tree/master/aten), -showing how a Torch client for Kotlin/Native could look like. - -## Installation - -To build [ATen (Torch for C)](https://github.com/pytorch/pytorch/tree/master/aten), -make sure you have Python 2.X and pyyaml installed: - - # macOS: if you don't have pip - sudo easy_install pip - # Linux: if you don't have pip - apt-get -y install python-pip - - # if you don't have pyyaml or typing - sudo pip install pyyaml typing - -Now - - ./downloadTorch.sh - -will install it into `$HOME/.konan/third-party/torch` (if not yet done). One may override the location of -`third-party/torch` by setting the `KONAN_DATA_DIR` environment variable. - -To build use `../gradlew assemble`. - - ./downloadMNIST.sh - -will download and unzip the [MNIST dataset](https://en.wikipedia.org/wiki/MNIST_database) of -[70000 labeled handwritten digits](http://yann.lecun.com/exdb/mnist/) for training and testing a classifier (if not yet done). - -Then run - - ../gradlew runReleaseExecutableTorch - -Alternatively you can run the artifact directly through - - ./build/bin/torch/main/release/executable/torch.kexe - -You may need to specify `LD_LIBRARY_PATH` or `DYLD_LIBRARY_PATH` environment variables -to point to `$HOME/.konan/third-party/torch/lib` if the ATen dynamic library cannot be found. - -Even on a CPU, training should only take some minutes, -and you should observe a classification accuracy of about 95% on the test dataset. diff --git a/kotlin-native/samples/torch/build.gradle.kts b/kotlin-native/samples/torch/build.gradle.kts deleted file mode 100644 index 113a5e6c617..00000000000 --- a/kotlin-native/samples/torch/build.gradle.kts +++ /dev/null @@ -1,62 +0,0 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget -import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType - -plugins { - kotlin("multiplatform") -} - -val kotlinNativeDataPath = System.getenv("KONAN_DATA_DIR")?.let { File(it) } - ?: File(System.getProperty("user.home")).resolve(".konan") - -val torchHome = kotlinNativeDataPath.resolve("third-party/torch") - -kotlin { - // Determine host preset. - val hostOs = System.getProperty("os.name") - - // Create target for the host platform. - val hostTarget = when { - hostOs == "Mac OS X" -> macosX64("torch") - hostOs == "Linux" -> linuxX64("torch") - // Windows is not supported - else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native $project.") - } - - hostTarget.apply { - binaries { - executable { - entryPoint = "sample.torch.main" - linkerOpts("-L${torchHome.resolve("lib")}", "-lATen") - runTask?.environment( - "LD_LIBRARY_PATH" to torchHome.resolve("lib"), - "DYLD_LIBRARY_PATH" to torchHome.resolve("lib") - ) - } - } - compilations["main"].cinterops { - val torch by creating { - includeDirs( - torchHome.resolve("include"), - torchHome.resolve("include/TH") - ) - } - } - } -} - -val downloadTorch by tasks.creating(Exec::class) { - workingDir = projectDir - commandLine("./downloadTorch.sh") -} - -val torch: KotlinNativeTarget by kotlin.targets -tasks[torch.compilations["main"].cinterops["torch"].interopProcessingTaskName].dependsOn(downloadTorch) - -val downloadMNIST by tasks.creating(Exec::class) { - workingDir = projectDir - commandLine("./downloadMNIST.sh") -} - -NativeBuildType.values() - .mapNotNull { torch.binaries.getExecutable(it).runTask } - .forEach { runTask -> runTask.dependsOn(downloadMNIST) } diff --git a/kotlin-native/samples/torch/downloadMNIST.sh b/kotlin-native/samples/torch/downloadMNIST.sh deleted file mode 100755 index ea348c32340..00000000000 --- a/kotlin-native/samples/torch/downloadMNIST.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -# See http://yann.lecun.com/exdb/mnist/ - -MNIST_TARGET_DIRECTORY="`pwd`/build/3rd-party/MNIST" - -echo "Downloading MNIST databases into $MNIST_TARGET_DIRECTORY ..." - -mkdir -p $MNIST_TARGET_DIRECTORY -cd $MNIST_TARGET_DIRECTORY - -wget -nv -N http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz -wget -nv -N http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz -wget -nv -N http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz -wget -nv -N http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz - -gunzip -fk *.gz diff --git a/kotlin-native/samples/torch/downloadTorch.sh b/kotlin-native/samples/torch/downloadTorch.sh deleted file mode 100755 index 4fa7c03c84a..00000000000 --- a/kotlin-native/samples/torch/downloadTorch.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -KONAN_USER_DIR=${KONAN_DATA_DIR:-"$HOME/.konan"} -TH_TARGET_DIRECTORY="$KONAN_USER_DIR/third-party/torch" -NO_CUDA=true # set to false for GPU support - -if [ ! -d $TH_TARGET_DIRECTORY/include/THNN ]; then - echo "Installing Torch into $TH_TARGET_DIRECTORY ..." - - mkdir -p build/3rd-party - cd build/3rd-party - - git clone https://github.com/pytorch/pytorch.git - # Current pytorch master fails the build so we need to checkout a correct revision. - cd pytorch && git checkout 310c3735b9eb97f30cee743b773e5bb054989edc^ && cd ../ - - mkdir build_torch - cd build_torch - - cmake -DNO_CUDA=$NO_CUDA ../pytorch/aten - make - make DESTDIR=$TH_TARGET_DIRECTORY install - - cd $TH_TARGET_DIRECTORY - - # remove 'usr/local' prefix produced by make: - mv usr/local/* . - rm -d usr/local usr - - # hack to solve "fatal error: 'generic/THNN.h' file not found" when linking, -I$/include/THNN did not work - cp include/THNN/generic/THNN.h include/TH/generic/THNN.h -fi diff --git a/kotlin-native/samples/torch/gradle.properties b/kotlin-native/samples/torch/gradle.properties deleted file mode 100644 index 790a07d5124..00000000000 --- a/kotlin-native/samples/torch/gradle.properties +++ /dev/null @@ -1,2 +0,0 @@ -kotlin.code.style=official -kotlin.import.noCommonSourceSets=true diff --git a/kotlin-native/samples/torch/src/nativeInterop/cinterop/torch.def b/kotlin-native/samples/torch/src/nativeInterop/cinterop/torch.def deleted file mode 100644 index 958c948be70..00000000000 --- a/kotlin-native/samples/torch/src/nativeInterop/cinterop/torch.def +++ /dev/null @@ -1 +0,0 @@ -headers = TH/TH.h THNN/THNN.h diff --git a/kotlin-native/samples/torch/src/torchMain/kotlin/ClassifierDemo.kt b/kotlin-native/samples/torch/src/torchMain/kotlin/ClassifierDemo.kt deleted file mode 100644 index 0526a49cbfe..00000000000 --- a/kotlin-native/samples/torch/src/torchMain/kotlin/ClassifierDemo.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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. - */ - -package sample.torch - -fun Float.toRoundedString(digits: Int = 0): String { - var factor = 1 - - for (i in 0 until digits) { - factor *= 10 - } - - return (kotlin.math.round(this * factor) / factor).toString() -} - -fun Float.toPercentageString(roundToDigits: Int = 1) = (this * 100).toRoundedString(roundToDigits) - -fun List.maxIndex() = withIndex().maxByOrNull { it.value }!!.index - -fun accuracy(predictionBatch: FloatMatrix, labelBatch: FloatMatrix): Float { - val resultIndexes = predictionBatch.toList().map { it.maxIndex() } - val labelBatchIndexes = labelBatch.toList().map { it.maxIndex() } - return resultIndexes.zip(labelBatchIndexes). - count { (result, label) -> result == label }.toFloat() / resultIndexes.size -} - -fun Backpropagatable.trainClassifier( - dataset: Dataset, - lossByLabels: (FloatMatrix) -> Backpropagatable, - learningRateByProgress: (Float) -> Float = { 5f * kotlin.math.exp(-it * 3) }, - batchSize: Int = 64, - iterations: Int = 500) { - - for (i in 0 until iterations) { - disposeScoped { - val (inputBatch, labelBatch) = dataset.sampleBatch(batchSize) - val errorNetwork = this@trainClassifier before lossByLabels(labelBatch) - val forwardResults = use { errorNetwork.forwardPass(inputBatch) } - val accuracy = accuracy(forwardResults.hidden, labelBatch) - val progress = i.toFloat() / iterations - val learningRate = learningRateByProgress(progress) - val backpropResults = use { forwardResults.backpropagate(outputGradient = tensor(learningRate)) } - val crossEntropy = forwardResults.output[0] - backpropResults.descend() - println("Iteration ${i + 1}/$iterations: " + - "${accuracy.toPercentageString()}% training batch accuracy, " + - "cross entropy loss = ${crossEntropy.toRoundedString(4)}, " + - "learning rate = ${learningRate.toRoundedString(4)}") - } - } -} - -fun Backpropagatable.testClassifier(dataset: Dataset, batchSize: Int = 100): Float { - val testBatches = dataset.testBatches(batchSize) - return testBatches.withIndex().map { (i, batchPair) -> - val (inputBatch, outputBatch) = batchPair - val accuracy = accuracy(this.forwardPass(inputBatch).output, outputBatch) - println("Test batch ${i + 1}/${testBatches.size}: ${accuracy.toPercentageString()}% accuracy") - accuracy * inputBatch.shape[0] - }.sum() / dataset.inputs.size -} - -fun randomInit(size: Int) = random(-.01, .01, size) -fun randomInit(size0: Int, size1: Int) = random(-.1, .1, size0, size1) - -fun linear(inputSize: Int, outputSize: Int) = Linear(randomInit(outputSize, inputSize), randomInit(outputSize)) -fun twoLayerClassifier(dataset: Dataset, hiddenSize: Int = 64) = - linear(dataset.inputs[0].size, hiddenSize) before Relu before - linear(hiddenSize, dataset.labels[0].size) before Softmax - -fun main() { - val trainingDataset = MNIST.labeledTrainingImages() - val predictionNetwork = twoLayerClassifier(trainingDataset) - predictionNetwork.trainClassifier(trainingDataset, lossByLabels = { CrossEntropyLoss(labels = it) }) - - val testDataset = MNIST.labeledTestImages() - val averageAccuracy = predictionNetwork.testClassifier(testDataset) - println("Accuracy on the test set: ${averageAccuracy.toPercentageString()}") -} diff --git a/kotlin-native/samples/torch/src/torchMain/kotlin/Dataset.kt b/kotlin-native/samples/torch/src/torchMain/kotlin/Dataset.kt deleted file mode 100644 index 8db12819f85..00000000000 --- a/kotlin-native/samples/torch/src/torchMain/kotlin/Dataset.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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. - */ - -package sample.torch - -import kotlinx.cinterop.* -import platform.posix.* - -data class Dataset(val inputs: List, val labels: List) { - fun batch(indices: List): Pair { - val inputBatch = tensor(*(indices.map { inputs[it].toTypedArray() }.toTypedArray())) - val labelBatch = tensor(*(indices.map { labels[it].toTypedArray() }.toTypedArray())) - return inputBatch to labelBatch - } - - fun sampleBatch(batchSize: Int) = batch((0 until batchSize).map { randomInt(inputs.size) }) - private fun batchAt(batchIndex: Int, batchSize: Int) = - batch((0 until inputs.size).drop(batchSize + batchIndex).take(batchSize)) - - fun testBatches(batchSize: Int) = (0 until inputs.size / batchSize).map { batchAt(it, batchSize = batchSize) } -} - -/** - * Provides the MNIST labeled handwritten digit dataset, described at http://yann.lecun.com/exdb/mnist/ - */ -object MNIST { - private fun readFileData(fileName: String) = memScoped { - val path = "build/3rd-party/MNIST/$fileName" - fun fail(): Nothing = throw Error("Cannot read input file $path") - - val size = alloc().also { if (stat(path, it.ptr) != 0) fail() }.st_size.toInt() - - println("Reading $size bytes from $path...") - - val file = fopen(path, "rb") ?: fail() - try { - ByteArray(size).also { fread(it.refTo(0), 1, size.convert(), file) } - } finally { - fclose(file) - } - } - - private fun Byte.reinterpretAsUnsigned() = this.toInt().let { it + if (it < 0) 256 else 0 } - - private fun unsignedBytesToInt(bytes: List) = - bytes.withIndex().map { (i, value) -> value.reinterpretAsUnsigned().shl(8 * (3 - i)) }.sum() - - private val intSize = 4 - private fun ByteArray.getIntAt(index: Int) = - unsignedBytesToInt((index until (index + intSize)).map { this[it] }) - - private val imageLength = 28 - private val imageSize = imageLength * imageLength - - private fun ByteArray.getImageAt(index: Int) = - FloatArray(imageSize) { this[index + it].reinterpretAsUnsigned().toFloat() / 255 } - - private fun oneHot(size: Int, index: Int) = FloatArray(size) { if (it == index) 1f else 0f } - - private fun readLabels(fileName: String, totalLabels: Int = 10): List { - val data = readFileData(fileName) - val check = data.getIntAt(0) - val expectedCheck = 2049 - if (check != 2049) throw Error("File should start with int $expectedCheck, but was $check.") - - val count = data.getIntAt(4) - - val offset = 8 - - if (count + offset != data.size) throw Error("Unexpected file size: ${data.size}.") - - return (0 until count).map { oneHot(totalLabels, index = data[offset + it].reinterpretAsUnsigned()) } - } - - private fun readImages(fileName: String): List { - val data = readFileData(fileName) - val check = data.getIntAt(0) - val expectedCheck = 2051 - if (check != expectedCheck) throw Error("File should start with int $expectedCheck, but was $check.") - - val count = data.getIntAt(4) - val width = data.getIntAt(8) - val height = data.getIntAt(12) - - val offset = 16 - - if (width != imageLength) throw Error() - if (height != imageLength) throw Error() - - if (count * imageSize + offset != data.size) throw Error("Unexpected file size: ${data.size}.") - - return (0 until count).map { data.getImageAt(offset + imageSize * it) } - } - - fun labeledTrainingImages() = Dataset( - inputs = readImages("train-images-idx3-ubyte"), - labels = readLabels("train-labels-idx1-ubyte")) - - fun labeledTestImages() = Dataset( - inputs = readImages("t10k-images-idx3-ubyte"), - labels = readLabels("t10k-labels-idx1-ubyte")) -} \ No newline at end of file diff --git a/kotlin-native/samples/torch/src/torchMain/kotlin/Disposable.kt b/kotlin-native/samples/torch/src/torchMain/kotlin/Disposable.kt deleted file mode 100644 index 2e94e0ed718..00000000000 --- a/kotlin-native/samples/torch/src/torchMain/kotlin/Disposable.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ - -package sample.torch - -/** - * NOTE: resource management in this sample suffers from resource leaks - * and double-free bugs (see workaround in [FloatTensor.dispose]). - * - * This might mean that the entire approach for resource management in the sample is faulty. - * Please take this into account when considering reusing the same approach in your project. - * - * TODO: rework resource management. -*/ -interface Disposable { - fun dispose() -} - -open class DisposableContainer(private val disposables: MutableList = ArrayList()) : Disposable { - /** - * Creates the object and schedules its disposal for the end of the scope. - */ - fun use(create: () -> T) = create().also { disposables.add(it) } - - override fun dispose() { - for (disposable in disposables) { - disposable.dispose() - } - } -} - -fun disposeScoped(action: DisposableContainer.() -> T): T { - val scope = DisposableContainer() - - try { - return scope.action() - } finally { - scope.dispose() - } -} \ No newline at end of file diff --git a/kotlin-native/samples/torch/src/torchMain/kotlin/Modules.kt b/kotlin-native/samples/torch/src/torchMain/kotlin/Modules.kt deleted file mode 100644 index bc07fa2a47b..00000000000 --- a/kotlin-native/samples/torch/src/torchMain/kotlin/Modules.kt +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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. - */ - -package sample.torch - -import kotlinx.cinterop.* -import torch.* - -// Defines network modules with the ability for backpropagation using both TH.h and THNN.h from the ATen library - -abstract class Backpropagatable { - abstract inner class ForwardResults(val input: Input) : DisposableContainer() { - init { - use { input } - } - - abstract val output: Output - abstract fun backpropagate(outputGradient: Output): BackpropagationResults - } - - abstract inner class BackpropagationResults( - val input: Input, - val output: Output, - val outputGradient: Output - ) : DisposableContainer() { - init { - use { input } - use { output } - use { outputGradient } - } - - abstract val inputGradient: Input - abstract fun descend() - } - - abstract fun forwardPass(input: Input): ForwardResults -} - -abstract class Module : Backpropagatable() { - abstract var parameters: Parameters - abstract fun parametersToList(parameters: Parameters): List - abstract fun parametersFromList(list: List): Parameters - private val parameterList get() = parametersToList(parameters) - - abstract operator fun invoke(input: Input): Output - abstract fun inputGradient(input: Input, outputGradient: Output, output: Output): Input - abstract fun parameterGradient(input: Input, outputGradient: Output, inputGradient: Input): Parameters - - override fun forwardPass(input: Input) = object : ForwardResults(input) { - override val output = use { this@Module(input) } - override fun backpropagate(outputGradient: Output) = - object : Backpropagatable.BackpropagationResults(input, output, outputGradient) { - override val inputGradient = use { this@Module.inputGradient(input, outputGradient, output) } - val parameterGradient = this@Module.parameterGradient(input, - outputGradient = outputGradient, inputGradient = inputGradient) - - override fun descend() = this@Module.descend(parameterGradient) - } - } - - open fun descend(parameterGradient: Parameters) { - parameters = parametersFromList(parameterList.zip( - parametersToList(parameterGradient)) { parameter, gradient -> parameter - gradient }) - } -} - -abstract class ParameterFreeModule : Module() { - override var parameters = Unit - override fun parametersToList(parameters: Unit) = emptyList() - override fun parametersFromList(list: List) = Unit - override fun parameterGradient(input: Input, outputGradient: Output, inputGradient: Input) = Unit - override fun descend(parameterGradient: Unit) {} -} - -class Chain( - val module1: Backpropagatable