stdlib/internal/types/collections/list.codon

pull/13/head
Ishak Numanagić 2022-01-24 09:33:49 +01:00
parent 5bfc46d1b5
commit 2d707e35a2
1 changed files with 77 additions and 59 deletions

View File

@ -1,42 +1,45 @@
# (c) 2022 Exaloop Inc. All rights reserved.
import internal.gc as gc
@extend
class List:
def __init__(self):
def __init__(self) -> void:
self.arr = Array[T](10)
self.len = 0
def __init__(self, it: Generator[T]):
def __init__(self, it: Generator[T]) -> void:
self.arr = Array[T](10)
self.len = 0
for i in it:
self.append(i)
def __init__(self, other: List[T]):
def __init__(self, other: List[T]) -> void:
self.arr = Array[T](other.len)
self.len = 0
for i in other:
self.append(i)
def __init__(self, capacity: int):
def __init__(self, capacity: int) -> void:
self.arr = Array[T](capacity)
self.len = 0
def __init__(self, dummy: bool, other):
def __init__(self, dummy: bool, other) -> void:
"""Dummy __init__ used for list comprehension optimization"""
if hasattr(other, '__len__'):
if hasattr(other, "__len__"):
self.__init__(other.__len__())
else:
self.__init__()
def __init__(self, arr: Array[T], len: int):
def __init__(self, arr: Array[T], len: int) -> void:
self.arr = arr
self.len = len
def __len__(self):
def __len__(self) -> int:
return self.len
def __bool__(self):
def __bool__(self) -> bool:
return self.__len__() > 0
def __getitem__(self, idx: int) -> T:
@ -45,13 +48,13 @@ class List:
self._idx_check(idx, "list index out of range")
return self.arr[idx]
def __setitem__(self, idx: int, val: T):
def __setitem__(self, idx: int, val: T) -> void:
if idx < 0:
idx += self.__len__()
self._idx_check(idx, "list assignment index out of range")
self.arr[idx] = val
def __delitem__(self, idx: int):
def __delitem__(self, idx: int) -> void:
if idx < 0:
idx += self.__len__()
self._idx_check(idx, "list assignment index out of range")
@ -60,7 +63,7 @@ class List:
idx += 1
self.len -= 1
def __eq__(self, other: List[T]):
def __eq__(self, other: List[T]) -> bool:
if self.__len__() != other.__len__():
return False
for i in range(self.__len__()):
@ -68,10 +71,10 @@ class List:
return False
return True
def __ne__(self, other: List[T]):
def __ne__(self, other: List[T]) -> bool:
return not (self == other)
def __getitem__(self, s: Slice):
def __getitem__(self, s: Slice) -> List[T]:
if s.start is None and s.stop is None and s.step is None:
return self.__copy__()
if s.step is None:
@ -84,7 +87,7 @@ class List:
other.append(self.arr[i])
return other
def __setitem__(self, s: Slice, other):
def __setitem__(self, s: Slice, other) -> void:
if s.start is None and s.stop is None and s.step is None:
self.clear()
for a in other:
@ -115,7 +118,9 @@ class List:
seq_len = seq.__len__()
if seq_len != length:
raise ValueError(f"attempt to assign sequence of size {seq_len} to extended slice of size {length}")
raise ValueError(
f"attempt to assign sequence of size {seq_len} to extended slice of size {length}"
)
if length == 0:
return
@ -127,7 +132,7 @@ class List:
cur += step
i += 1
def __delitem__(self, s: Slice):
def __delitem__(self, s: Slice) -> void:
if s.start is None and s.stop is None and s.step is None:
self.clear()
else:
@ -140,7 +145,7 @@ class List:
if step < 0:
stop = start + 1
start = stop + step*(length - 1) - 1
start = stop + step * (length - 1) - 1
step = -step
cur = start
@ -149,34 +154,38 @@ class List:
lim = step - 1
if cur + step > self.__len__():
lim = self.__len__() - cur - 1
str.memmove((self.arr.ptr + (cur - i)).as_byte(),
(self.arr.ptr + (cur + 1)).as_byte(),
lim * gc.sizeof(T))
str.memmove(
(self.arr.ptr + (cur - i)).as_byte(),
(self.arr.ptr + (cur + 1)).as_byte(),
lim * gc.sizeof(T),
)
cur += step
i += 1
cur = start + length*step
cur = start + length * step
if cur < self.__len__():
str.memmove((self.arr.ptr + (cur - length)).as_byte(),
(self.arr.ptr + cur).as_byte(),
(self.__len__() - cur) * gc.sizeof(T))
str.memmove(
(self.arr.ptr + (cur - length)).as_byte(),
(self.arr.ptr + cur).as_byte(),
(self.__len__() - cur) * gc.sizeof(T),
)
self.len -= length
# self._resize(self.__len__())
def __contains__(self, x: T):
def __contains__(self, x: T) -> bool:
for a in self:
if a == x:
return True
return False
def __copy__(self):
def __copy__(self) -> List[T]:
return List[T](self.arr.__copy__(), self.len)
def __deepcopy__(self):
def __deepcopy__(self) -> List[T]:
return [l.__deepcopy__() for l in self]
def __iter__(self):
def __iter__(self) -> Generator[T]:
i = 0
N = self.len
p = self.arr.ptr
@ -184,13 +193,13 @@ class List:
yield p[i]
i += 1
def __reversed__(self):
def __reversed__(self) -> Generator[T]:
i = self.len - 1
while i >= 0:
yield self.arr[i]
i -= 1
def __add__(self, other: List[T]):
def __add__(self, other: List[T]) -> List[T]:
v = List[T](self.len + other.len)
for a in self:
v.append(a)
@ -198,12 +207,12 @@ class List:
v.append(a)
return v
def __iadd__(self, other: List[T]):
def __iadd__(self, other: List[T]) -> List[T]:
for a in other:
self.append(a)
return self
def __mul__(self, n: int):
def __mul__(self, n: int) -> List[T]:
if n <= 0:
return List[T]()
@ -218,7 +227,7 @@ class List:
i += 1
return v
def __imul__(self, n: int):
def __imul__(self, n: int) -> List[T]:
if n == 1:
return self
@ -257,19 +266,18 @@ class List:
y.append("]")
return str.cat(y)
# Helper functions
# Helper functions
def append(self, x: T):
def append(self, x: T) -> void:
self._resize_if_full()
self.arr[self.len] = x
self.len += 1
def extend(self, itr: Generator[T]):
def extend(self, itr: Generator[T]) -> void:
for a in itr:
self.append(a)
def insert(self, idx: int, x: T):
def insert(self, idx: int, x: T) -> void:
n = self.__len__()
if idx < 0:
idx += n
@ -280,12 +288,12 @@ class List:
self._resize_if_full()
i = n
while i > idx:
self.arr[i] = self.arr[i-1]
self.arr[i] = self.arr[i - 1]
i -= 1
self.arr[idx] = x
self.len += 1
def pop(self, idx: int = -1):
def pop(self, idx: int = -1) -> T:
if self.__len__() == 0:
raise IndexError("pop from empty list")
if idx < 0:
@ -295,7 +303,7 @@ class List:
del self[idx]
return x
def remove(self, x: T):
def remove(self, x: T) -> bool:
i = 0
for a in self:
if a == x:
@ -304,10 +312,10 @@ class List:
i += 1
return False
def clear(self):
def clear(self) -> void:
self.len = 0
def index(self, x: T):
def index(self, x: T) -> int:
i = 0
for a in self:
if a == x:
@ -315,48 +323,48 @@ class List:
i += 1
return -1
def count(self, x: T):
def count(self, x: T) -> int:
count = 0
for a in self:
if a == x:
count += 1
return count
def reverse(self):
def reverse(self) -> void:
i = 0
while i < self.len//2:
while i < self.len // 2:
j = self.len - i - 1
x = self[i]
self[i] = self[j]
self[j] = x
i += 1
def copy(self):
def copy(self) -> List[T]:
return self.__copy__()
# Internal helpers
# Internal helpers
def _idx_check(self, idx: int, msg: str):
def _idx_check(self, idx: int, msg: str) -> void:
if idx >= self.len or idx < 0:
raise IndexError(msg)
def _resize(self, new_cap: int):
def _resize(self, new_cap: int) -> void:
p = Ptr[T](gc.realloc(self.arr.ptr.as_byte(), new_cap * gc.sizeof(T)))
self.arr = Array[T](p, new_cap)
def _resize_if_full(self):
def _resize_if_full(self) -> void:
if self.len == self.arr.len:
new_cap = (1 + 3*self.len) // 2
new_cap = (1 + 3 * self.len) // 2
self._resize(new_cap)
def __hash__(self):
def __hash__(self) -> int:
# https://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html
seed = 0
for v in self:
seed ^= v.__hash__() + 0x9e3779b9 + (seed << 6) + (seed >> 2)
seed ^= v.__hash__() + 0x9E3779B9 + (seed << 6) + (seed >> 2)
return seed
def _assign_slice(self, ilow: int, ihigh: int, v: Ptr[T], n: int):
def _assign_slice(self, ilow: int, ihigh: int, v: Ptr[T], n: int) -> void:
a = self
L = a.len
@ -379,12 +387,20 @@ class List:
if d < 0:
tail = L - ihigh
str.memmove((a.arr.ptr + (ihigh + d)).as_byte(), (a.arr.ptr + ihigh).as_byte(), tail * gc.sizeof(T))
str.memmove(
(a.arr.ptr + (ihigh + d)).as_byte(),
(a.arr.ptr + ihigh).as_byte(),
tail * gc.sizeof(T),
)
a._resize(L + d)
elif d > 0:
k = L
a._resize(k + d)
str.memmove((a.arr.ptr + (ihigh + d)).as_byte(), (a.arr.ptr + ihigh).as_byte(), (k - ihigh) * gc.sizeof(T))
str.memmove(
(a.arr.ptr + (ihigh + d)).as_byte(),
(a.arr.ptr + ihigh).as_byte(),
(k - ihigh) * gc.sizeof(T),
)
k = 0
while k < n:
@ -393,8 +409,10 @@ class List:
ilow += 1
a.len += d
def _copy_arr(self, start: int, stop: int, length: int):
def _copy_arr(self, start: int, stop: int, length: int) -> Array[T]:
if length <= 0:
return Array[T](Ptr[T](), 0)
return self.arr.slice(start, stop).__copy__()
list = List