Skip to content

Commit

Permalink
Merge branch 'release/1.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
tunjid committed Oct 16, 2024
2 parents e505b5c + f310d17 commit 03a2483
Show file tree
Hide file tree
Showing 35 changed files with 632 additions and 87 deletions.
2 changes: 1 addition & 1 deletion benchmarks/benchmarkable/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {


kotlin {
jvmToolchain(11)
jvmToolchain(17)
}
android {
namespace = "com.example.benchmarks"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.example.benchmarks.data

const val PAGE_TO_SCROLL_TO = 10
const val PAGE_TO_SCROLL_TO = 20
const val ITEMS_PER_PAGE = 100

internal const val NUM_PAGES_IN_MEMORY = 3
internal const val MAX_LOAD_SIZE = NUM_PAGES_IN_MEMORY * ITEMS_PER_PAGE

@Suppress("EmptyRange")
val emptyPages = 0 until 0
val onScreenPages = ((PAGE_TO_SCROLL_TO + 1) - NUM_PAGES_IN_MEMORY)..PAGE_TO_SCROLL_TO
val onScreenPages = (PAGE_TO_SCROLL_TO - NUM_PAGES_IN_MEMORY)..PAGE_TO_SCROLL_TO
val offScreenPages = (onScreenPages.first - NUM_PAGES_IN_MEMORY) until onScreenPages.first

sealed interface Benchmarked {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.benchmarks.data

import android.annotation.SuppressLint
import androidx.paging.CombinedLoadStates
import androidx.paging.DifferCallback
import androidx.paging.LoadState
Expand All @@ -12,11 +13,8 @@ import androidx.paging.PagingSource
import androidx.paging.PagingState
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.transformWhile
import kotlinx.coroutines.launch
import kotlin.math.max

private val pagingConfig = PagingConfig(
pageSize = ITEMS_PER_PAGE,
Expand All @@ -30,8 +28,9 @@ class PagingBenchmark(
private val pagesToInvalidate: IntRange
) : Benchmarked {

private var lastInvalidatedPage: Int = Int.MIN_VALUE
private var lastInvalidatedPage: Int = pagesToInvalidate.first + 1

@SuppressLint("RestrictedApi")
override suspend fun benchmark() = coroutineScope {
val differ = pagingDataDiffer()
val collectJob = launch {
Expand All @@ -50,7 +49,6 @@ class PagingBenchmark(
// When items are delivered, read them
.onPagesUpdatedFlow
.transformWhile {
differ.loadStateFlow
if (!differ.loadStateFlow.value.isIdle()) return@transformWhile true
val latestItems = differ.snapshot().items

Expand All @@ -64,29 +62,42 @@ class PagingBenchmark(
return@transformWhile true
}

emit(latestItems)
// Currently at the page scrolled to. If there's nothing to invalidate, complete
if (pagesToInvalidate.isEmpty()) return@transformWhile false

// Find an item from the page that was invalidated
val invalidatedItem = latestItems.lastInvalidatedItem()

val isFinished = invalidatedItem != null
&& invalidatedItem.lastInvalidatedPage >= pagesToInvalidate.last

val isFinished = pagesToInvalidate.isEmpty() ||
lastItem.lastInvalidatedPage >= pagesToInvalidate.last
emit(latestItems)

!isFinished
}
.collect {
// Account for start
lastInvalidatedPage = max(
a = lastInvalidatedPage,
b = pagesToInvalidate.first - 1
)
if (lastInvalidatedPage < pagesToInvalidate.last) {
++lastInvalidatedPage
// Invalidate
val invalidatedItem = it.lastInvalidatedItem()
val canIncrementAndInvalidate = invalidatedItem == null
|| invalidatedItem.lastInvalidatedPage == lastInvalidatedPage

if (canIncrementAndInvalidate && ++lastInvalidatedPage <= pagesToInvalidate.last) {
differ.refresh()
}
}

collectJob.cancel()
}

private fun List<Item>.lastInvalidatedItem(): Item? {
for (item in this) {
if (item.lastInvalidatedPage == lastInvalidatedPage) return item
}
return null
}
}

@SuppressLint("RestrictedApi")
private fun pagingDataDiffer() = object : PagingDataDiffer<Item>(
differCallback = object : DifferCallback {
override fun onChanged(position: Int, count: Int) = Unit
Expand Down Expand Up @@ -151,11 +162,3 @@ private fun LoadStates.isIdle(): Boolean {
prepend is LoadState.NotLoading
}

abstract class M<T> {
abstract val initial: T

private var seed: T = initial

val flow = flowOf(seed)
.onEach { seed = it }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.example.benchmarks.data

import com.tunjid.tiler.PivotRequest
import com.tunjid.tiler.Tile
import com.tunjid.tiler.TiledList
import com.tunjid.tiler.listTiler
import com.tunjid.tiler.queries
import com.tunjid.tiler.toPivotedTileInputs
import com.tunjid.tiler.toTiledList
import kotlinx.coroutines.flow.Flow
Expand All @@ -28,7 +30,7 @@ class TilingBenchmark(
private val pagesToInvalidate: IntRange
) : Benchmarked {

private var lastInvalidatedPage: Int = pagesToInvalidate.first - 1
private var lastInvalidatedPage: Int = pagesToInvalidate.first + 1

override suspend fun benchmark() {
val offsetFlow = MutableSharedFlow<Int>()
Expand All @@ -52,45 +54,48 @@ class TilingBenchmark(
return@transformWhile true
}

// Currently at the page scrolled to. If there's nothing to invalidate, complete
if (pagesToInvalidate.isEmpty()) return@transformWhile false

// ** Invalidation code ** //

// Outside the range, nothing to invalidate so terminate
// Outside the visible range, nothing to invalidate so terminate
if (pagesToInvalidate.first > lastPage) return@transformWhile false
if (pagesToInvalidate.last < firstPage) return@transformWhile false

// Final page invalidated, terminate
val invalidatedPage = latestItems.itemAtPage(lastPage)
println(latestItems.queries())
// Find an item from the page that was invalidated
val invalidatedItem = latestItems.lastInvalidatedItem()

val isFinished = invalidatedPage != null
&& invalidatedPage.lastInvalidatedPage >= pagesToInvalidate.last
val isFinished = invalidatedItem != null
&& invalidatedItem.lastInvalidatedPage >= pagesToInvalidate.last

emit(latestItems)
!isFinished
}
.collect {
// Invalidate
if (++lastInvalidatedPage <= pagesToInvalidate.last) {
val invalidatedItem = it.lastInvalidatedItem()
val canIncrementAndInvalidate = invalidatedItem == null
|| invalidatedItem.lastInvalidatedPage == lastInvalidatedPage

if (canIncrementAndInvalidate && ++lastInvalidatedPage <= pagesToInvalidate.last) {
invalidationSignal.emit(lastInvalidatedPage)
}
}
}
}

private fun List<Item>.itemAtPage(page: Int): Item? {
val startPage = pageFor(first())
val endPage = pageFor(last())
if (page !in startPage..endPage) return null
val diff = page - startPage
val index = diff * ITEMS_PER_PAGE
return get(index)
private fun TiledList<Int, Item>.lastInvalidatedItem(): Item? {
for (item in this) {
if (item.lastInvalidatedPage == lastInvalidatedPage) return item
}
return null
}
}

private fun Flow<Int>.listTiler() = listTiler(
limiter = Tile.Limiter(
maxQueries = NUM_PAGES_IN_MEMORY,
itemSizeHint = ITEMS_PER_PAGE,
),
order = Tile.Order.PivotSorted(
query = 0,
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/microbenchmark/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
}

kotlin {
jvmToolchain(11)
jvmToolchain(17)
}
android {
namespace = "com.example.microbenchmark"
Expand Down
1 change: 1 addition & 0 deletions build-logic/convention/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ dependencies {
implementation(libs.jetbrains.compose.gradlePlugin)
implementation(libs.kotlin.gradlePlugin)
implementation(libs.android.gradlePlugin)
implementation(libs.compose.compiler.plugin)
implementation(libs.dokka.gradlePlugin)
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import org.gradle.api.artifacts.VersionCatalogsExtension
* Sets common values for Android Applications and Libraries
*/
fun org.gradle.api.Project.androidConfiguration(
extension: CommonExtension<*, *, *, *>
extension: CommonExtension<*, *, *, *, *, *>
) = extension.apply {
namespace = "com.tunjid.tiler.${project.name}"
compileSdk = 34
Expand All @@ -51,13 +51,6 @@ fun org.gradle.api.Project.androidConfiguration(
buildFeatures {
compose = true
}
composeOptions {
val composeCompilerVersion = versionCatalog
.findVersion("androidxComposeCompiler")
.get()
.requiredVersion
kotlinCompilerExtensionVersion = composeCompilerVersion
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.androidx.benchmark) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.jetbrains.compose) apply false
alias(libs.plugins.jetbrains.dokka) apply false
alias(libs.plugins.kotlin.android) apply false
Expand Down
Binary file modified docs/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ android.useAndroidX=true
kotlin.code.style=official
org.jetbrains.compose.experimental.jscanvas.enabled=true
kotlin.mpp.androidSourceSetLayoutVersion=2
xcodeproj=~/sample/ios

41 changes: 21 additions & 20 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
[versions]
androidGradlePlugin = "8.0.2"
androidxActivity = "1.8.2"
androidxAppCompat = "1.6.1"
androidxBenchmark = "1.2.3"
androidxCore = "1.12.0"
androidxCompose = "1.6.1"
androidxComposeCompiler = "1.5.8"
androidxPaging = "3.2.1"
androidxTestCore = "1.5.0"
androidxTestExt = "1.1.5"
androidxTestRunner = "1.5.2"
androidxTestRules = "1.5.0"
dokka = "1.8.10"
jetbrainsCompose = "1.6.0-rc01"
androidGradlePlugin = "8.6.1"
androidxActivity = "1.9.2"
androidxAppCompat = "1.7.0"
androidxBenchmark = "1.2.4"
androidxCore = "1.13.1"
androidxCompose = "1.7.0"
androidxPaging = "3.3.2"
androidxTestCore = "1.6.1"
androidxTestExt = "1.2.1"
androidxTestRunner = "1.6.2"
androidxTestRules = "1.6.1"
dokka = "1.8.20"
jetbrainsCompose = "1.7.0-rc01"
junit4 = "4.13.2"
kotlin = "1.9.22"
kotlinxCoroutines = "1.7.3"
googleMaterial = "1.11.0"
tunjidMutator = "0.0.9"
tunjidTreeNav = "0.0.6"
turbine = "0.12.1"
kotlin = "2.0.21"
kotlinxCoroutines = "1.9.0"
googleMaterial = "1.12.0"
tunjidMutator = "1.1.0"
tunjidTreeNav = "0.0.8"
turbine = "1.1.0"

[libraries]
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
Expand All @@ -45,6 +44,7 @@ androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref
androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "androidxTestRules" }
androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidxTestRunner" }
cashapp-turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbine" }
compose-compiler-plugin = { group = "org.jetbrains.kotlin", name = "compose-compiler-gradle-plugin", version.ref = "kotlin" }
google-material = { group = "com.google.android.material", name = "material", version.ref = "googleMaterial" }
jetbrains-compose-animation = { group = "org.jetbrains.compose.animation", name = "animation", version.ref = "jetbrainsCompose" }
jetbrains-compose-foundation = { group = "org.jetbrains.compose.foundation", name = "foundation", version.ref = "jetbrainsCompose" }
Expand Down Expand Up @@ -74,6 +74,7 @@ tunjid-treenav-common = { group = "com.tunjid.treenav", name = "treenav", versio
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }
androidx-benchmark = { id = "androidx.benchmark", version.ref = "androidxBenchmark" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#Mon Jul 05 07:23:39 EDT 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
12 changes: 12 additions & 0 deletions library/compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ plugins {
signing
id("org.jetbrains.dokka")
id("org.jetbrains.compose")
alias(libs.plugins.compose.compiler)
}

kotlin {
applyDefaultHierarchyTemplate()
js(IR) {
nodejs()
browser()
Expand All @@ -35,6 +37,16 @@ kotlin {
useJUnit()
}
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64(),
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "tiler-compose"
isStatic = true
}
}

sourceSets {
commonMain {
Expand Down
13 changes: 11 additions & 2 deletions library/tiler/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ plugins {
}

kotlin {
applyDefaultHierarchyTemplate()
js(IR) {
nodejs()
browser()
Expand All @@ -34,8 +35,16 @@ kotlin {
useJUnit()
}
}
applyDefaultHierarchyTemplate()
iosSimulatorArm64()
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64(),
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "tiler"
isStatic = true
}
}
linuxX64()
macosX64()
macosArm64()
Expand Down
Loading

0 comments on commit 03a2483

Please sign in to comment.