bulk code format fix (#8707)

This commit is contained in:
Derek Bailey
2025-09-23 21:50:27 -07:00
committed by GitHub
parent 0e047869da
commit caf3b494db
559 changed files with 38871 additions and 31276 deletions

View File

@@ -8,6 +8,7 @@ plugins {
}
group = "com.google.flatbuffers.jmh"
version = "2.0.0-SNAPSHOT"
// Reads latest version from Java's runtime pom.xml,
@@ -15,10 +16,11 @@ version = "2.0.0-SNAPSHOT"
// runtime
fun readJavaFlatBufferVersion(): String {
val pom = XmlParser().parse(File("../java/pom.xml"))
val versionTag = pom.children().find {
val node = it as groovy.util.Node
node.name().toString().contains("version")
} as groovy.util.Node
val versionTag =
pom.children().find {
val node = it as groovy.util.Node
node.name().toString().contains("version")
} as groovy.util.Node
return versionTag.value().toString()
}
@@ -39,27 +41,26 @@ benchmark {
iterationTime = 300
iterationTimeUnit = "ms"
// uncomment for benchmarking JSON op only
include(".*FlatbufferBenchmark.*")
include(".*FlatbufferBenchmark.*")
}
}
targets {
register("jvm")
}
targets { register("jvm") }
}
kotlin {
jvm {
compilations {
val main by getting { }
val main by getting {}
// custom benchmark compilation
val benchmarks by compilations.creating {
defaultSourceSet {
dependencies {
// Compile against the main compilation's compile classpath and outputs:
implementation(main.compileDependencyFiles + main.output.classesDirs)
val benchmarks by
compilations.creating {
defaultSourceSet {
dependencies {
// Compile against the main compilation's compile classpath and outputs:
implementation(main.compileDependencyFiles + main.output.classesDirs)
}
}
}
}
}
}
@@ -91,17 +92,13 @@ tasks.register<de.undercouch.gradle.tasks.download.Download>("downloadMultipleFi
}
abstract class GenerateFBTestClasses : DefaultTask() {
@get:InputFiles
abstract val inputFiles: ConfigurableFileCollection
@get:InputFiles abstract val inputFiles: ConfigurableFileCollection
@get:Input
abstract val includeFolder: Property<String>
@get:Input abstract val includeFolder: Property<String>
@get:Input
abstract val outputFolder: Property<String>
@get:Input abstract val outputFolder: Property<String>
@get:Input
abstract val variants: ListProperty<String>
@get:Input abstract val variants: ListProperty<String>
@Inject
protected open fun getExecActionFactory(): org.gradle.process.internal.ExecActionFactory? {
@@ -117,7 +114,7 @@ abstract class GenerateFBTestClasses : DefaultTask() {
val execAction = getExecActionFactory()!!.newExecAction()
val sources = inputFiles.asPath.split(":")
val langs = variants.get().map { "--$it" }
val args = mutableListOf("flatc","-o", outputFolder.get(), *langs.toTypedArray())
val args = mutableListOf("flatc", "-o", outputFolder.get(), *langs.toTypedArray())
if (includeFolder.get().isNotEmpty()) {
args.add("-I")
args.add(includeFolder.get())

View File

@@ -2,8 +2,8 @@
package com.google.flatbuffers.kotlin.benchmark
import com.google.flatbuffers.kotlin.FlatBufferBuilder
import java.util.concurrent.TimeUnit
import jmonster.JAllMonsters
import jmonster.JColor
import jmonster.JMonster
@@ -17,7 +17,6 @@ import monster.MonsterOffsetArray
import monster.Vec3
import org.openjdk.jmh.annotations.*
import org.openjdk.jmh.infra.Blackhole
import java.util.concurrent.TimeUnit
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@@ -32,48 +31,55 @@ open class FlatbufferBenchmark {
val fbDeserializationJava = com.google.flatbuffers.FlatBufferBuilder(1024 * repetition)
init {
populateMosterKotlin(fbDeserializationKotlin)
populateMosterJava(fbDeserializationJava)
populateMosterKotlin(fbDeserializationKotlin)
populateMosterJava(fbDeserializationJava)
}
@OptIn(ExperimentalUnsignedTypes::class)
private fun populateMosterKotlin(fb: FlatBufferBuilder) {
fb.clear()
val monsterName = fb.createString("MonsterName");
val monsterName = fb.createString("MonsterName")
val items = ubyteArrayOf(0u, 1u, 2u, 3u, 4u)
val inv = createInventoryVector(fb, items)
val monsterOffsets: MonsterOffsetArray = MonsterOffsetArray(repetition) {
Monster.startMonster(fb)
Monster.addName(fb, monsterName)
Monster.addPos(fb, Vec3.createVec3(fb, 1.0f, 2.0f, 3.0f))
Monster.addHp(fb, 80)
Monster.addMana(fb, 150)
Monster.addInventory(fb, inv)
Monster.addColor(fb, monster.Color.Red)
Monster.endMonster(fb)
}
val monsterOffsets: MonsterOffsetArray =
MonsterOffsetArray(repetition) {
Monster.startMonster(fb)
Monster.addName(fb, monsterName)
Monster.addPos(fb, Vec3.createVec3(fb, 1.0f, 2.0f, 3.0f))
Monster.addHp(fb, 80)
Monster.addMana(fb, 150)
Monster.addInventory(fb, inv)
Monster.addColor(fb, monster.Color.Red)
Monster.endMonster(fb)
}
val monsters = createMonstersVector(fb, monsterOffsets)
val allMonsters = createAllMonsters(fb, monsters)
fb.finish(allMonsters)
}
@OptIn(ExperimentalUnsignedTypes::class)
private fun populateMosterJava(fb: com.google.flatbuffers.FlatBufferBuilder){
private fun populateMosterJava(fb: com.google.flatbuffers.FlatBufferBuilder) {
fb.clear()
val monsterName = fb.createString("MonsterName");
val monsterName = fb.createString("MonsterName")
val inv = JMonster.createInventoryVector(fb, ubyteArrayOf(0u, 1u, 2u, 3u, 4u))
val monsters = JAllMonsters.createMonstersVector(fb, IntArray(repetition) {
JMonster.startJMonster(fb)
JMonster.addName(fb, monsterName)
JMonster.addPos(fb, JVec3.createJVec3(fb, 1.0f, 2.0f, 3.0f))
JMonster.addHp(fb, 80)
JMonster.addMana(fb, 150)
JMonster.addInventory(fb, inv)
JMonster.addColor(fb, JColor.Red)
JMonster.endJMonster(fb)
})
val monsters =
JAllMonsters.createMonstersVector(
fb,
IntArray(repetition) {
JMonster.startJMonster(fb)
JMonster.addName(fb, monsterName)
JMonster.addPos(fb, JVec3.createJVec3(fb, 1.0f, 2.0f, 3.0f))
JMonster.addHp(fb, 80)
JMonster.addMana(fb, 150)
JMonster.addInventory(fb, inv)
JMonster.addColor(fb, JColor.Red)
JMonster.endJMonster(fb)
},
)
val allMonsters = JAllMonsters.createJAllMonsters(fb, monsters)
fb.finish(allMonsters)
}
@Benchmark
fun monstersSerializationKotlin() {
populateMosterKotlin(fbKotlin)
@@ -100,6 +106,7 @@ open class FlatbufferBenchmark {
hole.consume(monster.inventory(3))
}
}
@Benchmark
fun monstersSerializationJava() {
populateMosterJava(fbJava)
@@ -125,5 +132,4 @@ open class FlatbufferBenchmark {
hole.consume(monster.inventory(3))
}
}
}

View File

@@ -16,11 +16,13 @@
@file:OptIn(ExperimentalUnsignedTypes::class)
package com.google.flatbuffers.kotlin.benchmark
import com.google.flatbuffers.ArrayReadWriteBuf
import com.google.flatbuffers.FlexBuffers
import com.google.flatbuffers.FlexBuffersBuilder.BUILDER_FLAG_SHARE_ALL
import com.google.flatbuffers.kotlin.FlexBuffersBuilder
import com.google.flatbuffers.kotlin.getRoot
import java.util.concurrent.TimeUnit
import kotlinx.benchmark.Blackhole
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.BenchmarkMode
@@ -30,7 +32,6 @@ import org.openjdk.jmh.annotations.OutputTimeUnit
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.Setup
import org.openjdk.jmh.annotations.State
import java.util.concurrent.TimeUnit
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@@ -57,9 +58,7 @@ open class FlexBuffersBenchmark {
this["int"] = 10
this["float"] = 12.3
this["intarray"] = bigIntArray
this.putMap("myMap") {
this["cool"] = "beans"
}
this.putMap("myMap") { this["cool"] = "beans" }
}
val ref = getRoot(kBuilder.finish())
val map = ref.toMap()
@@ -74,7 +73,11 @@ open class FlexBuffersBenchmark {
@Benchmark
open fun mapJava(blackhole: Blackhole) {
val jBuilder = com.google.flatbuffers.FlexBuffersBuilder(ArrayReadWriteBuf(initialCapacity), BUILDER_FLAG_SHARE_ALL)
val jBuilder =
com.google.flatbuffers.FlexBuffersBuilder(
ArrayReadWriteBuf(initialCapacity),
BUILDER_FLAG_SHARE_ALL,
)
val startMap = jBuilder.startMap()
jBuilder.putString("hello", "world")
jBuilder.putInt("int", 10)
@@ -112,18 +115,18 @@ open class FlexBuffersBenchmark {
@Benchmark
open fun intArrayJava(blackhole: Blackhole) {
val jBuilder = com.google.flatbuffers.FlexBuffersBuilder(ArrayReadWriteBuf(initialCapacity), BUILDER_FLAG_SHARE_ALL)
val jBuilder =
com.google.flatbuffers.FlexBuffersBuilder(
ArrayReadWriteBuf(initialCapacity),
BUILDER_FLAG_SHARE_ALL,
)
val v = jBuilder.startVector()
bigIntArray.forEach { jBuilder.putInt(it) }
jBuilder.endVector(null, v, true, false)
jBuilder.finish()
val root = FlexBuffers.getRoot(jBuilder.buffer)
val vec = root.asVector()
blackhole.consume(
IntArray(vec.size()) {
vec[it].asInt()
}
)
blackhole.consume(IntArray(vec.size()) { vec[it].asInt() })
}
@Benchmark
@@ -138,7 +141,11 @@ open class FlexBuffersBenchmark {
@Benchmark
open fun stringArrayJava(blackhole: Blackhole) {
val jBuilder = com.google.flatbuffers.FlexBuffersBuilder(ArrayReadWriteBuf(initialCapacity), BUILDER_FLAG_SHARE_ALL)
val jBuilder =
com.google.flatbuffers.FlexBuffersBuilder(
ArrayReadWriteBuf(initialCapacity),
BUILDER_FLAG_SHARE_ALL,
)
val v = jBuilder.startVector()
stringValue.forEach { jBuilder.putString(it) }
jBuilder.endVector(null, v, false, false)
@@ -182,7 +189,11 @@ open class FlexBuffersBenchmark {
@Benchmark
open fun stringMapJava(blackhole: Blackhole) {
val jBuilder = com.google.flatbuffers.FlexBuffersBuilder(ArrayReadWriteBuf(initialCapacity), BUILDER_FLAG_SHARE_ALL)
val jBuilder =
com.google.flatbuffers.FlexBuffersBuilder(
ArrayReadWriteBuf(initialCapacity),
BUILDER_FLAG_SHARE_ALL,
)
val v = jBuilder.startMap()
for (i in stringKey.indices) {
jBuilder.putString(stringKey[i], stringValue[i])

View File

@@ -24,6 +24,9 @@ import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import java.io.ByteArrayInputStream
import java.io.InputStreamReader
import java.util.concurrent.TimeUnit
import kotlinx.benchmark.Blackhole
import okio.Buffer
import org.openjdk.jmh.annotations.Benchmark
@@ -33,9 +36,6 @@ import org.openjdk.jmh.annotations.Mode
import org.openjdk.jmh.annotations.OutputTimeUnit
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.State
import java.io.ByteArrayInputStream
import java.io.InputStreamReader
import java.util.concurrent.TimeUnit
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@@ -43,9 +43,7 @@ import java.util.concurrent.TimeUnit
@Measurement(iterations = 100, time = 1, timeUnit = TimeUnit.MICROSECONDS)
open class JsonBenchmark {
final val moshi = Moshi.Builder()
.addLast(KotlinJsonAdapterFactory())
.build()
final val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build()
final val moshiAdapter = moshi.adapter(Map::class.java)
final val gson = Gson()
@@ -77,46 +75,60 @@ open class JsonBenchmark {
// TWITTER
@Benchmark
open fun readTwitterFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(twitterData))
@Benchmark
open fun readTwitterMoshi(hole: Blackhole?) = hole?.consume(readMoshi(twitterData))
@Benchmark
open fun readTwitterGson(hole: Blackhole?) = hole?.consume(readGson(twitterData))
open fun readTwitterFlexBuffers(hole: Blackhole? = null) =
hole?.consume(readFlexBuffers(twitterData))
@Benchmark open fun readTwitterMoshi(hole: Blackhole?) = hole?.consume(readMoshi(twitterData))
@Benchmark open fun readTwitterGson(hole: Blackhole?) = hole?.consume(readGson(twitterData))
@Benchmark
open fun roundTripTwitterFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(twitterData).toJson())
open fun roundTripTwitterFlexBuffers(hole: Blackhole? = null) =
hole?.consume(readFlexBuffers(twitterData).toJson())
@Benchmark
open fun roundTripTwitterMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(twitterData)))
open fun roundTripTwitterMoshi(hole: Blackhole?) =
hole?.consume(moshiAdapter.toJson(readMoshi(twitterData)))
@Benchmark
open fun roundTripTwitterGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(twitterData)))
open fun roundTripTwitterGson(hole: Blackhole?) =
hole?.consume(gson.toJson(readGson(twitterData)))
// CITM
@Benchmark
open fun readCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(citmData))
@Benchmark
open fun readCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(citmData)))
@Benchmark
open fun readCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(citmData)))
@Benchmark
open fun roundTripCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(citmData).toJson())
open fun roundTripCITMFlexBuffers(hole: Blackhole? = null) =
hole?.consume(readFlexBuffers(citmData).toJson())
@Benchmark
open fun roundTripCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(readMoshi(citmData)))
open fun roundTripCITMMoshi(hole: Blackhole?) =
hole?.consume(moshiAdapter.toJson(readMoshi(citmData)))
@Benchmark
open fun roundTripCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(readGson(citmData)))
@Benchmark
open fun writeCITMFlexBuffers(hole: Blackhole? = null) = hole?.consume(fbCitmRef.toJson())
@Benchmark
open fun writeCITMMoshi(hole: Blackhole?) = hole?.consume(moshiAdapter.toJson(moshiCitmRef))
@Benchmark
open fun writeCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(gsonCitmRef))
@Benchmark open fun writeCITMGson(hole: Blackhole?) = hole?.consume(gson.toJson(gsonCitmRef))
// CANADA
@Benchmark
open fun readCanadaFlexBuffers(hole: Blackhole? = null) = hole?.consume(readFlexBuffers(canadaData))
@Benchmark
open fun readCanadaMoshi(hole: Blackhole?) = hole?.consume(readMoshi(canadaData))
@Benchmark
open fun readCanadaGson(hole: Blackhole?) = hole?.consume(readGson(canadaData))
open fun readCanadaFlexBuffers(hole: Blackhole? = null) =
hole?.consume(readFlexBuffers(canadaData))
@Benchmark open fun readCanadaMoshi(hole: Blackhole?) = hole?.consume(readMoshi(canadaData))
@Benchmark open fun readCanadaGson(hole: Blackhole?) = hole?.consume(readGson(canadaData))
}

View File

@@ -18,6 +18,9 @@ package com.google.flatbuffers.kotlin.benchmark
import com.google.flatbuffers.kotlin.ArrayReadWriteBuffer
import com.google.flatbuffers.kotlin.Key
import com.google.flatbuffers.kotlin.Utf8
import java.nio.ByteBuffer
import java.util.concurrent.TimeUnit
import kotlin.random.Random
import kotlinx.benchmark.Blackhole
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.BenchmarkMode
@@ -27,9 +30,6 @@ import org.openjdk.jmh.annotations.OutputTimeUnit
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.Setup
import org.openjdk.jmh.annotations.State
import java.nio.ByteBuffer
import java.util.concurrent.TimeUnit
import kotlin.random.Random
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@@ -44,9 +44,7 @@ open class UTF8Benchmark {
private var sampleSmallAscii = (0..sampleSize).map { populateAscii(stringSize) }.toList()
private var sampleSmallAsciiDecoded = sampleSmallAscii.map { it.encodeToByteArray() }.toList()
@Setup
fun setUp() {
}
@Setup fun setUp() {}
@Benchmark
fun encodeUtf8KotlinStandard(blackhole: Blackhole) {
@@ -54,6 +52,7 @@ open class UTF8Benchmark {
blackhole.consume(i.encodeToByteArray())
}
}
@Benchmark
fun encodeUtf8KotlinFlatbuffers(blackhole: Blackhole) {
for (i in sampleSmallUtf8) {
@@ -61,6 +60,7 @@ open class UTF8Benchmark {
blackhole.consume(Utf8.encodeUtf8Array(i, byteArray, 0, byteArray.size))
}
}
@Benchmark
fun encodeUtf8JavaFlatbuffers(blackhole: Blackhole) {
val javaUtf8 = com.google.flatbuffers.Utf8.getDefault()
@@ -101,6 +101,7 @@ open class UTF8Benchmark {
blackhole.consume(i.encodeToByteArray())
}
}
@Benchmark
fun encodeAsciiKotlinFlatbuffers(blackhole: Blackhole) {
for (i in sampleSmallAscii) {
@@ -108,6 +109,7 @@ open class UTF8Benchmark {
blackhole.consume(Utf8.encodeUtf8Array(i, byteArray, 0, byteArray.size))
}
}
@Benchmark
fun encodeAsciiJavaFlatbuffers(blackhole: Blackhole) {
val javaUtf8 = com.google.flatbuffers.Utf8.getDefault()
@@ -179,7 +181,8 @@ open class UTF8Benchmark {
while (i < size) {
val w = Random.nextInt() and 0xFF
when {
w < 0x80 -> data[i++] = 0x20; // w;
w < 0x80 -> data[i++] = 0x20
// w;
w < 0xE0 -> {
data[i++] = (0xC2 + Random.nextInt() % (0xDF - 0xC2 + 1)).toByte()
data[i++] = (0x80 + Random.nextInt() % (0xBF - 0x80 + 1)).toByte()

View File

@@ -1,7 +1,6 @@
import org.gradle.internal.impldep.org.testng.ITestResult.STARTED
import java.nio.charset.StandardCharsets
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.nio.charset.StandardCharsets
buildscript {
repositories {
@@ -26,7 +25,8 @@ allprojects {
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<KotlinCommonOptions>>().configureEach {
kotlinOptions {
freeCompilerArgs += "-progressive" // https://kotlinlang.org/docs/whatsnew13.html#progressive-mode
freeCompilerArgs +=
"-progressive" // https://kotlinlang.org/docs/whatsnew13.html#progressive-mode
}
}

View File

@@ -1,7 +1,3 @@
plugins {
`kotlin-dsl`
}
plugins { `kotlin-dsl` }
repositories {
gradlePluginPortal()
}
repositories { gradlePluginPortal() }

View File

@@ -1,8 +1,8 @@
import java.util.*
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.`maven-publish`
import org.gradle.kotlin.dsl.signing
import java.util.*
plugins {
`maven-publish`
@@ -11,21 +11,24 @@ plugins {
// Stub secrets to let the project sync and build without the publication values set up
ext["signing.keyId"] = null
ext["signing.password"] = null
ext["signing.secretKeyRingFile"] = null
ext["ossrhUsername"] = null
ext["ossrhPassword"] = null
// Grabbing secrets from local.properties file or from environment variables, which could be used on CI
// Grabbing secrets from local.properties file or from environment variables, which could be used on
// CI
val secretPropsFile = project.rootProject.file("local.properties")
if (secretPropsFile.exists()) {
secretPropsFile.reader().use {
Properties().apply {
load(it)
}
}.onEach { (name, value) ->
ext[name.toString()] = value
}
secretPropsFile
.reader()
.use { Properties().apply { load(it) } }
.onEach { (name, value) -> ext[name.toString()] = value }
} else {
ext["signing.keyId"] = System.getenv("OSSRH_USERNAME")
ext["signing.password"] = System.getenv("OSSRH_PASSWORD")
@@ -34,9 +37,7 @@ if (secretPropsFile.exists()) {
ext["ossrhPassword"] = System.getenv("OSSRH_PASSWORD")
}
val javadocJar by tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
}
val javadocJar by tasks.registering(Jar::class) { archiveClassifier.set("javadoc") }
fun getExtraString(name: String) = ext[name]?.toString()
@@ -82,14 +83,10 @@ publishing {
email.set("dbaileychess@gmail.com")
}
}
scm {
url.set("https://github.com/google/flatbuffers")
}
scm { url.set("https://github.com/google/flatbuffers") }
}
}
}
// Signing artifacts. Signing.* extra properties values will be used
signing {
sign(publishing.publications)
}
signing { sign(publishing.publications) }

View File

@@ -1,29 +1,19 @@
import org.gradle.internal.impldep.org.fusesource.jansi.AnsiRenderer.test
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
import org.jetbrains.kotlin.cli.common.toBooleanLenient
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkConfig
plugins {
kotlin("multiplatform")
id("convention.publication")
}
val libName = "Flatbuffers"
group = "com.google.flatbuffers.kotlin"
version = "2.0.0-SNAPSHOT"
kotlin {
explicitApi()
jvm()
js(IR) {
browser {
testTask {
enabled = false
}
}
browser { testTask { enabled = false } }
binaries.executable()
}
macosX64()
@@ -32,17 +22,10 @@ kotlin {
iosSimulatorArm64()
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
}
}
val commonMain by getting { dependencies { implementation(kotlin("stdlib-common")) } }
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
dependencies { implementation(kotlin("test")) }
kotlin.srcDir("src/commonTest/generated/kotlin/")
}
@@ -52,8 +35,7 @@ kotlin {
implementation("com.google.flatbuffers:flatbuffers-java:2.0.3")
}
}
val jvmMain by getting {
}
val jvmMain by getting {}
val macosX64Main by getting
val macosArm64Main by getting
@@ -69,53 +51,47 @@ kotlin {
iosSimulatorArm64Main.dependsOn(this)
}
all {
languageSettings.optIn("kotlin.ExperimentalUnsignedTypes")
}
all { languageSettings.optIn("kotlin.ExperimentalUnsignedTypes") }
}
}
// Fixes JS issue: https://youtrack.jetbrains.com/issue/KT-49109
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().nodeVersion = "16.0.0"
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().nodeVersion =
"16.0.0"
}
// Use the default greeting
tasks.register<GenerateFBTestClasses>("generateFBTestClassesKt") {
inputFiles.setFrom("$rootDir/../tests/monster_test.fbs",
inputFiles.setFrom(
"$rootDir/../tests/monster_test.fbs",
"$rootDir/../tests/dictionary_lookup.fbs",
// @todo Seems like nesting code generation is broken for all generators.
// disabling test for now.
// "$rootDir/../tests/namespace_test/namespace_test1.fbs",
// "$rootDir/../tests/namespace_test/namespace_test2.fbs",
// @todo Seems like nesting code generation is broken for all generators.
// disabling test for now.
// "$rootDir/../tests/namespace_test/namespace_test1.fbs",
// "$rootDir/../tests/namespace_test/namespace_test2.fbs",
"$rootDir/../tests/union_vector/union_vector.fbs",
"$rootDir/../tests/optional_scalars.fbs")
"$rootDir/../tests/optional_scalars.fbs",
)
includeFolder.set("$rootDir/../tests/include_test")
outputFolder.set("${projectDir}/src/commonTest/generated/kotlin/")
variant.set("kotlin-kmp")
}
project.tasks.forEach {
if (it.name.contains("compileKotlin"))
it.dependsOn("generateFBTestClassesKt")
if (it.name.contains("compileKotlin")) it.dependsOn("generateFBTestClassesKt")
}
fun String.intProperty() = findProperty(this).toString().toInt()
abstract class GenerateFBTestClasses : DefaultTask() {
@get:InputFiles
abstract val inputFiles: ConfigurableFileCollection
@get:InputFiles abstract val inputFiles: ConfigurableFileCollection
@get:Input
abstract val includeFolder: Property<String>
@get:Input abstract val includeFolder: Property<String>
@get:Input
abstract val outputFolder: Property<String>
@get:Input abstract val outputFolder: Property<String>
@get:Input
abstract val variant: Property<String>
@get:Input abstract val variant: Property<String>
@Inject
protected open fun getExecActionFactory(): org.gradle.process.internal.ExecActionFactory? {
@@ -130,7 +106,7 @@ abstract class GenerateFBTestClasses : DefaultTask() {
fun compile() {
val execAction = getExecActionFactory()!!.newExecAction()
val sources = inputFiles.asPath.split(":")
val args = mutableListOf("flatc","-o", outputFolder.get(), "--${variant.get()}")
val args = mutableListOf("flatc", "-o", outputFolder.get(), "--${variant.get()}")
if (includeFolder.get().isNotEmpty()) {
args.add("-I")
args.add(includeFolder.get())

View File

@@ -18,13 +18,12 @@ package com.google.flatbuffers.kotlin
import kotlin.math.max
import kotlin.math.min
/**
* Represent a chunk of data, where FlexBuffers will be read from.
*/
/** Represent a chunk of data, where FlexBuffers will be read from. */
public interface ReadBuffer {
/**
* Scan through the buffer for first byte matching value.
*
* @param value to be match
* @param start inclusive initial position to start searching
* @param end exclusive final position of the search
@@ -34,6 +33,7 @@ public interface ReadBuffer {
/**
* Read boolean from the buffer. Booleans as stored as a single byte
*
* @param index position of the element in [ReadBuffer]
* @return [Boolean] element
*/
@@ -41,6 +41,7 @@ public interface ReadBuffer {
/**
* Read a [Byte] from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return a byte
*/
@@ -48,6 +49,7 @@ public interface ReadBuffer {
/**
* Read a [UByte] from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return a [UByte]
*/
@@ -55,6 +57,7 @@ public interface ReadBuffer {
/**
* Read a [Short] from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return a [Short]
*/
@@ -62,6 +65,7 @@ public interface ReadBuffer {
/**
* Read a [UShort] from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return a [UShort]
*/
@@ -69,6 +73,7 @@ public interface ReadBuffer {
/**
* Read a [Int] from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return an [Int]
*/
@@ -76,6 +81,7 @@ public interface ReadBuffer {
/**
* Read a [UInt] from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return an [UInt]
*/
@@ -83,6 +89,7 @@ public interface ReadBuffer {
/**
* Read a [Long] from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return a [Long]
*/
@@ -90,6 +97,7 @@ public interface ReadBuffer {
/**
* Read a [ULong] from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return a [ULong]
*/
@@ -97,6 +105,7 @@ public interface ReadBuffer {
/**
* Read a 32-bit float from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return a float
*/
@@ -104,6 +113,7 @@ public interface ReadBuffer {
/**
* Read a 64-bit float from the buffer.
*
* @param index position of the element in [ReadBuffer]
* @return a double
*/
@@ -111,6 +121,7 @@ public interface ReadBuffer {
/**
* Read a UTF-8 string from the buffer.
*
* @param start initial element of the string
* @param size size of the string in bytes.
* @return a `String`
@@ -119,22 +130,25 @@ public interface ReadBuffer {
/**
* Read a ByteArray from the buffer.
*
* @param start position from the [ReadBuffer] to be read
* @param length maximum number of bytes to be written in the buffer
*/
public fun getBytes(array: ByteArray, start: Int, length: Int = array.size)
/**
* Expose [ReadBuffer] as an array of bytes.
* This method is meant to be as efficient as possible, so for an array-backed [ReadBuffer], it should
* return its own internal data. In case access to internal data is not possible,
* a copy of the data into an array of bytes might occur.
* Expose [ReadBuffer] as an array of bytes. This method is meant to be as efficient as possible,
* so for an array-backed [ReadBuffer], it should return its own internal data. In case access to
* internal data is not possible, a copy of the data into an array of bytes might occur.
*
* @return [ReadBuffer] as an array of bytes
*/
public fun data(): ByteArray
/**
* Creates a new [ReadBuffer] point to a region of the current buffer, starting at [start] with size [size].
* Creates a new [ReadBuffer] point to a region of the current buffer, starting at [start] with
* size [size].
*
* @param start starting position of the [ReadBuffer]
* @param size in bytes of the [ReadBuffer]
* @return [ReadBuffer] slice.
@@ -142,15 +156,17 @@ public interface ReadBuffer {
public fun slice(start: Int, size: Int): ReadBuffer
/**
* Defines the size of the message in the buffer. It also determines last position that buffer
* can be read. Last byte to be accessed is in position `limit() -1`.
* Defines the size of the message in the buffer. It also determines last position that buffer can
* be read. Last byte to be accessed is in position `limit() -1`.
*
* @return indicate last position
*/
public val limit: Int
}
/**
* Interface to represent a read-write buffers. This interface will be used to access and write FlexBuffer messages.
* Interface to represent a read-write buffers. This interface will be used to access and write
* FlexBuffer messages.
*/
public interface ReadWriteBuffer : ReadBuffer {
/**
@@ -160,9 +176,9 @@ public interface ReadWriteBuffer : ReadBuffer {
/**
* Request capacity of the buffer relative to [writePosition]. In case buffer is already larger
* than the requested, this method will just return true. Otherwise,
* It might try to resize the buffer. In case of being unable to allocate
* enough memory, an exception will be thrown.
* than the requested, this method will just return true. Otherwise, It might try to resize the
* buffer. In case of being unable to allocate enough memory, an exception will be thrown.
*
* @param additional capacity in bytes to be added on top of [writePosition]
* @param copyAtEnd copy current data at the end of new underlying buffer
* @return new capacity in bytes
@@ -171,10 +187,10 @@ public interface ReadWriteBuffer : ReadBuffer {
requestCapacity(writePosition + additional, copyAtEnd)
/**
* Request capacity of the buffer in absolute values. In case buffer is already larger
* than the requested the method is a no-op. Otherwise,
* It might try to resize the buffer. In case of being unable to allocate
* enough memory, an exception will be thrown.
* Request capacity of the buffer in absolute values. In case buffer is already larger than the
* requested the method is a no-op. Otherwise, It might try to resize the buffer. In case of being
* unable to allocate enough memory, an exception will be thrown.
*
* @param capacity new capacity
* @param copyAtEnd copy current data at the end of new underlying buffer
* @return new capacity in bytes
@@ -182,14 +198,16 @@ public interface ReadWriteBuffer : ReadBuffer {
public fun requestCapacity(capacity: Int, copyAtEnd: Boolean = false): Int
/**
* Put a [Boolean] into the buffer at [writePosition] . Booleans as stored as single byte.
* Write position will be incremented.
* Put a [Boolean] into the buffer at [writePosition] . Booleans as stored as single byte. Write
* position will be incremented.
*
* @return [Boolean] element
*/
public fun put(value: Boolean)
/**
* Put an array of bytes into the buffer at [writePosition]. Write position will be incremented.
*
* @param value the data to be copied
* @param start initial position on value to be copied
* @param length amount of bytes to be copied
@@ -198,74 +216,58 @@ public interface ReadWriteBuffer : ReadBuffer {
/**
* Put an array of bytes into the buffer at [writePosition]. Write position will be incremented.
*
* @param value [ReadBuffer] the data to be copied
* @param start initial position on value to be copied
* @param length amount of bytes to be copied
*/
public fun put(value: ReadBuffer, start: Int = 0, length: Int = value.limit - start)
/**
* Write a [Byte] into the buffer at [writePosition]. Write position will be incremented.
*/
/** Write a [Byte] into the buffer at [writePosition]. Write position will be incremented. */
public fun put(value: Byte)
/**
* Write a [UByte] into the buffer at [writePosition]. Write position will be incremented.
*/
/** Write a [UByte] into the buffer at [writePosition]. Write position will be incremented. */
public fun put(value: UByte)
/**
* Write a [Short] into in the buffer at [writePosition]. Write position will be incremented.
*/
/** Write a [Short] into in the buffer at [writePosition]. Write position will be incremented. */
public fun put(value: Short)
/**
* Write a [UShort] into in the buffer at [writePosition]. Write position will be incremented.
*/
/** Write a [UShort] into in the buffer at [writePosition]. Write position will be incremented. */
public fun put(value: UShort)
/**
* Write a [Int] in the buffer at [writePosition]. Write position will be incremented.
*/
/** Write a [Int] in the buffer at [writePosition]. Write position will be incremented. */
public fun put(value: Int)
/**
* Write a [UInt] into in the buffer at [writePosition]. Write position will be incremented.
*/
/** Write a [UInt] into in the buffer at [writePosition]. Write position will be incremented. */
public fun put(value: UInt)
/**
* Write a [Long] into in the buffer at [writePosition]. Write position will be
* incremented.
*/
/** Write a [Long] into in the buffer at [writePosition]. Write position will be incremented. */
public fun put(value: Long)
/**
* Write a [ULong] into in the buffer at [writePosition]. Write position will be
* incremented.
*/
/** Write a [ULong] into in the buffer at [writePosition]. Write position will be incremented. */
public fun put(value: ULong)
/**
* Write a 32-bit [Float] into the buffer at [writePosition]. Write position will be
* incremented.
* Write a 32-bit [Float] into the buffer at [writePosition]. Write position will be incremented.
*/
public fun put(value: Float)
/**
* Write a 64-bit [Double] into the buffer at [writePosition]. Write position will be
* incremented.
* Write a 64-bit [Double] into the buffer at [writePosition]. Write position will be incremented.
*/
public fun put(value: Double)
/**
* Write a [String] encoded as UTF-8 into the buffer at [writePosition]. Write position will be incremented.
* Write a [String] encoded as UTF-8 into the buffer at [writePosition]. Write position will be
* incremented.
*
* @return size in bytes of the encoded string
*/
public fun put(value: CharSequence, encodedLength: Int = -1): Int
/**
* Write an array of bytes into the buffer.
*
* @param dstIndex initial position where [src] will be copied into.
* @param src the data to be copied.
* @param srcStart initial position on [src] that will be copied.
@@ -275,6 +277,7 @@ public interface ReadWriteBuffer : ReadBuffer {
/**
* Write an array of bytes into the buffer.
*
* @param dstIndex initial position where [src] will be copied into.
* @param src the data to be copied.
* @param srcStart initial position on [src] that will be copied.
@@ -284,66 +287,77 @@ public interface ReadWriteBuffer : ReadBuffer {
/**
* Write [Boolean] into a given position [index] on the buffer. Booleans as stored as single byte.
*
* @param index position of the element in buffer
*/
public operator fun set(index: Int, value: Boolean)
/**
* Write [Byte] into a given position [index] on the buffer.
*
* @param index position of the element in the buffer
*/
public operator fun set(index: Int, value: Byte)
/**
* Write [UByte] into a given position [index] on the buffer.
*
* @param index position of the element in the buffer
*/
public operator fun set(index: Int, value: UByte)
/**
Short
* Short
*
* @param index position of the element in [ReadBuffer]
*/
public fun set(index: Int, value: Short)
/**
* Write [UShort] into a given position [index] on the buffer.
*
* @param index position of the element in [ReadBuffer]
*/
public fun set(index: Int, value: UShort)
/**
* Write [Int] into a given position [index] on the buffer.
*
* @param index position of the element in [ReadBuffer]
*/
public fun set(index: Int, value: Int)
/**
* Write [UInt] into a given position [index] on the buffer.
*
* @param index position of the element in [ReadBuffer]
*/
public fun set(index: Int, value: UInt)
/**
* Write [Long] into a given position [index] on the buffer.
*
* @param index position of the element in [ReadBuffer]
*/
public fun set(index: Int, value: Long)
/**
* Write [ULong] into a given position [index] on the buffer.
*
* @param index position of the element in [ReadBuffer]
*/
public fun set(index: Int, value: ULong)
/**
* Write [Float] into a given position [index] on the buffer.
*
* @param index position of the element in [ReadBuffer]
*/
public fun set(index: Int, value: Float)
/**
* Write [Double] into a given position [index] on the buffer.
*
* @param index position of the element in [ReadBuffer]
*/
public fun set(index: Int, value: Double)
@@ -351,12 +365,15 @@ public interface ReadWriteBuffer : ReadBuffer {
public fun fill(value: Byte, start: Int, end: Int)
/**
* Current position of the buffer to be written. It will be automatically updated on [put] operations.
* Current position of the buffer to be written. It will be automatically updated on [put]
* operations.
*/
public var writePosition: Int
/**
* Creates a new [ReadWriteBuffer] point to a region of the current buffer, starting at [offset] with size [size].
* Creates a new [ReadWriteBuffer] point to a region of the current buffer, starting at [offset]
* with size [size].
*
* @param offset starting position of the [ReadWriteBuffer]
* @param size in bytes of the [ReadWriteBuffer]
* @return [ReadWriteBuffer] slice.
@@ -364,35 +381,35 @@ public interface ReadWriteBuffer : ReadBuffer {
public fun writeSlice(offset: Int, size: Int): ReadWriteBuffer
/**
* Special operation where we increase the backed buffer size to [capacity]
* and shift all already written data to the end of the buffer.
* Special operation where we increase the backed buffer size to [capacity] and shift all already
* written data to the end of the buffer.
*
* This function is mostly used when creating a Flatbuffer message, as data is written from the
* end of the buffer towards index 0.
*
* This function is mostly used when creating a Flatbuffer message, as
* data is written from the end of the buffer towards index 0.
* @param capacity required in bytes
* @return new capacity in bytes
*/
public fun moveWrittenDataToEnd(capacity: Int): Int
/**
* Maximum size in bytes that the backed buffer supports.
*/
/** Maximum size in bytes that the backed buffer supports. */
public val capacity: Int
/**
* Defines last relative position of the backed buffer that can be written.
* Any addition to the buffer that goes beyond will throw an exception
* instead of regrow the buffer (default behavior).
* Defines last relative position of the backed buffer that can be written. Any addition to the
* buffer that goes beyond will throw an exception instead of regrow the buffer (default
* behavior).
*/
public val writeLimit: Int
}
public open class ArrayReadBuffer(protected var buffer: ByteArray,
// offsets writePosition against backed buffer e.g. offset = 1, writePosition = 1
// will write first byte at position 2 of the backed buffer
internal val offset: Int = 0,
override val limit: Int = buffer.size - offset) : ReadBuffer {
public open class ArrayReadBuffer(
protected var buffer: ByteArray,
// offsets writePosition against backed buffer e.g. offset = 1, writePosition = 1
// will write first byte at position 2 of the backed buffer
internal val offset: Int = 0,
override val limit: Int = buffer.size - offset,
) : ReadBuffer {
override fun findFirst(value: Byte, start: Int, end: Int): Int {
val e = min(end, limit)
@@ -423,8 +440,8 @@ public open class ArrayReadBuffer(protected var buffer: ByteArray,
override fun getDouble(index: Int): Double = buffer.getDouble(offset + index)
override fun getString(start: Int, size: Int): String = buffer.decodeToString(this.offset + start,
this.offset + start + size)
override fun getString(start: Int, size: Int): String =
buffer.decodeToString(this.offset + start, this.offset + start + size)
override fun getBytes(array: ByteArray, start: Int, length: Int) {
val end = min(this.offset + start + length, buffer.size)
@@ -436,19 +453,19 @@ public open class ArrayReadBuffer(protected var buffer: ByteArray,
override fun data(): ByteArray = buffer
override fun slice(start: Int, size: Int): ReadBuffer = ArrayReadBuffer(buffer, this.offset + start, size)
override fun slice(start: Int, size: Int): ReadBuffer =
ArrayReadBuffer(buffer, this.offset + start, size)
}
/**
* Implements `[ReadWriteBuffer]` using [ByteArray] as backing buffer. Using array of bytes are
* usually faster than `ByteBuffer`.
*
* This class is not thread-safe, meaning that
* it must operate on a single thread. Operating from
* This class is not thread-safe, meaning that it must operate on a single thread. Operating from
* multiple thread leads into an undefined behavior
*
* All operations assume Little Endian byte order.
*/
public class ArrayReadWriteBuffer(
buffer: ByteArray,
offset: Int = 0,
@@ -456,12 +473,13 @@ public class ArrayReadWriteBuffer(
// Any addition to the buffer that goes beyond will throw an exception
// instead of regrow the buffer (default behavior).
public override val writeLimit: Int = -1,
override var writePosition: Int = offset
override var writePosition: Int = offset,
) : ArrayReadBuffer(buffer, offset, writePosition), ReadWriteBuffer {
public constructor(initialCapacity: Int = 10) : this(ByteArray(initialCapacity))
override val limit: Int get() = writePosition
override val limit: Int
get() = writePosition
override fun clear(): Unit = run { writePosition = 0 }
@@ -545,35 +563,69 @@ public class ArrayReadWriteBuffer(
}
override operator fun set(dstIndex: Int, src: ReadBuffer, srcStart: Int, srcLength: Int) {
when(src) {
is ArrayReadBuffer -> {
src.data().copyInto(buffer, dstIndex, src.offset + srcStart, src.offset + srcStart + srcLength)
}
else -> {
for (i in 0 until srcLength) {
buffer[dstIndex + i] = src[srcStart + i]
}
when (src) {
is ArrayReadBuffer -> {
src
.data()
.copyInto(buffer, dstIndex, src.offset + srcStart, src.offset + srcStart + srcLength)
}
else -> {
for (i in 0 until srcLength) {
buffer[dstIndex + i] = src[srcStart + i]
}
}
}
}
override operator fun set(index: Int, value: Byte) { buffer[index] = value }
override operator fun set(index: Int, value: UByte) { buffer.setUByte(index, value) }
override operator fun set(index: Int, value: Short) { buffer.setShort(index, value) }
override operator fun set(index: Int, value: UShort) { buffer.setUShort(index, value) }
override operator fun set(index: Int, value: Int) { buffer.setInt(index, value) }
override operator fun set(index: Int, value: UInt) { buffer.setUInt(index, value) }
override operator fun set(index: Int, value: Long) { buffer.setLong(index, value) }
override operator fun set(index: Int, value: ULong) { buffer.setULong(index, value) }
override operator fun set(index: Int, value: Float) { buffer.setFloat(index, value) }
override operator fun set(index: Int, value: Double) { buffer.setDouble(index, value) }
override fun fill(value: Byte, start: Int, end: Int) { buffer.fill(value, start, end) }
override operator fun set(index: Int, value: Byte) {
buffer[index] = value
}
override operator fun set(index: Int, value: UByte) {
buffer.setUByte(index, value)
}
override operator fun set(index: Int, value: Short) {
buffer.setShort(index, value)
}
override operator fun set(index: Int, value: UShort) {
buffer.setUShort(index, value)
}
override operator fun set(index: Int, value: Int) {
buffer.setInt(index, value)
}
override operator fun set(index: Int, value: UInt) {
buffer.setUInt(index, value)
}
override operator fun set(index: Int, value: Long) {
buffer.setLong(index, value)
}
override operator fun set(index: Int, value: ULong) {
buffer.setULong(index, value)
}
override operator fun set(index: Int, value: Float) {
buffer.setFloat(index, value)
}
override operator fun set(index: Int, value: Double) {
buffer.setDouble(index, value)
}
override fun fill(value: Byte, start: Int, end: Int) {
buffer.fill(value, start, end)
}
/**
* Request capacity of the buffer. In case buffer is already larger
* than the requested, it is a no-op. Otherwise,
* It might try to resize the buffer. In case of being unable to allocate
* enough memory, an exception will be thrown.
* Request capacity of the buffer. In case buffer is already larger than the requested, it is a
* no-op. Otherwise, It might try to resize the buffer. In case of being unable to allocate enough
* memory, an exception will be thrown.
*
* @param capacity new capacity
* @param copyAtEnd copy current data at the end of new underlying buffer
*/
@@ -582,15 +634,18 @@ public class ArrayReadWriteBuffer(
if (buffer.size >= capacity) return buffer.size
if (writeLimit > 0 && writeLimit + offset >= buffer.size) error("Buffer in writeLimit mode. In writeLimit mode" +
" the buffer does not grow automatically and any write beyond writeLimit will throw exception. " +
"(writeLimit: $writeLimit, newCapacity: $capacity")
if (writeLimit > 0 && writeLimit + offset >= buffer.size)
error(
"Buffer in writeLimit mode. In writeLimit mode" +
" the buffer does not grow automatically and any write beyond writeLimit will throw exception. " +
"(writeLimit: $writeLimit, newCapacity: $capacity"
)
// implemented in the same growing fashion as ArrayList
val oldCapacity = buffer.size
if (oldCapacity == Int.MAX_VALUE - 8) { // Ensure we don't grow beyond what fits in an int.
error("FlatBuffers: cannot grow buffer beyond 2 gigabytes.")
}
//(old_buf_size & 0xC0000000) != 0 ? MAX_BUFFER_SIZE : old_buf_size << 1;
// (old_buf_size & 0xC0000000) != 0 ? MAX_BUFFER_SIZE : old_buf_size << 1;
var newCapacity = 8
while (newCapacity < capacity) { // Note: this also catches newCapacity int overflow
newCapacity = if (newCapacity and -0x40000000 != 0) Int.MAX_VALUE - 8 else newCapacity shl 1
@@ -603,14 +658,13 @@ public class ArrayReadWriteBuffer(
}
override fun writeSlice(offset: Int, size: Int): ReadWriteBuffer {
return ArrayReadWriteBuffer(this.buffer, offset=offset, writeLimit=size)
return ArrayReadWriteBuffer(this.buffer, offset = offset, writeLimit = size)
}
override fun moveWrittenDataToEnd(capacity: Int): Int = requestCapacity(capacity, true)
override val capacity: Int
get() = buffer.size
}
public val emptyBuffer: ReadWriteBuffer = ArrayReadWriteBuffer(ByteArray(1))

View File

@@ -19,37 +19,53 @@ package com.google.flatbuffers.kotlin
import kotlin.experimental.and
internal fun ByteArray.getString(index: Int, size: Int): String = Utf8.decodeUtf8Array(this, index, size)
internal fun ByteArray.getString(index: Int, size: Int): String =
Utf8.decodeUtf8Array(this, index, size)
internal fun ByteArray.setCharSequence(index: Int, value: CharSequence): Int =
Utf8.encodeUtf8Array(value, this, index, this.size - index)
// List of functions that needs to be implemented on all platforms.
internal expect inline fun ByteArray.getUByte(index: Int): UByte
internal expect inline fun ByteArray.getShort(index: Int): Short
internal expect inline fun ByteArray.getUShort(index: Int): UShort
internal expect inline fun ByteArray.getInt(index: Int): Int
internal expect inline fun ByteArray.getUInt(index: Int): UInt
internal expect inline fun ByteArray.getLong(index: Int): Long
internal expect inline fun ByteArray.getULong(index: Int): ULong
internal expect inline fun ByteArray.getFloat(index: Int): Float
internal expect inline fun ByteArray.getDouble(index: Int): Double
internal expect inline fun ByteArray.setUByte(index: Int, value: UByte)
public expect inline fun ByteArray.setShort(index: Int, value: Short)
internal expect inline fun ByteArray.setUShort(index: Int, value: UShort)
internal expect inline fun ByteArray.setInt(index: Int, value: Int)
internal expect inline fun ByteArray.setUInt(index: Int, value: UInt)
internal expect inline fun ByteArray.setLong(index: Int, value: Long)
internal expect inline fun ByteArray.setULong(index: Int, value: ULong)
internal expect inline fun ByteArray.setFloat(index: Int, value: Float)
internal expect inline fun ByteArray.setDouble(index: Int, value: Double)
/**
* This implementation uses Little Endian order.
*/
/** This implementation uses Little Endian order. */
public object ByteArrayOps {
public inline fun getUByte(ary: ByteArray, index: Int): UByte = ary[index].toUByte()
public inline fun getShort(ary: ByteArray, index: Int): Short {
return (ary[index + 1].toInt() shl 8 or (ary[index].toInt() and 0xff)).toShort()
}
@@ -57,19 +73,18 @@ public object ByteArrayOps {
public inline fun getUShort(ary: ByteArray, index: Int): UShort = getShort(ary, index).toUShort()
public inline fun getInt(ary: ByteArray, index: Int): Int {
return (
(ary[index + 3].toInt() shl 24) or
((ary[index + 2].toInt() and 0xff) shl 16) or
((ary[index + 1].toInt() and 0xff) shl 8) or
((ary[index].toInt() and 0xff))
)
return ((ary[index + 3].toInt() shl 24) or
((ary[index + 2].toInt() and 0xff) shl 16) or
((ary[index + 1].toInt() and 0xff) shl 8) or
((ary[index].toInt() and 0xff)))
}
public inline fun getUInt(ary: ByteArray, index: Int): UInt = getInt(ary, index).toUInt()
public inline fun getLong(ary: ByteArray, index: Int): Long {
var idx = index
return ary[idx++].toLong() and 0xff or
return ary[idx++].toLong() and
0xff or
(ary[idx++].toLong() and 0xff shl 8) or
(ary[idx++].toLong() and 0xff shl 16) or
(ary[idx++].toLong() and 0xff shl 24) or
@@ -84,13 +99,15 @@ public object ByteArrayOps {
public inline fun setUByte(ary: ByteArray, index: Int, value: UByte) {
ary[index] = value.toByte()
}
public inline fun setShort(ary: ByteArray, index: Int, value: Short) {
var idx = index
ary[idx++] = (value and 0xff).toByte()
ary[idx] = (value.toInt() shr 8 and 0xff).toByte()
}
public inline fun setUShort(ary: ByteArray, index: Int, value: UShort): Unit = setShort(ary, index, value.toShort())
public inline fun setUShort(ary: ByteArray, index: Int, value: UShort): Unit =
setShort(ary, index, value.toShort())
public inline fun setInt(ary: ByteArray, index: Int, value: Int) {
var idx = index
@@ -100,7 +117,8 @@ public object ByteArrayOps {
ary[idx] = (value shr 24 and 0xff).toByte()
}
public inline fun setUInt(ary: ByteArray, index: Int, value: UInt): Unit = setInt(ary, index, value.toInt())
public inline fun setUInt(ary: ByteArray, index: Int, value: UInt): Unit =
setInt(ary, index, value.toInt())
public inline fun setLong(ary: ByteArray, index: Int, value: Long) {
var i = value.toInt()
@@ -109,7 +127,8 @@ public object ByteArrayOps {
setInt(ary, index + 4, i)
}
public inline fun setULong(ary: ByteArray, index: Int, value: ULong): Unit = setLong(ary, index, value.toLong())
public inline fun setULong(ary: ByteArray, index: Int, value: ULong): Unit =
setLong(ary, index, value.toLong())
public inline fun setFloat(ary: ByteArray, index: Int, value: Float) {
setInt(ary, index, value.toRawBits())
@@ -120,5 +139,7 @@ public object ByteArrayOps {
}
public inline fun getFloat(ary: ByteArray, index: Int): Float = Float.fromBits(getInt(ary, index))
public inline fun getDouble(ary: ByteArray, index: Int): Double = Double.fromBits(getLong(ary, index))
public inline fun getDouble(ary: ByteArray, index: Int): Double =
Double.fromBits(getLong(ary, index))
}

View File

@@ -17,14 +17,15 @@ package com.google.flatbuffers.kotlin
import kotlin.jvm.JvmOverloads
/**
* Class that helps you build a FlatBuffer. See the section
* "Use in Kotlin" in the main FlatBuffers documentation.
* Class that helps you build a FlatBuffer. See the section "Use in Kotlin" in the main FlatBuffers
* documentation.
*/
public class FlatBufferBuilder @JvmOverloads constructor(
public class FlatBufferBuilder
@JvmOverloads
constructor(
private val initialSize: Int = 1024,
private var buffer: ReadWriteBuffer = ArrayReadWriteBuffer(initialSize)
private var buffer: ReadWriteBuffer = ArrayReadWriteBuffer(initialSize),
) {
// Remaining space in the ByteBuffer.
private var space: Int = buffer.capacity
@@ -62,9 +63,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
// map used to cache shared strings.
private var stringPool: MutableMap<CharSequence, Offset<String>>? = null
/**
* Reset the FlatBufferBuilder by purging all data that it holds.
*/
/** Reset the FlatBufferBuilder by purging all data that it holds. */
public fun clear() {
space = buffer.capacity
buffer.clear()
@@ -96,11 +95,10 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Prepare to write an element of `size` after `additional_bytes`
* have been written, e.g. if you write a string, you need to align such
* the int length field is aligned to [com.google.flatbuffers.Int.SIZE_BYTES], and
* the string data follows it directly. If all you need to do is alignment, `additional_bytes`
* will be 0.
* Prepare to write an element of `size` after `additional_bytes` have been written, e.g. if you
* write a string, you need to align such the int length field is aligned to
* [com.google.flatbuffers.Int.SIZE_BYTES], and the string data follows it directly. If all you
* need to do is alignment, `additional_bytes` will be 0.
*
* @param size This is the of the new element to write.
* @param additionalBytes The padding size.
@@ -124,8 +122,8 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a `boolean` to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a `boolean` to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A `boolean` to put into the buffer.
*/
@@ -135,16 +133,16 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a [UByte] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a [UByte] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A [UByte] to put into the buffer.
*/
public fun put(x: UByte): Unit = put(x.toByte())
/**
* Add a [Byte] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a [Byte] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A [Byte] to put into the buffer.
*/
@@ -154,16 +152,16 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a [UShort] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a [UShort] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A [UShort] to put into the buffer.
*/
public fun put(x: UShort): Unit = put(x.toShort())
/**
* Add a [Short] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a [Short] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A [Short] to put into the buffer.
*/
@@ -173,35 +171,35 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add an [UInt] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add an [UInt] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x An [UInt] to put into the buffer.
*/
public fun put(x: UInt): Unit = put(x.toInt())
/**
* Add an [Int] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add an [Int] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x An [Int] to put into the buffer.
*/
public fun put(x: Int){
public fun put(x: Int) {
space -= Int.SIZE_BYTES
buffer.set(space, x)
}
/**
* Add a [ULong] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a [ULong] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A [ULong] to put into the buffer.
*/
public fun put(x: ULong): Unit = put(x.toLong())
/**
* Add a [Long] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a [Long] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A [Long] to put into the buffer.
*/
@@ -211,8 +209,8 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a [Float] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a [Float] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A [Float] to put into the buffer.
*/
@@ -222,8 +220,8 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a [Double] to the buffer, backwards from the current location. Doesn't align nor
* check for space.
* Add a [Double] to the buffer, backwards from the current location. Doesn't align nor check for
* space.
*
* @param x A [Double] to put into the buffer.
*/
@@ -336,26 +334,23 @@ public class FlatBufferBuilder @JvmOverloads constructor(
* @param off The offset to add.
*/
public fun add(off: Offset<*>): Unit = addOffset(off.value)
public fun add(off: VectorOffset<*>): Unit = addOffset(off.value)
private fun addOffset(off: Int) {
prep(Int.SIZE_BYTES, 0) // Ensure alignment is already done.
put(buffer.capacity - space - off + Int.SIZE_BYTES)
}
/**
* Start a new array/vector of objects. Users usually will not call
* this directly. The `FlatBuffers` compiler will create a start/end
* method for vector types in generated code.
*
* Start a new array/vector of objects. Users usually will not call this directly. The
* `FlatBuffers` compiler will create a start/end method for vector types in generated code.
*
* The expected sequence of calls is:
*
* 1. Start the array using this method.
* 1. Call [.addOffset] `num_elems` number of times to set
* the offset of each element in the array.
* 1. Call [.endVector] to retrieve the offset of the array.
*
*
* 1. Start the array using this method.
* 1. Call [.addOffset] `num_elems` number of times to set the offset of each element in the
* array.
* 1. Call [.endVector] to retrieve the offset of the array.
*
* For example, to create an array of strings, do:
* <pre>`// Need 10 strings
@@ -379,7 +374,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
*
* // Finish off the vector
* int offsetOfTheVector = fbb.endVector();
`</pre> *
* `</pre> *
*
* @param elemSize The size of each element in the array.
* @param numElems The number of elements in the array.
@@ -392,11 +387,12 @@ public class FlatBufferBuilder @JvmOverloads constructor(
prep(alignment, elemSize * numElems) // Just in case alignment > int.
nested = true
}
public fun startString(numElems: Int): Unit = startVector(1, numElems, 1)
/**
* Finish off the creation of an array and all its elements. The array
* must be created with [.startVector].
* Finish off the creation of an array and all its elements. The array must be created with
* [.startVector].
*
* @return The offset at which the newly created array starts.
* @see .startVector
@@ -423,16 +419,19 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Create a new array/vector and return a ByteBuffer to be filled later.
* Call [endVector] after this method to get an offset to the beginning
* of vector.
* Create a new array/vector and return a ByteBuffer to be filled later. Call [endVector] after
* this method to get an offset to the beginning of vector.
*
* @param elemSize the size of each element in bytes.
* @param numElems number of elements in the vector.
* @param alignment byte alignment.
* @return ByteBuffer with position and limit set to the space allocated for the array.
*/
public fun createUnintializedVector(elemSize: Int, numElems: Int, alignment: Int): ReadWriteBuffer {
public fun createUnintializedVector(
elemSize: Int,
numElems: Int,
alignment: Int,
): ReadWriteBuffer {
val length = elemSize * numElems
startVector(elemSize, numElems, alignment)
space -= length
@@ -460,19 +459,21 @@ public class FlatBufferBuilder @JvmOverloads constructor(
* @param offsets Offsets of the tables.
* @return Returns offset of the sorted vector.
*/
public fun <T : Table> createSortedVectorOfTables(obj: T, offsets: Array<Offset<T>>): VectorOffset<T> {
public fun <T : Table> createSortedVectorOfTables(
obj: T,
offsets: Array<Offset<T>>,
): VectorOffset<T> {
obj.sortTables(offsets, buffer)
return createVectorOfTables(offsets)
}
/**
* Encode the String `s` in the buffer using UTF-8. If a String with
* this exact contents has already been serialized using this method,
* instead simply returns the offset of the existing String.
* Encode the String `s` in the buffer using UTF-8. If a String with this exact contents has
* already been serialized using this method, instead simply returns the offset of the existing
* String.
*
* Usage of the method will incur into additional allocations,
* so it is advisable to use it only when it is known upfront that
* your message will have several repeated strings.
* Usage of the method will incur into additional allocations, so it is advisable to use it only
* when it is known upfront that your message will have several repeated strings.
*
* @param s The String to encode.
* @return The offset in the buffer where the encoded String starts.
@@ -494,6 +495,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
/**
* Encode the [CharSequence] `s` in the buffer using UTF-8.
*
* @param s The [CharSequence] to encode.
* @return The offset in the buffer where the encoded string starts.
*/
@@ -513,7 +515,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
* @param s An already encoded UTF-8 string as a `ByteBuffer`.
* @return The offset in the buffer where the encoded string starts.
*/
public fun createString(s: ReadBuffer): Offset<String> {
public fun createString(s: ReadBuffer): Offset<String> {
val length: Int = s.limit
add(0.toByte())
startVector(1, length, 1)
@@ -557,13 +559,16 @@ public class FlatBufferBuilder @JvmOverloads constructor(
/**
* Create a byte array in the buffer.
*
* The source [ReadBuffer] position is advanced until [ReadBuffer.limit]
* after this call.
* The source [ReadBuffer] position is advanced until [ReadBuffer.limit] after this call.
*
* @param data A source [ReadBuffer] with data.
* @return The offset in the buffer where the encoded array starts.
*/
public fun createByteVector(data: ReadBuffer, from: Int = 0, until: Int = data.limit): VectorOffset<Byte> {
public fun createByteVector(
data: ReadBuffer,
from: Int = 0,
until: Int = data.limit,
): VectorOffset<Byte> {
val length: Int = until - from
startVector(1, length, 1)
space -= length
@@ -572,28 +577,25 @@ public class FlatBufferBuilder @JvmOverloads constructor(
return VectorOffset(endVector())
}
/**
* Should not be accessing the final buffer before it is finished.
*/
/** Should not be accessing the final buffer before it is finished. */
public fun finished() {
if (!finished) throw AssertionError(
"FlatBuffers: you can only access the serialized buffer after it has been" +
" finished by FlatBufferBuilder.finish()."
)
if (!finished)
throw AssertionError(
"FlatBuffers: you can only access the serialized buffer after it has been" +
" finished by FlatBufferBuilder.finish()."
)
}
/**
* Should not be creating any other object, string or vector
* while an object is being constructed.
* Should not be creating any other object, string or vector while an object is being constructed.
*/
public fun notNested() {
if (nested) throw AssertionError("FlatBuffers: object serialization must not be nested.")
}
/**
* Structures are always stored inline, they need to be created right
* where they're used. You'll get this assertion failure if you
* created it elsewhere.
* Structures are always stored inline, they need to be created right where they're used. You'll
* get this assertion failure if you created it elsewhere.
*
* @param obj The offset of the created object.
*/
@@ -602,14 +604,11 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Start encoding a new object in the buffer. Users will not usually need to
* call this directly. The `FlatBuffers` compiler will generate helper methods
* that call this method internally.
*
*
* For example, using the "Monster" code found on the "landing page". An
* object of type `Monster` can be created using the following code:
* Start encoding a new object in the buffer. Users will not usually need to call this directly.
* The `FlatBuffers` compiler will generate helper methods that call this method internally.
*
* For example, using the "Monster" code found on the "landing page". An object of type `Monster`
* can be created using the following code:
* <pre>`int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
* fbb.createString("test1"),
* fbb.createString("test2")
@@ -626,19 +625,15 @@ public class FlatBufferBuilder @JvmOverloads constructor(
* Monster.addTest4(fbb, test4);
* Monster.addTestarrayofstring(fbb, testArrayOfString);
* int mon = Monster.endMonster(fbb);
`</pre> *
*
* `</pre> *
*
* Here:
* * The call to `Monster#startMonster(FlatBufferBuilder)` will call this method with the right
* number of fields set.
* * `Monster#endMonster(FlatBufferBuilder)` will ensure [.endObject] is called.
*
* * The call to `Monster#startMonster(FlatBufferBuilder)` will call this
* method with the right number of fields set.
* * `Monster#endMonster(FlatBufferBuilder)` will ensure [.endObject] is called.
*
*
*
* It's not recommended to call this method directly. If it's called manually, you must ensure
* to audit all calls to it whenever fields are added or removed from your schema. This is
* It's not recommended to call this method directly. If it's called manually, you must ensure to
* audit all calls to it whenever fields are added or removed from your schema. This is
* automatically done by the code generated by the `FlatBuffers` compiler.
*
* @param numFields The number of fields found in this object.
@@ -649,15 +644,14 @@ public class FlatBufferBuilder @JvmOverloads constructor(
vtable = IntArray(numFields)
}
vtableInUse = numFields
for (i in 0 until vtableInUse)
vtable[i] = 0
for (i in 0 until vtableInUse) vtable[i] = 0
nested = true
objectStart = offset()
}
/**
* Add a [Boolean] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [Boolean] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: Boolean, d: Boolean?) {
@@ -666,6 +660,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
// unboxed specialization
public fun add(o: Int, x: Boolean, d: Boolean) {
if (forceDefaults || x != d) {
@@ -675,17 +670,18 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a [UByte] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [UByte] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: UByte, d: UByte?): Unit = add(o, x.toByte(), d?.toByte())
// unboxed specialization
public fun add(o: Int, x: UByte, d: UByte): Unit = add(o, x.toByte(), d.toByte())
/**
* Add a [Byte] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [Byte] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: Byte, d: Byte?) {
@@ -694,6 +690,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
// unboxed specialization
public fun add(o: Int, x: Byte, d: Byte) {
if (forceDefaults || x != d) {
@@ -701,19 +698,20 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
/**
* Add a [UShort] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [UShort] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: UShort, d: UShort?): Unit = add(o, x.toShort(), d?.toShort())
// unboxed specialization
public fun add(o: Int, x: UShort, d: UShort): Unit = add(o, x.toShort(), d.toShort())
/**
* Add a [Short] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [Short] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: Short, d: Short?) {
@@ -722,6 +720,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
// unboxed specialization
public fun add(o: Int, x: Short, d: Short) {
if (forceDefaults || x != d) {
@@ -731,17 +730,18 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a [UInt] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [UInt] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: UInt, d: UInt?): Unit = add(o, x.toInt(), d?.toInt())
// unboxed specialization
public fun add(o: Int, x: UInt, d: UInt): Unit = add(o, x.toInt(), d.toInt())
/**
* Add a [Int] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [Int] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: Int, d: Int?) {
@@ -750,6 +750,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
// unboxed specialization
public fun add(o: Int, x: Int, d: Int) {
if (forceDefaults || x != d) {
@@ -757,17 +758,20 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
/**
* Add a [ULong] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [ULong] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: ULong, d: ULong?): Unit = add(o, x.toLong(), d?.toLong())
// unboxed specialization
public fun add(o: Int, x: ULong, d: ULong): Unit = add(o, x.toLong(), d.toLong())
/**
* Add a [Long] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [Long] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: Long, d: Long?) {
@@ -776,6 +780,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
// unboxed specialization
public fun add(o: Int, x: Long, d: Long) {
if (forceDefaults || x != d) {
@@ -785,8 +790,8 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a [Float] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [Float] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: Float, d: Float?) {
@@ -795,6 +800,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
// unboxed specialization
public fun add(o: Int, x: Float, d: Float) {
if (forceDefaults || x != d) {
@@ -804,8 +810,8 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Add a [Double] to a table at `o` into its vtable, with value `x` and default `d`.
* If `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* Add a [Double] to a table at `o` into its vtable, with value `x` and default `d`. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
*/
public fun add(o: Int, x: Double, d: Double?) {
@@ -814,6 +820,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
// unboxed specialization
public fun add(o: Int, x: Double, d: Double) {
if (forceDefaults || x != d) {
@@ -827,8 +834,8 @@ public class FlatBufferBuilder @JvmOverloads constructor(
*
* @param o The index into the vtable.
* @param x An `offset` to put into the buffer, depending on how defaults are handled. If
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
* `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
* default value, it can be skipped.
* @param d An `offset` default value to compare against when `force_defaults` is `false`.
*/
public fun add(o: Int, x: Offset<*>, d: Int) {
@@ -837,6 +844,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
slot(o)
}
}
public fun add(o: Int, x: VectorOffset<*>, d: Int) {
if (forceDefaults || x.value != d) {
add(x)
@@ -851,15 +859,20 @@ public class FlatBufferBuilder @JvmOverloads constructor(
* @param x The offset of the created struct.
* @param d The default value is always `0`.
*/
public fun addStruct(vOffset: Int, x: Offset<*>, d: Offset<*>?): Unit = addStruct(vOffset, x.value, d?.value)
public fun addStruct(vOffset: Int, x: Offset<*>, d: Offset<*>?): Unit =
addStruct(vOffset, x.value, d?.value)
// unboxed specialization
public fun addStruct(vOffset: Int, x: Offset<*>, d: Offset<*>): Unit = addStruct(vOffset, x.value, d.value)
public fun addStruct(vOffset: Int, x: Offset<*>, d: Offset<*>): Unit =
addStruct(vOffset, x.value, d.value)
public fun addStruct(vOffset: Int, x: Int, d: Int?) {
if (x != d) {
nested(x)
slot(vOffset)
}
}
// unboxed specialization
public fun addStruct(vOffset: Int, x: Int, d: Int) {
if (x != d) {
@@ -871,8 +884,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
/**
* Set the current vtable at `voffset` to the current location in the buffer.
*
* @param vOffset The index into the vtable to store the offset relative to the end of the
* buffer.
* @param vOffset The index into the vtable to store the offset relative to the end of the buffer.
*/
public fun slot(vOffset: Int) {
vtable[vOffset] = offset()
@@ -947,8 +959,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Checks that a required field has been set in a given table that has
* just been constructed.
* Checks that a required field has been set in a given table that has just been constructed.
*
* @param table The offset to the start of the table from the `ByteBuffer` capacity.
* @param field The offset to the field in the vtable.
@@ -1000,16 +1011,14 @@ public class FlatBufferBuilder @JvmOverloads constructor(
*
* @param rootTable An offset to be added to the buffer.
* @param fileIdentifier A FlatBuffer file identifier to be added to the buffer before
* `root_table`.
* `root_table`.
* @param sizePrefix Whether to prefix the size to the buffer.
*/
protected fun finish(rootTable: Offset<*>, fileIdentifier: String, sizePrefix: Boolean) {
val identifierSize = 4
prep(minalign, Int.SIZE_BYTES + identifierSize + if (sizePrefix) Int.SIZE_BYTES else 0)
if (fileIdentifier.length != identifierSize) throw AssertionError(
"FlatBuffers: file identifier must be length " +
identifierSize
)
if (fileIdentifier.length != identifierSize)
throw AssertionError("FlatBuffers: file identifier must be length " + identifierSize)
for (i in identifierSize - 1 downTo 0) {
add(fileIdentifier[i].code.toByte())
}
@@ -1021,7 +1030,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
*
* @param rootTable An offset to be added to the buffer.
* @param fileIdentifier A FlatBuffer file identifier to be added to the buffer before
* `root_table`.
* `root_table`.
*/
public fun finish(rootTable: Offset<*>, fileIdentifier: String) {
finish(rootTable, fileIdentifier, false)
@@ -1032,16 +1041,15 @@ public class FlatBufferBuilder @JvmOverloads constructor(
*
* @param rootTable An offset to be added to the buffer.
* @param fileIdentifier A FlatBuffer file identifier to be added to the buffer before
* `root_table`.
* `root_table`.
*/
public fun finishSizePrefixed(rootTable: Offset<*>, fileIdentifier: String) {
finish(rootTable, fileIdentifier, true)
}
/**
* In order to save space, fields that are set to their default value
* don't get serialized into the buffer. Forcing defaults provides a
* way to manually disable this optimization.
* In order to save space, fields that are set to their default value don't get serialized into
* the buffer. Forcing defaults provides a way to manually disable this optimization.
*
* @param forceDefaults When set to `true`, always serializes default values.
* @return Returns `this`.
@@ -1052,9 +1060,8 @@ public class FlatBufferBuilder @JvmOverloads constructor(
}
/**
* Get the ByteBuffer representing the FlatBuffer. Only call this after you've
* called `finish()`. The actual data starts at the ByteBuffer's current position,
* not necessarily at `0`.
* Get the ByteBuffer representing the FlatBuffer. Only call this after you've called `finish()`.
* The actual data starts at the ByteBuffer's current position, not necessarily at `0`.
*
* @return The [ReadBuffer] representing the FlatBuffer
*/
@@ -1068,7 +1075,7 @@ public class FlatBufferBuilder @JvmOverloads constructor(
*
* @return A full copy of the [data buffer][.dataBuffer].
*/
public fun sizedByteArray(start: Int = space, length: Int = buffer.capacity - space): ByteArray {
public fun sizedByteArray(start: Int = space, length: Int = buffer.capacity - space): ByteArray {
finished()
val array = ByteArray(length)
buffer.getBytes(array, start)
@@ -1080,26 +1087,29 @@ public class FlatBufferBuilder @JvmOverloads constructor(
*
* @param offset virtual table offset
* @return true if the filed is present
*/
*/
public fun Table.isFieldPresent(offset: Int): Boolean = this.offset(offset) != 0
}
public fun Double.sign(): Double = when {
this.isNaN() -> Double.NaN
this > 0 -> 1.0
this < 0 -> -1.0
else -> this
}
public fun Double.sign(): Double =
when {
this.isNaN() -> Double.NaN
this > 0 -> 1.0
this < 0 -> -1.0
else -> this
}
public fun Float.sign(): Float = when {
this.isNaN() -> Float.NaN
this > 0 -> 1.0f
this < 0 -> -1.0f
else -> this
}
public fun Float.sign(): Float =
when {
this.isNaN() -> Float.NaN
this > 0 -> 1.0f
this < 0 -> -1.0f
else -> this
}
public fun Int.sign(): Int = when {
this > 0 -> 1
this < 0 -> -1
else -> this
}
public fun Int.sign(): Int =
when {
this > 0 -> 1
this < 0 -> -1
else -> this
}

View File

@@ -20,29 +20,33 @@ import kotlin.math.min
// For now a typealias to guarantee type safety.
public typealias UnionOffset = Offset<Any>
public typealias UnionOffsetArray = OffsetArray<Any>
public typealias StringOffsetArray = OffsetArray<String>
public inline fun UnionOffsetArray(size: Int, crossinline call: (Int) -> Offset<Any>): UnionOffsetArray =
UnionOffsetArray(IntArray(size) { call(it).value })
public inline fun StringOffsetArray(size: Int, crossinline call: (Int) -> Offset<String>): StringOffsetArray =
StringOffsetArray(IntArray(size) { call(it).value })
/**
* Represents a "pointer" to a pointer types (table, string, struct) within the buffer
*/
public inline fun UnionOffsetArray(
size: Int,
crossinline call: (Int) -> Offset<Any>,
): UnionOffsetArray = UnionOffsetArray(IntArray(size) { call(it).value })
public inline fun StringOffsetArray(
size: Int,
crossinline call: (Int) -> Offset<String>,
): StringOffsetArray = StringOffsetArray(IntArray(size) { call(it).value })
/** Represents a "pointer" to a pointer types (table, string, struct) within the buffer */
@JvmInline
public value class Offset<T>(public val value: Int) {
public fun toUnion(): UnionOffset = UnionOffset(value)
}
/**
* Represents an array of offsets. Used to avoid boxing
* offset types.
*/
/** Represents an array of offsets. Used to avoid boxing offset types. */
@JvmInline
public value class OffsetArray<T>(public val value: IntArray) {
public inline val size: Int
get() = value.size
public inline operator fun get(index: Int): Offset<T> = Offset(value[index])
}
@@ -50,12 +54,8 @@ public inline fun <T> OffsetArray(size: Int, crossinline call: (Int) -> Offset<T
return OffsetArray(IntArray(size) { call(it).value })
}
/**
* Represents a "pointer" to a vector type with elements T
*/
@JvmInline
public value class VectorOffset<T>(public val value: Int)
/** Represents a "pointer" to a vector type with elements T */
@JvmInline public value class VectorOffset<T>(public val value: Int)
public fun <T> Int.toOffset(): Offset<T> = Offset(this)
@@ -64,28 +64,30 @@ public operator fun <T> Offset<T>.minus(other: Int): Offset<T> = Offset(this.val
public operator fun <T> Int.minus(other: Offset<T>): Int {
return this - other.value
}
/**
* All tables in the generated code derive from this class, and add their own accessors.
*/
/** All tables in the generated code derive from this class, and add their own accessors. */
public open class Table {
/** Used to hold the position of the `bb` buffer. */
/** Used to hold the position of the `bb` buffer. */
public var bufferPos: Int = 0
/** The underlying ReadWriteBuffer to hold the data of the Table. */
/** The underlying ReadWriteBuffer to hold the data of the Table. */
public var bb: ReadWriteBuffer = emptyBuffer
/** Used to hold the vtable position. */
/** Used to hold the vtable position. */
public var vtableStart: Int = 0
/** Used to hold the vtable size. */
/** Used to hold the vtable size. */
public var vtableSize: Int = 0
protected inline fun <reified T> Int.invalid(default: T, crossinline valid: (Int) -> T) : T =
protected inline fun <reified T> Int.invalid(default: T, crossinline valid: (Int) -> T): T =
if (this != 0) valid(this) else default
protected inline fun <reified T> lookupField(i: Int, default: T, crossinline found: (Int) -> T) : T =
offset(i).invalid(default) { found(it) }
protected inline fun <reified T> lookupField(
i: Int,
default: T,
crossinline found: (Int) -> T,
): T = offset(i).invalid(default) { found(it) }
/**
* Look up a field in the vtable.
@@ -107,10 +109,10 @@ public open class Table {
/**
* Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
*
* This allocates a new string and converts to wide chars upon each access,
* which is not very efficient. Instead, each FlatBuffer string also comes with an
* accessor based on __vector_as_ReadWriteBuffer below, which is much more efficient,
* assuming your Java program can handle UTF-8 data directly.
* This allocates a new string and converts to wide chars upon each access, which is not very
* efficient. Instead, each FlatBuffer string also comes with an accessor based on
* __vector_as_ReadWriteBuffer below, which is much more efficient, assuming your Java program can
* handle UTF-8 data directly.
*
* @param offset An `int` index into the Table's ReadWriteBuffer.
* @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
@@ -141,23 +143,24 @@ public open class Table {
newOffset += bufferPos
return newOffset + bb.getInt(newOffset) + Int.SIZE_BYTES // data starts after the length
}
/**
* Initialize vector as a ReadWriteBuffer.
*
* This is more efficient than using duplicate, since it doesn't copy the data
* nor allocates a new [ReadBuffer], creating no garbage to be collected.
*
* @param buffer The [ReadBuffer] for the array
* @param vectorOffset The position of the vector in the byte buffer
* @param elemSize The size of each element in the array
* @return The [ReadBuffer] for the array
*/
public fun vectorAsBuffer(buffer: ReadWriteBuffer, vectorOffset: Int, elemSize: Int): ReadBuffer {
val o = offset(vectorOffset)
if (o == 0) return emptyBuffer
val vectorStart = vector(o)
return buffer.slice(vectorStart, vectorLength(o) * elemSize)
}
/**
* Initialize vector as a ReadWriteBuffer.
*
* This is more efficient than using duplicate, since it doesn't copy the data nor allocates a new
* [ReadBuffer], creating no garbage to be collected.
*
* @param buffer The [ReadBuffer] for the array
* @param vectorOffset The position of the vector in the byte buffer
* @param elemSize The size of each element in the array
* @return The [ReadBuffer] for the array
*/
public fun vectorAsBuffer(buffer: ReadWriteBuffer, vectorOffset: Int, elemSize: Int): ReadBuffer {
val o = offset(vectorOffset)
if (o == 0) return emptyBuffer
val vectorStart = vector(o)
return buffer.slice(vectorStart, vectorLength(o) * elemSize)
}
/**
* Initialize any Table-derived type to point to the union at the given `offset`.
@@ -194,7 +197,7 @@ public open class Table {
* This method exists primarily to allow recycling Table instances without risking memory leaks
* due to `ReadWriteBuffer` references.
*/
public inline fun <reified T: Table> reset(i: Int, reuseBuffer: ReadWriteBuffer): T {
public inline fun <reified T : Table> reset(i: Int, reuseBuffer: ReadWriteBuffer): T {
bb = reuseBuffer
if (bb != emptyBuffer) {
bufferPos = i
@@ -212,10 +215,10 @@ public open class Table {
* Resets the internal state with a null `ReadWriteBuffer` and a zero position.
*
* This method exists primarily to allow recycling Table instances without risking memory leaks
* due to `ReadWriteBuffer` references. The instance will be unusable until it is assigned
* again to a `ReadWriteBuffer`.
* due to `ReadWriteBuffer` references. The instance will be unusable until it is assigned again
* to a `ReadWriteBuffer`.
*/
public inline fun <reified T: Table> reset(): T = reset(0, emptyBuffer)
public inline fun <reified T : Table> reset(): T = reset(0, emptyBuffer)
public companion object {
@@ -238,10 +241,10 @@ public open class Table {
/**
* Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
*
* This allocates a new string and converts to wide chars upon each access,
* which is not very efficient. Instead, each FlatBuffer string also comes with an
* accessor based on __vector_as_ReadWriteBuffer below, which is much more efficient,
* assuming your Java program can handle UTF-8 data directly.
* This allocates a new string and converts to wide chars upon each access, which is not very
* efficient. Instead, each FlatBuffer string also comes with an accessor based on
* __vector_as_ReadWriteBuffer below, which is much more efficient, assuming your Java program
* can handle UTF-8 data directly.
*
* @param offset An `int` index into the Table's ReadWriteBuffer.
* @param bb Table ReadWriteBuffer used to read a string at given offset.
@@ -268,8 +271,7 @@ public open class Table {
/**
* Check if a [ReadWriteBuffer] contains a file identifier.
*
* @param bb A `ReadWriteBuffer` to check if it contains the identifier
* `ident`.
* @param bb A `ReadWriteBuffer` to check if it contains the identifier `ident`.
* @param ident A `String` identifier of the FlatBuffer file.
* @return True if the buffer contains the file identifier
*/
@@ -330,14 +332,12 @@ public open class Table {
}
}
/**
* All structs in the generated code derive from this class, and add their own accessors.
*/
/** All structs in the generated code derive from this class, and add their own accessors. */
public open class Struct {
/** Used to hold the position of the `bb` buffer. */
/** Used to hold the position of the `bb` buffer. */
protected var bufferPos: Int = 0
/** The underlying ByteBuffer to hold the data of the Struct. */
/** The underlying ByteBuffer to hold the data of the Struct. */
protected var bb: ReadWriteBuffer = emptyBuffer
/**
@@ -346,7 +346,7 @@ public open class Struct {
* This method exists primarily to allow recycling Table instances without risking memory leaks
* due to `ByteBuffer` references.
*/
protected inline fun <reified T: Struct> reset(i: Int, reuseBuffer: ReadWriteBuffer): T {
protected inline fun <reified T : Struct> reset(i: Int, reuseBuffer: ReadWriteBuffer): T {
bb = reuseBuffer
bufferPos = if (bb != emptyBuffer) i else 0
return this as T
@@ -356,12 +356,13 @@ public open class Struct {
* Resets internal state with a null `ByteBuffer` and a zero position.
*
* This method exists primarily to allow recycling Struct instances without risking memory leaks
* due to `ByteBuffer` references. The instance will be unusable until it is assigned
* again to a `ByteBuffer`.
* due to `ByteBuffer` references. The instance will be unusable until it is assigned again to a
* `ByteBuffer`.
*/
private inline fun <reified T: Struct> reset(): T = reset(0, emptyBuffer)
private inline fun <reified T : Struct> reset(): T = reset(0, emptyBuffer)
}
public inline val <T> T.value: T get() = this
public inline val <T> T.value: T
get() = this
public const val VERSION_2_0_8: Int = 1

View File

@@ -15,13 +15,14 @@
*/
@file:Suppress("NOTHING_TO_INLINE")
@file:JvmName("FlexBuffers")
package com.google.flatbuffers.kotlin
import kotlin.jvm.JvmName
/**
* Reads a FlexBuffer message in ReadBuf and returns [Reference] to
* the root element.
* Reads a FlexBuffer message in ReadBuf and returns [Reference] to the root element.
*
* @param buffer ReadBuf containing FlexBuffer message
* @return [Reference] to the root object
*/
@@ -34,199 +35,231 @@ public fun getRoot(buffer: ReadBuffer): Reference {
}
/**
* Represents an generic element in the buffer. It can be specialized into scalar types, using for example,
* [Reference.toInt], or casted into Flexbuffer object types, like [Reference.toMap] or [Reference.toBlob].
* Represents an generic element in the buffer. It can be specialized into scalar types, using for
* example, [Reference.toInt], or casted into Flexbuffer object types, like [Reference.toMap] or
* [Reference.toBlob].
*/
@Suppress("NOTHING_TO_INLINE")
public class Reference internal constructor(
public class Reference
internal constructor(
internal val buffer: ReadBuffer,
internal val end: Int,
internal val parentWidth: ByteWidth,
internal val byteWidth: ByteWidth,
public val type: FlexBufferType
public val type: FlexBufferType,
) {
internal constructor(bb: ReadBuffer, end: Int, parentWidth: ByteWidth, packedType: Int) :
this(bb, end, parentWidth, ByteWidth(1 shl (packedType and 3)), FlexBufferType((packedType shr 2)))
internal constructor(
bb: ReadBuffer,
end: Int,
parentWidth: ByteWidth,
packedType: Int,
) : this(
bb,
end,
parentWidth,
ByteWidth(1 shl (packedType and 3)),
FlexBufferType((packedType shr 2)),
)
/**
* Checks whether the element is null type
*
* @return true if null type
*/
public val isNull: Boolean get() = type == T_NULL
public val isNull: Boolean
get() = type == T_NULL
/**
* Checks whether the element is boolean type
*
* @return true if boolean type
*/
public val isBoolean: Boolean get() = type == T_BOOL
public val isBoolean: Boolean
get() = type == T_BOOL
/**
* Checks whether the element type is numeric (signed/unsigned integers and floats)
*
* @return true if numeric type
*/
public val isNumeric: Boolean get() = isIntOrUInt || isFloat
public val isNumeric: Boolean
get() = isIntOrUInt || isFloat
/**
* Checks whether the element type is signed or unsigned integers
*
* @return true if an integer type
*/
public val isIntOrUInt: Boolean get() = isInt || isUInt
public val isIntOrUInt: Boolean
get() = isInt || isUInt
/**
* Checks whether the element type is float
*
* @return true if a float type
*/
public val isFloat: Boolean get() = type == T_FLOAT || type == T_INDIRECT_FLOAT
public val isFloat: Boolean
get() = type == T_FLOAT || type == T_INDIRECT_FLOAT
/**
* Checks whether the element type is signed integer
*
* @return true if a signed integer type
*/
public val isInt: Boolean get() = type == T_INT || type == T_INDIRECT_INT
public val isInt: Boolean
get() = type == T_INT || type == T_INDIRECT_INT
/**
* Checks whether the element type is signed integer
*
* @return true if a signed integer type
*/
public val isUInt: Boolean get() = type == T_UINT || type == T_INDIRECT_UINT
public val isUInt: Boolean
get() = type == T_UINT || type == T_INDIRECT_UINT
/**
* Checks whether the element type is string
*
* @return true if a string type
*/
public val isString: Boolean get() = type == T_STRING
public val isString: Boolean
get() = type == T_STRING
/**
* Checks whether the element type is key
*
* @return true if a key type
*/
public val isKey: Boolean get() = type == T_KEY
public val isKey: Boolean
get() = type == T_KEY
/**
* Checks whether the element type is vector or a map. [TypedVector] are considered different types and will return
* false.
* Checks whether the element type is vector or a map. [TypedVector] are considered different
* types and will return false.
*
* @return true if a vector type
*/
public val isVector: Boolean get() = type == T_VECTOR || type == T_MAP
public val isVector: Boolean
get() = type == T_VECTOR || type == T_MAP
/**
* Checks whether the element type is typed vector
*
* @return true if a typed vector type
*/
public val isTypedVector: Boolean get() = type.isTypedVector()
public val isTypedVector: Boolean
get() = type.isTypedVector()
/**
* Checks whether the element type is a map
*
* @return true if a map type
*/
public val isMap: Boolean get() = type == T_MAP
public val isMap: Boolean
get() = type == T_MAP
/**
* Checks whether the element type is a blob
*
* @return true if a blob type
*/
public val isBlob: Boolean get() = type == T_BLOB
public val isBlob: Boolean
get() = type == T_BLOB
/**
* Assumes [Reference] as a [Vector] and returns a [Reference] at index [index].
*/
/** Assumes [Reference] as a [Vector] and returns a [Reference] at index [index]. */
public operator fun get(index: Int): Reference = toVector()[index]
/**
* Assumes [Reference] as a [Map] and returns a [Reference] for the value at key [key].
*/
/** Assumes [Reference] as a [Map] and returns a [Reference] for the value at key [key]. */
public operator fun get(key: String): Reference = toMap()[key]
/**
* Returns element as a [Boolean].
* If element type is not boolean, it will be casted to integer and compared against 0
* Returns element as a [Boolean]. If element type is not boolean, it will be casted to integer
* and compared against 0
*
* @return element as [Boolean]
*/
public fun toBoolean(): Boolean = if (isBoolean) buffer.getBoolean(end) else toUInt() != 0u
/**
* Returns element as [Byte].
* For vector types, it will return size of the vector.
* For String type, it will be parsed as integer.
* Unsigned elements will become signed (with possible overflow).
* Float elements will be casted to [Byte].
* Returns element as [Byte]. For vector types, it will return size of the vector. For String
* type, it will be parsed as integer. Unsigned elements will become signed (with possible
* overflow). Float elements will be casted to [Byte].
*
* @return [Byte] or 0 if fail to convert element to integer.
*/
public fun toByte(): Byte = toULong().toByte()
/**
* Returns element as [Short].
* For vector types, it will return size of the vector.
* For String type, it will type to be parsed as integer.
* Unsigned elements will become signed (with possible overflow).
* Float elements will be casted to [Short]
* Returns element as [Short]. For vector types, it will return size of the vector. For String
* type, it will type to be parsed as integer. Unsigned elements will become signed (with possible
* overflow). Float elements will be casted to [Short]
*
* @return [Short] or 0 if fail to convert element to integer.
*/
public fun toShort(): Short = toULong().toShort()
/**
* Returns element as [Int].
* For vector types, it will return size of the vector.
* For String type, it will type to be parsed as integer.
* Unsigned elements will become signed (with possible overflow).
* Float elements will be casted to [Int]
* Returns element as [Int]. For vector types, it will return size of the vector. For String type,
* it will type to be parsed as integer. Unsigned elements will become signed (with possible
* overflow). Float elements will be casted to [Int]
*
* @return [Int] or 0 if fail to convert element to integer.
*/
public fun toInt(): Int = toULong().toInt()
/**
* Returns element as [Long].
* For vector types, it will return size of the vector
* For String type, it will type to be parsed as integer
* Unsigned elements will become negative
* Float elements will be casted to integer
* Returns element as [Long]. For vector types, it will return size of the vector For String type,
* it will type to be parsed as integer Unsigned elements will become negative Float elements will
* be casted to integer
*
* @return [Long] integer or 0 if fail to convert element to long.
*/
public fun toLong(): Long = toULong().toLong()
/**
* Returns element as [UByte].
* For vector types, it will return size of the vector.
* For String type, it will type to be parsed as integer.
* Negative elements will become unsigned counterpart.
* Float elements will be casted to [UByte]
* Returns element as [UByte]. For vector types, it will return size of the vector. For String
* type, it will type to be parsed as integer. Negative elements will become unsigned counterpart.
* Float elements will be casted to [UByte]
*
* @return [UByte] or 0 if fail to convert element to integer.
*/
public fun toUByte(): UByte = toULong().toUByte()
/**
* Returns element as [UShort].
* For vector types, it will return size of the vector.
* For String type, it will type to be parsed as integer.
* Negative elements will become unsigned counterpart.
* Float elements will be casted to [UShort]
* Returns element as [UShort]. For vector types, it will return size of the vector. For String
* type, it will type to be parsed as integer. Negative elements will become unsigned counterpart.
* Float elements will be casted to [UShort]
*
* @return [UShort] or 0 if fail to convert element to integer.
*/
public fun toUShort(): UShort = toULong().toUShort()
/**
* Returns element as [UInt].
* For vector types, it will return size of the vector.
* For String type, it will type to be parsed as integer.
* Negative elements will become unsigned counterpart.
* Float elements will be casted to [UInt]
* Returns element as [UInt]. For vector types, it will return size of the vector. For String
* type, it will type to be parsed as integer. Negative elements will become unsigned counterpart.
* Float elements will be casted to [UInt]
*
* @return [UInt] or 0 if fail to convert element to integer.
*/
public fun toUInt(): UInt = toULong().toUInt()
/**
* Returns element as [ULong] integer.
* For vector types, it will return size of the vector
* For String type, it will type to be parsed as integer
* Negative elements will become unsigned counterpart.
* Float elements will be casted to integer
* Returns element as [ULong] integer. For vector types, it will return size of the vector For
* String type, it will type to be parsed as integer Negative elements will become unsigned
* counterpart. Float elements will be casted to integer
*
* @return [ULong] integer or 0 if fail to convert element to long.
*/
public fun toULong(): ULong = resolve { pos: Int, width: ByteWidth ->
when (type) {
T_INDIRECT_INT, T_INDIRECT_UINT, T_INT, T_BOOL, T_UINT -> buffer.readULong(pos, width)
T_FLOAT, T_INDIRECT_FLOAT -> buffer.readFloat(pos, width).toULong()
T_INDIRECT_INT,
T_INDIRECT_UINT,
T_INT,
T_BOOL,
T_UINT -> buffer.readULong(pos, width)
T_FLOAT,
T_INDIRECT_FLOAT -> buffer.readFloat(pos, width).toULong()
T_STRING -> toString().toULong()
T_VECTOR -> toVector().size.toULong()
else -> 0UL
@@ -234,17 +267,18 @@ public class Reference internal constructor(
}
/**
* Returns element as [Float].
* For vector types, it will return size of the vector
* For String type, it will type to be parsed as [Float]
* Float elements will be casted to integer
* Returns element as [Float]. For vector types, it will return size of the vector For String
* type, it will type to be parsed as [Float] Float elements will be casted to integer
*
* @return [Float] integer or 0 if fail to convert element to long.
*/
public fun toFloat(): Float = resolve { pos: Int, width: ByteWidth ->
when (type) {
T_INDIRECT_FLOAT, T_FLOAT -> buffer.readFloat(pos, width).toFloat()
T_INDIRECT_FLOAT,
T_FLOAT -> buffer.readFloat(pos, width).toFloat()
T_INT -> buffer.readInt(end, parentWidth).toFloat()
T_UINT, T_BOOL -> buffer.readUInt(end, parentWidth).toFloat()
T_UINT,
T_BOOL -> buffer.readUInt(end, parentWidth).toFloat()
T_INDIRECT_INT -> buffer.readInt(pos, width).toFloat()
T_INDIRECT_UINT -> buffer.readUInt(pos, width).toFloat()
T_NULL -> 0.0f
@@ -255,16 +289,18 @@ public class Reference internal constructor(
}
/**
* Returns element as [Double].
* For vector types, it will return size of the vector
* For String type, it will type to be parsed as [Double]
* Returns element as [Double]. For vector types, it will return size of the vector For String
* type, it will type to be parsed as [Double]
*
* @return [Float] integer or 0 if fail to convert element to long.
*/
public fun toDouble(): Double = resolve { pos: Int, width: ByteWidth ->
when (type) {
T_INDIRECT_FLOAT, T_FLOAT -> buffer.readFloat(pos, width)
T_INDIRECT_FLOAT,
T_FLOAT -> buffer.readFloat(pos, width)
T_INT -> buffer.readInt(pos, width).toDouble()
T_UINT, T_BOOL -> buffer.readUInt(pos, width).toDouble()
T_UINT,
T_BOOL -> buffer.readUInt(pos, width).toDouble()
T_INDIRECT_INT -> buffer.readInt(pos, width).toDouble()
T_INDIRECT_UINT -> buffer.readUInt(pos, width).toDouble()
T_NULL -> 0.0
@@ -274,40 +310,48 @@ public class Reference internal constructor(
}
}
/**
* Returns element as [Key] or invalid key.
*/
public fun toKey(): Key = when (type) {
T_KEY -> Key(buffer, buffer.indirect(end, parentWidth))
else -> nullKey()
}
/** Returns element as [Key] or invalid key. */
public fun toKey(): Key =
when (type) {
T_KEY -> Key(buffer, buffer.indirect(end, parentWidth))
else -> nullKey()
}
/**
* Returns element as a [String]
*
* @return element as [String] or empty [String] if fail
*/
override fun toString(): String = when (type) {
T_STRING -> {
val start = buffer.indirect(end, parentWidth)
val size = buffer.readULong(start - byteWidth, byteWidth).toInt()
buffer.getString(start, size)
override fun toString(): String =
when (type) {
T_STRING -> {
val start = buffer.indirect(end, parentWidth)
val size = buffer.readULong(start - byteWidth, byteWidth).toInt()
buffer.getString(start, size)
}
T_KEY -> buffer.getKeyString(buffer.indirect(end, parentWidth))
T_MAP -> "{ ${toMap().entries.joinToString(", ") { "${it.key}: ${it.value}"}} }"
T_VECTOR,
T_VECTOR_BOOL,
T_VECTOR_FLOAT,
T_VECTOR_INT,
T_VECTOR_UINT,
T_VECTOR_KEY,
T_VECTOR_STRING_DEPRECATED -> "[ ${toVector().joinToString(", ") { it.toString() }} ]"
T_INT -> toLong().toString()
T_UINT -> toULong().toString()
T_FLOAT -> toDouble().toString()
else -> "${type.typeToString()}(end=$end)"
}
T_KEY -> buffer.getKeyString(buffer.indirect(end, parentWidth))
T_MAP -> "{ ${toMap().entries.joinToString(", ") { "${it.key}: ${it.value}"}} }"
T_VECTOR, T_VECTOR_BOOL, T_VECTOR_FLOAT, T_VECTOR_INT,
T_VECTOR_UINT, T_VECTOR_KEY, T_VECTOR_STRING_DEPRECATED ->
"[ ${toVector().joinToString(", ") { it.toString() }} ]"
T_INT -> toLong().toString()
T_UINT -> toULong().toString()
T_FLOAT -> toDouble().toString()
else -> "${type.typeToString()}(end=$end)"
}
/**
* Returns element as a [ByteArray], converting scalar types when possible.
*
* @return element as [ByteArray] or empty [ByteArray] if fail.
*/
public fun toByteArray(): ByteArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_INT -> ByteArray(vec.size) { vec.getInt(it).toByte() }
T_VECTOR_UINT -> ByteArray(vec.size) { vec.getUInt(it).toByte() }
@@ -319,10 +363,12 @@ public class Reference internal constructor(
/**
* Returns element as a [ByteArray], converting scalar types when possible.
*
* @return element as [ByteArray] or empty [ByteArray] if fail.
*/
public fun toShortArray(): ShortArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_INT -> ShortArray(vec.size) { vec.getInt(it).toShort() }
T_VECTOR_UINT -> ShortArray(vec.size) { vec.getUInt(it).toShort() }
@@ -334,10 +380,12 @@ public class Reference internal constructor(
/**
* Returns element as a [IntArray], converting scalar types when possible.
*
* @return element as [IntArray] or empty [IntArray] if fail.
*/
public fun toIntArray(): IntArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_INT -> IntArray(vec.size) { vec.getInt(it).toInt() }
T_VECTOR_UINT -> IntArray(vec.size) { vec.getUInt(it).toInt() }
@@ -349,10 +397,12 @@ public class Reference internal constructor(
/**
* Returns element as a [LongArray], converting scalar types when possible.
*
* @return element as [LongArray] or empty [LongArray] if fail.
*/
public fun toLongArray(): LongArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_INT -> LongArray(vec.size) { vec.getInt(it) }
T_VECTOR_UINT -> LongArray(vec.size) { vec.getInt(it) }
@@ -364,10 +414,12 @@ public class Reference internal constructor(
/**
* Returns element as a [UByteArray], converting scalar types when possible.
*
* @return element as [UByteArray] or empty [UByteArray] if fail.
*/
public fun toUByteArray(): UByteArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_INT -> UByteArray(vec.size) { vec.getInt(it).toUByte() }
T_VECTOR_UINT -> UByteArray(vec.size) { vec.getUInt(it).toUByte() }
@@ -379,10 +431,12 @@ public class Reference internal constructor(
/**
* Returns element as a [UIntArray], converting scalar types when possible.
*
* @return element as [UIntArray] or empty [UIntArray] if fail.
*/
public fun toUShortArray(): UShortArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_INT -> UShortArray(vec.size) { vec.getInt(it).toUShort() }
T_VECTOR_UINT -> UShortArray(vec.size) { vec.getUInt(it).toUShort() }
@@ -394,10 +448,12 @@ public class Reference internal constructor(
/**
* Returns element as a [UIntArray], converting scalar types when possible.
*
* @return element as [UIntArray] or empty [UIntArray] if fail.
*/
public fun toUIntArray(): UIntArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_INT -> UIntArray(vec.size) { vec.getInt(it).toUInt() }
T_VECTOR_UINT -> UIntArray(vec.size) { vec.getUInt(it).toUInt() }
@@ -409,10 +465,12 @@ public class Reference internal constructor(
/**
* Returns element as a [ULongArray], converting scalar types when possible.
*
* @return element as [ULongArray] or empty [ULongArray] if fail.
*/
public fun toULongArray(): ULongArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_INT -> ULongArray(vec.size) { vec.getUInt(it) }
T_VECTOR_UINT -> ULongArray(vec.size) { vec.getUInt(it) }
@@ -424,10 +482,12 @@ public class Reference internal constructor(
/**
* Returns element as a [FloatArray], converting scalar types when possible.
*
* @return element as [FloatArray] or empty [FloatArray] if fail.
*/
public fun toFloatArray(): FloatArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_FLOAT -> FloatArray(vec.size) { vec.getFloat(it).toFloat() }
T_VECTOR_INT -> FloatArray(vec.size) { vec.getInt(it).toFloat() }
@@ -439,10 +499,12 @@ public class Reference internal constructor(
/**
* Returns element as a [DoubleArray], converting scalar types when possible.
*
* @return element as [DoubleArray] or empty [DoubleArray] if fail.
*/
public fun toDoubleArray(): DoubleArray {
val vec = TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
val vec =
TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
return when (type) {
T_VECTOR_FLOAT -> DoubleArray(vec.size) { vec[it].toDouble() }
T_VECTOR_INT -> DoubleArray(vec.size) { vec[it].toDouble() }
@@ -454,35 +516,46 @@ public class Reference internal constructor(
/**
* Returns element as a [Vector]
*
* @return element as [Vector] or empty [Vector] if fail
*/
public fun toVector(): Vector {
return when {
isVector -> Vector(buffer, buffer.indirect(end, parentWidth), byteWidth)
isTypedVector -> TypedVector(type.toElementTypedVector(), buffer, buffer.indirect(end, parentWidth), byteWidth)
isTypedVector ->
TypedVector(
type.toElementTypedVector(),
buffer,
buffer.indirect(end, parentWidth),
byteWidth,
)
else -> emptyVector()
}
}
/**
* Returns element as a [Blob]
*
* @return element as [Blob] or empty [Blob] if fail
*/
public fun toBlob(): Blob {
return when (type) {
T_BLOB, T_STRING -> Blob(buffer, buffer.indirect(end, parentWidth), byteWidth)
T_BLOB,
T_STRING -> Blob(buffer, buffer.indirect(end, parentWidth), byteWidth)
else -> emptyBlob()
}
}
/**
* Returns element as a [Map].
*
* @return element as [Map] or empty [Map] if fail
*/
public fun toMap(): Map = when (type) {
T_MAP -> Map(buffer, buffer.indirect(end, parentWidth), byteWidth)
else -> emptyMap()
}
public fun toMap(): Map =
when (type) {
T_MAP -> Map(buffer, buffer.indirect(end, parentWidth), byteWidth)
else -> emptyMap()
}
private inline fun <T> resolve(crossinline block: (pos: Int, width: ByteWidth) -> T): T {
return if (type.isIndirectScalar()) {
@@ -496,12 +569,14 @@ public class Reference internal constructor(
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Reference
if (buffer != other.buffer ||
end != other.end ||
parentWidth != other.parentWidth ||
byteWidth != other.byteWidth ||
type != other.type
) return false
if (
buffer != other.buffer ||
end != other.end ||
parentWidth != other.parentWidth ||
byteWidth != other.byteWidth ||
type != other.type
)
return false
return true
}
@@ -518,30 +593,28 @@ public class Reference internal constructor(
/**
* Represents any element that has a size property to it, like: [Map], [Vector] and [TypedVector].
*/
public open class Sized internal constructor(
public open class Sized
internal constructor(
public val buffer: ReadBuffer,
public val end: Int,
public val byteWidth: ByteWidth
public val byteWidth: ByteWidth,
) {
public open val size: Int = buffer.readSize(end, byteWidth)
}
/**
* Represent an array of bytes in the buffer.
*/
public open class Blob internal constructor(
buffer: ReadBuffer,
end: Int,
byteWidth: ByteWidth
) : Sized(buffer, end, byteWidth) {
/** Represent an array of bytes in the buffer. */
public open class Blob internal constructor(buffer: ReadBuffer, end: Int, byteWidth: ByteWidth) :
Sized(buffer, end, byteWidth) {
/**
* Return [Blob] as [ReadBuffer]
*
* @return blob as [ReadBuffer]
*/
public fun data(): ReadBuffer = buffer.slice(end, size)
/**
* Copy [Blob] into a [ByteArray]
*
* @return A [ByteArray] containing the blob data.
*/
public fun toByteArray(): ByteArray {
@@ -554,6 +627,7 @@ public open class Blob internal constructor(
/**
* Return individual byte at a given position
*
* @param pos position of the byte to be read
*/
public operator fun get(pos: Int): Byte {
@@ -564,18 +638,13 @@ public open class Blob internal constructor(
override fun toString(): String = buffer.getString(end, size)
}
/**
* [Vector] represents an array of elements in the buffer. The element can be of any type.
*/
public open class Vector internal constructor(
buffer: ReadBuffer,
end: Int,
byteWidth: ByteWidth
) : Collection<Reference>,
Sized(buffer, end, byteWidth) {
/** [Vector] represents an array of elements in the buffer. The element can be of any type. */
public open class Vector internal constructor(buffer: ReadBuffer, end: Int, byteWidth: ByteWidth) :
Collection<Reference>, Sized(buffer, end, byteWidth) {
/**
* Returns a [Reference] from the [Vector] at position [index]. Returns a null reference
*
* @param index position in the vector.
* @return [Reference] for a key or a null [Reference] if not found.
*/
@@ -597,25 +666,27 @@ public open class Vector internal constructor(
override fun isEmpty(): Boolean = size == 0
override fun iterator(): Iterator<Reference> = object : Iterator<Reference> {
var position = 0
override fun hasNext(): Boolean = position != size
override fun next(): Reference = get(position++)
}
override fun iterator(): Iterator<Reference> =
object : Iterator<Reference> {
var position = 0
override fun hasNext(): Boolean = position != size
override fun next(): Reference = get(position++)
}
}
/**
* [TypedVector] represents an array of scalar elements of the same type in the buffer.
*/
/** [TypedVector] represents an array of scalar elements of the same type in the buffer. */
public open class TypedVector(
private val elementType: FlexBufferType,
buffer: ReadBuffer,
end: Int,
byteWidth: ByteWidth
byteWidth: ByteWidth,
) : Vector(buffer, end, byteWidth) {
/**
* Returns a [Reference] from the [TypedVector] at position [index]. Returns a null reference
*
* @param index position in the vector.
* @return [Reference] for a key or a null [Reference] if not found.
*/
@@ -630,28 +701,24 @@ public open class TypedVector(
return block(childPos, byteWidth)
}
internal fun getBoolean(index: Int): Boolean = resolveAt(index) {
pos: Int, _: ByteWidth -> buffer.getBoolean(pos)
}
internal fun getInt(index: Int): Long = resolveAt(index) {
pos: Int, width: ByteWidth -> buffer.readLong(pos, width)
}
internal fun getUInt(index: Int): ULong = resolveAt(index) {
pos: Int, width: ByteWidth -> buffer.readULong(pos, width)
}
internal fun getFloat(index: Int): Double = resolveAt(index) {
pos: Int, width: ByteWidth -> buffer.readFloat(pos, width)
}
internal fun getBoolean(index: Int): Boolean =
resolveAt(index) { pos: Int, _: ByteWidth -> buffer.getBoolean(pos) }
internal fun getInt(index: Int): Long =
resolveAt(index) { pos: Int, width: ByteWidth -> buffer.readLong(pos, width) }
internal fun getUInt(index: Int): ULong =
resolveAt(index) { pos: Int, width: ByteWidth -> buffer.readULong(pos, width) }
internal fun getFloat(index: Int): Double =
resolveAt(index) { pos: Int, width: ByteWidth -> buffer.readFloat(pos, width) }
}
/**
* Represents a key element in the buffer. Keys are
* used to reference objects in a [Map]
*/
/** Represents a key element in the buffer. Keys are used to reference objects in a [Map] */
public data class Key(
public val buffer: ReadBuffer,
public val start: Int,
public val end: Int = buffer.findFirst(ZeroByte, start)
public val end: Int = buffer.findFirst(ZeroByte, start),
) {
val sizeInBytes: Int = end - start
@@ -704,25 +771,21 @@ public data class Key(
}
}
override fun toString(): String = if (sizeInBytes > 0) buffer.getString(start, sizeInBytes) else ""
override fun toString(): String =
if (sizeInBytes > 0) buffer.getString(start, sizeInBytes) else ""
/**
* Checks whether Key is invalid or not.
*/
/** Checks whether Key is invalid or not. */
public fun isInvalid(): Boolean = sizeInBytes <= 0
}
/**
* A Map class that provide support to access Key-Value data from Flexbuffers.
*/
public class Map
internal constructor(buffer: ReadBuffer, end: Int, byteWidth: ByteWidth):
Sized(buffer, end, byteWidth),
kotlin.collections.Map<Key, Reference> {
/** A Map class that provide support to access Key-Value data from Flexbuffers. */
public class Map internal constructor(buffer: ReadBuffer, end: Int, byteWidth: ByteWidth) :
Sized(buffer, end, byteWidth), kotlin.collections.Map<Key, Reference> {
// used for accessing the key vector elements
private var keyVectorEnd: Int
private var keyVectorByteWidth: ByteWidth
init {
val keysOffset = end - (3 * byteWidth) // 3 is number of prefixed fields
keyVectorEnd = buffer.indirect(keysOffset, byteWidth)
@@ -731,6 +794,7 @@ public class Map
/**
* Returns a [Reference] from the [Map] at position [index]. Returns a null reference
*
* @param index position in the map
* @return [Reference] for a key or a null [Reference] if not found.
*/
@@ -744,6 +808,7 @@ public class Map
/**
* Returns a [Reference] from the [Map] for a given [String] [key].
*
* @param key access key to element on map
* @return [Reference] for a key or a null [Reference] if not found.
*/
@@ -756,6 +821,7 @@ public class Map
/**
* Returns a [Reference] from the [Map] for a given [Key] [key].
*
* @param key access key to element on map
* @return [Reference] for a key or a null [Reference] if not found.
*/
@@ -768,6 +834,7 @@ public class Map
/**
* Checks whether the map contains a [key].
*
* @param key [String]
* @return true if key is found in the map, otherwise false.
*/
@@ -775,6 +842,7 @@ public class Map
/**
* Returns a [Key] for a given position [index] in the [Map].
*
* @param index of the key in the map
* @return a Key for the given index. Out of bounds indexes returns invalid keys.
*/
@@ -785,6 +853,7 @@ public class Map
/**
* Returns a [Key] as [String] for a given position [index] in the [Map].
*
* @param index of the key in the map
* @return a Key for the given index. Out of bounds indexes returns empty string.
*/
@@ -815,6 +884,7 @@ public class Map
/**
* Returns a [Vector] for accessing all values in the [Map].
*
* @return [Vector] of values.
*/
override val values: Collection<Reference>
@@ -822,8 +892,7 @@ public class Map
override fun containsKey(key: Key): Boolean {
for (i in 0 until size) {
if (key == keyAt(i))
return true
if (key == keyAt(i)) return true
}
return false
}
@@ -833,7 +902,10 @@ public class Map
override fun isEmpty(): Boolean = size == 0
// Performs a binary search on a key vector and return index of the key in key vector
private fun binarySearch(searchedKey: String) = binarySearch { compareCharSequence(it, searchedKey) }
private fun binarySearch(searchedKey: String) = binarySearch {
compareCharSequence(it, searchedKey)
}
// Performs a binary search on a key vector and return index of the key in key vector
private fun binarySearch(key: Key): Int = binarySearch { compareKeys(it, key.start) }
@@ -891,8 +963,7 @@ public class Map
++bufferPos
++otherPos
}
if (bufferPos < limit)
return 0
if (bufferPos < limit) return 0
val comparisonBuffer = ByteArray(4)
while (bufferPos < limit) {

View File

@@ -20,11 +20,13 @@ package com.google.flatbuffers.kotlin
@ExperimentalUnsignedTypes
public class FlexBuffersBuilder(
public val buffer: ReadWriteBuffer,
private val shareFlag: Int = SHARE_KEYS
private val shareFlag: Int = SHARE_KEYS,
) {
public constructor(initialCapacity: Int = 1024, shareFlag: Int = SHARE_KEYS) :
this(ArrayReadWriteBuffer(initialCapacity), shareFlag)
public constructor(
initialCapacity: Int = 1024,
shareFlag: Int = SHARE_KEYS,
) : this(ArrayReadWriteBuffer(initialCapacity), shareFlag)
private val stringValuePool: HashMap<String, Value> = HashMap()
private val stringKeyPool: HashMap<String, Int> = HashMap()
@@ -32,8 +34,8 @@ public class FlexBuffersBuilder(
private var finished: Boolean = false
/**
* Reset the FlexBuffersBuilder by purging all data that it holds. Buffer might
* keep its capacity after a reset.
* Reset the FlexBuffersBuilder by purging all data that it holds. Buffer might keep its capacity
* after a reset.
*/
public fun clear() {
buffer.clear()
@@ -44,9 +46,9 @@ public class FlexBuffersBuilder(
}
/**
* Finish writing the message into the buffer. After that no other element must
* be inserted into the buffer. Also, you must call this function before start using the
* FlexBuffer message
* Finish writing the message into the buffer. After that no other element must be inserted into
* the buffer. Also, you must call this function before start using the FlexBuffer message
*
* @return [ReadBuffer] containing the FlexBuffer message
*/
public fun finish(): ReadBuffer {
@@ -69,45 +71,46 @@ public class FlexBuffersBuilder(
/**
* Insert a single [Boolean] into the buffer
*
* @param value true or false
*/
public fun put(value: Boolean): Unit = run { this[null] = value }
/**
* Insert a null reference into the buffer. A key must be present if element is inserted into a map.
* Insert a null reference into the buffer. A key must be present if element is inserted into a
* map.
*/
public fun putNull(key: String? = null): Unit =
run { stack.add(Value(T_NULL, putKey(key), W_8, 0UL)) }
public fun putNull(key: String? = null): Unit = run {
stack.add(Value(T_NULL, putKey(key), W_8, 0UL))
}
/**
* Insert a single [Boolean] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [Boolean] into the buffer. A key must be present if element is inserted into a
* map.
*/
public operator fun set(key: String? = null, value: Boolean): Unit =
run { stack.add(Value(T_BOOL, putKey(key), W_8, if (value) 1UL else 0UL)) }
public operator fun set(key: String? = null, value: Boolean): Unit = run {
stack.add(Value(T_BOOL, putKey(key), W_8, if (value) 1UL else 0UL))
}
/**
* Insert a single [Byte] into the buffer
*/
/** Insert a single [Byte] into the buffer */
public fun put(value: Byte): Unit = set(null, value.toLong())
/**
* Insert a single [Byte] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [Byte] into the buffer. A key must be present if element is inserted into a
* map.
*/
public operator fun set(key: String? = null, value: Byte): Unit = set(key, value.toLong())
/**
* Insert a single [Short] into the buffer.
*/
/** Insert a single [Short] into the buffer. */
public fun put(value: Short): Unit = set(null, value.toLong())
/**
* Insert a single [Short] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [Short] into the buffer. A key must be present if element is inserted into a
* map.
*/
public inline operator fun set(key: String? = null, value: Short): Unit = set(key, value.toLong())
/**
* Insert a single [Int] into the buffer.
*/
/** Insert a single [Int] into the buffer. */
public fun put(value: Int): Unit = set(null, value.toLong())
/**
@@ -115,110 +118,113 @@ public class FlexBuffersBuilder(
*/
public inline operator fun set(key: String? = null, value: Int): Unit = set(key, value.toLong())
/**
* Insert a single [Long] into the buffer.
*/
/** Insert a single [Long] into the buffer. */
public fun put(value: Long): Unit = set(null, value)
/**
* Insert a single [Long] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [Long] into the buffer. A key must be present if element is inserted into a
* map.
*/
public operator fun set(key: String? = null, value: Long): Unit =
run { stack.add(Value(T_INT, putKey(key), value.toULong().widthInUBits(), value.toULong())) }
public operator fun set(key: String? = null, value: Long): Unit = run {
stack.add(Value(T_INT, putKey(key), value.toULong().widthInUBits(), value.toULong()))
}
/**
* Insert a single [UByte] into the buffer
*/
/** Insert a single [UByte] into the buffer */
public fun put(value: UByte): Unit = set(null, value.toULong())
/**
* Insert a single [UByte] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [UByte] into the buffer. A key must be present if element is inserted into a
* map.
*/
public inline operator fun set(key: String? = null, value: UByte): Unit = set(key, value.toULong())
public inline operator fun set(key: String? = null, value: UByte): Unit =
set(key, value.toULong())
/**
* Insert a single [UShort] into the buffer.
*/
/** Insert a single [UShort] into the buffer. */
public fun put(value: UShort): Unit = set(null, value.toULong())
/**
* Insert a single [UShort] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [UShort] into the buffer. A key must be present if element is inserted into a
* map.
*/
private inline operator fun set(key: String? = null, value: UShort): Unit = set(key, value.toULong())
private inline operator fun set(key: String? = null, value: UShort): Unit =
set(key, value.toULong())
/**
* Insert a single [UInt] into the buffer.
*/
/** Insert a single [UInt] into the buffer. */
public fun put(value: UInt): Unit = set(null, value.toULong())
/**
* Insert a single [UInt] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [UInt] into the buffer. A key must be present if element is inserted into a
* map.
*/
private inline operator fun set(key: String? = null, value: UInt): Unit = set(key, value.toULong())
private inline operator fun set(key: String? = null, value: UInt): Unit =
set(key, value.toULong())
/**
* Insert a single [ULong] into the buffer.
*/
/** Insert a single [ULong] into the buffer. */
public fun put(value: ULong): Unit = set(null, value)
/**
* Insert a single [ULong] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [ULong] into the buffer. A key must be present if element is inserted into a
* map.
*/
public operator fun set(key: String? = null, value: ULong): Unit =
run { stack.add(Value(T_UINT, putKey(key), value.widthInUBits(), value)) }
public operator fun set(key: String? = null, value: ULong): Unit = run {
stack.add(Value(T_UINT, putKey(key), value.widthInUBits(), value))
}
/**
* Insert a single [Float] into the buffer.
*/
/** Insert a single [Float] into the buffer. */
public fun put(value: Float): Unit = run { this[null] = value }
/**
* Insert a single [Float] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [Float] into the buffer. A key must be present if element is inserted into a
* map.
*/
public operator fun set(key: String? = null, value: Float): Unit =
run { stack.add(Value(T_FLOAT, putKey(key), W_32, dValue = value.toDouble())) }
public operator fun set(key: String? = null, value: Float): Unit = run {
stack.add(Value(T_FLOAT, putKey(key), W_32, dValue = value.toDouble()))
}
/**
* Insert a single [Double] into the buffer.
*/
/** Insert a single [Double] into the buffer. */
public fun put(value: Double): Unit = run { this[null] = value }
/**
* Insert a single [Double] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [Double] into the buffer. A key must be present if element is inserted into a
* map.
*/
public operator fun set(key: String? = null, value: Double): Unit =
run { stack.add(Value(T_FLOAT, putKey(key), W_64, dValue = value)) }
public operator fun set(key: String? = null, value: Double): Unit = run {
stack.add(Value(T_FLOAT, putKey(key), W_64, dValue = value))
}
/**
* Insert a single [String] into the buffer.
*/
/** Insert a single [String] into the buffer. */
public fun put(value: String): Int = set(null, value)
/**
* Insert a single [String] into the buffer. A key must be present if element is inserted into a map.
* Insert a single [String] into the buffer. A key must be present if element is inserted into a
* map.
*/
public operator fun set(key: String? = null, value: String): Int {
val iKey = putKey(key)
val holder = if (shareFlag and SHARE_STRINGS != 0) {
stringValuePool.getOrPut(value) {
writeString(iKey, value).also { stringValuePool[value] = it }
}.copy(key = iKey)
} else {
writeString(iKey, value)
}
val holder =
if (shareFlag and SHARE_STRINGS != 0) {
stringValuePool
.getOrPut(value) { writeString(iKey, value).also { stringValuePool[value] = it } }
.copy(key = iKey)
} else {
writeString(iKey, value)
}
stack.add(holder)
return holder.iValue.toInt()
}
/**
* Adds a [ByteArray] into the message as a [Blob].
*
* @param value byte array
* @return position in buffer as the start of byte array
*/
public fun put(value: ByteArray): Int = set(null, value)
/**
* Adds a [ByteArray] into the message as a [Blob]. A key must be present if element is inserted into a map.
* Adds a [ByteArray] into the message as a [Blob]. A key must be present if element is inserted
* into a map.
*
* @param value byte array
* @return position in buffer as the start of byte array
*/
@@ -230,14 +236,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [IntArray] into the message as a typed vector of fixed size.
*
* @param value [IntArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: IntArray): Int = set(null, value)
/**
* Adds a [IntArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [IntArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [IntArray]
* @return position in buffer as the start of byte array
*/
@@ -246,14 +254,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [ShortArray] into the message as a typed vector of fixed size.
*
* @param value [ShortArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: ShortArray): Int = set(null, value)
/**
* Adds a [ShortArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [ShortArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [ShortArray]
* @return position in buffer as the start of byte array
*/
@@ -262,14 +272,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [LongArray] into the message as a typed vector of fixed size.
*
* @param value [LongArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: LongArray): Int = set(null, value)
/**
* Adds a [LongArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [LongArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [LongArray]
* @return position in buffer as the start of byte array
*/
@@ -278,14 +290,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [FloatArray] into the message as a typed vector of fixed size.
*
* @param value [FloatArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: FloatArray): Int = set(null, value)
/**
* Adds a [FloatArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [FloatArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [FloatArray]
* @return position in buffer as the start of byte array
*/
@@ -294,14 +308,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [DoubleArray] into the message as a typed vector of fixed size.
*
* @param value [DoubleArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: DoubleArray): Int = set(null, value)
/**
* Adds a [DoubleArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [DoubleArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [DoubleArray]
* @return position in buffer as the start of byte array
*/
@@ -310,14 +326,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [UByteArray] into the message as a typed vector of fixed size.
*
* @param value [UByteArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: UByteArray): Int = set(null, value)
/**
* Adds a [UByteArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [UByteArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [UByteArray]
* @return position in buffer as the start of byte array
*/
@@ -326,14 +344,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [UShortArray] into the message as a typed vector of fixed size.
*
* @param value [UShortArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: UShortArray): Int = set(null, value)
/**
* Adds a [UShortArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [UShortArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [UShortArray]
* @return position in buffer as the start of byte array
*/
@@ -342,14 +362,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [UIntArray] into the message as a typed vector of fixed size.
*
* @param value [UIntArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: UIntArray): Int = set(null, value)
/**
* Adds a [UIntArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [UIntArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [UIntArray]
* @return position in buffer as the start of byte array
*/
@@ -358,14 +380,16 @@ public class FlexBuffersBuilder(
/**
* Adds a [ULongArray] into the message as a typed vector of fixed size.
*
* @param value [ULongArray]
* @return position in buffer as the start of byte array
*/
public fun put(value: ULongArray): Int = set(null, value)
/**
* Adds a [ULongArray] into the message as a typed vector of fixed size.
* A key must be present if element is inserted into a map.
* Adds a [ULongArray] into the message as a typed vector of fixed size. A key must be present if
* element is inserted into a map.
*
* @param value [ULongArray]
* @return position in buffer as the start of byte array
*/
@@ -374,6 +398,7 @@ public class FlexBuffersBuilder(
/**
* Creates a new vector will all elements inserted in [block].
*
* @param block where elements will be inserted
* @return position in buffer as the start of byte array
*/
@@ -385,6 +410,7 @@ public class FlexBuffersBuilder(
/**
* Creates a new typed vector will all elements inserted in [block].
*
* @param block where elements will be inserted
* @return position in buffer as the start of byte array
*/
@@ -394,40 +420,44 @@ public class FlexBuffersBuilder(
return endTypedVector(pos)
}
/**
* Helper function to return position for starting a new vector.
*/
/** Helper function to return position for starting a new vector. */
public fun startVector(): Int = stack.size
/**
* Finishes a vector element. The initial position of the vector must be passed
*
* @param position position at the start of the vector
*/
public fun endVector(position: Int): Int = endVector(null, position)
/**
* Finishes a vector element. The initial position of the vector must be passed
*
* @param position position at the start of the vector
*/
public fun endVector(key: String? = null, position: Int): Int =
endAnyVector(position) { createVector(putKey(key), position, stack.size - position) }
/**
* Finishes a typed vector element. The initial position of the vector must be passed
*
* @param position position at the start of the vector
*/
public fun endTypedVector(position: Int): Int = endTypedVector(position, null)
/**
* Helper function to return position for starting a new vector.
*/
/** Helper function to return position for starting a new vector. */
public fun startMap(): Int = stack.size
/**
* Creates a new map will all elements inserted in [block].
*
* @param block where elements will be inserted
* @return position in buffer as the start of byte array
*/
public inline fun putMap(key: String? = null, crossinline block: FlexBuffersBuilder.() -> Unit): Int {
public inline fun putMap(
key: String? = null,
crossinline block: FlexBuffersBuilder.() -> Unit,
): Int {
val pos = startMap()
this.block()
return endMap(pos, key)
@@ -435,7 +465,8 @@ public class FlexBuffersBuilder(
/**
* Finishes a map, but writing the information in the buffer
* @param key key used to store element in map
*
* @param key key used to store element in map
* @return Reference to the map
*/
public fun endMap(start: Int, key: String? = null): Int {
@@ -456,7 +487,7 @@ public class FlexBuffersBuilder(
length: Int,
vecType: FlexBufferType,
bitWidth: BitWidth,
crossinline writeBlock: (ByteWidth) -> Unit
crossinline writeBlock: (ByteWidth) -> Unit,
): Int {
val keyPos = putKey(key)
val byteWidth = align(bitWidth)
@@ -471,7 +502,10 @@ public class FlexBuffersBuilder(
return vloc
}
private inline fun setTypedVec(key: String? = null, crossinline block: FlexBuffersBuilder.() -> Unit): Int {
private inline fun setTypedVec(
key: String? = null,
crossinline block: FlexBuffersBuilder.() -> Unit,
): Int {
val pos = startVector()
this.block()
return endTypedVector(pos, key)
@@ -511,11 +545,15 @@ public class FlexBuffersBuilder(
}
}
private fun writeAny(toWrite: Value, byteWidth: ByteWidth) = when (toWrite.type) {
T_NULL, T_BOOL, T_INT, T_UINT -> writeInt(toWrite.iValue, byteWidth)
T_FLOAT -> writeDouble(toWrite.dValue, byteWidth)
else -> writeOffset(toWrite.iValue.toInt(), byteWidth)
}
private fun writeAny(toWrite: Value, byteWidth: ByteWidth) =
when (toWrite.type) {
T_NULL,
T_BOOL,
T_INT,
T_UINT -> writeInt(toWrite.iValue, byteWidth)
T_FLOAT -> writeDouble(toWrite.dValue, byteWidth)
else -> writeOffset(toWrite.iValue.toInt(), byteWidth)
}
private fun writeString(key: Int, s: String): Value {
val encodedSize = Utf8.encodedLength(s)
@@ -526,8 +564,7 @@ public class FlexBuffersBuilder(
buffer.requestAdditionalCapacity(encodedSize + 1)
val sloc: Int = buffer.writePosition
if (encodedSize > 0)
buffer.put(s, encodedSize)
if (encodedSize > 0) buffer.put(s, encodedSize)
buffer.put(ZeroByte)
return Value(T_STRING, key, bitWidth, sloc.toULong())
}
@@ -544,11 +581,17 @@ public class FlexBuffersBuilder(
private fun writeOffset(toWrite: Int, byteWidth: ByteWidth) {
buffer.requestAdditionalCapacity(byteWidth.value)
val relativeOffset = (buffer.writePosition - toWrite)
if (byteWidth.value != 8 && relativeOffset >= 1L shl byteWidth.value * 8) error("invalid offset $relativeOffset, writer pos ${buffer.writePosition}")
if (byteWidth.value != 8 && relativeOffset >= 1L shl byteWidth.value * 8)
error("invalid offset $relativeOffset, writer pos ${buffer.writePosition}")
writeInt(relativeOffset, byteWidth)
}
private inline fun writeBlob(key: Int, blob: ByteArray, type: FlexBufferType, trailing: Boolean): Value {
private inline fun writeBlob(
key: Int,
blob: ByteArray,
type: FlexBufferType,
trailing: Boolean,
): Value {
val bitWidth = blob.size.toULong().widthInUBits()
val byteWidth = align(bitWidth)
@@ -586,22 +629,26 @@ public class FlexBuffersBuilder(
start: Int,
size: Int,
byteWidth: ByteWidth,
crossinline valueBlock: (Int) -> ULong
crossinline valueBlock: (Int) -> ULong,
) {
buffer.requestAdditionalCapacity(size * byteWidth.value)
return when (byteWidth.value) {
1 -> for (i in start until start + size) {
buffer.put(valueBlock(i).toUByte())
}
2 -> for (i in start until start + size) {
buffer.put(valueBlock(i).toUShort())
}
4 -> for (i in start until start + size) {
buffer.put(valueBlock(i).toUInt())
}
8 -> for (i in start until start + size) {
buffer.put(valueBlock(i))
}
1 ->
for (i in start until start + size) {
buffer.put(valueBlock(i).toUByte())
}
2 ->
for (i in start until start + size) {
buffer.put(valueBlock(i).toUShort())
}
4 ->
for (i in start until start + size) {
buffer.put(valueBlock(i).toUInt())
}
8 ->
for (i in start until start + size) {
buffer.put(valueBlock(i))
}
else -> Unit
}
}
@@ -619,7 +666,7 @@ public class FlexBuffersBuilder(
private fun writeInt(value: ULong, byteWidth: ByteWidth) {
buffer.requestAdditionalCapacity(byteWidth.value)
when(byteWidth.value) {
when (byteWidth.value) {
1 -> buffer.put(value.toUByte())
2 -> buffer.put(value.toUShort())
4 -> buffer.put(value.toUInt())
@@ -646,7 +693,8 @@ public class FlexBuffersBuilder(
val prefixElems = 1
// Check bit widths and types for all elements.
for (i in start until stack.size) {
val elemWidth = elemWidth(T_KEY, W_8, stack[i].key.toLong(), buffer.writePosition, i + prefixElems)
val elemWidth =
elemWidth(T_KEY, W_8, stack[i].key.toLong(), buffer.writePosition, i + prefixElems)
width = width.max(elemWidth)
}
return width
@@ -689,13 +737,20 @@ public class FlexBuffersBuilder(
}
}
private inline fun createTypedVector(key: Int, start: Int, length: Int, keys: Value? = null): Value {
private inline fun createTypedVector(
key: Int,
start: Int,
length: Int,
keys: Value? = null,
): Value {
// We assume the callers of this method guarantees all elements are of the same type.
val elementType: FlexBufferType = stack[start].type
for (i in start + 1 until length) {
if (elementType != stack[i].type) error("TypedVector does not support array of different element types")
if (elementType != stack[i].type)
error("TypedVector does not support array of different element types")
}
if (!elementType.isTypedVectorElementType()) error("TypedVector does not support this element type")
if (!elementType.isTypedVectorElementType())
error("TypedVector does not support this element type")
return createAnyVector(key, start, length, elementType.toTypedVector(), keys)
}
@@ -705,7 +760,7 @@ public class FlexBuffersBuilder(
length: Int,
type: FlexBufferType,
keys: Value? = null,
crossinline typeBlock: (BitWidth) -> Unit = {}
crossinline typeBlock: (BitWidth) -> Unit = {},
): Value {
// Figure out the smallest bit width we can store this vector with.
var bitWidth = W_8.max(length.toULong().widthInUBits())
@@ -742,45 +797,43 @@ public class FlexBuffersBuilder(
}
// A lambda to sort map keys
internal val keyComparator = object : Comparator<Value> {
override fun compare(a: Value, b: Value): Int {
var ia: Int = a.key
var io: Int = b.key
var c1: Byte
var c2: Byte
do {
c1 = buffer[ia]
c2 = buffer[io]
if (c1.toInt() == 0) return c1 - c2
ia++
io++
} while (c1 == c2)
return c1 - c2
internal val keyComparator =
object : Comparator<Value> {
override fun compare(a: Value, b: Value): Int {
var ia: Int = a.key
var io: Int = b.key
var c1: Byte
var c2: Byte
do {
c1 = buffer[ia]
c2 = buffer[io]
if (c1.toInt() == 0) return c1 - c2
ia++
io++
} while (c1 == c2)
return c1 - c2
}
}
}
public companion object {
/**
* No keys or strings will be shared
*/
/** No keys or strings will be shared */
public const val SHARE_NONE: Int = 0
/**
* Keys will be shared between elements. Identical keys will only be serialized once, thus possibly saving space.
* But serialization performance might be slower and consumes more memory.
* Keys will be shared between elements. Identical keys will only be serialized once, thus
* possibly saving space. But serialization performance might be slower and consumes more
* memory.
*/
public const val SHARE_KEYS: Int = 1
/**
* Strings will be shared between elements. Identical strings will only be serialized once, thus possibly saving space.
* But serialization performance might be slower and consumes more memory. This is ideal if you expect many repeated
* strings on the message.
* Strings will be shared between elements. Identical strings will only be serialized once, thus
* possibly saving space. But serialization performance might be slower and consumes more
* memory. This is ideal if you expect many repeated strings on the message.
*/
public const val SHARE_STRINGS: Int = 2
/**
* Strings and keys will be shared between elements.
*/
/** Strings and keys will be shared between elements. */
public const val SHARE_KEYS_AND_STRINGS: Int = 3
}
}

View File

@@ -24,19 +24,25 @@ public value class BitWidth(public val value: Int) {
public inline fun max(other: BitWidth): BitWidth = if (this.value >= other.value) this else other
}
@JvmInline
public value class ByteWidth(public val value: Int)
@JvmInline public value class ByteWidth(public val value: Int)
@JvmInline
public value class FlexBufferType(public val value: Int) {
public operator fun minus(other: FlexBufferType): FlexBufferType = FlexBufferType(this.value - other.value)
public operator fun plus(other: FlexBufferType): FlexBufferType = FlexBufferType(this.value + other.value)
public operator fun minus(other: FlexBufferType): FlexBufferType =
FlexBufferType(this.value - other.value)
public operator fun plus(other: FlexBufferType): FlexBufferType =
FlexBufferType(this.value + other.value)
public operator fun compareTo(other: FlexBufferType): Int = this.value - other.value
}
internal operator fun Int.times(width: ByteWidth): Int = this * width.value
internal operator fun Int.minus(width: ByteWidth): Int = this - width.value
internal operator fun Int.plus(width: ByteWidth): Int = this + width.value
internal operator fun Int.minus(type: FlexBufferType): Int = this - type.value
// Returns a Key string from the buffer starting at index [start]. Key Strings are stored as
@@ -61,23 +67,42 @@ internal inline fun ReadBuffer.readFloat(end: Int, byteWidth: ByteWidth): Double
return when (byteWidth.value) {
4 -> this.getFloat(end).toDouble()
8 -> this.getDouble(end)
else -> error("invalid byte width $byteWidth for floating point scalar") // we should never reach here
else ->
error("invalid byte width $byteWidth for floating point scalar") // we should never reach here
}
}
// return position on the [ReadBuffer] of the element that the offset is pointing to
// we assume all offset fits on a int, since ReadBuffer operates with that assumption
internal inline fun ReadBuffer.indirect(offset: Int, byteWidth: ByteWidth): Int = offset - readInt(offset, byteWidth)
internal inline fun ReadBuffer.indirect(offset: Int, byteWidth: ByteWidth): Int =
offset - readInt(offset, byteWidth)
// returns the size of an array-like element from [ReadBuffer].
internal inline fun ReadBuffer.readSize(end: Int, byteWidth: ByteWidth) = readInt(end - byteWidth, byteWidth)
internal inline fun ReadBuffer.readUInt(end: Int, byteWidth: ByteWidth): UInt = readULong(end, byteWidth).toUInt()
internal inline fun ReadBuffer.readInt(end: Int, byteWidth: ByteWidth): Int = readULong(end, byteWidth).toInt()
internal inline fun ReadBuffer.readLong(end: Int, byteWidth: ByteWidth): Long = readULong(end, byteWidth).toLong()
internal inline fun ReadBuffer.readSize(end: Int, byteWidth: ByteWidth) =
readInt(end - byteWidth, byteWidth)
internal fun IntArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
internal fun ShortArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
internal fun LongArray.widthInUBits(): BitWidth = arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
internal inline fun ReadBuffer.readUInt(end: Int, byteWidth: ByteWidth): UInt =
readULong(end, byteWidth).toUInt()
private inline fun arrayWidthInUBits(size: Int, crossinline elemWidthBlock: (Int) -> BitWidth): BitWidth {
internal inline fun ReadBuffer.readInt(end: Int, byteWidth: ByteWidth): Int =
readULong(end, byteWidth).toInt()
internal inline fun ReadBuffer.readLong(end: Int, byteWidth: ByteWidth): Long =
readULong(end, byteWidth).toLong()
internal fun IntArray.widthInUBits(): BitWidth =
arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
internal fun ShortArray.widthInUBits(): BitWidth =
arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
internal fun LongArray.widthInUBits(): BitWidth =
arrayWidthInUBits(this.size) { this[it].toULong().widthInUBits() }
private inline fun arrayWidthInUBits(
size: Int,
crossinline elemWidthBlock: (Int) -> BitWidth,
): BitWidth {
// Figure out smallest bit width we can store this vector with.
var bitWidth = W_8.max(size.toULong().widthInUBits())
// Check bit widths and types for all elements.
@@ -88,27 +113,37 @@ private inline fun arrayWidthInUBits(size: Int, crossinline elemWidthBlock: (Int
return bitWidth
}
internal fun ULong.widthInUBits(): BitWidth = when {
this <= MAX_UBYTE_ULONG -> W_8
this <= UShort.MAX_VALUE -> W_16
this <= UInt.MAX_VALUE -> W_32
else -> W_64
}
internal fun ULong.widthInUBits(): BitWidth =
when {
this <= MAX_UBYTE_ULONG -> W_8
this <= UShort.MAX_VALUE -> W_16
this <= UInt.MAX_VALUE -> W_32
else -> W_64
}
// returns the number of bytes needed for padding the scalar of size scalarSize.
internal inline fun paddingBytes(bufSize: Int, scalarSize: Int): Int = bufSize.inv() + 1 and scalarSize - 1
internal inline fun paddingBytes(bufSize: Int, scalarSize: Int): Int =
bufSize.inv() + 1 and scalarSize - 1
internal inline fun FlexBufferType.isInline(): Boolean = this.value <= T_FLOAT.value || this == T_BOOL
internal inline fun FlexBufferType.isInline(): Boolean =
this.value <= T_FLOAT.value || this == T_BOOL
internal fun FlexBufferType.isScalar(): Boolean = when (this) {
T_INT, T_UINT, T_FLOAT, T_BOOL -> true
else -> false
}
internal fun FlexBufferType.isScalar(): Boolean =
when (this) {
T_INT,
T_UINT,
T_FLOAT,
T_BOOL -> true
else -> false
}
internal fun FlexBufferType.isIndirectScalar(): Boolean = when (this) {
T_INDIRECT_INT, T_INDIRECT_UINT, T_INDIRECT_FLOAT -> true
else -> false
}
internal fun FlexBufferType.isIndirectScalar(): Boolean =
when (this) {
T_INDIRECT_INT,
T_INDIRECT_UINT,
T_INDIRECT_FLOAT -> true
else -> false
}
internal fun FlexBufferType.isTypedVector(): Boolean =
this >= T_VECTOR_INT && this <= T_VECTOR_STRING_DEPRECATED || this == T_VECTOR_BOOL
@@ -118,6 +153,7 @@ internal fun FlexBufferType.isTypedVectorElementType(): Boolean =
// returns the typed vector of a given scalar type.
internal fun FlexBufferType.toTypedVector(): FlexBufferType = (this - T_INT) + T_VECTOR_INT
// returns the element type of given typed vector.
internal fun FlexBufferType.toElementTypedVector(): FlexBufferType = this - T_VECTOR_INT + T_INT
@@ -127,10 +163,11 @@ internal data class Value(
var key: Int = -1,
var minBitWidth: BitWidth = W_8,
var iValue: ULong = 0UL, // integer value
var dValue: Double = 0.0 // TODO(paulovap): maybe we can keep floating type on iValue as well.
var dValue: Double = 0.0, // TODO(paulovap): maybe we can keep floating type on iValue as well.
) { // float value
inline fun storedPackedType(parentBitWidth: BitWidth = W_8): Byte = packedType(storedWidth(parentBitWidth), type)
inline fun storedPackedType(parentBitWidth: BitWidth = W_8): Byte =
packedType(storedWidth(parentBitWidth), type)
private inline fun packedType(bitWidth: BitWidth, type: FlexBufferType): Byte =
(bitWidth.value or (type.value shl 2)).toByte()
@@ -147,7 +184,7 @@ internal fun elemWidth(
minBitWidth: BitWidth,
iValue: Long,
bufSize: Int,
elemIndex: Int
elemIndex: Int,
): BitWidth {
if (type.isInline()) return minBitWidth
@@ -173,43 +210,48 @@ internal fun elemWidth(
}
// For debugging purposes, convert type to a human-readable string.
internal fun FlexBufferType.typeToString(): String = when (this) {
T_NULL -> "Null"
T_INT -> "Int"
T_UINT -> "UInt"
T_FLOAT -> "Float"
T_KEY -> "Key"
T_STRING -> "String"
T_INDIRECT_INT -> "IndirectInt"
T_INDIRECT_UINT -> "IndirectUInt"
T_INDIRECT_FLOAT -> "IndirectFloat"
T_MAP -> "Map"
T_VECTOR -> "Vector"
T_VECTOR_INT -> "IntVector"
T_VECTOR_UINT -> "UIntVector"
T_VECTOR_FLOAT -> "FloatVector"
T_VECTOR_KEY -> "KeyVector"
T_VECTOR_STRING_DEPRECATED -> "StringVectorDeprecated"
T_VECTOR_INT2 -> "Int2Vector"
T_VECTOR_UINT2 -> "UInt2Vector"
T_VECTOR_FLOAT2 -> "Float2Vector"
T_VECTOR_INT3 -> "Int3Vector"
T_VECTOR_UINT3 -> "UInt3Vector"
T_VECTOR_FLOAT3 -> "Float3Vector"
T_VECTOR_INT4 -> "Int4Vector"
T_VECTOR_UINT4 -> "UInt4Vector"
T_VECTOR_FLOAT4 -> "Float4Vector"
T_BLOB -> "BlobVector"
T_BOOL -> "BoolVector"
T_VECTOR_BOOL -> "BoolVector"
else -> "UnknownType"
}
internal fun FlexBufferType.typeToString(): String =
when (this) {
T_NULL -> "Null"
T_INT -> "Int"
T_UINT -> "UInt"
T_FLOAT -> "Float"
T_KEY -> "Key"
T_STRING -> "String"
T_INDIRECT_INT -> "IndirectInt"
T_INDIRECT_UINT -> "IndirectUInt"
T_INDIRECT_FLOAT -> "IndirectFloat"
T_MAP -> "Map"
T_VECTOR -> "Vector"
T_VECTOR_INT -> "IntVector"
T_VECTOR_UINT -> "UIntVector"
T_VECTOR_FLOAT -> "FloatVector"
T_VECTOR_KEY -> "KeyVector"
T_VECTOR_STRING_DEPRECATED -> "StringVectorDeprecated"
T_VECTOR_INT2 -> "Int2Vector"
T_VECTOR_UINT2 -> "UInt2Vector"
T_VECTOR_FLOAT2 -> "Float2Vector"
T_VECTOR_INT3 -> "Int3Vector"
T_VECTOR_UINT3 -> "UInt3Vector"
T_VECTOR_FLOAT3 -> "Float3Vector"
T_VECTOR_INT4 -> "Int4Vector"
T_VECTOR_UINT4 -> "UInt4Vector"
T_VECTOR_FLOAT4 -> "Float4Vector"
T_BLOB -> "BlobVector"
T_BOOL -> "BoolVector"
T_VECTOR_BOOL -> "BoolVector"
else -> "UnknownType"
}
// Few repeated values used in hot path is cached here
internal fun emptyBlob() = Blob(emptyBuffer, 1, ByteWidth(1))
internal fun emptyVector() = Vector(emptyBuffer, 1, ByteWidth(1))
internal fun emptyMap() = Map(ArrayReadWriteBuffer(3), 3, ByteWidth(1))
internal fun nullReference() = Reference(emptyBuffer, 1, ByteWidth(0), T_NULL.value)
internal fun nullKey() = Key(emptyBuffer, 1)
internal const val ZeroByte = 0.toByte()
@@ -228,7 +270,8 @@ internal val T_INVALID = FlexBufferType(-1)
internal val T_NULL = FlexBufferType(0)
internal val T_INT = FlexBufferType(1)
internal val T_UINT = FlexBufferType(2)
internal val T_FLOAT = FlexBufferType(3) // Types above stored inline, types below are stored in an offset.
internal val T_FLOAT =
FlexBufferType(3) // Types above stored inline, types below are stored in an offset.
internal val T_KEY = FlexBufferType(4)
internal val T_STRING = FlexBufferType(5)
internal val T_INDIRECT_INT = FlexBufferType(6)
@@ -254,4 +297,5 @@ internal val T_VECTOR_UINT4 = FlexBufferType(23)
internal val T_VECTOR_FLOAT4 = FlexBufferType(24)
internal val T_BLOB = FlexBufferType(25)
internal val T_BOOL = FlexBufferType(26)
internal val T_VECTOR_BOOL = FlexBufferType(36) // To Allow the same type of conversion of type to vector type
internal val T_VECTOR_BOOL =
FlexBufferType(36) // To Allow the same type of conversion of type to vector type

View File

@@ -19,12 +19,10 @@ package com.google.flatbuffers.kotlin
public object Utf8 {
/**
* Returns the number of bytes in the UTF-8-encoded form of `sequence`. For a string,
* this method is equivalent to `string.getBytes(UTF_8).length`, but is more efficient in
* both time and space.
* Returns the number of bytes in the UTF-8-encoded form of `sequence`. For a string, this method
* is equivalent to `string.getBytes(UTF_8).length`, but is more efficient in both time and space.
*
* @throws IllegalArgumentException if `sequence` contains ill-formed UTF-16 (unpaired
* surrogates)
* @throws IllegalArgumentException if `sequence` contains ill-formed UTF-16 (unpaired surrogates)
*/
private fun computeEncodedLength(sequence: CharSequence): Int {
// Warning to maintainers: this implementation is highly optimized.
@@ -80,45 +78,30 @@ public object Utf8 {
}
/**
* Returns the number of bytes in the UTF-8-encoded form of `sequence`. For a string,
* this method is equivalent to `string.getBytes(UTF_8).length`, but is more efficient in
* both time and space.
* Returns the number of bytes in the UTF-8-encoded form of `sequence`. For a string, this method
* is equivalent to `string.getBytes(UTF_8).length`, but is more efficient in both time and space.
*
* @throws IllegalArgumentException if `sequence` contains ill-formed UTF-16 (unpaired
* surrogates)
* @throws IllegalArgumentException if `sequence` contains ill-formed UTF-16 (unpaired surrogates)
*/
public fun encodedLength(sequence: CharSequence): Int = computeEncodedLength(sequence)
/**
* Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'.
*/
/** Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'. */
public inline fun isOneByte(b: Byte): Boolean = b >= 0
/**
* Returns whether this is a two-byte codepoint with the form 110xxxxx 0xC0..0xDF.
*/
/** Returns whether this is a two-byte codepoint with the form 110xxxxx 0xC0..0xDF. */
public inline fun isTwoBytes(b: Byte): Boolean = b < 0xE0.toByte()
/**
* Returns whether this is a three-byte codepoint with the form 1110xxxx 0xE0..0xEF.
*/
/** Returns whether this is a three-byte codepoint with the form 1110xxxx 0xE0..0xEF. */
public inline fun isThreeBytes(b: Byte): Boolean = b < 0xF0.toByte()
/**
* Returns whether this is a four-byte codepoint with the form 11110xxx 0xF0..0xF4.
*/
/** Returns whether this is a four-byte codepoint with the form 11110xxx 0xF0..0xF4. */
public inline fun isFourByte(b: Byte): Boolean = b < 0xF8.toByte()
public fun handleOneByte(byte1: Byte, resultArr: CharArray, resultPos: Int) {
resultArr[resultPos] = byte1.toInt().toChar()
}
public fun handleTwoBytes(
byte1: Byte,
byte2: Byte,
resultArr: CharArray,
resultPos: Int
) {
public fun handleTwoBytes(byte1: Byte, byte2: Byte, resultArr: CharArray, resultPos: Int) {
// Simultaneously checks for illegal trailing-byte in leading position (<= '11000000') and
// overlong 2-byte, '11000001'.
if (byte1 < 0xC2.toByte()) {
@@ -135,17 +118,23 @@ public object Utf8 {
byte2: Byte,
byte3: Byte,
resultArr: CharArray,
resultPos: Int
resultPos: Int,
) {
if (isNotTrailingByte(byte2) || // overlong? 5 most significant bits must not all be zero
byte1 == 0xE0.toByte() && byte2 < 0xA0.toByte() || // check for illegal surrogate codepoints
byte1 == 0xED.toByte() && byte2 >= 0xA0.toByte() ||
isNotTrailingByte(byte3)
if (
isNotTrailingByte(byte2) || // overlong? 5 most significant bits must not all be zero
byte1 == 0xE0.toByte() && byte2 < 0xA0.toByte() || // check for illegal surrogate codepoints
byte1 == 0xED.toByte() && byte2 >= 0xA0.toByte() ||
isNotTrailingByte(byte3)
) {
error("Invalid UTF-8")
}
resultArr[resultPos] =
(byte1.toInt() and 0x0F shl 12 or (trailingByteValue(byte2) shl 6) or trailingByteValue(byte3)).toChar()
(byte1.toInt() and
0x0F shl
12 or
(trailingByteValue(byte2) shl 6) or
trailingByteValue(byte3))
.toChar()
}
public fun handleFourBytes(
@@ -154,50 +143,47 @@ public object Utf8 {
byte3: Byte,
byte4: Byte,
resultArr: CharArray,
resultPos: Int
resultPos: Int,
) {
if (isNotTrailingByte(byte2) || // Check that 1 <= plane <= 16. Tricky optimized form of:
// valid 4-byte leading byte?
// if (byte1 > (byte) 0xF4 ||
// overlong? 4 most significant bits must not all be zero
// byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
// codepoint larger than the highest code point (U+10FFFF)?
// byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
(byte1.toInt() shl 28) + (byte2 - 0x90.toByte()) shr 30 != 0 || isNotTrailingByte(byte3) ||
isNotTrailingByte(byte4)
if (
isNotTrailingByte(byte2) || // Check that 1 <= plane <= 16. Tricky optimized form of:
// valid 4-byte leading byte?
// if (byte1 > (byte) 0xF4 ||
// overlong? 4 most significant bits must not all be zero
// byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
// codepoint larger than the highest code point (U+10FFFF)?
// byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
(byte1.toInt() shl 28) + (byte2 - 0x90.toByte()) shr 30 != 0 ||
isNotTrailingByte(byte3) ||
isNotTrailingByte(byte4)
) {
error("Invalid UTF-8")
}
val codepoint: Int = (
byte1.toInt() and 0x07 shl 18
or (trailingByteValue(byte2) shl 12)
or (trailingByteValue(byte3) shl 6)
or trailingByteValue(byte4)
)
val codepoint: Int =
(byte1.toInt() and
0x07 shl
18 or
(trailingByteValue(byte2) shl 12) or
(trailingByteValue(byte3) shl 6) or
trailingByteValue(byte4))
resultArr[resultPos] = highSurrogate(codepoint)
resultArr[resultPos + 1] = lowSurrogate(codepoint)
}
/**
* Returns whether the byte is not a valid continuation of the form '10XXXXXX'.
*/
/** Returns whether the byte is not a valid continuation of the form '10XXXXXX'. */
private fun isNotTrailingByte(b: Byte): Boolean = b > 0xBF.toByte()
/**
* Returns the actual value of the trailing byte (removes the prefix '10') for composition.
*/
/** Returns the actual value of the trailing byte (removes the prefix '10') for composition. */
private fun trailingByteValue(b: Byte): Int = b.toInt() and 0x3F
private fun highSurrogate(codePoint: Int): Char =
(
Char.MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT ushr 10) +
(codePoint ushr 10)
)
(Char.MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT ushr 10) + (codePoint ushr 10))
private fun lowSurrogate(codePoint: Int): Char = (Char.MIN_LOW_SURROGATE + (codePoint and 0x3ff))
/**
* Encode a [CharSequence] UTF8 codepoint into a byte array.
*
* @param `in` CharSequence to be encoded
* @param start start position of the first char in the codepoint
* @param out byte array of 4 bytes to be filled
@@ -297,10 +283,7 @@ public object Utf8 {
if (offset >= limit) {
error("Invalid UTF-8")
}
handleTwoBytes(
byte1, /* byte2 */
bytes[offset++], resultArr, resultPos++
)
handleTwoBytes(byte1, /* byte2 */ bytes[offset++], resultArr, resultPos++)
} else if (isThreeBytes(byte1)) {
if (offset >= limit - 1) {
error("Invalid UTF-8")
@@ -310,7 +293,7 @@ public object Utf8 {
bytes[offset++], /* byte3 */
bytes[offset++],
resultArr,
resultPos++
resultPos++,
)
} else {
if (offset >= limit - 2) {
@@ -322,7 +305,7 @@ public object Utf8 {
bytes[offset++], /* byte4 */
bytes[offset++],
resultArr,
resultPos++
resultPos++,
)
// 4-byte case requires two chars.
resultPos++
@@ -331,10 +314,12 @@ public object Utf8 {
return resultArr.concatToString(0, resultPos)
}
public fun encodeUtf8Array(input: CharSequence,
out: ByteArray,
offset: Int = 0,
length: Int = out.size - offset): Int {
public fun encodeUtf8Array(
input: CharSequence,
out: ByteArray,
offset: Int = 0,
length: Int = out.size - offset,
): Int {
val utf16Length = input.length
var j = offset
var i = 0
@@ -342,8 +327,7 @@ public object Utf8 {
// Designed to take advantage of
// https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
if (utf16Length == 0)
return 0
if (utf16Length == 0) return 0
var cc: Char = input[i]
while (i < utf16Length && i + j < limit && input[i].also { cc = it }.code < 0x80) {
out[j + i] = cc.code.toByte()
@@ -370,9 +354,7 @@ public object Utf8 {
// Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
// four UTF-8 bytes
var low: Char = Char.MIN_VALUE
if (i + 1 == input.length ||
!isSurrogatePair(c, input[++i].also { low = it })
) {
if (i + 1 == input.length || !isSurrogatePair(c, input[++i].also { low = it })) {
errorSurrogate(i - 1, utf16Length)
}
val codePoint: Int = toCodePoint(c, low)
@@ -383,8 +365,10 @@ public object Utf8 {
} else {
// If we are surrogates and we're not a surrogate pair, always throw an
// UnpairedSurrogateException instead of an ArrayOutOfBoundsException.
if (Char.MIN_SURROGATE <= c && c <= Char.MAX_SURROGATE &&
(i + 1 == input.length || !isSurrogatePair(c, input[i + 1]))
if (
Char.MIN_SURROGATE <= c &&
c <= Char.MAX_SURROGATE &&
(i + 1 == input.length || !isSurrogatePair(c, input[i + 1]))
) {
errorSurrogate(i, utf16Length)
}
@@ -407,10 +391,15 @@ public object Utf8 {
return c1.code
}
private fun isSurrogatePair(high: Char, low: Char) = high.isHighSurrogate() and low.isLowSurrogate()
private fun isSurrogatePair(high: Char, low: Char) =
high.isHighSurrogate() and low.isLowSurrogate()
private fun toCodePoint(high: Char, low: Char): Int = (high.code shl 10) + low.code +
(MIN_SUPPLEMENTARY_CODE_POINT - (Char.MIN_HIGH_SURROGATE.code shl 10) - Char.MIN_LOW_SURROGATE.code)
private fun toCodePoint(high: Char, low: Char): Int =
(high.code shl 10) +
low.code +
(MIN_SUPPLEMENTARY_CODE_POINT -
(Char.MIN_HIGH_SURROGATE.code shl 10) -
Char.MIN_LOW_SURROGATE.code)
private fun errorSurrogate(i: Int, utf16Length: Int): Unit =
error("Unpaired surrogate at index $i of $utf16Length length")

View File

@@ -22,17 +22,17 @@ import kotlin.experimental.and
import kotlin.jvm.JvmInline
import kotlin.math.pow
/**
* Returns a minified version of this FlexBuffer as a JSON.
*/
public fun Reference.toJson(): String = ArrayReadWriteBuffer(1024).let {
toJson(it)
val data = it.data() // it.getString(0, it.writePosition)
return data.decodeToString(0, it.writePosition)
}
/** Returns a minified version of this FlexBuffer as a JSON. */
public fun Reference.toJson(): String =
ArrayReadWriteBuffer(1024).let {
toJson(it)
val data = it.data() // it.getString(0, it.writePosition)
return data.decodeToString(0, it.writePosition)
}
/**
* Returns a minified version of this FlexBuffer as a JSON.
*
* @param out [ReadWriteBuffer] the JSON will be written.
*/
public fun Reference.toJson(out: ReadWriteBuffer) {
@@ -57,19 +57,27 @@ public fun Reference.toJson(out: ReadWriteBuffer) {
T_NULL -> out.put("null")
T_BOOL -> out.put(toBoolean().toString())
T_MAP -> toMap().toJson(out)
T_VECTOR, T_VECTOR_BOOL, T_VECTOR_FLOAT, T_VECTOR_INT,
T_VECTOR_UINT, T_VECTOR_KEY, T_VECTOR_STRING_DEPRECATED -> toVector().toJson(out)
T_VECTOR,
T_VECTOR_BOOL,
T_VECTOR_FLOAT,
T_VECTOR_INT,
T_VECTOR_UINT,
T_VECTOR_KEY,
T_VECTOR_STRING_DEPRECATED -> toVector().toJson(out)
else -> error("Unable to convert type ${type.typeToString()} to JSON")
}
}
/**
* Returns a minified version of this FlexBuffer as a JSON.
*/
public fun Map.toJson(): String = ArrayReadWriteBuffer(1024).let { toJson(it); it.toString() }
/** Returns a minified version of this FlexBuffer as a JSON. */
public fun Map.toJson(): String =
ArrayReadWriteBuffer(1024).let {
toJson(it)
it.toString()
}
/**
* Returns a minified version of this FlexBuffer as a JSON.
*
* @param out [ReadWriteBuffer] the JSON will be written.
*/
public fun Map.toJson(out: ReadWriteBuffer) {
@@ -88,13 +96,16 @@ public fun Map.toJson(out: ReadWriteBuffer) {
out.put('}'.code.toByte())
}
/**
* Returns a minified version of this FlexBuffer as a JSON.
*/
public fun Vector.toJson(): String = ArrayReadWriteBuffer(1024).let { toJson(it); it.toString() }
/** Returns a minified version of this FlexBuffer as a JSON. */
public fun Vector.toJson(): String =
ArrayReadWriteBuffer(1024).let {
toJson(it)
it.toString()
}
/**
* Returns a minified version of this FlexBuffer as a JSON.
*
* @param out that the JSON is being concatenated.
*/
public fun Vector.toJson(out: ReadWriteBuffer) {
@@ -109,27 +120,23 @@ public fun Vector.toJson(out: ReadWriteBuffer) {
}
/**
* JSONParser class is used to parse a JSON as FlexBuffers. Calling [JSONParser.parse] fiils [output]
* and returns a [Reference] ready to be used.
* JSONParser class is used to parse a JSON as FlexBuffers. Calling [JSONParser.parse] fiils
* [output] and returns a [Reference] ready to be used.
*/
@ExperimentalUnsignedTypes
public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuilder(1024, SHARE_KEYS_AND_STRINGS)) {
public class JSONParser(
public var output: FlexBuffersBuilder = FlexBuffersBuilder(1024, SHARE_KEYS_AND_STRINGS)
) {
private var readPos = 0
private var scopes = ScopeStack()
/**
* Parse a json as [String] and returns a [Reference] to a FlexBuffer.
*/
/** Parse a json as [String] and returns a [Reference] to a FlexBuffer. */
public fun parse(data: String): Reference = parse(ArrayReadBuffer(data.encodeToByteArray()))
/**
* Parse a json as [ByteArray] and returns a [Reference] to a FlexBuffer.
*/
/** Parse a json as [ByteArray] and returns a [Reference] to a FlexBuffer. */
public fun parse(data: ByteArray): Reference = parse(ArrayReadBuffer(data))
/**
* Parse a json as [ReadBuffer] and returns a [Reference] to a FlexBuffer.
*/
/** Parse a json as [ReadBuffer] and returns a [Reference] to a FlexBuffer. */
public fun parse(data: ReadBuffer): Reference {
reset()
parseValue(data, nextToken(data), null)
@@ -165,7 +172,8 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
when (val tok = nextToken(data)) {
TOK_END_OBJECT -> {
this.scopes.pop()
output.endMap(fPos, key); return T_MAP
output.endMap(fPos, key)
return T_MAP
}
TOK_BEGIN_QUOTE -> {
val childKey = readString(data)
@@ -347,7 +355,11 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
return readString(data, limit) { data[it] }
}
private inline fun readString(data: ReadBuffer, limit: Int, crossinline fetch: (Int) -> Byte): String {
private inline fun readString(
data: ReadBuffer,
limit: Int,
crossinline fetch: (Int) -> Byte,
): String {
var cursorPos = readPos
var foundEscape = false
var currentChar: Byte = 0
@@ -420,7 +432,8 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
endOfString = pos + 1
}
else -> {
endOfString = pos; break
endOfString = pos
break
}
}
}
@@ -478,7 +491,8 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
else -> makeError(data, "Unfinished Array", c)
}
}
SCOPE_OBJ_EMPTY, SCOPE_OBJ_FILLED -> {
SCOPE_OBJ_EMPTY,
SCOPE_OBJ_FILLED -> {
this.scopes.last = SCOPE_OBJ_KEY
// Look for a comma before the next element.
if (scope == SCOPE_OBJ_FILLED) {
@@ -490,11 +504,12 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
}
return when (val c = skipWhitespace(data)) {
CHAR_DOUBLE_QUOTE -> TOK_BEGIN_QUOTE
CHAR_CLOSE_OBJECT -> if (scope != SCOPE_OBJ_FILLED) {
TOK_END_OBJECT
} else {
makeError(data, "Expected Key", c)
}
CHAR_CLOSE_OBJECT ->
if (scope != SCOPE_OBJ_FILLED) {
TOK_END_OBJECT
} else {
makeError(data, "Expected Key", c)
}
else -> {
makeError(data, "Expected Key/Value", c)
}
@@ -510,8 +525,7 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
SCOPE_DOC_EMPTY -> this.scopes.last = SCOPE_DOC_FILLED
SCOPE_DOC_FILLED -> {
val c = skipWhitespace(data)
if (c != CHAR_EOF)
makeError(data, "Root object already finished", c)
if (c != CHAR_EOF) makeError(data, "Root object already finished", c)
return TOK_EOF
}
}
@@ -550,10 +564,20 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
readPos += 4
return TOK_FALSE
}
CHAR_0, CHAR_1, CHAR_2, CHAR_3, CHAR_4, CHAR_5,
CHAR_6, CHAR_7, CHAR_8, CHAR_9, CHAR_MINUS -> return TOK_NUMBER.also {
readPos-- // rewind one position so we don't lose first digit
}
CHAR_0,
CHAR_1,
CHAR_2,
CHAR_3,
CHAR_4,
CHAR_5,
CHAR_6,
CHAR_7,
CHAR_8,
CHAR_9,
CHAR_MINUS ->
return TOK_NUMBER.also {
readPos-- // rewind one position so we don't lose first digit
}
}
makeError(data, "Expecting element", c)
}
@@ -593,12 +617,13 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
while (i < end) {
val part: Byte = data[i]
result = (result.code shl 4).toChar()
result += when (part) {
in CHAR_0..CHAR_9 -> part - CHAR_0
in CHAR_a..CHAR_f -> part - CHAR_a + 10
in CHAR_A..CHAR_F -> part - CHAR_A + 10
else -> makeError(data, "Invalid utf8 escaped character", -1)
}
result +=
when (part) {
in CHAR_0..CHAR_9 -> part - CHAR_0
in CHAR_a..CHAR_f -> part - CHAR_a + 10
in CHAR_A..CHAR_F -> part - CHAR_A + 10
else -> makeError(data, "Invalid utf8 escaped character", -1)
}
i++
}
result
@@ -608,16 +633,19 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
CHAR_r -> '\r'
CHAR_n -> '\n'
CHAR_f -> 12.toChar() // '\f'
CHAR_DOUBLE_QUOTE, CHAR_BACKSLASH, CHAR_FORWARDSLASH -> byte1.toInt().toChar()
CHAR_DOUBLE_QUOTE,
CHAR_BACKSLASH,
CHAR_FORWARDSLASH -> byte1.toInt().toChar()
else -> makeError(data, "Invalid escape sequence.", byte1)
}
}
private fun Byte.print(): String = when (this) {
in 0x21..0x7E -> "'${this.toInt().toChar()}'" // visible ascii chars
CHAR_EOF -> "EOF"
else -> "'0x${this.toString(16)}'"
}
private fun Byte.print(): String =
when (this) {
in 0x21..0x7E -> "'${this.toInt().toChar()}'" // visible ascii chars
CHAR_EOF -> "EOF"
else -> "'0x${this.toString(16)}'"
}
private inline fun makeError(data: ReadBuffer, msg: String, tok: Byte? = null): Nothing {
val (line, column) = calculateErrorPosition(data, readPos)
@@ -634,8 +662,7 @@ public class JSONParser(public var output: FlexBuffersBuilder = FlexBuffersBuild
}
private inline fun checkEOF(data: ReadBuffer, pos: Int) {
if (pos >= data.limit)
makeError(data, "Unexpected end of file", -1)
if (pos >= data.limit) makeError(data, "Unexpected end of file", -1)
}
private fun calculateErrorPosition(data: ReadBuffer, endPos: Int): Pair<Int, Int> {
@@ -686,22 +713,23 @@ private inline fun ReadWriteBuffer.jsonEscape(data: ReadBuffer, start: Int, size
}
// Following escape strategy defined in RFC7159.
private val JSON_ESCAPE_CHARS: Array<ByteArray?> = arrayOfNulls<ByteArray>(128).apply {
this['\n'.code] = "\\n".encodeToByteArray()
this['\t'.code] = "\\t".encodeToByteArray()
this['\r'.code] = "\\r".encodeToByteArray()
this['\b'.code] = "\\b".encodeToByteArray()
this[0x0c] = "\\f".encodeToByteArray()
this['"'.code] = "\\\"".encodeToByteArray()
this['\\'.code] = "\\\\".encodeToByteArray()
for (i in 0..0x1f) {
this[i] = "\\u${i.toPaddedHex()}".encodeToByteArray()
private val JSON_ESCAPE_CHARS: Array<ByteArray?> =
arrayOfNulls<ByteArray>(128).apply {
this['\n'.code] = "\\n".encodeToByteArray()
this['\t'.code] = "\\t".encodeToByteArray()
this['\r'.code] = "\\r".encodeToByteArray()
this['\b'.code] = "\\b".encodeToByteArray()
this[0x0c] = "\\f".encodeToByteArray()
this['"'.code] = "\\\"".encodeToByteArray()
this['\\'.code] = "\\\\".encodeToByteArray()
for (i in 0..0x1f) {
this[i] = "\\u${i.toPaddedHex()}".encodeToByteArray()
}
}
}
// Scope is used to the define current space that the scanner is operating.
@JvmInline
private value class Scope(val id: Int)
@JvmInline private value class Scope(val id: Int)
private val SCOPE_DOC_EMPTY = Scope(0)
private val SCOPE_DOC_FILLED = Scope(1)
private val SCOPE_OBJ_EMPTY = Scope(2)
@@ -714,7 +742,7 @@ private val SCOPE_ARRAY_FILLED = Scope(6)
// max stack size of 22, as per tests cases defined in http://json.org/JSON_checker/
private class ScopeStack(
private val ary: IntArray = IntArray(22) { SCOPE_DOC_EMPTY.id },
var lastPos: Int = 0
var lastPos: Int = 0,
) {
var last: Scope
get() = Scope(ary[lastPos])
@@ -743,20 +771,21 @@ private class ScopeStack(
@JvmInline
private value class Token(val id: Int) {
fun print(): String = when (this) {
TOK_EOF -> "TOK_EOF"
TOK_NONE -> "TOK_NONE"
TOK_BEGIN_OBJECT -> "TOK_BEGIN_OBJECT"
TOK_END_OBJECT -> "TOK_END_OBJECT"
TOK_BEGIN_ARRAY -> "TOK_BEGIN_ARRAY"
TOK_END_ARRAY -> "TOK_END_ARRAY"
TOK_NUMBER -> "TOK_NUMBER"
TOK_TRUE -> "TOK_TRUE"
TOK_FALSE -> "TOK_FALSE"
TOK_NULL -> "TOK_NULL"
TOK_BEGIN_QUOTE -> "TOK_BEGIN_QUOTE"
else -> this.toString()
}
fun print(): String =
when (this) {
TOK_EOF -> "TOK_EOF"
TOK_NONE -> "TOK_NONE"
TOK_BEGIN_OBJECT -> "TOK_BEGIN_OBJECT"
TOK_END_OBJECT -> "TOK_END_OBJECT"
TOK_BEGIN_ARRAY -> "TOK_BEGIN_ARRAY"
TOK_END_ARRAY -> "TOK_END_ARRAY"
TOK_NUMBER -> "TOK_NUMBER"
TOK_TRUE -> "TOK_TRUE"
TOK_FALSE -> "TOK_FALSE"
TOK_NULL -> "TOK_NULL"
TOK_BEGIN_QUOTE -> "TOK_BEGIN_QUOTE"
else -> this.toString()
}
}
private val TOK_EOF = Token(-1)
@@ -813,20 +842,265 @@ private const val CHAR_DOT = '.'.code.toByte()
// bit 0 (1) - set if: plain ASCII string character
// bit 1 (2) - set if: whitespace
// bit 4 (0x10) - set if: 0-9 e E .
private val parseFlags = byteArrayOf(
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
3, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x11, 1, // 2
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1, 1, 1, 1, 1, 1, // 3
1, 1, 1, 1, 1, 0x11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 5
1, 1, 1, 1, 1, 0x11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
private val parseFlags =
byteArrayOf(
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0,
0,
0,
0,
0,
0,
0,
0,
0,
2,
2,
0,
0,
2,
0,
0, // 0
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, // 1
3,
1,
0,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0x11,
1, // 2
0x11,
0x11,
0x11,
0x11,
0x11,
0x11,
0x11,
0x11,
0x11,
0x11,
1,
1,
1,
1,
1,
1, // 3
1,
1,
1,
1,
1,
0x11,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1, // 4
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
1,
1,
1, // 5
1,
1,
1,
1,
1,
0x11,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1, // 6
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1, // 7
// 128-255
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
)
// 128-255
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
)

View File

@@ -35,8 +35,7 @@ fun arrayFailMessage(expected: ShortArray, actual: ShortArray): String =
fun arrayFailMessage(expected: LongArray, actual: LongArray): String =
failMessage(expected.contentToString(), actual.contentToString())
fun failMessage(expected: String, actual: String): String =
"Expected: $expected\nActual: $actual"
fun failMessage(expected: String, actual: String): String = "Expected: $expected\nActual: $actual"
fun arrayFailMessage(expected: FloatArray, actual: FloatArray): String {
return "Expected: ${expected.contentToString()}\nActual: ${actual.contentToString()}"

View File

@@ -16,10 +16,10 @@ class BuffersTest {
assertEquals(bytes.size, fullRead.limit)
assertEquals(text, fullRead.getString(0, fullRead.limit))
assertEquals("Hello" , helloRead.getString(0, helloRead.limit))
assertEquals("world!" , worldRead.getString())
assertEquals(fullRead.getString(0, 5) , helloRead.getString(0, helloRead.limit))
assertEquals(fullRead.getString(6, 6) , worldRead.getString(0, worldRead.limit))
assertEquals("Hello", helloRead.getString(0, helloRead.limit))
assertEquals("world!", worldRead.getString())
assertEquals(fullRead.getString(0, 5), helloRead.getString(0, helloRead.limit))
assertEquals(fullRead.getString(6, 6), worldRead.getString(0, worldRead.limit))
for (i in 0 until helloRead.limit) {
assertEquals(fullRead[i], helloRead[i])

View File

@@ -17,18 +17,18 @@ package com.google.flatbuffers.kotlin
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class ByteArrayTest {
@Test
fun testByte() {
val testSet = arrayOf(
67.toByte() to byteArrayOf(67),
Byte.MIN_VALUE to byteArrayOf(-128),
Byte.MAX_VALUE to byteArrayOf(127),
0.toByte() to byteArrayOf(0)
)
val testSet =
arrayOf(
67.toByte() to byteArrayOf(67),
Byte.MIN_VALUE to byteArrayOf(-128),
Byte.MAX_VALUE to byteArrayOf(127),
0.toByte() to byteArrayOf(0),
)
val data = ByteArray(1)
testSet.forEach {
data[0] = it.first
@@ -39,12 +39,13 @@ class ByteArrayTest {
@Test
fun testShort() {
val testSet = arrayOf(
6712.toShort() to byteArrayOf(56, 26),
Short.MIN_VALUE to byteArrayOf(0, -128),
Short.MAX_VALUE to byteArrayOf(-1, 127),
0.toShort() to byteArrayOf(0, 0,)
)
val testSet =
arrayOf(
6712.toShort() to byteArrayOf(56, 26),
Short.MIN_VALUE to byteArrayOf(0, -128),
Short.MAX_VALUE to byteArrayOf(-1, 127),
0.toShort() to byteArrayOf(0, 0),
)
val data = ByteArray(Short.SIZE_BYTES)
testSet.forEach {
@@ -56,12 +57,13 @@ class ByteArrayTest {
@Test
fun testInt() {
val testSet = arrayOf(
33333500 to byteArrayOf(-4, -96, -4, 1),
Int.MIN_VALUE to byteArrayOf(0, 0, 0, -128),
Int.MAX_VALUE to byteArrayOf(-1, -1, -1, 127),
0 to byteArrayOf(0, 0, 0, 0)
)
val testSet =
arrayOf(
33333500 to byteArrayOf(-4, -96, -4, 1),
Int.MIN_VALUE to byteArrayOf(0, 0, 0, -128),
Int.MAX_VALUE to byteArrayOf(-1, -1, -1, 127),
0 to byteArrayOf(0, 0, 0, 0),
)
val data = ByteArray(Int.SIZE_BYTES)
testSet.forEach {
data.setInt(0, it.first)
@@ -72,13 +74,14 @@ class ByteArrayTest {
@Test
fun testLong() {
val testSet = arrayOf(
1234567123122890123L to byteArrayOf(-117, -91, 29, -23, 65, 16, 34, 17),
-1L to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, -1),
Long.MIN_VALUE to byteArrayOf(0, 0, 0, 0, 0, 0, 0, -128),
Long.MAX_VALUE to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, 127),
0L to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0)
)
val testSet =
arrayOf(
1234567123122890123L to byteArrayOf(-117, -91, 29, -23, 65, 16, 34, 17),
-1L to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, -1),
Long.MIN_VALUE to byteArrayOf(0, 0, 0, 0, 0, 0, 0, -128),
Long.MAX_VALUE to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, 127),
0L to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
)
val data = ByteArray(Long.SIZE_BYTES)
testSet.forEach {
data.setLong(0, it.first)
@@ -89,12 +92,13 @@ class ByteArrayTest {
@Test
fun testULong() {
val testSet = arrayOf(
1234567123122890123UL to byteArrayOf(-117, -91, 29, -23, 65, 16, 34, 17),
ULong.MIN_VALUE to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
(-1L).toULong() to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, -1),
0UL to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0)
)
val testSet =
arrayOf(
1234567123122890123UL to byteArrayOf(-117, -91, 29, -23, 65, 16, 34, 17),
ULong.MIN_VALUE to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
(-1L).toULong() to byteArrayOf(-1, -1, -1, -1, -1, -1, -1, -1),
0UL to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
)
val data = ByteArray(ULong.SIZE_BYTES)
testSet.forEach {
data.setULong(0, it.first)
@@ -105,12 +109,13 @@ class ByteArrayTest {
@Test
fun testFloat() {
val testSet = arrayOf(
3545.56337f to byteArrayOf(4, -103, 93, 69),
Float.MIN_VALUE to byteArrayOf(1, 0, 0, 0),
Float.MAX_VALUE to byteArrayOf(-1, -1, 127, 127),
0f to byteArrayOf(0, 0, 0, 0)
)
val testSet =
arrayOf(
3545.56337f to byteArrayOf(4, -103, 93, 69),
Float.MIN_VALUE to byteArrayOf(1, 0, 0, 0),
Float.MAX_VALUE to byteArrayOf(-1, -1, 127, 127),
0f to byteArrayOf(0, 0, 0, 0),
)
val data = ByteArray(Float.SIZE_BYTES)
testSet.forEach {
data.setFloat(0, it.first)
@@ -120,12 +125,13 @@ class ByteArrayTest {
@Test
fun testDouble() {
val testSet = arrayOf(
123456.523423423412 to byteArrayOf(88, 61, -15, 95, 8, 36, -2, 64),
Double.MIN_VALUE to byteArrayOf(1, 0, 0, 0, 0, 0, 0, 0),
Double.MAX_VALUE to byteArrayOf(-1, -1, -1, -1, -1, -1, -17, 127),
0.0 to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0)
)
val testSet =
arrayOf(
123456.523423423412 to byteArrayOf(88, 61, -15, 95, 8, 36, -2, 64),
Double.MIN_VALUE to byteArrayOf(1, 0, 0, 0, 0, 0, 0, 0),
Double.MAX_VALUE to byteArrayOf(-1, -1, -1, -1, -1, -1, -17, 127),
0.0 to byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
)
val data = ByteArray(Long.SIZE_BYTES)
testSet.forEach {
data.setDouble(0, it.first)
@@ -144,4 +150,3 @@ class ByteArrayTest {
assertEquals(testSet, data.getString(0, encoded.size))
}
}

View File

@@ -18,19 +18,17 @@
package com.google.flatbuffers.kotlin
import Attacker
import AttackerOffsetArray
import CharacterEArray
import dictionaryLookup.LongFloatEntry
import dictionaryLookup.LongFloatMap
import Movie
import dictionaryLookup.LongFloatEntry
import dictionaryLookup.LongFloatEntryOffsetArray
import dictionaryLookup.LongFloatMap
import kotlin.test.Test
import kotlin.test.assertEquals
import myGame.example.*
import myGame.example.Test.Companion.createTest
import optionalScalars.OptionalByte
import optionalScalars.ScalarStuff
import kotlin.test.Test
import kotlin.test.assertEquals
@ExperimentalUnsignedTypes
class FlatBufferBuilderTest {
@@ -43,10 +41,8 @@ class FlatBufferBuilderTest {
val inv = Monster.createInventoryVector(fbb, invValues)
Monster.startMonster(fbb)
Monster.addPos(
fbb, Vec3.createVec3(
fbb, 1.0f, 2.0f, 3.0f, 3.0,
Color.Green, 5.toShort(), 6.toByte()
)
fbb,
Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0, Color.Green, 5.toShort(), 6.toByte()),
)
Monster.addHp(fbb, 80.toShort())
Monster.addName(fbb, name)
@@ -86,12 +82,14 @@ class FlatBufferBuilderTest {
@Test
fun testSortedVector() {
val fbb = FlatBufferBuilder()
val names = arrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma"))
val monsters = MonsterOffsetArray(3) {
Monster.startMonster(fbb)
Monster.addName(fbb, names[it])
Monster.endMonster(fbb)
}
val names =
arrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma"))
val monsters =
MonsterOffsetArray(3) {
Monster.startMonster(fbb)
Monster.addName(fbb, names[it])
Monster.endMonster(fbb)
}
val ary = Monster.createTestarrayoftablesVector(fbb, monsters)
Monster.startMonster(fbb)
Monster.addName(fbb, names[0])
@@ -161,7 +159,8 @@ class FlatBufferBuilderTest {
@Test
fun testBuilderBasics() {
val fbb = FlatBufferBuilder()
val names = arrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma"))
val names =
arrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma"))
val off = Array<Offset<Monster>>(3) { Offset(0) }
Monster.startMonster(fbb)
Monster.addName(fbb, names[0])
@@ -176,7 +175,7 @@ class FlatBufferBuilderTest {
// We set up the same values as monsterdata.json:
val inv = Monster.createInventoryVector(fbb, byteArrayOf(0,1,2,3,4).toUByteArray())
val inv = Monster.createInventoryVector(fbb, byteArrayOf(0, 1, 2, 3, 4).toUByteArray())
val fred = fbb.createString("Fred")
Monster.startMonster(fbb)
@@ -189,15 +188,14 @@ class FlatBufferBuilderTest {
val test4 = fbb.endVector<myGame.example.Test>()
val strings = StringOffsetArray(2) { fbb.createString("test$it") }
val testArrayOfString =
Monster.createTestarrayofstringVector(fbb, strings)
val testArrayOfString = Monster.createTestarrayofstringVector(fbb, strings)
Monster.startMonster(fbb)
Monster.addName(fbb, names[0])
Monster.addPos(fbb, Vec3.createVec3(
fbb, 1.0f, 2.0f, 3.0f, 3.0,
Color.Green, 5.toShort(), 6.toByte()
))
Monster.addPos(
fbb,
Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0, Color.Green, 5.toShort(), 6.toByte()),
)
Monster.addHp(fbb, 80)
Monster.addMana(fbb, 150)
Monster.addInventory(fbb, inv)
@@ -210,7 +208,7 @@ class FlatBufferBuilderTest {
Monster.addTestarrayoftables(fbb, sortMons)
val mon = Monster.endMonster(fbb)
Monster.finishMonsterBuffer(fbb, mon)
//Attempt to mutate Monster fields and check whether the buffer has been mutated properly
// Attempt to mutate Monster fields and check whether the buffer has been mutated properly
// revert to original values after testing
val monster = Monster.asRoot(fbb.dataBuffer())
@@ -255,14 +253,12 @@ class FlatBufferBuilderTest {
CharacterE.MuLan,
attacker,
Movie.createCharactersTypeVector(fbb, characters),
Movie.createCharactersVector(fbb, attackers)
)
Movie.createCharactersVector(fbb, attackers),
),
)
val movie: Movie = Movie.asRoot(fbb.dataBuffer())
assertEquals(movie.charactersTypeLength, 1)
assertEquals(movie.charactersLength, 1)
@@ -326,7 +322,7 @@ class FlatBufferBuilderTest {
fbb.clear()
val largeData = ByteArray(1024)
offset = fbb.createByteVector(largeData) as VectorOffset<UByte> //TODO: fix me
offset = fbb.createByteVector(largeData) as VectorOffset<UByte> // TODO: fix me
str = fbb.createString("ByteMonster")
Monster.startMonster(fbb)
Monster.addName(fbb, str)
@@ -340,7 +336,7 @@ class FlatBufferBuilderTest {
fbb.clear()
var bb = ArrayReadBuffer(largeData, 512)
offset = fbb.createByteVector(bb) as VectorOffset<UByte> //TODO: fix me
offset = fbb.createByteVector(bb) as VectorOffset<UByte> // TODO: fix me
str = fbb.createString("ByteMonster")
Monster.startMonster(fbb)
Monster.addName(fbb, str)
@@ -354,7 +350,7 @@ class FlatBufferBuilderTest {
bb = ArrayReadBuffer(largeData, largeData.size - 216)
val stringBuffer = ArrayReadBuffer("AlreadyBufferedString".encodeToByteArray())
offset = fbb.createByteVector(bb) as VectorOffset<UByte> //TODO: fix me
offset = fbb.createByteVector(bb) as VectorOffset<UByte> // TODO: fix me
str = fbb.createString(stringBuffer)
Monster.startMonster(fbb)
Monster.addName(fbb, str)
@@ -507,19 +503,19 @@ class FlatBufferBuilderTest {
assertEquals(scalarStuff.defaultEnum, OptionalByte.Two)
}
// @todo Seems like nesting code generation is broken for all generators.
// disabling test for now.
// @Test
// fun testNamespaceNesting() {
// // reference / manipulate these to verify compilation
// val fbb = FlatBufferBuilder(1)
// TableInNestedNS.startTableInNestedNS(fbb)
// TableInNestedNS.addFoo(fbb, 1234)
// val nestedTableOff = TableInNestedNS.endTableInNestedNs(fbb)
// TableInFirstNS.startTableInFirstNS(fbb)
// TableInFirstNS.addFooTable(fbb, nestedTableOff)
// TableInFirstNS.endTableInFirstNs(fbb)
// }
// @todo Seems like nesting code generation is broken for all generators.
// disabling test for now.
// @Test
// fun testNamespaceNesting() {
// // reference / manipulate these to verify compilation
// val fbb = FlatBufferBuilder(1)
// TableInNestedNS.startTableInNestedNS(fbb)
// TableInNestedNS.addFoo(fbb, 1234)
// val nestedTableOff = TableInNestedNS.endTableInNestedNs(fbb)
// TableInFirstNS.startTableInFirstNS(fbb)
// TableInFirstNS.addFooTable(fbb, nestedTableOff)
// TableInFirstNS.endTableInFirstNs(fbb)
// }
@Test
fun testNestedFlatBuffer() {
@@ -558,7 +554,8 @@ class FlatBufferBuilderTest {
fun testDictionaryLookup() {
val fbb = FlatBufferBuilder(16)
val lfIndex = LongFloatEntry.createLongFloatEntry(fbb, 0, 99.0f)
val vectorEntriesIdx = LongFloatMap.createEntriesVector(fbb, LongFloatEntryOffsetArray(1) { lfIndex })
val vectorEntriesIdx =
LongFloatMap.createEntriesVector(fbb, LongFloatEntryOffsetArray(1) { lfIndex })
val rootIdx = LongFloatMap.createLongFloatMap(fbb, vectorEntriesIdx)
LongFloatMap.finishLongFloatMapBuffer(fbb, rootIdx)
val map: LongFloatMap = LongFloatMap.asRoot(fbb.dataBuffer())

View File

@@ -24,12 +24,13 @@ class FlexBuffersTest {
@Test
fun testWriteInt() {
val values = listOf(
Byte.MAX_VALUE.toLong() to 3,
Short.MAX_VALUE.toLong() to 4,
Int.MAX_VALUE.toLong() to 6,
Long.MAX_VALUE to 10
)
val values =
listOf(
Byte.MAX_VALUE.toLong() to 3,
Short.MAX_VALUE.toLong() to 4,
Int.MAX_VALUE.toLong() to 6,
Long.MAX_VALUE to 10,
)
val builder = FlexBuffersBuilder()
values.forEach {
builder.clear()
@@ -44,12 +45,13 @@ class FlexBuffersTest {
@Test
fun testWriteUInt() {
val values = listOf(
UByte.MAX_VALUE.toULong() to 3,
UShort.MAX_VALUE.toULong() to 4,
UInt.MAX_VALUE.toULong() to 6,
ULong.MAX_VALUE to 10
)
val values =
listOf(
UByte.MAX_VALUE.toULong() to 3,
UShort.MAX_VALUE.toULong() to 4,
UInt.MAX_VALUE.toULong() to 6,
ULong.MAX_VALUE to 10,
)
val builder = FlexBuffersBuilder()
values.forEach {
builder.clear()
@@ -126,7 +128,8 @@ class FlexBuffersTest {
@Test
fun testLongArray() {
val ary: LongArray = longArrayOf(0, Short.MIN_VALUE.toLong(), Int.MAX_VALUE.toLong(), Long.MAX_VALUE)
val ary: LongArray =
longArrayOf(0, Short.MIN_VALUE.toLong(), Int.MAX_VALUE.toLong(), Long.MAX_VALUE)
val builder = FlexBuffersBuilder()
builder.put(ary)
val data = builder.finish()
@@ -139,9 +142,7 @@ class FlexBuffersTest {
fun testStringArray() {
val ary = Array(5) { "Hello world number: $it" }
val builder = FlexBuffersBuilder(ArrayReadWriteBuffer(20), SHARE_NONE)
builder.putVector {
ary.forEach { put(it) }
}
builder.putVector { ary.forEach { put(it) } }
val data = builder.finish()
val vec = getRoot(data).toVector()
// although we put a long, it is shrink to a byte
@@ -237,9 +238,7 @@ class FlexBuffersTest {
this["int"] = 10
this["float"] = 12.3
this["intarray"] = intArrayOf(1, 2, 3, 4, 5)
this.putMap("myMap") {
this["cool"] = "beans"
}
this.putMap("myMap") { this["cool"] = "beans" }
}
val ref = getRoot(builder.finish())
@@ -257,7 +256,9 @@ class FlexBuffersTest {
assertEquals(true, ref["invalid_key"].isNull)
val keys = map.keys.toTypedArray()
arrayOf("hello", "int", "float", "intarray", "myMap").sortedArray().forEachIndexed { i: Int, it: String ->
arrayOf("hello", "int", "float", "intarray", "myMap").sortedArray().forEachIndexed {
i: Int,
it: String ->
assertEquals(it, keys[i].toString())
}
}

View File

@@ -23,9 +23,11 @@ class JSONTest {
@Test
fun parse2Test() {
val dataStr = """
{ "myKey" : [1, "yay"] }
""".trimIndent()
val dataStr =
"""
{ "myKey" : [1, "yay"] }
"""
.trimIndent()
val data = dataStr.encodeToByteArray()
val buffer = ArrayReadWriteBuffer(data, writePosition = data.size)
val parser = JSONParser()
@@ -35,7 +37,8 @@ class JSONTest {
@Test
fun parseSample() {
val dataStr = """
val dataStr =
"""
{
"ary" : [1, 2, 3],
"boolean_false": false,
@@ -69,26 +72,29 @@ class JSONTest {
val obj = map["object"]
assertEquals(true, obj.isMap)
assertEquals("{\"field1\":\"hello\"}", obj.toJson())
// TODO: Kotlin Double.toString() produce different strings dependending on the platform, so on JVM
// TODO: Kotlin Double.toString() produce different strings dependending on the platform, so on
// JVM
// is 1.2E33, while on js is 1.2e+33. For now we are disabling this test.
//
// val minified = data.filterNot { it == ' '.toByte() || it == '\n'.toByte() }.toByteArray().decodeToString()
// val minified = data.filterNot { it == ' '.toByte() || it == '\n'.toByte()
// }.toByteArray().decodeToString()
// assertEquals(minified, root.toJson())
}
@Test
fun testDoubles() {
val values = arrayOf(
"-0.0",
"1.0",
"1.7976931348613157",
"0.0",
"-0.5",
"3.141592653589793",
"2.718281828459045E-3",
"2.2250738585072014E-308",
"4.9E-15",
)
val values =
arrayOf(
"-0.0",
"1.0",
"1.7976931348613157",
"0.0",
"-0.5",
"3.141592653589793",
"2.718281828459045E-3",
"2.2250738585072014E-308",
"4.9E-15",
)
val parser = JSONParser()
assertEquals(-0.0, parser.parse(values[0]).toDouble())
assertEquals(1.0, parser.parse(values[1]).toDouble())
@@ -103,15 +109,16 @@ class JSONTest {
@Test
fun testInts() {
val values = arrayOf(
"-0",
"0",
"-1",
"${Int.MAX_VALUE}",
"${Int.MIN_VALUE}",
"${Long.MAX_VALUE}",
"${Long.MIN_VALUE}",
)
val values =
arrayOf(
"-0",
"0",
"-1",
"${Int.MAX_VALUE}",
"${Int.MIN_VALUE}",
"${Long.MAX_VALUE}",
"${Long.MIN_VALUE}",
)
val parser = JSONParser()
assertEquals(parser.parse(values[0]).toInt(), 0)
@@ -125,11 +132,7 @@ class JSONTest {
@Test
fun testBooleansAndNull() {
val values = arrayOf(
"true",
"false",
"null"
)
val values = arrayOf("true", "false", "null")
val parser = JSONParser()
assertEquals(true, parser.parse(values[0]).toBoolean())
@@ -139,16 +142,17 @@ class JSONTest {
@Test
fun testStrings() {
val values = arrayOf(
"\"\"",
"\"a\"",
"\"hello world\"",
"\"\\\"\\\\\\/\\b\\f\\n\\r\\t cool\"",
"\"\\u0000\"",
"\"\\u0021\"",
"\"hell\\u24AC\\n\\ro wor \\u0021 ld\"",
"\"\\/_\\\\_\\\"_\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\n\\r\\t`1~!@#\$%^&*()_+-=[]{}|;:',./<>?\"",
)
val values =
arrayOf(
"\"\"",
"\"a\"",
"\"hello world\"",
"\"\\\"\\\\\\/\\b\\f\\n\\r\\t cool\"",
"\"\\u0000\"",
"\"\\u0021\"",
"\"hell\\u24AC\\n\\ro wor \\u0021 ld\"",
"\"\\/_\\\\_\\\"_\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\n\\r\\t`1~!@#\$%^&*()_+-=[]{}|;:',./<>?\"",
)
val parser = JSONParser()
// empty
@@ -189,39 +193,41 @@ class JSONTest {
@Test
fun testUnicode() {
// took from test/unicode_test.json
val data = """
{
"name": "unicode_test",
"testarrayofstring": [
"Цлїςσδε",
"フムアムカモケモ",
"フムヤムカモケモ",
"㊀㊁㊂㊃㊄",
"☳☶☲",
"𡇙𝌆"
],
"testarrayoftables": [
{
"name": "Цлїςσδε"
},
{
"name": "☳☶☲"
},
{
"name": "フムヤムカモケモ"
},
{
"name": "㊀㊁㊂㊃㊄"
},
{
"name": "フムアムカモケモ"
},
{
"name": "𡇙𝌆"
}
]
}
""".trimIndent()
val data =
"""
{
"name": "unicode_test",
"testarrayofstring": [
"Цлїςσδε",
"フムアムカモケモ",
"フムヤムカモケモ",
"㊀㊁㊂㊃㊄",
"☳☶☲",
"𡇙𝌆"
],
"testarrayoftables": [
{
"name": "Цлїςσδε"
},
{
"name": "☳☶☲"
},
{
"name": "フムヤムカモケモ"
},
{
"name": "㊀㊁㊂㊃㊄"
},
{
"name": "フムアムカモケモ"
},
{
"name": "𡇙𝌆"
}
]
}
"""
.trimIndent()
val parser = JSONParser()
val ref = parser.parse(data)
@@ -248,15 +254,16 @@ class JSONTest {
@Test
fun testArrays() {
val values = arrayOf(
"[]",
"[1]",
"[0,1, 2,3 , 4 ]",
"[1.0, 2.2250738585072014E-308, 4.9E-320]",
"[1.0, 2, \"hello world\"] ",
"[ 1.1, 2, [ \"hello\" ] ]",
"[[[1]]]"
)
val values =
arrayOf(
"[]",
"[1]",
"[0,1, 2,3 , 4 ]",
"[1.0, 2.2250738585072014E-308, 4.9E-320]",
"[1.0, 2, \"hello world\"] ",
"[ 1.1, 2, [ \"hello\" ] ]",
"[[[1]]]",
)
val parser = JSONParser()
// empty
@@ -300,47 +307,47 @@ class JSONTest {
}
/**
* Several test cases provided by json.org
* For more details, see: http://json.org/JSON_checker/, with only
* one exception. Single strings are considered accepted, whereas on
* the test suit is should fail.
* Several test cases provided by json.org For more details, see: http://json.org/JSON_checker/,
* with only one exception. Single strings are considered accepted, whereas on the test suit is
* should fail.
*/
@Test
fun testParseMustFail() {
val failList = listOf(
"[\"Unclosed array\"",
"{unquoted_key: \"keys must be quoted\"}",
"[\"extra comma\",]",
"[\"double extra comma\",,]",
"[ , \"<-- missing value\"]",
"[\"Comma after the close\"],",
"[\"Extra close\"]]",
"{\"Extra comma\": true,}",
"{\"Extra value after close\": true} \"misplaced quoted value\"",
"{\"Illegal expression\": 1 + 2}",
"{\"Illegal invocation\": alert()}",
"{\"Numbers cannot have leading zeroes\": 013}",
"{\"Numbers cannot be hex\": 0x14}",
"[\"Illegal backslash escape: \\x15\"]",
"[\\naked]",
"[\"Illegal backslash escape: \\017\"]",
"[[[[[[[[[[[[[[[[[[[[[[[\"Too deep\"]]]]]]]]]]]]]]]]]]]]]]]",
"{\"Missing colon\" null}",
"{\"Double colon\":: null}",
"{\"Comma instead of colon\", null}",
"[\"Colon instead of comma\": false]",
"[\"Bad value\", truth]",
"['single quote']",
"[\"\ttab\tcharacter\tin\tstring\t\"]",
"[\"tab\\ character\\ in\\ string\\ \"]",
"[\"line\nbreak\"]",
"[\"line\\\nbreak\"]",
"[0e]",
"[0e+]",
"[0e+-1]",
"{\"Comma instead if closing brace\": true,",
"[\"mismatch\"}"
)
val failList =
listOf(
"[\"Unclosed array\"",
"{unquoted_key: \"keys must be quoted\"}",
"[\"extra comma\",]",
"[\"double extra comma\",,]",
"[ , \"<-- missing value\"]",
"[\"Comma after the close\"],",
"[\"Extra close\"]]",
"{\"Extra comma\": true,}",
"{\"Extra value after close\": true} \"misplaced quoted value\"",
"{\"Illegal expression\": 1 + 2}",
"{\"Illegal invocation\": alert()}",
"{\"Numbers cannot have leading zeroes\": 013}",
"{\"Numbers cannot be hex\": 0x14}",
"[\"Illegal backslash escape: \\x15\"]",
"[\\naked]",
"[\"Illegal backslash escape: \\017\"]",
"[[[[[[[[[[[[[[[[[[[[[[[\"Too deep\"]]]]]]]]]]]]]]]]]]]]]]]",
"{\"Missing colon\" null}",
"{\"Double colon\":: null}",
"{\"Comma instead of colon\", null}",
"[\"Colon instead of comma\": false]",
"[\"Bad value\", truth]",
"['single quote']",
"[\"\ttab\tcharacter\tin\tstring\t\"]",
"[\"tab\\ character\\ in\\ string\\ \"]",
"[\"line\nbreak\"]",
"[\"line\\\nbreak\"]",
"[0e]",
"[0e+]",
"[0e+-1]",
"{\"Comma instead if closing brace\": true,",
"[\"mismatch\"}",
)
for (data in failList) {
try {
JSONParser().parse(ArrayReadBuffer(data.encodeToByteArray()))
@@ -353,73 +360,74 @@ class JSONTest {
@Test
fun testParseMustPass() {
val passList = listOf(
"[\n" +
" \"JSON Test Pattern pass1\",\n" +
" {\"object with 1 member\":[\"array with 1 element\"]},\n" +
" {},\n" +
" [],\n" +
" -42,\n" +
" true,\n" +
" false,\n" +
" null,\n" +
" {\n" +
" \"integer\": 1234567890,\n" +
" \"real\": -9876.543210,\n" +
" \"e\": 0.123456789e-12,\n" +
" \"E\": 1.234567890E+34,\n" +
" \"\": 23456789012E66,\n" +
" \"zero\": 0,\n" +
" \"one\": 1,\n" +
" \"space\": \" \",\n" +
" \"quote\": \"\\\"\",\n" +
" \"backslash\": \"\\\\\",\n" +
" \"controls\": \"\\b\\f\\n\\r\\t\",\n" +
" \"slash\": \"/ & \\/\",\n" +
" \"alpha\": \"abcdefghijklmnopqrstuvwyz\",\n" +
" \"ALPHA\": \"ABCDEFGHIJKLMNOPQRSTUVWYZ\",\n" +
" \"digit\": \"0123456789\",\n" +
" \"0123456789\": \"digit\",\n" +
" \"special\": \"`1~!@#\$%^&*()_+-={':[,]}|;.</>?\",\n" +
" \"hex\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",\n" +
" \"true\": true,\n" +
" \"false\": false,\n" +
" \"null\": null,\n" +
" \"array\":[ ],\n" +
" \"object\":{ },\n" +
" \"address\": \"50 St. James Street\",\n" +
" \"url\": \"http://www.JSON.org/\",\n" +
" \"comment\": \"// /* <!-- --\",\n" +
" \"# -- --> */\": \" \",\n" +
" \" s p a c e d \" :[1,2 , 3\n" +
"\n" +
",\n" +
"\n" +
"4 , 5 , 6 ,7 ],\"compact\":[1,2,3,4,5,6,7],\n" +
" \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",\n" +
" \"quotes\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",\n" +
" \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#\$%^&*()_+-=[]{}|;:',./<>?\"\n" +
": \"A key can be any string\"\n" +
" },\n" +
" 0.5 ,98.6\n" +
",\n" +
"99.44\n" +
",\n" +
"\n" +
"1066,\n" +
"1e1,\n" +
"0.1e1,\n" +
"1e-1,\n" +
"1e00,2e+00,2e-00\n" +
",\"rosebud\"]",
"{\n" +
" \"JSON Test Pattern pass3\": {\n" +
" \"The outermost value\": \"must be an object or array.\",\n" +
" \"In this test\": \"It is an object.\"\n" +
" }\n" +
"}",
"[[[[[[[[[[[[[[[[[[[\"Not too deep\"]]]]]]]]]]]]]]]]]]]",
)
val passList =
listOf(
"[\n" +
" \"JSON Test Pattern pass1\",\n" +
" {\"object with 1 member\":[\"array with 1 element\"]},\n" +
" {},\n" +
" [],\n" +
" -42,\n" +
" true,\n" +
" false,\n" +
" null,\n" +
" {\n" +
" \"integer\": 1234567890,\n" +
" \"real\": -9876.543210,\n" +
" \"e\": 0.123456789e-12,\n" +
" \"E\": 1.234567890E+34,\n" +
" \"\": 23456789012E66,\n" +
" \"zero\": 0,\n" +
" \"one\": 1,\n" +
" \"space\": \" \",\n" +
" \"quote\": \"\\\"\",\n" +
" \"backslash\": \"\\\\\",\n" +
" \"controls\": \"\\b\\f\\n\\r\\t\",\n" +
" \"slash\": \"/ & \\/\",\n" +
" \"alpha\": \"abcdefghijklmnopqrstuvwyz\",\n" +
" \"ALPHA\": \"ABCDEFGHIJKLMNOPQRSTUVWYZ\",\n" +
" \"digit\": \"0123456789\",\n" +
" \"0123456789\": \"digit\",\n" +
" \"special\": \"`1~!@#\$%^&*()_+-={':[,]}|;.</>?\",\n" +
" \"hex\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",\n" +
" \"true\": true,\n" +
" \"false\": false,\n" +
" \"null\": null,\n" +
" \"array\":[ ],\n" +
" \"object\":{ },\n" +
" \"address\": \"50 St. James Street\",\n" +
" \"url\": \"http://www.JSON.org/\",\n" +
" \"comment\": \"// /* <!-- --\",\n" +
" \"# -- --> */\": \" \",\n" +
" \" s p a c e d \" :[1,2 , 3\n" +
"\n" +
",\n" +
"\n" +
"4 , 5 , 6 ,7 ],\"compact\":[1,2,3,4,5,6,7],\n" +
" \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",\n" +
" \"quotes\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",\n" +
" \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#\$%^&*()_+-=[]{}|;:',./<>?\"\n" +
": \"A key can be any string\"\n" +
" },\n" +
" 0.5 ,98.6\n" +
",\n" +
"99.44\n" +
",\n" +
"\n" +
"1066,\n" +
"1e1,\n" +
"0.1e1,\n" +
"1e-1,\n" +
"1e00,2e+00,2e-00\n" +
",\"rosebud\"]",
"{\n" +
" \"JSON Test Pattern pass3\": {\n" +
" \"The outermost value\": \"must be an object or array.\",\n" +
" \"In this test\": \"It is an object.\"\n" +
" }\n" +
"}",
"[[[[[[[[[[[[[[[[[[[\"Not too deep\"]]]]]]]]]]]]]]]]]]]",
)
for (data in passList) {
JSONParser().parse(ArrayReadBuffer(data.encodeToByteArray()))
}

View File

@@ -17,25 +17,50 @@
package com.google.flatbuffers.kotlin
/**
* This implementation uses Little Endian order.
*/
/** This implementation uses Little Endian order. */
public actual inline fun ByteArray.getUByte(index: Int): UByte = ByteArrayOps.getUByte(this, index)
public actual inline fun ByteArray.getShort(index: Int): Short = ByteArrayOps.getShort(this, index)
public actual inline fun ByteArray.getUShort(index: Int): UShort = ByteArrayOps.getUShort(this, index)
public actual inline fun ByteArray.getInt(index: Int): Int = ByteArrayOps.getInt(this, index)
public actual inline fun ByteArray.getUInt(index: Int): UInt = ByteArrayOps.getUInt(this, index)
public actual inline fun ByteArray.getLong(index: Int): Long = ByteArrayOps.getLong(this, index)
public actual inline fun ByteArray.getULong(index: Int): ULong = ByteArrayOps.getULong(this, index)
public actual inline fun ByteArray.getFloat(index: Int): Float = ByteArrayOps.getFloat(this, index)
public actual inline fun ByteArray.getDouble(index: Int): Double = ByteArrayOps.getDouble(this, index)
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit = ByteArrayOps.setUByte(this, index, value)
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit = ByteArrayOps.setShort(this, index, value)
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit = ByteArrayOps.setUShort(this, index, value)
public actual inline fun ByteArray.setInt(index: Int, value: Int): Unit = ByteArrayOps.setInt(this, index, value)
public actual inline fun ByteArray.setUInt(index: Int, value: UInt): Unit = ByteArrayOps.setUInt(this, index, value)
public actual inline fun ByteArray.setLong(index: Int, value: Long): Unit = ByteArrayOps.setLong(this, index, value)
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit = ByteArrayOps.setULong(this, index, value)
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit = ByteArrayOps.setFloat(this, index, value)
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit = ByteArrayOps.setDouble(this, index, value)
public actual inline fun ByteArray.getShort(index: Int): Short = ByteArrayOps.getShort(this, index)
public actual inline fun ByteArray.getUShort(index: Int): UShort =
ByteArrayOps.getUShort(this, index)
public actual inline fun ByteArray.getInt(index: Int): Int = ByteArrayOps.getInt(this, index)
public actual inline fun ByteArray.getUInt(index: Int): UInt = ByteArrayOps.getUInt(this, index)
public actual inline fun ByteArray.getLong(index: Int): Long = ByteArrayOps.getLong(this, index)
public actual inline fun ByteArray.getULong(index: Int): ULong = ByteArrayOps.getULong(this, index)
public actual inline fun ByteArray.getFloat(index: Int): Float = ByteArrayOps.getFloat(this, index)
public actual inline fun ByteArray.getDouble(index: Int): Double =
ByteArrayOps.getDouble(this, index)
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit =
ByteArrayOps.setUByte(this, index, value)
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit =
ByteArrayOps.setShort(this, index, value)
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit =
ByteArrayOps.setUShort(this, index, value)
public actual inline fun ByteArray.setInt(index: Int, value: Int): Unit =
ByteArrayOps.setInt(this, index, value)
public actual inline fun ByteArray.setUInt(index: Int, value: UInt): Unit =
ByteArrayOps.setUInt(this, index, value)
public actual inline fun ByteArray.setLong(index: Int, value: Long): Unit =
ByteArrayOps.setLong(this, index, value)
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit =
ByteArrayOps.setULong(this, index, value)
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit =
ByteArrayOps.setFloat(this, index, value)
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit =
ByteArrayOps.setDouble(this, index, value)

View File

@@ -19,25 +19,50 @@
package com.google.flatbuffers.kotlin
/**
* This implementation uses Little Endian order.
*/
/** This implementation uses Little Endian order. */
public actual inline fun ByteArray.getUByte(index: Int): UByte = ByteArrayOps.getUByte(this, index)
public actual inline fun ByteArray.getShort(index: Int): Short = ByteArrayOps.getShort(this, index)
public actual inline fun ByteArray.getUShort(index: Int): UShort = ByteArrayOps.getUShort(this, index)
public actual inline fun ByteArray.getInt(index: Int): Int = ByteArrayOps.getInt(this, index)
public actual inline fun ByteArray.getUInt(index: Int): UInt = ByteArrayOps.getUInt(this, index)
public actual inline fun ByteArray.getLong(index: Int): Long = ByteArrayOps.getLong(this, index)
public actual inline fun ByteArray.getULong(index: Int): ULong = ByteArrayOps.getULong(this, index)
public actual inline fun ByteArray.getFloat(index: Int): Float = ByteArrayOps.getFloat(this, index)
public actual inline fun ByteArray.getDouble(index: Int): Double = ByteArrayOps.getDouble(this, index)
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit = ByteArrayOps.setUByte(this, index, value)
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit = ByteArrayOps.setShort(this, index, value)
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit = ByteArrayOps.setUShort(this, index, value)
public actual inline fun ByteArray.setInt(index: Int, value: Int): Unit = ByteArrayOps.setInt(this, index, value)
public actual inline fun ByteArray.setUInt(index: Int, value: UInt): Unit = ByteArrayOps.setUInt(this, index, value)
public actual inline fun ByteArray.setLong(index: Int, value: Long): Unit = ByteArrayOps.setLong(this, index, value)
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit = ByteArrayOps.setULong(this, index, value)
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit = ByteArrayOps.setFloat(this, index, value)
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit = ByteArrayOps.setDouble(this, index, value)
public actual inline fun ByteArray.getShort(index: Int): Short = ByteArrayOps.getShort(this, index)
public actual inline fun ByteArray.getUShort(index: Int): UShort =
ByteArrayOps.getUShort(this, index)
public actual inline fun ByteArray.getInt(index: Int): Int = ByteArrayOps.getInt(this, index)
public actual inline fun ByteArray.getUInt(index: Int): UInt = ByteArrayOps.getUInt(this, index)
public actual inline fun ByteArray.getLong(index: Int): Long = ByteArrayOps.getLong(this, index)
public actual inline fun ByteArray.getULong(index: Int): ULong = ByteArrayOps.getULong(this, index)
public actual inline fun ByteArray.getFloat(index: Int): Float = ByteArrayOps.getFloat(this, index)
public actual inline fun ByteArray.getDouble(index: Int): Double =
ByteArrayOps.getDouble(this, index)
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit =
ByteArrayOps.setUByte(this, index, value)
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit =
ByteArrayOps.setShort(this, index, value)
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit =
ByteArrayOps.setUShort(this, index, value)
public actual inline fun ByteArray.setInt(index: Int, value: Int): Unit =
ByteArrayOps.setInt(this, index, value)
public actual inline fun ByteArray.setUInt(index: Int, value: UInt): Unit =
ByteArrayOps.setUInt(this, index, value)
public actual inline fun ByteArray.setLong(index: Int, value: Long): Unit =
ByteArrayOps.setLong(this, index, value)
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit =
ByteArrayOps.setULong(this, index, value)
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit =
ByteArrayOps.setFloat(this, index, value)
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit =
ByteArrayOps.setDouble(this, index, value)

View File

@@ -15,23 +15,21 @@
*/
package com.google.flatbuffers.kotlin
import org.junit.Test
import kotlin.test.assertEquals
import org.junit.Test
class Utf8Test {
@Test
fun testUtf8EncodingDecoding() {
val classLoader = this.javaClass.classLoader
val utf8Lines = String(classLoader.getResourceAsStream("utf8_sample.txt")!!.readBytes())
.split("\n")
.filter { it.trim().isNotEmpty() }
val utf8Lines =
String(classLoader.getResourceAsStream("utf8_sample.txt")!!.readBytes()).split("\n").filter {
it.trim().isNotEmpty()
}
val utf8Bytes = utf8Lines.map {
s -> ByteArray(Utf8.encodedLength(s)).also {
Utf8.encodeUtf8Array(s, it)
}
}
val utf8Bytes =
utf8Lines.map { s -> ByteArray(Utf8.encodedLength(s)).also { Utf8.encodeUtf8Array(s, it) } }
utf8Bytes.indices.forEach {
assertArrayEquals(utf8Lines[it].encodeToByteArray(), utf8Bytes[it])
assertEquals(utf8Lines[it], Utf8.decodeUtf8Array(utf8Bytes[it]))

View File

@@ -18,25 +18,47 @@
package com.google.flatbuffers.kotlin
/**
* This implementation assumes that of native macOSX64 the byte order of the implementation is Little Endian.
* This implementation assumes that of native macOSX64 the byte order of the implementation is
* Little Endian.
*/
public actual inline fun ByteArray.getUByte(index: Int): UByte = getUByteAt(index)
public actual inline fun ByteArray.getShort(index: Int): Short = getShortAt(index)
public actual inline fun ByteArray.getUShort(index: Int): UShort = getUShortAt(index)
public actual inline fun ByteArray.getInt(index: Int): Int = getIntAt(index)
public actual inline fun ByteArray.getUInt(index: Int): UInt = getUIntAt(index)
public actual inline fun ByteArray.getLong(index: Int): Long = getLongAt(index)
public actual inline fun ByteArray.getULong(index: Int): ULong = getULongAt(index)
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit = setUByteAt(index, value)
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit = setShortAt(index, value)
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit = setUShortAt(index, value)
public actual inline fun ByteArray.setUByte(index: Int, value: UByte): Unit =
setUByteAt(index, value)
public actual inline fun ByteArray.setShort(index: Int, value: Short): Unit =
setShortAt(index, value)
public actual inline fun ByteArray.setUShort(index: Int, value: UShort): Unit =
setUShortAt(index, value)
public actual inline fun ByteArray.setInt(index: Int, value: Int): Unit = setIntAt(index, value)
public actual inline fun ByteArray.setUInt(index: Int, value: UInt): Unit = setUIntAt(index, value)
public actual inline fun ByteArray.setLong(index: Int, value: Long): Unit = setLongAt(index, value)
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit = setULongAt(index, value)
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit = setFloatAt(index, value)
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit = setDoubleAt(index, value)
public actual inline fun ByteArray.setULong(index: Int, value: ULong): Unit =
setULongAt(index, value)
public actual inline fun ByteArray.setFloat(index: Int, value: Float): Unit =
setFloatAt(index, value)
public actual inline fun ByteArray.setDouble(index: Int, value: Double): Unit =
setDoubleAt(index, value)
public actual inline fun ByteArray.getFloat(index: Int): Float = Float.fromBits(getIntAt(index))
public actual inline fun ByteArray.getDouble(index: Int): Double = Double.fromBits(getLongAt(index))

View File

@@ -1,4 +1,7 @@
rootProject.name = "flatbuffers-kotlin"
includeBuild("convention-plugins")
include("flatbuffers-kotlin")
include("benchmark")