Add EfficientIterables.md documentation for Kotlin interop. Optimize ObjInt operations by integrating value caching and updating number operations. Introduce high-performance enumerate method for ObjList, ObjSet, ObjRange, and custom iterables. Update compiler and loop handling for improved enumeration logic.
This commit is contained in:
1 parent
5f3a54d08f
commit
3f235878c0
12 files changed
+220
-77
No files matched your search
+1
-1
@@ -12,7 +12,7 @@ Is a [Iterable] with known `size`, a finite [Iterable]:
|
||||
(1)
|
||||
: `comparator(a,b)` should return -1 if `a < b`, +1 if `a > b` or zero.
|
||||
|
||||
See [List], [Set] and [Iterable]
|
||||
See [List], [Set], [Iterable] and [Efficient Iterables in Kotlin Interop](EfficientIterables.md)
|
||||
|
||||
[Iterable]: Iterable.md
|
||||
[List]: List.md
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# Efficient Iterables in Kotlin Interop
|
||||
|
||||
Lyng provides high-performance iteration mechanisms that allow Kotlin-side code to interact with Lyng iterables efficiently and vice versa.
|
||||
|
||||
## 1. Enumerating Lyng Objects from Kotlin
|
||||
|
||||
To iterate over a Lyng object (like a `List`, `Set`, or `Range`) from Kotlin code, use the virtual `enumerate` method:
|
||||
|
||||
```kotlin
|
||||
val lyngList: Obj = ...
|
||||
lyngList.enumerate(scope) { item ->
|
||||
println("Processing $item")
|
||||
true // return true to continue, false to break
|
||||
}
|
||||
```
|
||||
|
||||
### Why it's efficient:
|
||||
- **Zero allocation**: Unlike traditional iterators, it doesn't create a `LyngIterator` object or any intermediate wrappers.
|
||||
- **Direct access**: Subclasses like `ObjList` override `enumerate` to iterate directly over their internal Kotlin collections.
|
||||
- **Reduced overhead**: It avoids multiple `invokeInstanceMethod` calls for `hasNext()` and `next()` on every step, which would normally involve dynamic dispatch and scope overhead.
|
||||
|
||||
## 2. Reactive Enumeration with Flow
|
||||
|
||||
If you prefer a reactive approach or need to integrate with Kotlin Coroutines flows, use `toFlow()`:
|
||||
|
||||
```kotlin
|
||||
lyngList.toFlow(scope).collect { item ->
|
||||
// ...
|
||||
}
|
||||
```
|
||||
*Note: `toFlow()` internally uses the Lyng iterator protocol (`iterator()`, `hasNext()`, `next()`), so it's slightly less efficient than `enumerate()` for performance-critical loops, but more idiomatic for flow-based processing.*
|
||||
|
||||
## 3. Creating Efficient Iterables for Lyng in Kotlin
|
||||
|
||||
When implementing a custom object in Kotlin that should be iterable in Lyng (e.g., usable in `for (x in myObj) { ... }`), follow these steps to ensure maximum performance.
|
||||
|
||||
### A. Inherit from `Obj` and use `ObjIterable`
|
||||
Ensure your object's class has `ObjIterable` as a parent so the Lyng compiler recognizes it as an iterable.
|
||||
|
||||
```kotlin
|
||||
class MyCollection(val items: List<Obj>) : Obj() {
|
||||
override val objClass = MyCollection.type
|
||||
|
||||
companion object {
|
||||
val type = ObjClass("MyCollection", ObjIterable).apply {
|
||||
// Provide a Lyng-side iterator for compatibility with
|
||||
// manual iterator usage in Lyng scripts.
|
||||
// Using ObjKotlinObjIterator if items are already Obj instances:
|
||||
addFn("iterator") {
|
||||
ObjKotlinObjIterator(thisAs<MyCollection>().items.iterator())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### B. Override `enumerate` for Maximum Performance
|
||||
The Lyng compiler's `for` loops use the `enumerate` method. By overriding it in your Kotlin class, you provide a "fast path" for iteration.
|
||||
|
||||
```kotlin
|
||||
class MyCollection(val items: List<Obj>) : Obj() {
|
||||
// ...
|
||||
override suspend fun enumerate(scope: Scope, callback: suspend (Obj) -> Boolean) {
|
||||
for (item in items) {
|
||||
// If callback returns false, it means 'break' was called in Lyng
|
||||
if (!callback(item)) break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### C. Use `ObjInt.of()` for Numeric Data
|
||||
If your iterable contains integers, always use `ObjInt.of(Long)` instead of the `ObjInt(Long)` constructor. Lyng maintains a cache for small integers (-128 to 127), which significantly reduces object allocations and GC pressure during tight loops.
|
||||
|
||||
```kotlin
|
||||
// Efficiently creating an integer object
|
||||
val obj = ObjInt.of(42L)
|
||||
|
||||
// Or using extension methods which also use the cache:
|
||||
val obj2 = 42.toObj()
|
||||
val obj3 = 42L.toObj()
|
||||
```
|
||||
|
||||
#### Note on `toObj()` extensions:
|
||||
While `<reified T> T.toObj()` is convenient, using specific extensions like `Int.toObj()` or `Long.toObj()` is slightly more efficient as they use the `ObjInt` cache.
|
||||
|
||||
## 4. Summary of Best Practices
|
||||
|
||||
- **To Consume**: Use `enumerate(scope) { item -> ... true }`.
|
||||
- **To Implement**: Override `enumerate` in your `Obj` subclass.
|
||||
- **To Register**: Use `ObjIterable` (or `ObjCollection`) as a parent class in your `ObjClass` definition.
|
||||
- **To Optimize**: Use `ObjInt.of()` (or `.toObj()`) for all integer object allocations.
|
||||
@@ -142,6 +142,8 @@ optional function applied to each item that must return result string for an ite
|
||||
|
||||
fun iterator(): Iterator
|
||||
|
||||
For high-performance Kotlin-side interop and custom iterable implementation details, see [Efficient Iterables in Kotlin Interop](EfficientIterables.md).
|
||||
|
||||
## Included in interfaces:
|
||||
|
||||
- [Collection], Array, [List]
|
||||
|
||||
@@ -23,6 +23,8 @@ must throw `ObjIterationFinishedError`.
|
||||
|
||||
Iterators are returned when implementing [Iterable] interface.
|
||||
|
||||
For high-performance Kotlin-side interop and custom iterable implementation details, see [Efficient Iterables in Kotlin Interop](EfficientIterables.md).
|
||||
|
||||
## Implemented for classes:
|
||||
|
||||
- [List], [Range]
|
||||
|
||||
Reference in new issue
Block a user