Category talk:Wren-array: Difference between revisions

Content added Content deleted
m (→‎Source code: Now uses Wren S/H lexer.)
(Added ByteArray class.)
Line 246: Line 246:
for (i in 0...count) if (this[i]) bytes[i] = 1
for (i in 0...count) if (this[i]) bytes[i] = 1
return bytes.join()
return bytes.join()
}
}

/*
ByteArray represents a List<Byte> whose size cannot be changed after it has been constructed
but whose elements can be changed. A 'Byte' for this purpose is an integral Num with a value
between 0 and 255 inclusive. It uses only a quarter as much memory as a 'normal' List<Byte>
but is around 4 times slower to index. Also, unlike List<Byte>, ByteArray is not a Sequence.
*/
class ByteArray {
// Constructs a new ByteArray of a given size and sets all elements to the same value 'v'.
// 'size' is rounded to the higher multiple of 4 where necessary.
construct new(size, v) {
Check.posInt("size", size)
Check.int("value", v, 0, 255)
_len = (size / 4).ceil
// convert 'v' to a little-endian 32-bit unsigned integer.
v = (v == 0) ? 0 : v | v << 8 | v << 16 | v << 24
_a = List.filled(_len, v)
}

// Constructs a new ByteArray from a List<Byte>, optionally checking that the byte
// values are valid. Where necessary, the size of the ByteArray is rounded to the
// higher multiple of 4 and filled out with zero values.
construct fromList(a, checkBytes) {
Check.typedList("a", a, "Int", 1)
Check.bool("checkBytes", checkBytes)
_len = (a.count / 4).ceil
_a = List.filled(_len, 0)
if (checkBytes) {
for (i in 0...a.count) {
if (!(a[i].isInteger && a[i] >= 0 && a[i] < 256)) {
Fiber.abort("a[%(i)] = %(a[i]) is not a byte.")
}
}
}
for (i in 0..._len) {
var j = i * 4
if (i < _len - 1) {
_a[i] = a[j] | a[j+1] << 8 | a[j+2] << 16 | a[j+3] << 24
} else {
var b2 = (j + 1 < a.count) ? a[j+1] : 0
var b3 = (j + 2 < a.count) ? a[j+2] : 0
var b4 = (j + 3 < a.count) ? a[j+3] : 0
_a[i] = a[j] | b2 << 8 | b3 << 16 | b4 << 24
}
}
}

// Constructs a new ByteArray from a lower case hexadecimal string.
// Where necessary, the size of the ByteArray is rounded to the
// higher multiple of 4 and filled out with zero values.
static fromHexString(hs) {
Check.str("hs", hs, 2)
if (hs.count % 2 != 0) {
Fiber.abort("'hs' must contain an even number of hex digits >= 2.")
}
var digits = "0123456789abcdef"
var bytes = List.filled(hs.count/2, 0)
var i = 0
while (i < hs.count-1) {
bytes[i/2] = digits.indexOf(hs[i]) * 16 + digits.indexOf(hs[i+1])
i = i + 2
}
return fromList(bytes, false)
}

// As 'fromList' except constructs the new ByteArray from an Array<Byte> instead.
static fromArray(a, checkBytes) { fromList(a.toList, checkBytes) }

// Convenience version of 'new' which sets all elements to zero.
static new(size) { new(size, 0) }

// Convenience version of 'fromList' which does not check that the byte values are valid.
static fromList(a) { fromList(a, false) }

// Convenience version of 'fromArray' which does not check that the byte values are valid.
static fromArray(a) { fromList(a.toList, false) }

// Returns the number of elements in the ByteArray.
count { 4 * _len }

// Creates a copy of the current instance.
copy() {
var c = ByteArray.new(count, 0)
for (i in 0...count) c[i] = this[i]
return c
}

// Resets all elements of the ByteArray to 'v'.
reset(v) {
Check.int("value", v, 0, 255)
v = (v == 0) ? 0 : v | v << 8 | v << 16 | v << 24
for (i in 0..._len) _a[i] = v
}

// Gets the element at 'index'. If index is negative, it counts backwards
// from the end of the array where -1 is the last element.
// To maximize access speed, this method doesn't validate the index.
// Use the 'get' method instead if you need to do that.
[index] {
if (index < 0) index = count + index
var ix = (index/4).floor
var bit = (index%4) * 8
return (_a[ix] >> bit) & 255
}

// Sets the element at 'index'. Negative indices are treated as in the getter.
// To maximize access speed, this method doesn't validate the index nor the new value.
// Use the 'set' method instead if you need to do that.
[index]=(v) {
if (index < 0) index = count + index
var ix = (index/4).floor
var bit = (index%4) * 8
_a[ix] = (_a[ix] & ~(255 << bit)) | (v << bit)
}

// As [index] method but validates the index.
get(index) {
Check.int("index", index, -count, count-1)
return this[index]
}

// As [index]=(v) method but validates the index and the new value.
set(index, v) {
Check.int("index", index, -count, count-1)
Check.int("value", v, 0, 255)
this[index] = v
}

// Returns a List<Byte> using the normal 8 bytes for each element.
toList {
var bytes = List.filled(count, 0)
for (i in 0...count) bytes[i] = this[i]
return bytes
}

// Returns an Array<Byte> using the normal 8 bytes for each element.
toArray {
var bytes = Array.new(count, 0)
for (i in 0...count) bytes[i] = this[i]
return bytes
}

// Returns a string representation of this instance as if it were a list.
toString { toList.toString }

// Returns a lower case hex string representation of this instance.
toHexString {
var digits = "0123456789abcdef"
return toList.reduce("") { |acc, b| acc + digits[b>>4] + digits[b%16] }
}
}
}</syntaxhighlight>
}</syntaxhighlight>