Skip to content

Instantly share code, notes, and snippets.

@curioustorvald
Last active April 11, 2017 19:28
Show Gist options
  • Save curioustorvald/ceacf4eda31e1cc561dfd04426e4f444 to your computer and use it in GitHub Desktop.
Save curioustorvald/ceacf4eda31e1cc561dfd04426e4f444 to your computer and use it in GitHub Desktop.
ByteArray that can hold larger than 4 GiB of data
/**
* 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