Last active
April 11, 2017 19:28
-
-
Save curioustorvald/ceacf4eda31e1cc561dfd04426e4f444 to your computer and use it in GitHub Desktop.
ByteArray that can hold larger than 4 GiB of data
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ByteArray that can hold larger than 4 GiB of Data. | |
* | |
* Works kind of like Bank Switching of old game console's cartridges which does same thing. | |
* | |
* Created by Minjaesong on 2017-04-12. | |
*/ | |
class ByteArray64(val size: Long) { | |
private val bankSize: Int = 1 shr 30 // 2^30 Bytes, or 1 GiB | |
private val data: Array<ByteArray> | |
init { | |
if (size <= 0) | |
throw IllegalArgumentException("Invalid array size!") | |
val requiredBanks: Int = 1 + ((size - 1) / bankSize).toInt() | |
data = Array<ByteArray>( | |
requiredBanks, | |
{ bankIndex -> | |
kotlin.ByteArray( | |
if (bankIndex == requiredBanks - 1) | |
size.toBankOffset() | |
else | |
bankSize, | |
{ 0.toByte() } | |
) | |
} | |
) | |
} | |
private fun Long.toBankNumber(): Int = (this / bankSize).toInt() | |
private fun Long.toBankOffset(): Int = (this % bankSize).toInt() | |
operator fun set(index: Long, value: Byte) { | |
if (index < 0 || index >= size) | |
throw ArrayIndexOutOfBoundsException("size $size, index $index") | |
data[index.toBankNumber()][index.toBankOffset()] = value | |
} | |
operator fun get(index: Long): Byte { | |
if (index < 0 || index >= size) | |
throw ArrayIndexOutOfBoundsException("size $size, index $index") | |
return data[index.toBankNumber()][index.toBankOffset()] | |
} | |
operator fun iterator(): ByteIterator { | |
return object : ByteIterator() { | |
var iterationCounter = 0L | |
override fun nextByte(): Byte { | |
iterationCounter += 1 | |
return this@ByteArray64[iterationCounter - 1] | |
} | |
override fun hasNext() = iterationCounter < [email protected] | |
} | |
} | |
fun forEach(consumer: (Byte) -> Unit) = iterator().forEach { consumer(it) } | |
fun sliceArray(range: LongRange): ByteArray64 { | |
val newarr = ByteArray64(range.last - range.first + 1) | |
range.forEach { index -> | |
newarr[index - range.first] = this[index] | |
} | |
return newarr | |
} | |
fun toByteArray(): ByteArray { | |
if (this.size > Integer.MAX_VALUE - 8) // according to OpenJDK; the size itself is VM-dependent | |
throw TypeCastException("Impossible cast; too large to fit") | |
return ByteArray(this.size.toInt(), { this[it.toLong()] }) | |
} | |
fun writeToFile(file: File) { | |
var fos = FileOutputStream(file, false) | |
fos.write(data[0]) | |
fos.flush() | |
fos.close() | |
if (data.size > 1) { | |
fos = FileOutputStream(file, true) | |
for (i in 1..data.lastIndex) { | |
fos.write(data[i]) | |
fos.flush() | |
} | |
fos.close() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment