|
1 | 1 | package org.finos.toolbox.collection.array |
2 | 2 |
|
| 3 | +import org.finos.toolbox.collection.{ChunkSize, array} |
| 4 | + |
3 | 5 | import java.util |
4 | 6 | import scala.reflect.ClassTag |
5 | 7 | import scala.util.control.Breaks |
6 | 8 |
|
7 | | -object ChunkedImmutableArray{ |
| 9 | +object ChunkedImmutableArray { |
| 10 | + |
| 11 | + def from[T <: Object : ClassTag](arr: Array[T]): ImmutableArray[T] = { |
| 12 | + val chunkSize = ChunkSize.from(arr.length) |
| 13 | + new ChunkedImmutableArray[T](chunks = Array(), chunkSize = chunkSize).fromArray(arr) |
| 14 | + } |
8 | 15 |
|
9 | | - def fromArray[T <: Object:ClassTag](arr: Array[T], chunkSize: Int): ImmutableArray[T] = { |
10 | | - new ChunkedImmutableArray[T](Array(), chunkSize = chunkSize).fromArray(arr) |
| 16 | + def from[T <: Object:ClassTag](arr: Array[T], chunkSize: Int): ImmutableArray[T] = { |
| 17 | + new ChunkedImmutableArray[T](chunks = Array(), chunkSize = chunkSize).fromArray(arr) |
11 | 18 | } |
12 | 19 |
|
13 | | - def empty[T <: Object:ClassTag](chunkSize: Int = 1000): ImmutableArray[T] = { |
14 | | - new ChunkedImmutableArray[T](Array(), chunkSize = chunkSize) |
| 20 | + def empty[T <: Object:ClassTag](): ImmutableArray[T] = { |
| 21 | + val chunkSize = ChunkSize.from(0) |
| 22 | + new ChunkedImmutableArray[T](chunks = Array(), chunkSize = chunkSize) |
15 | 23 | } |
16 | 24 |
|
17 | | - def from[T <: Object:ClassTag](chunkSize: Int = 1000): ImmutableArray[T] = { |
18 | | - new ChunkedImmutableArray[T](Array(), chunkSize = chunkSize) |
| 25 | + def empty[T <: Object : ClassTag](chunkSize: Int): ImmutableArray[T] = { |
| 26 | + new ChunkedImmutableArray[T](chunks = Array(), chunkSize = chunkSize) |
19 | 27 | } |
20 | 28 |
|
21 | 29 | } |
22 | 30 |
|
23 | 31 | class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Array[T]], private val lastUsedIndex: Int = 0, val chunkSize: Int = 1000) extends ImmutableArray[T] with Iterable[T]{ |
24 | 32 |
|
25 | | - |
26 | | - |
27 | 33 | override def fromArray(arr: Array[T]): ImmutableArray[T] = { |
28 | 34 | //https://www.cs.nott.ac.uk/~psarb2/G51MPC/slides/NumberLogic.pdf |
29 | 35 | val chunkCount = (arr.length - 1) / chunkSize + 1 |
30 | 36 | val newChunks = new Array[Array[T]](chunkCount) |
31 | 37 |
|
32 | 38 | (0 until chunkCount).foreach( i => { |
33 | 39 | val start = i * chunkSize; |
34 | | - val end = Math.min(start + chunkSize, arr.length -1); |
| 40 | + val end = Math.min(start + chunkSize, arr.length); |
35 | 41 | val chunk = util.Arrays.copyOfRange[T](arr, start, end) |
36 | | - newChunks(i) = chunk |
| 42 | + if(chunk.length < chunkSize){ |
| 43 | + newChunks(i) = Array.concat(chunk, new Array[T](chunkSize - chunk.length)) |
| 44 | + }else{ |
| 45 | + newChunks(i) = chunk |
| 46 | + } |
37 | 47 | }) |
38 | 48 |
|
39 | 49 | val lastUsedIndex = arr.length |
@@ -95,15 +105,15 @@ class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Arra |
95 | 105 | private def indexMinusOne(): Int = lastUsedIndex - 1 |
96 | 106 |
|
97 | 107 | private def setFullChunks(oldChunks:Array[Array[T]], newChunks: Array[Array[T]]): Unit = { |
98 | | - for (a <- 0 until oldChunks.length){ |
| 108 | + for (a <- oldChunks.indices){ |
99 | 109 | if(oldChunks(a).length == chunkSize) { |
100 | 110 | newChunks(a) = oldChunks(a) |
101 | 111 | } |
102 | 112 | } |
103 | 113 | } |
104 | 114 |
|
105 | 115 | private def setChunks(oldChunks:Array[Array[T]], newChunks: Array[Array[T]]): Unit ={ |
106 | | - for (a <- 0 until oldChunks.length){ |
| 116 | + for (a <- oldChunks.indices){ |
107 | 117 | newChunks(a) = oldChunks(a) |
108 | 118 | } |
109 | 119 | } |
@@ -155,7 +165,7 @@ class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Arra |
155 | 165 |
|
156 | 166 | //create any empty chunks required till we get to required chunks |
157 | 167 | //create empty chunks |
158 | | - (currentChunks to requiredChunks - 1).foreach( i => |
| 168 | + (currentChunks until requiredChunks).foreach(i => |
159 | 169 | newChunks(i) = new Array[T](chunkSize) |
160 | 170 | ) |
161 | 171 |
|
@@ -190,8 +200,8 @@ class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Arra |
190 | 200 | activeChunk += 1 |
191 | 201 | } |
192 | 202 |
|
193 | | - //println(s"getIndex($index) -> ($activeChunk)($indexInChunk)") |
194 | | - chunks(activeChunk)(indexInChunk) |
| 203 | + val chunk = chunks(activeChunk) |
| 204 | + chunk(indexInChunk) |
195 | 205 | } |
196 | 206 |
|
197 | 207 | override def indexOf(element: T): Int = { |
@@ -247,14 +257,26 @@ class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Arra |
247 | 257 | setInPlace(a, getIndex(a), newChunks) |
248 | 258 | } |
249 | 259 |
|
250 | | - for(a <- idxOf until this.length){ |
| 260 | + for(a <- idxOf until this.length - 1){ |
251 | 261 | setInPlace(a, getIndex(a+ 1), newChunks) |
252 | 262 | } |
253 | 263 |
|
254 | 264 | new ChunkedImmutableArray[T](newChunks, indexMinusOne(), chunkSize = this.chunkSize) |
255 | 265 | } |
256 | 266 | } |
257 | 267 |
|
258 | | - override def distinct: ImmutableArray[T] = ??? |
| 268 | + override def distinct: ImmutableArray[T] = fromArray(iterator.distinct.toArray) |
| 269 | + |
| 270 | + private lazy val hash = iterator.foldLeft(0)((h, elem) => 31 * h + (if elem == null then 0 else elem.hashCode())) |
| 271 | + |
| 272 | + override def hashCode(): Int = hash |
| 273 | + |
| 274 | + override def equals(obj: Any): Boolean = { |
| 275 | + obj match { |
| 276 | + case value: ChunkedImmutableArray[_] => |
| 277 | + (this eq value) || (this.length == value.length && this.iterator.sameElements(value.iterator)) |
| 278 | + case _ => false |
| 279 | + } |
| 280 | + } |
259 | 281 |
|
260 | 282 | } |
0 commit comments