Skip to content

Commit

Permalink
Added NArray to IterableOnce implicit conversions, zip and zipAll ove…
Browse files Browse the repository at this point in the history
…rloaded methods, simplified TestFlatten to not need a custom implicit conversion. Added tests for zip, zipAll, and updated. Added NArrayAsIterableOnce
  • Loading branch information
c committed Jan 15, 2025
1 parent 2d6e3d7 commit 3f735b5
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 23 deletions.
6 changes: 3 additions & 3 deletions docs/FeatureGrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ def zip[B](that: IterableOnce[B]): Array[(T, B)]
</td>
<td>✓</td>
<td>✓</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
Expand All @@ -699,7 +699,7 @@ def zipAll[A1 >: T, B](
</td>
<td>✓</td>
<td>✓</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
Expand Down Expand Up @@ -1152,7 +1152,7 @@ def updated[B >: T : ClassTag](index: Int, elem: B): Array[B]
</td>
<td>✓</td>
<td>✓</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
Expand Down
75 changes: 75 additions & 0 deletions narr/js/src/main/scala/narr/native/Extensions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,54 @@ object Extensions {
given orderingToCompareFunction[T]: Conversion[Ordering[T], js.Function2[T, T, Int]] with
def apply(o: Ordering[T]): js.Function2[T, T, Int] = (a: T, b: T) => o.compare(a, b)

given ba2io: Conversion[ByteArray, IterableOnce[Byte]] = (a: ByteArray) => NArrayAsIterableOnce[Byte](a)
given sa2io: Conversion[ShortArray, IterableOnce[Short]] = (a: ShortArray) => NArrayAsIterableOnce[Short](a)
given ia2io: Conversion[IntArray, IterableOnce[Int]] = (a: IntArray) => NArrayAsIterableOnce[Int](a)
given fa2io: Conversion[FloatArray, IterableOnce[Float]] = (a: FloatArray) => NArrayAsIterableOnce[Float](a)
given da2io: Conversion[DoubleArray, IterableOnce[Double]] = (a: DoubleArray) => NArrayAsIterableOnce[Double](a)

given nArray2IterableOnce[T](using ct:ClassTag[T]): Conversion[NArray[T], IterableOnce[T]] with
def apply(a: NArray[T]):IterableOnce[T] = ct match {
case ClassTag.Byte => new NArrayAsIterableOnce[Byte](a)
case ClassTag.Short => new NArrayAsIterableOnce[Short](a)
case ClassTag.Int => new NArrayAsIterableOnce[Int](a)
case ClassTag.Float => new NArrayAsIterableOnce[Float](a)
case ClassTag.Double => new NArrayAsIterableOnce[Double](a)
case _ => NArrayAsIterableOnce[T](a)
}

extension[T:ClassTag] (aa: NArray[NArray[T]]) {
def flatten: NArray[T] = {
var c = 0
var i:Int = 0; while (i < aa.length) {
c = c + aa(i).length
i = i + 1
}
val out = NArray.ofSize[T](c)
i = 0
var j = 0
while (i < aa.length) {
var k = 0
while (k < aa(i).length) {
out(j) = aa(i)(k)
k = k + 1
j = j + 1
}
i = i + 1
}
out
}
def toArray: Array[Array[T]] = {
val arr: Array[Array[T]] = new Array[Array[T]](aa.length)
var i = 0;
while (i < arr.length) {
arr(i) = aa(i).toArray
i = i + 1
}
arr
}
}

extension (a: ByteArray) {
inline def head: Byte = a(0)
def sort(): ByteArray = sortByteArray(a)
Expand Down Expand Up @@ -810,6 +858,15 @@ object Extensions {
}


def zip[B](that: NArray[B]): NArray[(T, B)] = {
val out = new native.NativeArray[(T, B)](Math.min(a.length, that.length))
var i = 0; while (i < out.length) {
out(i) = (a(i), that(i))
i = i + 1
}
out
}

/** Returns an array formed from this array and another iterable collection
* by combining corresponding elements in pairs.
* If one of the two collections is longer than the other, its remaining elements are ignored.
Expand All @@ -832,6 +889,24 @@ object Extensions {
b.result
}

def zipAll[A1 >: T, B](that: NArray[B], thisElem: A1, thatElem: B): NArray[(A1, B)] = {
val out = new native.NativeArray[(A1, B)](Math.max(a.length, that.length))
var i = 0
val it = that.iterator
while (i < a.length && i < that.length) {
out(i) = ((a(i), it.next()))
i += 1
}
while (i < that.length) {
out(i) = ((thisElem, it.next()))
i += 1
}
while (i < a.length) {
out(i) = ((a(i), thatElem))
i += 1
}
out
}

/** Returns an array formed from this array and another iterable collection
* by combining corresponding elements in pairs.
Expand Down
14 changes: 14 additions & 0 deletions narr/shared/src/main/scala/narr/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,20 @@ package object narr {

@inline implicit def nArray2NArr[T](nArr:NArray[T]): NArr[T] & NArray[T] = nArr.asInstanceOf[NArr[T] & NArray[T]]

class NArrayAsIterableOnce[T](a:NArray[T]) extends IterableOnce[T] {
override def iterator: Iterator[T] = new Iterator[T] {
var i = 0
override def hasNext: Boolean = i < a.length
override def next(): T = {
if (hasNext) {
val r = a(i)
i = i + 1
r
} else throw new NoSuchElementException("next on empty iterator")
}
}
}

val Extensions: narr.native.Extensions.type = narr.native.Extensions
export Extensions.*
export Extensions.given
Expand Down
25 changes: 6 additions & 19 deletions tests/shared/src/test/scala/FlattenTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,6 @@ class FlattenTest extends munit.FunSuite {
val N:Int = 30

private case class TestFlatten[B](a: NArray[NArray[B]], nt: NArrayType)(using ClassTag[B], ClassTag[NArray[B]]) {
given f: Function1[NArray[B], IterableOnce[B]] = (ab:NArray[B]) => new IterableOnce[B] {
override def iterator: Iterator[B] = new Iterator[B] {
var i = 0
override def hasNext: Boolean = i < ab.length
override def next(): B = {
if (hasNext) {
val r = ab(i)
i = i + 1
r
} else throw new NoSuchElementException("next on empty iterator")
}
}
}

def test(): Unit = {
val afltnd: NArray[B] = a.flatten
Expand All @@ -48,42 +35,42 @@ class FlattenTest extends munit.FunSuite {
}
}

test("TestFlatten[NArray[Byte]]") {
test("TestFlatten[NArray[NArray[Byte]]]") {
TestFlatten[Byte](
NArray.tabulate[NArray[Byte]](N)((i: Int) => NArray.tabulate[Byte](i)((i0: Int) => i0.toByte)),
BYTE_ARRAY
).test()
}

test("TestFlatten[NArray[Short]]") {
test("TestFlatten[NArray[NArray[Short]]]]") {
TestFlatten[Short](
NArray.tabulate[NArray[Short]](N)((i: Int) => NArray.tabulate[Short](i)((i0: Int) => i0.toShort)),
SHORT_ARRAY
).test()
}

test("TestFlatten[NArray[Int]]") {
test("TestFlatten[NArray[NArray[Int]]]") {
TestFlatten[Int](
NArray.tabulate[NArray[Int]](N)((i: Int) => NArray.tabulate[Int](i)((i0: Int) => i0)),
INT_ARRAY
).test()
}

test("TestFlatten[NArray[Float]]") {
test("TestFlatten[NArray[NArray[Float]]]") {
TestFlatten[Float](
NArray.tabulate[NArray[Float]](N)((i: Int) => NArray.tabulate[Float](i)((i0: Int) => i0.toFloat)),
FLOAT_ARRAY
).test()
}

test("TestFlatten[NArray[Double], Double]") {
test("TestFlatten[NArray[NArray[Double]]]") {
TestFlatten[Double](
NArray.tabulate[NArray[Double]](N)((i: Int) => NArray.tabulate[Double](i)((i0: Int) => i0.toDouble)),
DOUBLE_ARRAY
).test()
}

test("TestFlatten[String, String]") {
test("TestFlatten[NArray[NArray[String]]]]") {
val rs = new Random()
TestFlatten[String](
NArray.tabulate[NArray[String]](N)((i: Int) => NArray.tabulate[String](i)((i0: Int) => rs.nextString(i))),
Expand Down
13 changes: 12 additions & 1 deletion tests/shared/src/test/scala/NArrayOpsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,17 @@ class NArrayOpsTest extends munit.FunSuite {
assertArray2NArrayEquality(arr.intersect(lArr), a.intersect(left.toSeq))
assertArray2NArrayEquality(arr.intersect(rArr), a.intersect(right.toSeq))

// zip
assertArray2NArrayEquality(lArr.zip(rArr), left.zip(right))

// zipAll
val e1 = a(fulcrum)
val e2 = a(a.length- (1 + fulcrum))
assertArray2NArrayEquality(lArr.zipAll(rArr, e1, e2), left.zipAll(right, e1, e2))

// updated
assertArray2NArrayEquality(arr.updated(fulcrum, a(0)), a.updated(fulcrum, a(0)))

fulcrum += 1
}

Expand Down Expand Up @@ -230,7 +241,7 @@ class NArrayOpsTest extends munit.FunSuite {
assertEquals(a(i).hashCode(), ampd(i))
i += 1
}

// zipWithIndex
val zippedWithIndex:NArray[(T, Int)] = a.zipWithIndex
i = 0; while (i < N) {
Expand Down

0 comments on commit 3f735b5

Please sign in to comment.