parrotcode: List aka array routines | |
Contents | C |
src/list.c - List aka array routines
List is roughly based on concepts of IntList (thanks to Steve), so I don't repeat them here.
Especially the same invariants hold, except an empty list is really empty, meaning, push does first check for space.
The main differences are:
- List can hold items of different size, it's suitable for ints and PMCs ..., calculations are still done in terms of items. The item_size is specified at list creation time with the "type" argument.
If you later store different item types in the list, as stated initially, you'll get probably not what you want - so don't do this.
- List does auto grow. The caller may implement a different behaviour if she likes.
- Error checking for out of bounds access is minimal, caller knows better, what should be done.
- List structure itself is different from List_chunk, implying:
list->prev
but list->end
- list chunks don't have ->start
and ->end
fields.
Instead the list has ->start
,
which is start of first chunk,
and ->cap
,
the total usable capacity in the list.
- number of items in chunks are not fixed, but there is a mode using same sized chunks
enum_grow_fixed
MAX_ITEMS
size,
chosen,
when the first access to the array is indexed and beyond MIN_ITEMS
and below 10 * MAX_ITEMS
MAX_ITEMS
a sparse chunk will be created. new P0, 'Array'
set P0, 100000 # sets fixed sized, no sparse
enum_grow_growing
MIN_ITEMS
to MAX_ITEMS
, this will be selected for pushing data on an empty array.enum_grow_mixed
get_chunk
below for details.To save memory, List can handle sparse arrays. This code snippet:
new P0, 'IntList' set P0[1000000], 42
generates 3 List_chunks, one at the beginning of the array, a big sparse chunk and a chunk for the actual data.
Setting values inside sparse chunks changes them to real chunks. For poping/shifting inside sparse chunks, s. return value below.
fixed_items
grow_items
no_power_2
sparse
chunk->items
holds the items of this sparse hole.A List can hold various datatypes. See src/datatypes.h for the enumeration of types.
Not all are yet implemented in list_set
/list_item
, see the switch()
.
Arbitrary length data:
Construct initializer with:
In list_assign
the values are copied into the array, list_get
returns a pointer as for all other data types.
See src/list_2.t and list_new_init()
.
List get functions return a (void*)
pointer to the location of the stored data. The caller has to extract the value from this pointer.
For non existent data beyond the dimensions of the array a NULL
pointer is returned.
For non existing data inside sparse holes, a pointer (void*)-1
is returned.
The caller can decide to assume these data as undef or 0 or whatever is appropriate.
See t/src/{int, }list.c and t/pmc/{int, }list.t.
Also all array usage depends on list.
PARROT_MALLOC PARROT_CANNOT_RETURN_NULL static List_chunk *allocate_chunk(PARROT_INTERP, NOTNULL(List *list), UINTVAL items, UINTVAL size)
static void list_dump(NOTNULL(const List *list), INTVAL type)
static void rebuild_chunk_ptrs(NOTNULL(List *list), int cut)
static void rebuild_sparse(NOTNULL(List *list))
static void rebuild_other(PARROT_INTERP, NOTNULL(List *list))
static void rebuild_fix_ends(NOTNULL(List *list))
rebuild_chunk_list()
.static UINTVAL rebuild_chunk_list(PARROT_INTERP, NOTNULL(List *list))
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static List_chunk *alloc_next_size(PARROT_INTERP, NOTNULL(List *list), int where, UINTVAL idx)
PARROT_IGNORABLE_RESULT PARROT_CANNOT_RETURN_NULL static List_chunk *add_chunk(PARROT_INTERP, NOTNULL(List *list), int where, UINTVAL idx)
PARROT_API PARROT_CONST_FUNCTION PARROT_WARN_UNUSED_RESULT UINTVAL ld(UINTVAL x)
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static List_chunk *get_chunk(PARROT_INTERP, NOTNULL(List *list), NOTNULL(UINTVAL *idx))
idx
, also update the idx
to point into the chunk.rebuild_chunk_list
does provide. if all_chunks_are_MAX_ITEMS
chunk = chunk_list[ idx / MAX_ITEMS ]
idx = idx % MAX_ITEMS
done.
chunk = first
repeat
if (index < chunk->items)
done.
if (index >= items_in_chunk_block)
index -= items_in_chunk_block
chunk += chunks_in_chunk_block
continue
calc chunk and index in this block
done.
rebuild_chunk_list
tries to reduce the complexity, but may fail, if you e.g. do a prime sieve by actually list_delet
ing the none prime numbers.chunk_blocks
are there. They come from:MAX_ITEMS
sized, when this would improve performance.static void split_chunk(PARROT_INTERP, NOTNULL(List *list), NOTNULL(List_chunk *chunk), UINTVAL ix)
idx
MAX_ITEMS
near idx
and if there is still sparse space after the real chunk, this also n*MAX_ITEMS
sized, so that consecutive writing would make MAX_ITEMS
sized real chunks.static void list_set(PARROT_INTERP, NOTNULL(List *list), NULLOK(void *item), INTVAL type, INTVAL idx)
item
of type type
in chunk at idx
.PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static void *list_item(PARROT_INTERP, NOTNULL(List *list), int type, INTVAL idx)
type
in the chunk at idx
.static void list_append(PARROT_INTERP, NOTNULL(List *list), NULLOK(void *item), int type, UINTVAL idx)
PARROT_API PARROT_MALLOC PARROT_CANNOT_RETURN_NULL List *list_new(PARROT_INTERP, PARROT_DATA_TYPE type)
type
.PARROT_API void list_pmc_new(PARROT_INTERP, NOTNULL(PMC *container))
PARROT_API PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL List *list_new_init(PARROT_INTERP, PARROT_DATA_TYPE type, NOTNULL(PMC *init))
list_new_init()
uses these initializers: 0 ... size (set initial size of list)
1 ... array dimensions (multiarray)
2 ... type (overriding type parameter)
3 ... item_size for enum_type_sized
4 ... items_per_chunk
PARROT_API void list_pmc_new_init(PARROT_INTERP, NOTNULL(PMC *container), NOTNULL(PMC *init))
PARROT_API PARROT_MALLOC PARROT_CANNOT_RETURN_NULL List *list_clone(PARROT_INTERP, NOTNULL(const List *other))
PARROT_API void list_mark(PARROT_INTERP, NOTNULL(List *list))
PARROT_API void list_visit(PARROT_INTERP, NOTNULL(List *list), NOTNULL(void *pinfo))
pinfo
is the visit info, (see include/parrot/pmc_freeze.h>).PARROT_API PARROT_WARN_UNUSED_RESULT PARROT_PURE_FUNCTION INTVAL list_length(SHIM_INTERP, NOTNULL(const List *list))
PARROT_API void list_set_length(PARROT_INTERP, NOTNULL(List *list), INTVAL len)
len
.PARROT_API void list_insert(PARROT_INTERP, NOTNULL(List *list), INTVAL idx, INTVAL n_items)
n_items
at idx
.PARROT_API void list_delete(PARROT_INTERP, NOTNULL(List *list), INTVAL idx, INTVAL n_items)
n_items
at idx
.PARROT_API void list_push(PARROT_INTERP, NOTNULL(List *list), NULLOK(void *item), int type)
item
of type type
on to the end of the list.PARROT_API void list_unshift(PARROT_INTERP, NOTNULL(List *list), NULLOK(void *item), int type)
item
of type type
on to the start of the list.PARROT_API PARROT_CAN_RETURN_NULL void *list_pop(PARROT_INTERP, NOTNULL(List *list), int type)
type
from the end of the list.PARROT_API PARROT_CAN_RETURN_NULL void *list_shift(PARROT_INTERP, NOTNULL(List *list), int type)
type
from the start of the list.PARROT_API void list_assign(PARROT_INTERP, NOTNULL(List *list), INTVAL idx, NULLOK(void *item), int type)
item
of type type
to index idx
.PARROT_API PARROT_CAN_RETURN_NULL PARROT_WARN_UNUSED_RESULT void *list_get(PARROT_INTERP, NOTNULL(List *list), INTVAL idx, int type)
type
at index idx
.PARROT_API void list_splice(PARROT_INTERP, NOTNULL(List *list), NULLOK(List *value_list), INTVAL offset, INTVAL count)
count
items starting at offset
with the items in value
.count
is 0 then the items in value
will be inserted after offset
.
|