refs #35 Buffer is not mutable, MutableBuffer added (to cache in serialized form)
This commit is contained in:
parent
f3d766d1b1
commit
7aee25ffef
@ -1,7 +1,8 @@
|
|||||||
# Binary `Buffer`
|
# Binary `Buffer`
|
||||||
|
|
||||||
Buffers are effective unsigned byte arrays of fixed size. Buffers content is mutable,
|
Buffers are effective unsigned byte arrays of fixed size. Buffers content is mutable,
|
||||||
unlike its size. Buffers are comparable and implement [Array], thus [Collection] and [Iterable]. Buffer iterators return its contents as unsigned bytes converted to `Int`
|
unlike its size. Buffers are comparable and implement [Array], thus [Collection] and [Iterable]. Buffer iterators return
|
||||||
|
its contents as unsigned bytes converted to `Int`
|
||||||
|
|
||||||
Buffers needs to be imported with `import lyng.buffer`:
|
Buffers needs to be imported with `import lyng.buffer`:
|
||||||
|
|
||||||
@ -10,6 +11,8 @@ Buffers needs to be imported with `import lyng.buffer`:
|
|||||||
assertEquals(5, Buffer("Hello").size)
|
assertEquals(5, Buffer("Hello").size)
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
|
Buffer is _immutable_, there is a `MutableBuffer` with same interface but mutable.
|
||||||
|
|
||||||
## Constructing
|
## Constructing
|
||||||
|
|
||||||
There are a lo of ways to construct a buffer:
|
There are a lo of ways to construct a buffer:
|
||||||
@ -36,15 +39,23 @@ There are a lo of ways to construct a buffer:
|
|||||||
|
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
## Accessing an modifying
|
## Accessing and modifying
|
||||||
|
|
||||||
Buffer implement [Array] and therefore can be accessed and modified with indexing:
|
Buffer implement [Array] and therefore can be accessed, and `MutableBuffers` also modified:
|
||||||
|
|
||||||
import lyng.buffer
|
import lyng.buffer
|
||||||
val b1 = Buffer( 1, 2, 3)
|
val b1 = Buffer( 1, 2, 3)
|
||||||
assertEquals( 2, b1[1] )
|
assertEquals( 2, b1[1] )
|
||||||
b1[0] = 199
|
|
||||||
assertEquals(199, b1[0])
|
val b2 = b1.toMutable()
|
||||||
|
assertEquals( 2, b1[1] )
|
||||||
|
b2[1]++
|
||||||
|
b2[0] = 100
|
||||||
|
assertEquals( Buffer(100, 3, 3), b2)
|
||||||
|
|
||||||
|
// b2 is a mutable copy so b1 has not been changed:
|
||||||
|
assertEquals( Buffer(1, 2, 3), b1)
|
||||||
|
|
||||||
>>> void
|
>>> void
|
||||||
|
|
||||||
Buffer provides concatenation with another Buffer:
|
Buffer provides concatenation with another Buffer:
|
||||||
@ -58,12 +69,12 @@ Please note that indexed bytes are _readonly projection_, e.g. you can't modify
|
|||||||
|
|
||||||
## Comparing
|
## Comparing
|
||||||
|
|
||||||
Buffers are comparable with other buffers:
|
Buffers are comparable with other buffers (and notice there are _mutable_ buffers, bu default buffers ar _immutable_):
|
||||||
|
|
||||||
import lyng.buffer
|
import lyng.buffer
|
||||||
val b1 = Buffer(1, 2, 3)
|
val b1 = Buffer(1, 2, 3)
|
||||||
val b2 = Buffer(1, 2, 3)
|
val b2 = Buffer(1, 2, 3)
|
||||||
val b3 = Buffer(b2)
|
val b3 = MutableBuffer(b2)
|
||||||
|
|
||||||
b3[0] = 101
|
b3[0] = 101
|
||||||
|
|
||||||
@ -93,20 +104,18 @@ As with [List], it is possible to use ranges as indexes to slice a Buffer:
|
|||||||
|
|
||||||
## Members
|
## Members
|
||||||
|
|
||||||
| name | meaning | type |
|
| name | meaning | type |
|
||||||
|---------------------|--------------------------------------|-------|
|
|---------------|------------------------------------|---------------|
|
||||||
| `size` | size | Int |
|
| `size` | size | Int |
|
||||||
| `+=` | add one or more elements | Any |
|
| `decodeUtf8` | decodee to String using UTF8 rules | Any |
|
||||||
| `+`, `union` | union sets | Any |
|
| `+` | buffer concatenation | Any |
|
||||||
| `-`, `subtract` | subtract sets | Any |
|
| `toMutable()` | create a mutable copy | MutableBuffer |
|
||||||
| `*`, `intersect` | subtract sets | Any |
|
|
||||||
| `remove(items...)` | remove one or more items | Range |
|
|
||||||
| `contains(element)` | check the element is in the list (1) | |
|
|
||||||
|
|
||||||
(1)
|
(1)
|
||||||
: optimized implementation that override `Iterable` one
|
: optimized implementation that override `Iterable` one
|
||||||
|
|
||||||
Also, it inherits methods from [Iterable].
|
Also, it inherits methods from [Iterable] and [Array].
|
||||||
|
|
||||||
|
|
||||||
[Range]: Range.md
|
[Range]: Range.md
|
||||||
|
[Iterable]: Iterable.md
|
@ -82,6 +82,11 @@ open class Scope(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun requireNoArgs() {
|
||||||
|
if( args.list.isNotEmpty())
|
||||||
|
raiseError("This function does not accept any arguments")
|
||||||
|
}
|
||||||
|
|
||||||
inline fun <reified T : Obj> thisAs(): T = (thisObj as? T)
|
inline fun <reified T : Obj> thisAs(): T = (thisObj as? T)
|
||||||
?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
|
?: raiseClassCastError("Cannot cast ${thisObj.objClass.className} to ${T::class.simpleName}")
|
||||||
|
|
||||||
|
@ -179,6 +179,7 @@ class Script(
|
|||||||
ImportManager(rootScope, SecurityManager.allowAll).apply {
|
ImportManager(rootScope, SecurityManager.allowAll).apply {
|
||||||
addPackage("lyng.buffer") {
|
addPackage("lyng.buffer") {
|
||||||
it.addConst("Buffer", ObjBuffer.type)
|
it.addConst("Buffer", ObjBuffer.type)
|
||||||
|
it.addConst("MutableBuffer", ObjMutableBuffer.type)
|
||||||
}
|
}
|
||||||
addPackage("lyng.time") {
|
addPackage("lyng.time") {
|
||||||
it.addConst("Instant", ObjInstant.type)
|
it.addConst("Instant", ObjInstant.type)
|
||||||
|
@ -6,7 +6,7 @@ import net.sergeych.lyng.Scope
|
|||||||
import net.sergeych.lyng.statement
|
import net.sergeych.lyng.statement
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
open class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
||||||
|
|
||||||
override val objClass: ObjClass = type
|
override val objClass: ObjClass = type
|
||||||
|
|
||||||
@ -30,16 +30,6 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
|||||||
} else ObjInt(byteArray[checkIndex(scope, index)].toLong(), true)
|
} else ObjInt(byteArray[checkIndex(scope, index)].toLong(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) {
|
|
||||||
byteArray[checkIndex(scope, index.toObj())] = when (newValue) {
|
|
||||||
is ObjInt -> newValue.value.toUByte()
|
|
||||||
is ObjChar -> newValue.value.code.toUByte()
|
|
||||||
else -> scope.raiseIllegalArgument(
|
|
||||||
"invalid byte value for buffer at index ${index.inspect()}: ${newValue.inspect()}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val size by byteArray::size
|
val size by byteArray::size
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
@ -144,18 +134,10 @@ class ObjBuffer(val byteArray: UByteArray) : Obj() {
|
|||||||
thisAs<ObjBuffer>().byteArray.toByteArray().decodeToString()
|
thisAs<ObjBuffer>().byteArray.toByteArray().decodeToString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// )
|
addFn("toMutable") {
|
||||||
// addFn("getAt") {
|
requireNoArgs()
|
||||||
// requireExactCount(1)
|
ObjMutableBuffer(thisAs<ObjBuffer>().byteArray.copyOf())
|
||||||
// thisAs<ObjList>().getAt(this, requiredArg<Obj>(0))
|
}
|
||||||
// }
|
|
||||||
// addFn("putAt") {
|
|
||||||
// requireExactCount(2)
|
|
||||||
// val newValue = args[1]
|
|
||||||
// thisAs<ObjList>().putAt(this, requiredArg<ObjInt>(0).value.toInt(), newValue)
|
|
||||||
// newValue
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package net.sergeych.lyng.obj
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.toList
|
||||||
|
import net.sergeych.lyng.Scope
|
||||||
|
|
||||||
|
class ObjMutableBuffer(byteArray: UByteArray) : ObjBuffer(byteArray) {
|
||||||
|
|
||||||
|
override suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) {
|
||||||
|
byteArray[checkIndex(scope, index.toObj())] = when (newValue) {
|
||||||
|
is ObjInt -> newValue.value.toUByte()
|
||||||
|
is ObjChar -> newValue.value.code.toUByte()
|
||||||
|
else -> scope.raiseIllegalArgument(
|
||||||
|
"invalid byte value for buffer at index ${index.inspect()}: ${newValue.inspect()}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private suspend fun createBufferFrom(scope: Scope, obj: Obj): ObjBuffer =
|
||||||
|
when (obj) {
|
||||||
|
is ObjBuffer -> ObjMutableBuffer(obj.byteArray.copyOf())
|
||||||
|
is ObjInt -> {
|
||||||
|
if (obj.value < 0)
|
||||||
|
scope.raiseIllegalArgument("buffer size must be positive")
|
||||||
|
val data = UByteArray(obj.value.toInt())
|
||||||
|
ObjMutableBuffer(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
is ObjString -> ObjMutableBuffer(obj.value.encodeToByteArray().asUByteArray())
|
||||||
|
else -> {
|
||||||
|
if (obj.isInstanceOf(ObjIterable)) {
|
||||||
|
ObjMutableBuffer(
|
||||||
|
obj.toFlow(scope).map { it.toLong().toUByte() }.toList().toTypedArray()
|
||||||
|
.toUByteArray()
|
||||||
|
)
|
||||||
|
} else
|
||||||
|
scope.raiseIllegalArgument(
|
||||||
|
"can't construct buffer from ${obj.inspect()}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val type = object : ObjClass("MutableBuffer", ObjBuffer.type) {
|
||||||
|
override suspend fun callOn(scope: Scope): Obj {
|
||||||
|
val args = scope.args.list
|
||||||
|
return when (args.size) {
|
||||||
|
// empty buffer
|
||||||
|
0 -> ObjMutableBuffer(ubyteArrayOf())
|
||||||
|
1 -> createBufferFrom(scope, args[0])
|
||||||
|
else -> {
|
||||||
|
// create buffer from array, each argument should be a byte then:
|
||||||
|
val data = UByteArray(args.size)
|
||||||
|
for ((i, b) in args.withIndex()) {
|
||||||
|
val code = when (b) {
|
||||||
|
is ObjChar -> b.value.code.toUByte()
|
||||||
|
is ObjInt -> b.value.toUByte()
|
||||||
|
else -> scope.raiseIllegalArgument(
|
||||||
|
"invalid byte value for buffer constructor at index $i: ${b.inspect()}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
data[i] = code
|
||||||
|
}
|
||||||
|
ObjMutableBuffer(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2477,12 +2477,14 @@ class ScriptTest {
|
|||||||
assertEquals( 3, Buffer(1, 2, 3).size )
|
assertEquals( 3, Buffer(1, 2, 3).size )
|
||||||
assertEquals( 5, Buffer("hello").size )
|
assertEquals( 5, Buffer("hello").size )
|
||||||
|
|
||||||
val buffer = Buffer("Hello")
|
var buffer = Buffer("Hello")
|
||||||
assertEquals( 5, buffer.size)
|
assertEquals( 5, buffer.size)
|
||||||
assertEquals('l'.code, buffer[2] )
|
assertEquals('l'.code, buffer[2] )
|
||||||
assertEquals('l'.code, buffer[3] )
|
assertEquals('l'.code, buffer[3] )
|
||||||
assertEquals("Hello", buffer.decodeUtf8())
|
assertEquals("Hello", buffer.decodeUtf8())
|
||||||
|
|
||||||
|
buffer = buffer.toMutable()
|
||||||
|
|
||||||
buffer[2] = 101
|
buffer[2] = 101
|
||||||
assertEquals(101, buffer[2])
|
assertEquals(101, buffer[2])
|
||||||
assertEquals("Heelo", buffer.decodeUtf8())
|
assertEquals("Heelo", buffer.decodeUtf8())
|
||||||
@ -2503,6 +2505,12 @@ class ScriptTest {
|
|||||||
val b3 = b1 + Buffer("!")
|
val b3 = b1 + Buffer("!")
|
||||||
assertEquals( "Hello!", b3.decodeUtf8())
|
assertEquals( "Hello!", b3.decodeUtf8())
|
||||||
assert( b3 > b1 )
|
assert( b3 > b1 )
|
||||||
|
assert( b1 !== b2)
|
||||||
|
|
||||||
|
val map = Map( b1 => "foo")
|
||||||
|
assertEquals("foo", map[b1])
|
||||||
|
assertEquals("foo", map[b2])
|
||||||
|
assertEquals(null, map[b3])
|
||||||
|
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
}
|
}
|
||||||
@ -2615,7 +2623,7 @@ class ScriptTest {
|
|||||||
|
|
||||||
import lyng.buffer
|
import lyng.buffer
|
||||||
|
|
||||||
val b = Buffer(1,2,3)
|
val b = MutableBuffer(1,2,3)
|
||||||
b[1]++
|
b[1]++
|
||||||
assert( b == Buffer(1,3,3) )
|
assert( b == Buffer(1,3,3) )
|
||||||
++b[0]
|
++b[0]
|
||||||
@ -2633,7 +2641,7 @@ class ScriptTest {
|
|||||||
|
|
||||||
import lyng.buffer
|
import lyng.buffer
|
||||||
|
|
||||||
val b = Buffer(1,2,3)
|
val b = Buffer(1,2,3).toMutable()
|
||||||
b[1]--
|
b[1]--
|
||||||
assert( b == Buffer(1,1,3) )
|
assert( b == Buffer(1,1,3) )
|
||||||
--b[0]
|
--b[0]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user