60 lines
1.5 KiB
Python
60 lines
1.5 KiB
Python
# v1
|
|
# Written by nortti
|
|
# Under Unlicense
|
|
|
|
from functools import reduce
|
|
import operator
|
|
|
|
class RankError(Exception):
|
|
None
|
|
|
|
class RectangularArray:
|
|
def __init__(self, sizes, *, default = None, initial = None):
|
|
if isinstance(sizes, int):
|
|
self.sizes = (sizes,)
|
|
else:
|
|
self.sizes = tuple(sizes)
|
|
|
|
self.rank = len(self.sizes)
|
|
|
|
combined_size = reduce(operator.mul, self.sizes)
|
|
|
|
if initial is None:
|
|
self.array = [default] * combined_size
|
|
else:
|
|
if len(initial) != combined_size:
|
|
raise ValueError('Initial array of wrong size passed (expected %i, got %i)' % (combined_size, len(initial)))
|
|
|
|
|
|
def __get_location_from_indices(self, indices):
|
|
if isinstance(indices, int):
|
|
indices = (indices,)
|
|
else:
|
|
indices = tuple(indices)
|
|
|
|
if len(indices) != self.rank:
|
|
raise RankError('Rank mismatch accessing array (expected %i, got %i)' % (self.rank, len(indices)))
|
|
|
|
location = 0
|
|
for dimension in range(self.rank):
|
|
index = indices[dimension]
|
|
size = self.sizes[dimension]
|
|
if index >= size:
|
|
raise IndexError('Index Out of Range (is %i, max %i)' % (index, self.sizes[dimension] - 1))
|
|
|
|
location *= size
|
|
location += index
|
|
|
|
return location
|
|
|
|
def __getitem__(self, indices):
|
|
location = self.__get_location_from_indices(indices)
|
|
return self.array[location]
|
|
|
|
def __setitem__(self, indices, value):
|
|
location = self.__get_location_from_indices(indices)
|
|
self.array[location] = value
|
|
|
|
def __repr__(self):
|
|
return 'RectangularArray(%s, initial = %s)' % (repr(self.sizes), repr(self.array))
|