Category talk:Wren-array: Difference between revisions
Content added Content deleted
(→Source code: Numerous changes to BitArray and ByteArray classes including new methods.) |
(→Source code: Added CharArray class.) |
||
Line 462: | Line 462: | ||
return toList.reduce("") { |acc, b| acc + digits[b>>4] + digits[b%16] } |
return toList.reduce("") { |acc, b| acc + digits[b>>4] + digits[b%16] } |
||
} |
} |
||
} |
|||
/* |
|||
CharArray represents a List<Char> whose size cannot be changed after it has been constructed |
|||
but whose elements can be changed. A 'Char' for this purpose is a unicode character with a |
|||
codepoint less than 256 (i.e. Latin-1). Internally, a ByteArray is used for storage. |
|||
This means that it only uses a quarter as much memory as a 'normal' List<Byte> (or about an |
|||
eighth as much as a List of single character strings) but is around 5 times slower to index. |
|||
*/ |
|||
class CharArray is Sequence { |
|||
// Constructs a new CharArray of a given size and sets all elements to the same Char 'c'. |
|||
// As a ByteArray is used for storage, its size is rounded to the higher multiple of 4 |
|||
// where necessary. |
|||
construct new(size, c) { |
|||
Check.char("c", c, 0, 255) |
|||
_a = ByteArray.new(size, c.codePoints[0]) |
|||
_rng = 0..._a.count |
|||
} |
|||
// Constructs a new CharArray from a List<Char>, checking that the character values |
|||
// are valid. As a ByteArray is used for storage, its size is rounded to the |
|||
// higher multiple of 4 and filled out with space characters, where necessary. |
|||
construct fromList(a) { |
|||
Check.typedList("a", a, String, 1) |
|||
var size = (a.count / 4).ceil * 4 |
|||
var ca = List.filled(size, 32) |
|||
for (i in 0...a.count) { |
|||
Check.char("a[%(i)]", a[i], 0, 255) |
|||
ca[i] = a[i].codePoints[0] |
|||
} |
|||
_a = ByteArray.fromList(ca, false) |
|||
_rng = 0...size |
|||
} |
|||
// Constructs a new ByteArray from a string of Chars. |
|||
// As a ByteArray is used for storage, its size is rounded to the higher |
|||
// multiple of 4 and filled out with space characters, where necessary. |
|||
construct fromString(s) { |
|||
Check.str("s", s, 1) |
|||
var size = (s.count / 4).ceil * 4 |
|||
if (s.count < size) s = s + " " * (size - s.count) |
|||
_a = ByteArray.fromList(s.codePoints.toList, true) |
|||
_rng = 0...size |
|||
} |
|||
// As 'fromList' except constructs the new CharArray from an Array<Char> instead. |
|||
static fromArray(a) { fromList(a.toList) } |
|||
// Convenience version of 'new' which sets all elements to the space character. |
|||
static new(size) { new(size, " ") } |
|||
// Returns the number of elements in the CharArray. |
|||
count { _a.count } |
|||
// Creates a copy of the current instance. |
|||
copy() { |
|||
var ca = CharArray.new(count, " ") |
|||
for (i in _rng) ca[i] = this[i] |
|||
return ca |
|||
} |
|||
// Resets all elements of the CharArray to 'c'. |
|||
reset(c) { |
|||
Check.char("c", c, 0, 255) |
|||
_a.reset(c.codePoints[0]) |
|||
} |
|||
// 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] { String.fromCodePoint(_a[index]) } |
|||
// 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]=(c) { |
|||
_a[index] = c.codePoints[0] |
|||
} |
|||
// As [index] method but validates the index. |
|||
get(index) { String.fromCodePoint(_a.get(index)) } |
|||
// As [index]=(c) method but validates the index and the new value. |
|||
set(index, c) { |
|||
Check.char("c", c) |
|||
_a.set(index, c.codePoints[0]) |
|||
} |
|||
// Writes the string 's' into the CharArray buffer starting from index 'start'. |
|||
// Throws an error if 'start' is out of range, if 's' is too long to fit into |
|||
// the buffer or if it contains an invalid Char. |
|||
write(start, s) { |
|||
Check.str("s", s, 1) |
|||
var i = 0 |
|||
for (cp in s.codePoints) { |
|||
_a.set(start + i, cp) |
|||
i = i + 1 |
|||
} |
|||
} |
|||
// Returns the index of 'c' in the current instance or -1 if 'c' is not found. |
|||
// Throws an error if 'c' is an invalid Char. |
|||
indexOf(c) { |
|||
Check.char("c", c, 0, 255) |
|||
return _a.indexOf(c.codePoints[0]) |
|||
} |
|||
// Returns the index of the last occurrence of 'c' in the current instance |
|||
// or -1 if 'c' is not found. Throws an error if 'c' is an invalid Char. |
|||
lastIndexOf(c) { |
|||
Check.char("c", c, 0, 255) |
|||
for (i in count-1..0) if (this[i] == c) return i |
|||
return -1 |
|||
} |
|||
// Replaces all occurrences of 'old' by 'new' in the current instance |
|||
// and returns ['old', 'new']. |
|||
replace(old, new) { |
|||
Check.char("old", old, 0, 255) |
|||
Check.char("new", new, 0, 255) |
|||
for (i in _rng) if (this[i] == old) this[i] = new |
|||
return [old, new] |
|||
} |
|||
// Swaps the elements at index1 and index2 within the CharArray. |
|||
swap(index1, index2) { |
|||
var t = this[index1] |
|||
this[index1] = this[index2] |
|||
this[index2] = t |
|||
} |
|||
// Applies a function to each element of the CharArray. |
|||
apply(fn) { |
|||
Check.func("fn", fn, 1) |
|||
for (i in 0..._rng) this[i] = fn.call(this[i]) |
|||
} |
|||
// Converts 'in place' all upper case Chars in this instance to lower case. |
|||
toLower { |
|||
for (i in _rng) { |
|||
var c = this[i].codePoints[0] |
|||
if ((c >= 65 && c <= 90) || (c >= 192 && c <= 214) || (c >= 216 && c <= 222)) { |
|||
this[i] = String.fromCodePoint(c + 32) |
|||
} |
|||
} |
|||
} |
|||
// Converts 'in place' all lower case Chars in this instance to upper case. |
|||
toUpper { |
|||
for (i in _rng) { |
|||
var c = this[i].codePoints[0] |
|||
if ((c >= 97 && c <= 122) || (c >= 224 && c <= 246) || (c >= 248 && c <= 254)) { |
|||
this[i] = String.fromCodePoint(c - 32) |
|||
} |
|||
} |
|||
} |
|||
// Capitalizes 'in place' the first Char of this instance. |
|||
capitalize { |
|||
var c = this[0].codePoints[0] |
|||
if ((c >= 97 && c <= 122) || (c >= 224 && c <= 246) || (c >= 248 && c <= 254)) { |
|||
this[0] = String.fromCodePoint(c - 32) |
|||
} |
|||
} |
|||
// Iterator protocol methods. |
|||
iterate(iterator) { _rng.iterate(iterator) } |
|||
iteratorValue(iterator) { this[iterator] } |
|||
// Returns a List<Char> using the normal 8 bytes for each element. |
|||
toList { |
|||
var chars = List.filled(count, null) |
|||
for (i in _rng) chars[i] = this[i] |
|||
return chars |
|||
} |
|||
// Returns an Array<Char> using the normal 8 bytes for each element. |
|||
toArray { |
|||
var chars = List.filled(count, null) |
|||
for (i in _rng) chars[i] = this[i] |
|||
return chars |
|||
} |
|||
// Returns a string representation of this instance, optionally trimming trailing |
|||
// whitespace (space, tab, carriage return, and line feed characters). |
|||
toString(trimEnd) { |
|||
var res = toList.join() |
|||
return trimEnd ? res : res.trimEnd() |
|||
} |
|||
// Returns a string representation of this instance with trailing whitespace removed. |
|||
toString { toList.join() } |
|||
// Returns a string representation of this instance as if it were a list. |
|||
toListString { toList.toString } |
|||
}</syntaxhighlight> |
}</syntaxhighlight> |