KL MArray

## Description

The MArray module provides array objects, meaning sequences of values. For example, an array of numbers. Each number in the array is known as an item. The number of items in an array object can be changed (the array can grow or shrink in size).

MArray is homogeneous meaning all items within an MArray instance must be the same type. For example, it is not possible to have some items be type "TUInt8" while others are "TUInt32", in the same MArray instance. Supporting the ability for items to have different sizes/types within the same instance (meaning heterogeneous) would impose substantial extra memory and processing overhead.

The maximum number of items that can be stored in an array instance is an indefinitely large amount. Storing 100 thousand items is no problem, if the items are small. Storing 100 million items is theoretically possible but would probably be slow, inefficient, and impractical. If you need to store a gigantic number of items, then MArray is the wrong solution for your particular problem; perhaps try a database instead.

## Ordinals

Each item in an array is accessed/specified using its ordinal. The ordinal of the first item is 0. The ordinal of the second item is 1. The ordinal of the third item is 2, etc. Thus if you want to retrieve the value of the first item, then you would be required to specify that you want the item at ordinal 0. If there are 14 items in total, then the ordinal of the last item is 13.

The ordinal of the first item is not 1 because starting at 1 (as opposed to 0) tends to be awkward mathematically, requiring that 1 be subtracted from or added to various calculations. 0-based is more natural mathematically. For example, if you have the ordinal of an item, and you wish to calculate how many items from (and including) that position to the end of the array, then the formula is the total number/count of items minus the ordinal, if the ordinals are 0-based. However if the ordinals are 1-based, then the formula is the total number/count of items minus the ordinal, then plus 1. It is also slightly faster/easier to verify the validity of a 0-based ordinal than a 1-based ordinal.

Note that when a new item is inserted into the array, the ordinals of all following items automatically increase by 1. And when an item is removed from the array, the ordinals of all following items automatically decrease by 1. Thus the ordinals cannot be relied upon to always identify the same items, unless the array never changes, or unless items are only appended never inserted or removed. If this behavior is a problem for you, then MArray is probably the wrong solution for your particular problem; use one of the other modules.

 1
 2
 3
 4
 5
 6

After inserting a new item with value 456 at ordinal 3:

 1
 2
 3
 4
 5
 6
 7

The ordinals are not literally stored with the items. Only the item values are actually stored. The ordinals are known implicitly, or calculated mathematically.

## MNumArray::Create

### Description

This command creates an empty numeric array object, and sets the specified variable to contain a reference to the new array object. You can save memory and increase performance by choosing a smaller numeric type, for example uint16 uses half of the memory that uint32 does, but obviously you can only use uint16 if its smaller range (0-65535) is sufficient for your purposes.

### Pedantic Details

* Any existing reference in the outAry variable is removed and replaced by the reference to the new array object.
* If creation of the new object fails, the outAry variable is unchanged.
* The reference is set to be a non-subset reference (but can subsequently be changed to a subset).

## MNumArray::Append

### Description

This command appends a new item to the specified numeric array object, and sets the value of the item to the specified numeric value (the value is copied into the item).

### Pedantic Details

* If this command fails, the reference and the object are (or appear) unchanged.
* If the object reference is a subset, this command will append to the end of the subset, not to the end of the entire array. Thus it may actually be inserting into the middle of the array, if the subset ends before the end of the array. In other words, it inserts at the subset end.
* The subset range is expanded to include the appended new item.
* Fails if the subset range starts or ends beyond the end of the array. Acceptable if is exactly at end.
* It is acceptable if the specified array or subset is empty.

### Errors

 MArray::kError::IncorrectObjectType
 MArray::kError::InvalidSubset
 MArray::kError::MaxLimit
 MMemory::kError::Insufficient

## MNumArray::InsertAtStart

### Description

This command inserts a new item into the specified numeric array object, and sets the value of the item to the specified numeric value. The item is inserted at the start to become the first item (its ordinal will be 0). This command produces exactly the same result as invoking MNumArray::Insert with an ordinal of 0.

This command is not named "Prepend" (by analogy with "Append") because prepend tends to imply that the new item can be "tacked on" or joined with the pre-existing items with little or no disturbance to the pre-existing items, whereas in reality this command is forced to move/copy every single pre-existing item value to the next storage slot to make the first storage slot free for the new item value being inserted.

Although this command is unable to operate as "prepend" implies, the MNumArray::Append command does in fact operate as "append" implies (with little or no disturbance to the pre-existing items, except if it is a subset). Thus the MNumArray::Append command is usually much faster than the MNumArray::InsertAtStart command, especially if the array contains a large number of items.

### Pedantic Details

* If the reference is a subset, it inserts at the start of the subset.
* It is acceptable if the specified array or subset is empty.
* See MNumArray::Insert for other details.

## MNumArray::Insert

### Parameters

 inAtOrdinal
 inValue

### Description

This command inserts a new item into the specified numeric array object at the specified ordinal (position), and sets the value of the new item to the specified numeric value.

The ordinal of the last item in the array is the item count minus 1. Therefore if you insert at that ordinal, the last item will continue to be the last item (the new item will be the second-last item). If inAtOrdinal exactly equals the item count (being the ordinal of the first non-existent item) then the new item will be the last of the items, meaning the same result as if the item were appended.

If inAtOrdinal is greater than the item count, then this command fails with the kError::InvalidOrdinal error code. This strict behavior means that the ordinal of the newly inserted item is always exactly equal to inAtOrdinal. Whereas if inAtOrdinal being greater than the item count was interpreted to mean that the item should be appended (relaxed behavior), then it would be possible for the ordinal of the newly inserted item to be different to inAtOrdinal (and then inAtOrdinal would probably have to be changed to an in/out parameter). It was decided that it is simpler and safer to be able to say that as a rule the ordinal of the newly inserted item is always exactly equal to inAtOrdinal.

### Pedantic Details

* The new item is inserted AT the specified ordinal, meaning BEFORE any existing item at the ordinal, not after. The existing item (and all following items) is pushed forward to the next ordinal / storage slot. Inserting at ordinal 0 means the newly inserted item will be the first item.
* Immediately after this command finishes successfully, the ordinal of the newly inserted item is always exactly equal to inAtOrdinal (until other items are inserted or removed).
* If this command fails, the reference and the object are (or appear) unchanged.
* If the object reference is a subset, then inAtOrdinal is an ordinal into the subset, and it inserts into the subset. For example, inAtOrdinal being 0 would mean that it inserts at the start of the subset.
* The subset range is expanded with the newly inserted item (it inserts into the subset).
* Fails if the subset range starts or ends beyond the end of the array. Acceptable if is exactly at end.

### Errors

 MArray::kError::IncorrectObjectType
 MArray::kError::InvalidOrdinal
 MArray::kError::InvalidSubset
 MArray::kError::MaxLimit
 MMemory::kError::Insufficient

## MNumArray::Set

### Parameters

 inOrdinal
 inValue

### Description

This command sets the value of the specified item in the specified numeric array object to the specified value. The item must already exist (it was previously appended or inserted). The existing value of the item is overwritten by the specified value (that is copied into the item).

Fails if inOrdinal is invalid (greater than or equal to the number of items).

The type of the inValue parameter is flexible depending on the type of items the array is storing. If you supply a value bigger than the array item can store, the value is truncated (upper digits/bits removed).

\*\*\*\* TO DO: Perhaps the compiler should disallow supplying a variable of a bigger or incompatible type than the type of items the array is storing. (This would be a compile-time error, not runtime.)

### Pedantic Details

* If the object reference is a subset, then inOrdinal is an ordinal into the subset. For example, inOrdinal being 0 would mean the first item in the subset.
* Fails if inOrdinal specifies an item beyond the end of the subset.
* Fails if the subset range starts beyond the end of the array.
* inOrdinal is added to the subset-start-ordinal to calculate the real ordinal. If this calculation overflows, inOrdinal is considered to be invalid.

### Errors

 MArray::kError::IncorrectObjectType
 MArray::kError::InvalidOrdinal

## MNumArray::Get

### Parameters

 inOrdinal
 outValue

### Description

This command sets the value of the specified item in the specified numeric array object to the specified value. The item must already exist (it was previously appended or inserted). The existing value of the item is overwritten by the specified value (that is copied into the item).

Fails if inOrdinal is invalid (greater than or equal to the number of items).

The type of the outValue parameter is flexible depending on the type of items the array is storing.

\*\*\*\* TO DO: Should the compiler produce an error message if the type of the variable supplied for the outValue parameter is a smaller size than the type of items the array is storing? Perhaps produce an error message if the type is not an exact match? (This would be a compile-time error, not runtime.)

### Pedantic Details

* Behavior regarding subsets is the same as MNumArray::Set.
* This command cannot be used to get the value of items outside of the subset range.

## MNumArray::GetCount

### Description

This command sets the specified variable to the number of items (count of items) in the specified array. However if the reference is a subset, then the variable is set to the number of items in the subset (consistent with the fact that a subset behaves/appears as if it were a separate array object containing only the items within the subset range).