Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
99fa4da
Build: upgrade to Kotlin 2.1.0, datetime 0.6.1, and Gradle 8.11.1
Whathecode Dec 14, 2024
30066e4
Fix: prevent size overflows
Whathecode Dec 22, 2024
bfe429d
Fix/add native targets
Whathecode Dec 22, 2024
9f80b3f
Fix: publish error/rollback to Kotlin 2.0.0 for now
Whathecode Dec 22, 2024
590aef0
Fix: `EmptyIntervalUnion.contains` failed
Whathecode Dec 14, 2024
cf75389
Refactor: move `IntervalTypeOperations` tests
Whathecode Jan 1, 2025
aa06815
Fix: make `unsafeValueAt` positive for signed types
Whathecode Dec 26, 2024
eb191c1
Change distance calc. in `IntervalTypeOperations`
Whathecode Dec 24, 2024
4b7af38
Refactor: move test verifying TSize range
Whathecode Jan 3, 2025
9065f72
Add `IntervalTypeOperations.unsafeShift`
Whathecode Dec 25, 2024
43218a4
Add `IntervalUnion.shift`
Whathecode Dec 22, 2024
92c1413
Build: bump to version 2.0.0
Whathecode Dec 24, 2024
3e7a02e
Add shift infex operators
Whathecode Jan 4, 2025
a28b123
Fix: shift intervals of imprecise types long distances
Whathecode Jan 6, 2025
ce35819
Add from/to double conversion to `TypeOperations`
Whathecode Jan 8, 2025
331b0da
Build: use parameter to publish snapshot version
Whathecode Jan 12, 2025
cae6091
Build: upgrade to Kotlin 2.1.0
Whathecode Jan 12, 2025
74264f6
Build: upgrade to Kotlin 2.1.20 and dokka 2.0.0
Whathecode May 10, 2025
8855037
Fix: publish to local Maven repository for testing output
Whathecode May 11, 2025
3e40be5
Build: Upgrade to dokka 2.0.0, and new V2 gradle plugin
Whathecode May 11, 2025
774542d
Fix: `Uint` and `ULong.fromDouble()` operations did not round
Whathecode May 27, 2025
fc39bc9
Add `Interval.getValueAt()`
Whathecode May 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/publish-snapshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

jobs:
publish:
runs-on: ubuntu-latest
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -24,4 +24,4 @@ jobs:

- name: Publish snapshot
if: success()
run: ./gradlew setSnapshotVersion publishToSonatype closeAndReleaseSonatypeStagingRepository
run: ./gradlew -Psnapshot publishToSonatype closeAndReleaseSonatypeStagingRepository
13 changes: 11 additions & 2 deletions .github/workflows/pull-requests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@ on:

jobs:
unit-tests-pass:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- test: jvmTest jsTest linuxX64Test
os: ubuntu-latest
- test: macosX64Test macosArm64Test iosSimulatorArm64Test iosX64Test
os: macos-latest
- test: mingwX64Test
os: windows-latest
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -19,4 +28,4 @@ jobs:
uses: gradle/[email protected]

- name: Build and test
run: ./gradlew check
run: ./gradlew ${{ matrix.test }}
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

jobs:
release:
runs-on: ubuntu-latest
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ val interval: IntInterval = interval( 0, 10, isEndIncluded = false )
val areIncluded = 0 in interval && 5 in interval // true
val areExcluded = 10 !in interval && 15 !in interval // true
val size: UInt = interval.size // 10
val shifted = interval shr 10u // Shifted right by 10: [10, 20)
```

This protects against overflows (e.g. if `size > Int.MAX_VALUE`) but also offers better semantics.
Expand All @@ -24,6 +25,7 @@ val now = Clock.System.now()
val interval: InstantInterval = interval( now, now + 100.seconds )
val areIncluded = now + 50.seconds in interval // true
val size: Duration = interval.size // 100 seconds
val shifted = interval shr 24.hours // 100 seconds 24 hours from now
```

## Interval Unions
Expand All @@ -36,6 +38,7 @@ Since operations are generally defined on the base interface, you can easily cha
val start = interval( 0, 100 ) // Interval: [0, 100]
val areIncluded = 50 in start && 100 in start // true
val splitInTwo = start - interval( 25, 85 ) // Union: [[0, 25), (85, 100]]
val shiftBackAndForth = splitInTwo shr 100u shl 100u // == splitInTwo
val areExcluded = 50 !in splitInTwo && 85 !in splitInTwo // true
val unite = splitInTwo + interval( 10, 90 ) // Interval: [0, 100]
val backToStart = start == unite // true
Expand Down Expand Up @@ -63,17 +66,18 @@ Instead, new instances are returned if the operation results in a different set

The following operations are available for any `IntervalUnion<T, TSize>`:

| Operation | Description |
|:-------------------:|:--------------------------------------------------------------------------------------------:|
| `isEmpty()` | Determines whether this is an empty set. |
| `getBounds()` | Gets the upper and lower bound of the set. |
| `contains()` (`in`) | Determines whether a value lies in the set. |
| `minus()` (`-`) | Subtract an interval from the set. |
| `plus()` (`+`) | Add an interval from the set. |
| `intersects()` | Determines whether another interval intersects with this set. |
| `setEquals()` | Determines whether a set represents the same values. |
| `iterator()` | Iterate over all intervals in the union, in order. |
| `toString()` | Output as a string using common interval notation, e.g., `[0, 10]` or `[[0, 10), (10, 20]]`. |
| Operation | Description |
|:-----------------------:|:--------------------------------------------------------------------------------------------:|
| `isEmpty()` | Determines whether this is an empty set. |
| `getBounds()` | Gets the upper and lower bound of the set. |
| `contains()` (`in`) | Determines whether a value lies in the set. |
| `minus()` (`-`) | Subtract an interval from the set. |
| `plus()` (`+`) | Add an interval to the set. |
| `shift()` (`shl`/`shr`) | Move the interval by a specified offset. |
| `intersects()` | Determines whether another interval intersects with this set. |
| `setEquals()` | Determines whether a set represents the same values. |
| `iterator()` | Iterate over all intervals in the union, in order. |
| `toString()` | Output as a string using common interval notation, e.g., `[0, 10]` or `[[0, 10), (10, 20]]`. |

The following operations are specific to `Interval<T, TSize>`:

Expand All @@ -87,6 +91,7 @@ The following operations are specific to `Interval<T, TSize>`:
| `lowerBound`, `upperBound` | Corresponds to `start` and `end`, but swapped if `isReversed`. |
| `isLowerBoundIncluded`, `isUpperBoundIncluded` | Corresponds to `isStartIncluded` and `isEndIncluded`, but swapped if `isReversed`. |
| `size` | The absolute difference between `start` and `end`. |
| `getValueAt()` | Get the value at a given percentage inside (0.0–1.0) or outside (< 0.0, > 1.0) the interval. |
| `nonReversed()` | `reverse()` the interval in case it `isReversed`. |
| `reverse()` | Return an interval which swaps `start` with `end`, as well as boundary inclusions. |
| `canonicalize()` | Return the interval in canonical form. E.g., The canonical form of `[5, 1)` is `[2, 5]` for integer types. |
Expand Down
4 changes: 2 additions & 2 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ repositories {
}

dependencies {
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.0")
implementation("org.jetbrains.dokka:dokka-gradle-plugin:1.9.20")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.20")
implementation("org.jetbrains.dokka:dokka-gradle-plugin:2.0.0")
}
43 changes: 21 additions & 22 deletions build-logic/src/main/kotlin/interval.library-conventions.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import java.io.FileInputStream
import java.util.Properties
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.dokka.gradle.engine.parameters.KotlinPlatform
import org.jetbrains.dokka.gradle.internal.InternalDokkaGradlePluginApi
import org.jetbrains.dokka.gradle.tasks.DokkaGenerateTask
import org.jetbrains.kotlin.gradle.dsl.JvmTarget


Expand All @@ -20,7 +20,6 @@ repositories {

kotlin {
jvm {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget = JvmTarget.JVM_1_8
}
Expand All @@ -34,14 +33,15 @@ kotlin {
}
binaries.executable()
}
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
val nativeTarget = when {
hostOs == "Mac OS X" -> macosX64("native")
hostOs == "Linux" -> linuxX64("native")
isMingwX64 -> mingwX64("native")
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
}
linuxX64()

macosX64()
macosArm64()
iosSimulatorArm64()
iosX64()
iosArm64()

mingwX64()


sourceSets {
Expand All @@ -51,30 +51,29 @@ kotlin {
implementation(kotlin("test"))
}
}
val jvmMain by getting
val jvmTest by getting
val jsMain by getting
val jsTest by getting
val nativeMain by getting
val nativeTest by getting
}
}


// Documentation.
val dokkaJvmJavadoc by tasks.creating(DokkaTask::class) {
dokka {
dokkaSourceSets {
register("jvm") {
platform.set(Platform.jvm)
analysisPlatform.set(KotlinPlatform.JVM)
sourceRoots.from(kotlin.sourceSets.getByName("jvmMain").kotlin.srcDirs)
}
}
}
tasks.withType<DokkaGenerateTask>().configureEach {
// HACK: Dokka 2.0.0 exposes this debug file by default (https://github.com/Kotlin/dokka/issues/3958)
@OptIn( InternalDokkaGradlePluginApi::class )
dokkaConfigurationJsonFile.convention( null as RegularFile? )
}
val javadocJar by tasks.creating(Jar::class) {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Create javadoc jar using Dokka"
archiveClassifier.set("javadoc")
from(dokkaJvmJavadoc)
from(tasks.dokkaGeneratePublicationHtml)
}


Expand All @@ -88,7 +87,7 @@ publishing {
repositories {
maven {
name = "local"
url = uri("${layout.buildDirectory}/repo")
url = uri("${layout.projectDirectory}/build/repository")
}
}
publications.filterIsInstance<MavenPublication>().forEach {
Expand Down
18 changes: 8 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ if (publishPropertiesFile.exists()) {
publishProperties.load(java.io.FileInputStream(publishPropertiesFile))
}
group = "io.github.whathecode.kotlinx.interval"
version = "1.0.1"
version = "2.0.0"
if (properties.containsKey("snapshot"))
{
val versionSplit = version.toString().split("-")
val snapshotVersion = "${versionSplit[0]}-SNAPSHOT"
version = snapshotVersion
rootProject.subprojects.forEach { it.version = snapshotVersion }
}
nexusPublishing {
repositories {
sonatype {
Expand All @@ -32,12 +39,3 @@ nexusPublishing {
}
}
}
val setSnapshotVersion: Task by tasks.creating {
doFirst {
val versionSplit = version.toString().split("-")
val snapshotVersion = "${versionSplit[0]}-SNAPSHOT"
version = snapshotVersion

rootProject.subprojects.forEach { it.version = snapshotVersion }
}
}
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
kotlin.mpp.applyDefaultHierarchyTemplate=false
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true

# Prevent out of memory errors.
org.gradle.jvmargs=-XX:MaxMetaspaceSize=1024m
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading