Skip to content

Commit

Permalink
Add atRawUnsafe and atUnsafe to array classes (scala-native#3327)
Browse files Browse the repository at this point in the history
* Don't IOOB `.at(n)` for arrays of length `n`

* Revert "Don't IOOB `.at(n)` for arrays of length `n`"

This reverts commit 61d46ae.

* Add `atRawUnsafe` and `atUnsafe`

* Add `atUnsafe` to syntax
  • Loading branch information
armanbilge committed Aug 4, 2023
1 parent af36d31 commit 513df72
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 22 deletions.
80 changes: 61 additions & 19 deletions nativelib/src/main/scala/scala/scalanative/runtime/Arrays.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// scripts/gyb.py \
// nativelib/src/main/scala/scala/scalanative/runtime/Arrays.scala.gyb \
// --line-directive '' \
// -o /nativelib/src/main/scala/scala/scalanative/runtime/Arrays.scala
// -o nativelib/src/main/scala/scala/scalanative/runtime/Arrays.scala
//
// After executing the script, you may want to edit this file to remove
// personally or build-system specific identifiable information.
Expand Down Expand Up @@ -49,9 +49,15 @@ sealed abstract class Array[T]
/** Pointer to the element. */
@inline def at(i: Int): Ptr[T] = fromRawPtr[T](atRaw(i))

/** Pointer to the element without a bounds check. */
@inline def atUnsafe(i: Int): Ptr[T] = fromRawPtr[T](atRawUnsafe(i))

/** Raw pointer to the element. */
def atRaw(i: Int): RawPtr

/** Raw pointer to the element without a bounds check. */
def atRawUnsafe(i: Int): RawPtr

/** Loads element at i, throws ArrayIndexOutOfBoundsException. */
def apply(i: Int): T

Expand Down Expand Up @@ -163,10 +169,14 @@ final class BooleanArray private () extends Array[Boolean] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 1 * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 1 * i))
}

@inline def apply(i: Int): Boolean = loadBoolean(atRaw(i))

@inline def update(i: Int, value: Boolean): Unit = storeBoolean(atRaw(i), value)
Expand Down Expand Up @@ -226,10 +236,14 @@ final class CharArray private () extends Array[Char] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 2 * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 2 * i))
}

@inline def apply(i: Int): Char = loadChar(atRaw(i))

@inline def update(i: Int, value: Char): Unit = storeChar(atRaw(i), value)
Expand Down Expand Up @@ -289,10 +303,14 @@ final class ByteArray private () extends Array[Byte] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 1 * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 1 * i))
}

@inline def apply(i: Int): Byte = loadByte(atRaw(i))

@inline def update(i: Int, value: Byte): Unit = storeByte(atRaw(i), value)
Expand Down Expand Up @@ -352,10 +370,14 @@ final class ShortArray private () extends Array[Short] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 2 * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 2 * i))
}

@inline def apply(i: Int): Short = loadShort(atRaw(i))

@inline def update(i: Int, value: Short): Unit = storeShort(atRaw(i), value)
Expand Down Expand Up @@ -415,10 +437,14 @@ final class IntArray private () extends Array[Int] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 4 * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 4 * i))
}

@inline def apply(i: Int): Int = loadInt(atRaw(i))

@inline def update(i: Int, value: Int): Unit = storeInt(atRaw(i), value)
Expand Down Expand Up @@ -478,10 +504,14 @@ final class LongArray private () extends Array[Long] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 8 * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 8 * i))
}

@inline def apply(i: Int): Long = loadLong(atRaw(i))

@inline def update(i: Int, value: Long): Unit = storeLong(atRaw(i), value)
Expand Down Expand Up @@ -541,10 +571,14 @@ final class FloatArray private () extends Array[Float] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 4 * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 4 * i))
}

@inline def apply(i: Int): Float = loadFloat(atRaw(i))

@inline def update(i: Int, value: Float): Unit = storeFloat(atRaw(i), value)
Expand Down Expand Up @@ -604,10 +638,14 @@ final class DoubleArray private () extends Array[Double] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 8 * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + 8 * i))
}

@inline def apply(i: Int): Double = loadDouble(atRaw(i))

@inline def update(i: Int, value: Double): Unit = storeDouble(atRaw(i), value)
Expand Down Expand Up @@ -667,10 +705,14 @@ final class ObjectArray private () extends Array[Object] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + castRawSizeToInt(sizeOfPtr) * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + castRawSizeToInt(sizeOfPtr) * i))
}

@inline def apply(i: Int): Object = loadObject(atRaw(i))

@inline def update(i: Int, value: Object): Unit = storeObject(atRaw(i), value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// scripts/gyb.py \
// nativelib/src/main/scala/scala/scalanative/runtime/Arrays.scala.gyb \
// --line-directive '' \
// -o /nativelib/src/main/scala/scala/scalanative/runtime/Arrays.scala
// -o nativelib/src/main/scala/scala/scalanative/runtime/Arrays.scala
//
// After executing the script, you may want to edit this file to remove
// personally or build-system specific identifiable information.
Expand Down Expand Up @@ -49,9 +49,15 @@ sealed abstract class Array[T]
/** Pointer to the element. */
@inline def at(i: Int): Ptr[T] = fromRawPtr[T](atRaw(i))

/** Pointer to the element without a bounds check. */
@inline def atUnsafe(i: Int): Ptr[T] = fromRawPtr[T](atRawUnsafe(i))

/** Raw pointer to the element. */
def atRaw(i: Int): RawPtr

/** Raw pointer to the element without a bounds check. */
def atRawUnsafe(i: Int): RawPtr

/** Loads element at i, throws ArrayIndexOutOfBoundsException. */
def apply(i: Int): T

Expand Down Expand Up @@ -179,10 +185,14 @@ final class ${T}Array private () extends Array[${T}] {
if (i < 0 || i >= length) {
throwOutOfBounds(i)
} else {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + ${sizeT} * i))
atRawUnsafe(i)
}

@inline def atRawUnsafe(i: Int): RawPtr = {
val rawptr = castObjectToRawPtr(this)
elemRawPtr(rawptr, intToUSize(MemoryLayout.Array.ValuesOffset + ${sizeT} * i))
}

@inline def apply(i: Int): ${T} = load${T}(atRaw(i))

@inline def update(i: Int, value: ${T}): Unit = store${T}(atRaw(i), value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ package object unsafe extends unsafe.UnsafePackageCompat {
/** Scala Native unsafe extensions to Arrays */
implicit class UnsafeRichArray[T](val value: Array[T]) extends AnyVal {
@inline def at(i: Int): Ptr[T] = value.asInstanceOf[runtime.Array[T]].at(i)
@inline def atUnsafe(i: Int): Ptr[T] =
value.asInstanceOf[runtime.Array[T]].atUnsafe(i)
}

/** Convert a CString to a String using given charset. */
Expand Down

0 comments on commit 513df72

Please sign in to comment.