Skip to content

Commit c5171fd

Browse files
authored
Fixed two filtering bugs (#1991)
1 parent 05bbc3d commit c5171fd

File tree

19 files changed

+589
-314
lines changed

19 files changed

+589
-314
lines changed

toolbox/.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
target
2-
target/**
2+
target/**
3+
4+
test-graphviz.txt
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.finos.toolbox.collection
2+
3+
object ChunkSize {
4+
5+
def from(hint: Int): Int = {
6+
hint match
7+
case h if h < 100_000 => 5_000
8+
case h if h < 9_000_000 => 50_000
9+
case _ => 100_000
10+
}
11+
12+
}

toolbox/src/main/scala/org/finos/toolbox/collection/array/ChunkedImmutableArray.scala

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,49 @@
11
package org.finos.toolbox.collection.array
22

3+
import org.finos.toolbox.collection.{ChunkSize, array}
4+
35
import java.util
46
import scala.reflect.ClassTag
57
import scala.util.control.Breaks
68

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+
}
815

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)
1118
}
1219

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)
1523
}
1624

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)
1927
}
2028

2129
}
2230

2331
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]{
2432

25-
26-
2733
override def fromArray(arr: Array[T]): ImmutableArray[T] = {
2834
//https://www.cs.nott.ac.uk/~psarb2/G51MPC/slides/NumberLogic.pdf
2935
val chunkCount = (arr.length - 1) / chunkSize + 1
3036
val newChunks = new Array[Array[T]](chunkCount)
3137

3238
(0 until chunkCount).foreach( i => {
3339
val start = i * chunkSize;
34-
val end = Math.min(start + chunkSize, arr.length -1);
40+
val end = Math.min(start + chunkSize, arr.length);
3541
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+
}
3747
})
3848

3949
val lastUsedIndex = arr.length
@@ -95,15 +105,15 @@ class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Arra
95105
private def indexMinusOne(): Int = lastUsedIndex - 1
96106

97107
private def setFullChunks(oldChunks:Array[Array[T]], newChunks: Array[Array[T]]): Unit = {
98-
for (a <- 0 until oldChunks.length){
108+
for (a <- oldChunks.indices){
99109
if(oldChunks(a).length == chunkSize) {
100110
newChunks(a) = oldChunks(a)
101111
}
102112
}
103113
}
104114

105115
private def setChunks(oldChunks:Array[Array[T]], newChunks: Array[Array[T]]): Unit ={
106-
for (a <- 0 until oldChunks.length){
116+
for (a <- oldChunks.indices){
107117
newChunks(a) = oldChunks(a)
108118
}
109119
}
@@ -155,7 +165,7 @@ class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Arra
155165

156166
//create any empty chunks required till we get to required chunks
157167
//create empty chunks
158-
(currentChunks to requiredChunks - 1).foreach( i =>
168+
(currentChunks until requiredChunks).foreach(i =>
159169
newChunks(i) = new Array[T](chunkSize)
160170
)
161171

@@ -190,8 +200,8 @@ class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Arra
190200
activeChunk += 1
191201
}
192202

193-
//println(s"getIndex($index) -> ($activeChunk)($indexInChunk)")
194-
chunks(activeChunk)(indexInChunk)
203+
val chunk = chunks(activeChunk)
204+
chunk(indexInChunk)
195205
}
196206

197207
override def indexOf(element: T): Int = {
@@ -247,14 +257,26 @@ class ChunkedImmutableArray[T <: Object :ClassTag](private val chunks:Array[Arra
247257
setInPlace(a, getIndex(a), newChunks)
248258
}
249259

250-
for(a <- idxOf until this.length){
260+
for(a <- idxOf until this.length - 1){
251261
setInPlace(a, getIndex(a+ 1), newChunks)
252262
}
253263

254264
new ChunkedImmutableArray[T](newChunks, indexMinusOne(), chunkSize = this.chunkSize)
255265
}
256266
}
257267

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+
}
259281

260282
}

toolbox/src/main/scala/org/finos/toolbox/collection/array/ImmutableArray.scala

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,22 @@
11
package org.finos.toolbox.collection.array
22

3-
import org.finos.toolbox.collection.set.ChunkedUniqueImmutableArraySet
4-
53
import scala.reflect.ClassTag
64

7-
object ImmutableArray{
5+
object ImmutableArray {
6+
87
def empty[T <: Object](implicit c: ClassTag[T]): ImmutableArray[T] = {
9-
new ChunkedUniqueImmutableArraySet[T](Set(), Array(), chunkSize = 5000)
10-
}
11-
def from[T <: Object](array: Array[T])(implicit c: ClassTag[T]): ImmutableArray[T] = {
12-
empty[T].addAll(new NaiveImmutableArray[T](array))
8+
ChunkedImmutableArray.empty()
139
}
1410

15-
def fromArray[T <: Object](array: Array[T])(implicit c: ClassTag[T]): ImmutableArray[T] = {
16-
new ChunkedUniqueImmutableArraySet[T](Set(), Array(), chunkSize = chunkSize(array.length)).fromArray(array)
11+
def from[T <: Object](array: Array[T])(implicit c: ClassTag[T]): ImmutableArray[T] = {
12+
ChunkedImmutableArray.from(array)
1713
}
1814

19-
private def chunkSize(hint: Int): Int = {
20-
if(hint < 100_000){
21-
5000
22-
}else if(hint < 9000_000){
23-
50_000
24-
}else{
25-
100_000
26-
}
27-
}
2815
}
2916

3017
object ImmutableArrays{
3118
def empty[T <: Object :ClassTag](i: Int): Array[ImmutableArray[T]] = {
32-
(0 to (i - 1)).map( i=> new NaiveImmutableArray(Array[T]())).toArray
19+
(0 until i).map(i => ImmutableArray.empty()).toArray
3320
}
3421
}
3522

toolbox/src/main/scala/org/finos/toolbox/collection/array/NaiveImmutableArray.scala

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)