cvsuser 02/10/10 06:42:38
Modified: . intlist.c
t/pmc intlist.t
Added: . list.c
Log:
add list.c, fix intlist + test
Revision Changes Path
1.4 +13 -25 parrot/intlist.c
Index: intlist.c
===================================================================
RCS file: /cvs/public/parrot/intlist.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -w -r1.3 -r1.4
--- intlist.c 27 Sep 2002 14:50:48 -0000 1.3
+++ intlist.c 10 Oct 2002 13:42:32 -0000 1.4
@@ -1,7 +1,7 @@
/* intlists.c
* Copyright: (When this is determined...it will go here)
* CVS Info
- * $Id: intlist.c,v 1.3 2002/09/27 14:50:48 tom Exp $
+ * $Id: intlist.c,v 1.4 2002/10/10 13:42:32 leo Exp $
* Overview:
* Regex stack handling routines for Parrot
* Data Structure and Algorithms:
@@ -189,7 +189,7 @@
IntList_Chunk* lastChunk = list->prev;
size_t len = 0;
/* allocate a new chunk_list buffer, old one my have moved
- * firsr, count chunks */
+ * first, count chunks */
while (1) {
len++;
if (chunk == lastChunk) break;
@@ -394,26 +394,14 @@
intlist_extend(Interp* interpreter, IntList* list, INTVAL length)
{
IntList_Chunk* chunk = list->prev;
- INTVAL to_add = length - list->length;
-
- while (to_add > 0) {
- INTVAL available = INTLIST_CHUNK_SIZE - chunk->end;
- INTVAL end;
-
- /* Zero out all newly added elements */
- end = (to_add <= available) ? chunk->end + to_add : INTLIST_CHUNK_SIZE;
- memset(&((INTVAL*)chunk->buffer.bufstart)[chunk->end],
- 0,
- sizeof(INTVAL) * (end - chunk->end));
- to_add -= end - chunk->end;
- chunk->end = end;
-
- if (to_add > 0) push_chunk(interpreter, list);
-
+ INTVAL idx = length - list->length + chunk->end;
+ INTVAL chunks_to_add = idx / INTLIST_CHUNK_SIZE;
+ for (; chunks_to_add ; chunks_to_add--) {
+ chunk->end = INTLIST_CHUNK_SIZE;
+ push_chunk(interpreter, list);
chunk = chunk->next;
}
-
- assert(length >= list->length);
+ chunk->end = idx % INTLIST_CHUNK_SIZE;
list->length = length;
}
1.1 parrot/list.c
Index: list.c
===================================================================
#define INTLIST_EMUL
/* grrmml */
#define intlist_length xx_x
#include "parrot/parrot.h"
#ifdef LIST_TEST
#define LIST_DEBUG
#include "parrot/embed.h"
#undef INTLIST_EMUL
#endif
#undef intlist_length
#define intlist_length intlist_length
#include <limits.h>
typedef enum {
enum_type_undef,
enum_type_bit,
enum_type_char,
enum_type_short,
enum_type_int,
enum_type_ptr,
enum_type_INTVAL,
enum_type_FLOATVAL,
enum_type_PMC,
enum_type_STRING,
} ARRAY_ENTRY_TYPE;
typedef struct List_chunk {
Buffer data; /* item store */
UINTVAL items; /* items in this chunk */
UINTVAL n_chunks; /* # of chunks with grow policy in flags */
UINTVAL n_items; /* # of itemks with grow policy in flags */
struct List_chunk *next;
struct List_chunk *prev;
} List_chunk;
#define sparse_flag BUFFER_private0_FLAG
#define no_power_2 BUFFER_private1_FLAG
#define fixed_items BUFFER_private2_FLAG
#define grow_items BUFFER_private3_FLAG
typedef struct List {
Buffer chunk_list; /* pointers to chunks */
UINTVAL length; /* number of items in list */
UINTVAL start; /* offset, where array[0] is */
int item_type; /* item type */
int item_size; /* item size */
UINTVAL cap; /* list capacity in items */
int grow_policy; /* fixed / variable len */
UINTVAL collect_runs; /* counter, when chunklist was built */
UINTVAL n_chunks; /* number of chunks */
List_chunk *first; /* first chunk holding data */
List_chunk *last; /* last chunk */
} List;
enum {
enum_grow_unknown, /* at beginning, or after emptying list */
enum_grow_fixed = 1, /* fixed maximum size */
enum_grow_mixed = 2, /* other */
enum_grow_growing = 4, /* growing at begin of list */
} ARRAY_GROW_TYPE;
enum {
enum_add_at_start, /* don't swap these */
enum_add_at_end
} ARRAY_ADD_POS;
#define MIN_ITEMS 4 /* smallest chunk can hold */
#ifdef LIST_TEST
#define LD_MAX 4 /* log2(MAX_ITEMS) */
#define MAX_ITEMS 16 /* biggest chunk can hold */
#else
#define LD_MAX 10 /* log2(MAX_ITEMS) */
#define MAX_ITEMS 1024 /* biggest chunk can hold */
#endif
#define MAX_MASK (MAX_ITEMS-1)
/*
* bigger MAX_ITEMS didn't improve much in my tests
* 10^6 list_get, MAX_ITEMS 1024: 0.34s, 2048: 0.33s
*/
List * list_new(Interp *interpreter, INTVAL type);
List * list_clone(Interp *interpreter, List *other);
PMC* list_mark(Interp* interpreter, List* list, PMC* last);
INTVAL list_length(Interp* interpreter, List* list);
void list_push(Interp *interpreter, List *list, void *item, int type);
void list_unshift(Interp *interpreter, List *list, void *item, int type);
void * list_pop(Interp *interpreter, List *list, int type);
void * list_shift(Interp *interpreter, List *list, int type);
void list_assign(Interp *interpreter, List *list, INTVAL idx,
void *item, int type);
void * list_get(Interp *interpreter, List *list, INTVAL idx, int type);
void list_insert(Interp *interpreter, List *list, INTVAL idx, INTVAL n_items);
void list_delete(Interp *interpreter, List *list, INTVAL idx, INTVAL n_items);
/* EOH */
/* list.c */
static List_chunk* allocate_chunk(Interp *interpreter, List *list,
UINTVAL items, UINTVAL size);
#ifdef LIST_DEBUG
static void list_dump(FILE *fp, List *list, INTVAL type);
#endif
static UINTVAL rebuild_chunk_list(Interp *interpreter, List *list);
static List_chunk * next_size(Interp *interpreter, List *list,
int where, UINTVAL idx);
static List_chunk * add_chunk(Interp *interpreter, List *list,
int where, UINTVAL idx);
static UINTVAL ld(UINTVAL x);
static List_chunk * get_chunk(Interp * interpreter, List *list, UINTVAL *idx);
static void split_chunk(Interp *interpreter, List *list,
List_chunk *chunk, UINTVAL idx);
static void
list_set(Interp *interpreter, List *list, void *item, INTVAL type, INTVAL idx);
static void * list_item(Interp *interpreter, List *list, int type, INTVAL idx);
static void list_append(Interp *interpreter, List *list, void *item,
int type, UINTVAL idx);
#define chunk_list_size(list) \
(list->chunk_list.buflen / sizeof(List_chunk *))
/* hide the ugly cast somehow: */
#define chunk_list_ptr(list, idx) \
((List_chunk**)list->chunk_list.bufstart)[idx]
/*
* 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 ..., but calculations are still done in terms of items.
* The item_size is specified at list reation time in the item type.
*
* 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.
*
* - List is a standalone object, different fron List_chunk, implying:
* - end of list is not list->prev but list->end
* - start of list is list->first
* - the list of chunks is not closed, detecting the end is more simple
* - the List itself doesn't move around
*
* - 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 may differ, but there is a mode
* using same sized chunks
*
*
* Grow policy
* -----------
* enum_grow_fixed:
* All records are of MAX_ITEMS size, chosen, when the first access to
* the array is indexed and beyond MIN_ITEMS
*
* enum_grow_growing:
* chunk sizes grow from MIN_ITEMS to MAX_ITEMS, this will be selected
* for pushing data on an empty array
*
* enum_grow_mixed:
* any mixture of above chunk types and when sparse chunks are present
*
* The chunks hold the information, how many chunks are
* growing or fixed beginning from the current, and how many items are
* included in this range.
*
* Sparse lists
* ------------
*
* To save memory, List can handle sparse arrays. This code snippet:
*
* new P0, .List
* 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.
*
* Chunk types
* -----------
*
* fixed_items ... allocated space, size is a power of 2
* consecutive chunks are same sized
* grow_items ... same, but consecutive chunks are growing
* no_power_2 ... allocated space any size
* sparse_flag ... only dummy allocation, chunk->items holds
* the items of this sparse hole
*
* Return value
* ------------
*
* 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.
*
*
* Testing:
* --------
* If INTLIST_EMUL is defined, this code may be linked to parrot
* instead of intlist.c and can then run all intlist.t tests, which
* are pretty thorough.
*
* There are also some tests included at the bottom. This file can
* be linked against libparrot and run standalone when
* LIST_TEST is defined:
*
* cc -g -DLIST_TEST -Wall -Iinclude -o list list.c \
* blib/lib/libparrot.a -lm -ldl && ./list
*
*/
/* make a new chunk, size bytes big, holding items items */
static List_chunk*
allocate_chunk(Interp *interpreter, List *list, UINTVAL items, UINTVAL size)
{
List_chunk* chunk;
interpreter->DOD_block_level++;
interpreter->GC_block_level++;
chunk = (List_chunk *) new_bufferlike_header(interpreter, sizeof(*chunk));
chunk->items = items;
Parrot_allocate(interpreter, (Buffer*) chunk, size);
interpreter->DOD_block_level--;
interpreter->GC_block_level--;
return chunk;
}
#ifdef LIST_DEBUG
/* only char and int are supported currently */
static void list_dump(FILE *fp, List *list, INTVAL type)
{
List_chunk* chunk = list->first;
UINTVAL i;
UINTVAL idx = 0;
for (; chunk; chunk = chunk->next) {
printf("[");
if (chunk->data.flags & sparse_flag)
printf(INTVAL_FMT " x ''", chunk->items);
else
for(i=0; i < chunk->items; i++) {
if (idx++ >= list->start && idx <= list->length+list->start) {
switch (list->item_type) {
case enum_type_int:
case enum_type_short:
printf("%d", (int)((int*)chunk->data.bufstart)[i]);
break;
case enum_type_char:
printf("%c", (char)((char*)chunk->data.bufstart)[i]);
break;
}
}
if (i <chunk->data.buflen/list->item_size - 1)
printf(",");
}
printf("]");
if (chunk->next)
printf(" -> ");
}
printf("\n");
}
#endif
/* count chunks and fix prev pointers */
static void
rebuild_chunk_ptrs(List *list)
{
List_chunk* chunk, *prev;
UINTVAL len = 0;
for (prev = 0, chunk = list->first; chunk; chunk = chunk->next) {
/* skip empty chunks */
if (!chunk->items) {
if (prev)
prev->next = chunk->next;
else
list->first = chunk->next;
continue;
}
len++;
chunk->prev = prev;
prev = chunk;
list->last = chunk;
}
list->last->next = 0;
list->first->prev = 0;
list->n_chunks = len;
}
/* coalesce adjacent sparse chunks */
static void
rebuild_spares(List *list)
{
List_chunk* chunk, *prev;
int changes = 0;
for (prev = 0, chunk = list->first; chunk; chunk = chunk->next) {
if (prev && (prev->data.flags & sparse_flag) &&
(chunk->data.flags & sparse_flag)) {
prev->items += chunk->items;
chunk->items = 0;
changes++;
continue;
}
prev = chunk;
}
if (changes)
rebuild_chunk_ptrs(list);
}
/* coalesce adjacent irregular chunks */
static void
rebuild_other(Interp *interpreter, List *list)
{
List_chunk* chunk, *prev;
int changes = 0;
for (prev = 0, chunk = list->first; chunk; chunk = chunk->next) {
/* two adjacent irregular chunks */
if (prev && (prev->data.flags & no_power_2) &&
(chunk->data.flags & no_power_2)) {
/* XXX don't make chunks bigger then MAX_ITEMS,
* if bigger, split them */
Parrot_reallocate(interpreter, (Buffer *) prev,
(prev->items + chunk->items) * list->item_size);
mem_sys_memmove(
(char *)prev->data.bufstart + prev->items * list->item_size,
(char *)chunk->data.bufstart,
chunk->items * list->item_size);
prev->items += chunk->items;
chunk->items = 0;
changes++;
continue;
}
prev = chunk;
}
if (changes)
rebuild_chunk_ptrs(list);
}
static void
rebuild_fix_ends(Interp *interpreter, List *list)
{
List_chunk* chunk;
chunk = list->first;
/* irregular first chunk */
/* XXX doesn't work - disabled */
if (0 && (chunk->data.flags & no_power_2) && chunk->items < MAX_ITEMS) {
/* round up to power 2 */
UINTVAL items = 1 << (ld(chunk->items) + 1);
/* if we have a next chunk, check, if we can make a growing
* sequence, but only for short lists */
if (chunk->next && (chunk->next->data.flags != sparse_flag)) {
if (list->length < MAX_ITEMS &&
items <= (chunk->next->items >> 1)) {
items = chunk->next->items >> 1;
}
/* else make same size if possible */
else if (items < chunk->next->items) {
items = chunk->next->items;
}
}
assert(items >= chunk->items);
if (items != chunk->items && list->start == 0) {
INTVAL diff = items - (INTVAL) chunk->items;
list->start += diff;
list->cap += diff;
Parrot_reallocate(interpreter, (Buffer *) chunk,
items * list->item_size);
mem_sys_memmove(
(char *)chunk->data.bufstart + diff * list->item_size,
(char *)chunk->data.bufstart,
chunk->items * list->item_size);
chunk->items = items;
chunk->data.flags &= ~no_power_2;
}
}
/* fix end */
if (list->n_chunks <= 2 && (chunk->data.flags & no_power_2) &&
(!chunk->next || chunk->next->items == 0 ||
list->start + list->length <= chunk->items)) {
chunk->data.flags = 0;
list->grow_policy = enum_grow_unknown;
list->cap += chunk->data.buflen / list->item_size - chunk->items;
chunk->items = chunk->data.buflen / list->item_size;
}
/* XXX
* - if last is empty and last->prev not full then delete last
* - combine small chunks if list is big
*/
}
static UINTVAL
rebuild_chunk_list(Interp *interpreter, List *list)
{
List_chunk* chunk, *prev, *first;
UINTVAL len;
/* first, count chunks and fix prev pointers */
rebuild_chunk_ptrs(list);
/* if not regular, check & optimize */
if (list->grow_policy == enum_grow_mixed) {
rebuild_spares(list);
rebuild_other(interpreter, list);
rebuild_fix_ends(interpreter, list);
}
/* allocate a new chunk_list buffer, if old one has moved or
* is too small */
len = list->n_chunks;
if (list->collect_runs != interpreter->collect_runs ||
len > chunk_list_size(list)) {
len = 1 << (ld(len) + 1);
if (len < 4)
len = 4;
Parrot_allocate(interpreter, &list->chunk_list,
len * sizeof(List_chunk *));
list->collect_runs = interpreter->collect_runs;
}
chunk = list->first;
list->grow_policy = enum_grow_unknown;
/* fill list and update statistics */
for (first = chunk, prev = 0, len = 0; chunk; chunk = chunk->next) {
chunk_list_ptr(list, len) = chunk;
len++;
/* look, what type of item sizes we have */
chunk->n_chunks = 1;
chunk->n_items = chunk->items;
/* sparse hole or irregular chunk */
if (chunk->data.flags & (sparse_flag|no_power_2)) {
first = chunk->next;
list->grow_policy = enum_grow_mixed;
continue;
}
/* clear flag */
chunk->data.flags = enum_grow_unknown;
if (first && first != chunk) {
/* constant area */
if (first->items == chunk->items) {
first->n_chunks++;
first->n_items += chunk->items;
first->data.flags = fixed_items;
list->grow_policy |= enum_grow_fixed;
}
/* growing area */
else if (prev->items == chunk->items >> 1) {
first->n_chunks++;
first->n_items += chunk->items;
first->data.flags = grow_items;
list->grow_policy |= enum_grow_growing;
}
/* different growing scheme starts here */
else {
first = chunk;
}
}
prev = chunk;
}
if (list->grow_policy && list->grow_policy != enum_grow_growing &&
list->grow_policy != enum_grow_fixed)
list->grow_policy = enum_grow_mixed;
assert(len);
return len;
}
/* calculate size and items for next chunk and
* allocate it
*/
static List_chunk *
next_size(Interp *interpreter, List *list, int where, UINTVAL idx)
{
UINTVAL items, size;
List_chunk * new_chunk;
int much = idx - list->cap >= MIN_ITEMS;
int sparse = (INTVAL)idx - (INTVAL)list->cap >= 2*MAX_ITEMS;
if (sparse) {
assert(where);
/* don't add sparse chunk at start of list */
if (!list->n_chunks) {
list->grow_policy = enum_grow_fixed;
/* if wee need more, the next allocation will allocate
* the rest */
items = MAX_ITEMS;
size = items * list->item_size;
sparse = 0;
}
else {
items = idx - list->cap - 1;
/* round down
* this function will then be called again, to
* add the final real chunk, with the rest of the needed size */
items &= ~(MAX_ITEMS - 1);
list->grow_policy = enum_grow_mixed;
/* allocate a dummy chunk holding many items virtually */
size = list->item_size;
}
}
/* initial size for empty lists
* grow_policy is not known yet or was different
*/
else if (!list->cap) {
#ifdef ONLY_FIXED_ALLOCATIONS
list->grow_policy = enum_grow_fixed;
#else
list->grow_policy = enum_grow_unknown;
#endif
/* more then MIN_ITEMS, i.e. indexed access beyond length */
if (much) {
list->grow_policy = enum_grow_fixed;
items = MAX_ITEMS;
}
else {
/* TODO make bigger for small items like char */
items = MIN_ITEMS;
}
size = items * list->item_size;
}
else {
if (list->grow_policy & (enum_grow_fixed | enum_grow_mixed))
items = MAX_ITEMS;
else {
items = where ? list->last->items : list->first->items;
/* push: allocate at end, more if possbile */
if (where) {
if (items < MAX_ITEMS) {
items <<= 1;
list->grow_policy = enum_grow_growing;
}
}
/* unshift: if possible, make less items */
else {
list->grow_policy = enum_grow_growing;
if (items > MIN_ITEMS)
items >>= 1; /* allocate less */
/* if not: second allocation from unshift */
else {
list->grow_policy = enum_grow_mixed;
items = MAX_ITEMS;
}
}
}
size = items * list->item_size;
}
new_chunk = allocate_chunk(interpreter, list, items, size);
list->cap += items;
if (sparse)
new_chunk->data.flags |= sparse_flag;
return new_chunk;
}
/* add chunk at start or end */
static List_chunk *
add_chunk(Interp *interpreter, List *list, int where, UINTVAL idx)
{
List_chunk * chunk = where ? list->last : list->first;
List_chunk * new_chunk;
new_chunk = next_size(interpreter, list, where, idx);
if (where) { /* at end */
if (chunk)
chunk->next = new_chunk;
list->last = new_chunk;
if (!list->first)
list->first = new_chunk;
}
else {
new_chunk->next = chunk;
list->first = new_chunk;
if (!list->last)
list->last = new_chunk;
}
rebuild_chunk_list(interpreter, list);
return new_chunk;
}
/* stolen from malloc.c
* calc log2(x) */
static UINTVAL
ld(UINTVAL x)
{
UINTVAL m; /* bit position of highest set bit of m */
/* On intel, use BSRL instruction to find highest bit */
#if defined(__GNUC__) && defined(i386)
__asm__("bsrl %1,%0\n\t"
: "=r" (m)
: "g" (x));
#else
{
/*
Based on branch-free nlz algorithm in chapter 5 of Henry
S. Warren Jr's book "Hacker's Delight".
*/
unsigned int n = ((x - 0x100) >> 16) & 8;
x <<= n;
m = ((x - 0x1000) >> 16) & 4;
n += m;
x <<= m;
m = ((x - 0x4000) >> 16) & 2;
n += m;
x = (x << m) >> 14;
m = 13 - n + (x & ~(x>>1));
}
#endif
return m;
}
/*
* Here is a small table, providing the basics of growing sized
* addressing, for people like me, who's math lessons are +30 years
* in the past ;-)
*
* ch# size idx +4 bit ld2(idx) -ld2(4)
*
* 0 4 0..3 4..7 0000 01xx 2 0
* 1 8 4..11 8..15 0000 1xxx 3 1
* 2 16 12..27 16..31 0001 xxxx 4 2
* ...
* 8 1024 1020.. ...2047 10 8
*/
/* get the chunk for idx, also update the idx to point into the chunk */
static List_chunk *
get_chunk(Interp * interpreter, List *list, UINTVAL *idx)
{
List_chunk *chunk;
UINTVAL i;
#ifndef GC_IS_MALLOC
if (list->collect_runs != interpreter->collect_runs)
rebuild_chunk_list(interpreter, list);
#endif
/* fixed sized chunks - easy: all MAX_ITEMS sized */
if (list->grow_policy == enum_grow_fixed) {
chunk = chunk_list_ptr(list, *idx >> LD_MAX);
*idx &= MAX_MASK;
return chunk;
}
#ifdef SLOW_AND_BORING
for (chunk = list->first; chunk; chunk = chunk->next) {
if (*idx < chunk->items)
return chunk;
*idx -= chunk->items;
}
internal_exception(INTERNAL_PANIC , "list structure chaos!\n");
#endif
/* else look at chuns flags, what grow type follows and
* adjust chunks and idx */
for (i = 0, chunk = list->first; chunk; ) {
/* if we have no more items, we have found the chunk */
if (*idx < chunk->items)
return chunk;
/* now look, if we can use the range of items:
* if idx is beyond n_items, skip n_chunks */
if (*idx >= chunk->n_items) {
i += chunk->n_chunks;
*idx -= chunk->n_items;
chunk = chunk_list_ptr(list, i);
continue;
}
/* we are inside this range of items */
if (chunk->data.flags & fixed_items) {
/* all chunks are chunk->items big, a power of 2 */
chunk = chunk_list_ptr(list, i + (*idx >> ld(chunk->items)));
*idx &= chunk->items - 1;
return chunk;
}
if (chunk->data.flags & grow_items) {
/* the next chunks are growing from chunk->items ... last->items */
UINTVAL ld_first, slot;
List_chunk * last;
last = chunk_list_ptr(list, i + chunk->n_chunks - 1);
ld_first = ld(chunk->items);
slot = ld(*idx + chunk->items) - ld_first;
/* we are in this growing area, so we are done */
assert (slot < chunk->n_chunks);
*idx -= (1 << (ld_first + slot)) - chunk->items;
return chunk_list_ptr(list, i + slot);
}
if (chunk->data.flags & (sparse_flag | no_power_2)) {
/* these chunk hold exactly chunk->items */
*idx -= chunk->items;
i++;
chunk = chunk->next;
continue;
}
internal_exception(INTERNAL_PANIC , "list structure chaos!\n");
}
internal_exception(INTERNAL_PANIC , "list structure chaos!\n");
return 0;
}
/* split a sparse chunk, so that we have
* - allocated space at idx
* if sparse is big:
* - MAX_ITEMS near idx and if there is still sparse space after
* the real chunk, this whole also n*MAX_ITEMS sized, so that
* consecutive writing would make MAX_ITEMS sized real chunks
*/
static void
split_chunk(Interp *interpreter, List *list, List_chunk *chunk, UINTVAL ix)
{
List_chunk *new_chunk;
INTVAL n1, n2, n3, idx = ix;
/* allocate space at idx */
if (chunk->items <= MAX_ITEMS) {
/* it fits, just allocate */
Parrot_reallocate(interpreter, (Buffer *) chunk,
chunk->items * list->item_size);
chunk->data.flags |= no_power_2;
chunk->data.flags &= ~sparse_flag;
}
else {
/* split chunk->items:
* n3 = n*MAX_ITEMS after chunk
* n2 = MAX_ITEMS chunk
* n1 = rest before */
n2 = MAX_ITEMS;
n3 = ((chunk->items-idx) / MAX_ITEMS) * MAX_ITEMS;
n1 = chunk->items - n2 - n3;
chunk->items = n2;
Parrot_reallocate(interpreter, (Buffer *) chunk,
chunk->items * list->item_size);
chunk->data.flags &= ~sparse_flag;
if (n3) {
new_chunk = allocate_chunk(interpreter, list, n3, list->item_size);
new_chunk->data.flags |= sparse_flag;
new_chunk->next = chunk->next;
if (chunk->next)
chunk->next = new_chunk;
else
list->last = new_chunk;
}
/* size before idx */
if (n1 > 0) {
/* insert a new sparse chunk before this one */
new_chunk = allocate_chunk(interpreter, list, n1, list->item_size);
new_chunk->data.flags |= sparse_flag;
new_chunk->next = chunk;
if (chunk->prev)
chunk->prev->next = new_chunk;
else
list->first = new_chunk;
}
}
rebuild_chunk_list(interpreter, list);
}
/* set item of type in chunk at idx */
static void
list_set(Interp *interpreter, List *list, void *item, INTVAL type, INTVAL idx)
{
INTVAL oidx = idx;
List_chunk *chunk;
chunk = get_chunk(interpreter, list, (UINTVAL *)&idx);
assert(chunk);
/* if this is a sparse chunk:
* split in possibly 2 sparse parts before and after
* then make a real chunk, rebuild chunk list
* and set item */
if ( chunk->data.flags & sparse_flag ) {
split_chunk(interpreter, list, chunk, idx);
/* reget chunk and idx */
idx = oidx;
chunk = get_chunk(interpreter, list, (UINTVAL *)&idx);
assert(chunk);
assert(!(chunk->data.flags & sparse_flag) );
}
switch (type) {
case enum_type_char:
((char*)chunk->data.bufstart)[idx] = (char)PTR2INTVAL(item);
break;
case enum_type_short:
((short*)chunk->data.bufstart)[idx] = (short)PTR2INTVAL(item);
break;
case enum_type_int:
((int*)chunk->data.bufstart)[idx] = (int)PTR2INTVAL(item);
break;
case enum_type_INTVAL:
((INTVAL*)chunk->data.bufstart)[idx] = PTR2INTVAL(item);
break;
case enum_type_FLOATVAL:
((FLOATVAL*)chunk->data.bufstart)[idx] = *(FLOATVAL*) item;
break;
case enum_type_PMC:
((PMC**)chunk->data.bufstart)[idx] = (PMC*)item;
break;
case enum_type_STRING:
((STRING**)chunk->data.bufstart)[idx] = (STRING*)item;
break;
default:
internal_exception(1, "type N/Y\n");
break;
}
}
/* get pointer to item of type in chunk at idx */
static void *
list_item(Interp *interpreter, List *list, int type, INTVAL idx)
{
List_chunk *chunk;
chunk = get_chunk(interpreter, list, (UINTVAL *)&idx);
/* if this is a sparse chunk
* return -1, the caller may decide to return 0 or undef or
* whatever */
if (chunk->data.flags & sparse_flag) {
#ifdef INTLIST_EMUL
static int null = 0;
return (void*)&null;
#else
return (void*)-1;
#endif
}
switch (type) {
case enum_type_char:
return (void*)&((char*)chunk->data.bufstart)[idx];
break;
case enum_type_short:
return (void*)&((short*)chunk->data.bufstart)[idx];
break;
case enum_type_int:
return (void*)&((int*)chunk->data.bufstart)[idx];
break;
case enum_type_INTVAL:
return (void*)&((INTVAL*)chunk->data.bufstart)[idx];
break;
case enum_type_FLOATVAL:
return (void*)&((FLOATVAL*)chunk->data.bufstart)[idx];
break;
case enum_type_PMC:
return (void*)((PMC**)chunk->data.bufstart)[idx];
break;
case enum_type_STRING:
return (void*)((STRING**)chunk->data.bufstart)[idx];
break;
default:
internal_exception(1, "type N/Y\n");
break;
}
return 0;
}
/* add one or more chunks at end of list */
static void
list_append(Interp *interpreter, List *list, void *item, int type, UINTVAL idx)
{
/* initially, list may be empty, also used by assign */
while (idx >= list->cap)
add_chunk(interpreter, list, enum_add_at_end, idx);
list_set(interpreter, list, item, type, idx);
/* invariant: prepare for next push */
if (idx >= list->cap-1)
add_chunk(interpreter, list, enum_add_at_end, 0);
}
/* public interface functions */
/*
* TODO pass grow policy additionally
*/
List *
list_new(Interp *interpreter, INTVAL type)
{
List *list;
list = (List *) new_bufferlike_header(interpreter, sizeof(*list));
list->item_type = type;
switch (type) {
case enum_type_char:
list->item_size = sizeof(char); break;
case enum_type_short:
list->item_size = sizeof(short); break;
case enum_type_int:
list->item_size = sizeof(int); break;
case enum_type_INTVAL:
list->item_size = sizeof(INTVAL); break;
case enum_type_FLOATVAL:
list->item_size = sizeof(FLOATVAL); break;
case enum_type_PMC:
list->item_size = sizeof(PMC*); break;
case enum_type_STRING:
list->item_size = sizeof(STRING*); break;
default:
internal_exception(1, "N/Y\n"); break;
}
return list;
}
/* barely tested: clone */
/* TODO optimize new array structure, fixed if big */
List *
list_clone(Interp *interpreter, List *other)
{
List * l;
List_chunk * chunk, *prev, *new_chunk;
UINTVAL i;
PMC *op, *np;
STRING *s;
interpreter->DOD_block_level++;
interpreter->GC_block_level++;
l = list_new(interpreter, other->item_type);
mem_sys_memcopy(l, other, sizeof(List));
for (chunk = other->first, prev = 0; chunk ; chunk = chunk->next) {
new_chunk = allocate_chunk(interpreter, l,
chunk->items, chunk->data.buflen);
new_chunk->data.flags = chunk->data.flags;
if (!prev)
l->first = new_chunk;
else
prev->next = new_chunk;
prev = new_chunk;
if (!(new_chunk->data.flags & sparse_flag)) {
switch (l->item_type) {
case enum_type_PMC:
for (i = 0; i < chunk->items; i++) {
op = ((PMC**) chunk->data.bufstart) [i];
if (op) {
np = op->vtable->clone(interpreter, op);
((PMC**) new_chunk->data.bufstart)[i] = np;
}
}
break;
case enum_type_STRING:
for (i = 0; i < chunk->items; i++) {
s = ((STRING**) chunk->data.bufstart) [i];
if (s) {
((STRING**) new_chunk->data.bufstart)[i] =
string_copy(interpreter, s);
}
}
break;
}
}
}
rebuild_chunk_list(interpreter, l);
interpreter->DOD_block_level--;
interpreter->GC_block_level--;
return l;
}
PMC*
list_mark(Interp* interpreter, List* list, PMC* last)
{
List_chunk* chunk = list->first;
for (; chunk; chunk = chunk->next)
buffer_lives((Buffer *) chunk);
buffer_lives((Buffer *) list);
return last;
}
INTVAL
list_length(Interp* interpreter, List* list)
{
UNUSED(interpreter);
return list->length;
}
/* TODO list_set_length */
/* make room for n_items at idx */
void list_insert(Interp *interpreter, List *list, INTVAL idx, INTVAL n_items) {
List_chunk * chunk, *new_chunk, *rest;
INTVAL items;
assert(idx >= 0);
idx += list->start;
assert(n_items >= 0);
if (n_items == 0)
return;
/* empty list */
if (!list->cap) {
idx += n_items;
list->length = idx;
while (idx >= (INTVAL)list->cap)
add_chunk(interpreter, list, enum_add_at_end, idx);
return;
}
list->length += n_items;
list->cap += n_items;
chunk = get_chunk(interpreter, list, (UINTVAL *)&idx);
/* the easy case: */
if (chunk->data.flags & sparse_flag)
chunk->items += n_items;
else {
/* 1. cut this chunk at idx */
list->grow_policy = enum_grow_mixed;
/* allocate a sparse chunk, n_items big */
new_chunk = allocate_chunk(interpreter, list, n_items, list->item_size);
new_chunk->data.flags |= sparse_flag;
/* allocate a small chunk, holding the rest of chunk beyond idx */
items = chunk->items - idx;
/* TODO */
assert(!(chunk->data.flags & no_power_2));
/* TODO check for EOList */
if (items) {
chunk->data.flags = no_power_2;
rest = allocate_chunk(interpreter, list, items, items*list->item_size);
rest->data.flags |= no_power_2;
/* hang them togehter */
rest->next = chunk->next;
chunk->next = new_chunk;
new_chunk->next = rest;
/* copy data over */
mem_sys_memmove(
(char *)rest->data.bufstart,
(char *)chunk->data.bufstart +
idx * list->item_size,
(chunk->items - idx) * list->item_size);
}
else {
new_chunk->next = chunk->next;
chunk->next = new_chunk;
}
chunk->items = idx;
}
rebuild_chunk_list(interpreter, list);
}
/* delete n_items at idx */
void
list_delete(Interp *interpreter, List *list,
INTVAL idx, INTVAL n_items)
{
List_chunk * chunk;
assert(idx >= 0);
idx += list->start;
assert(n_items >= 0);
if (n_items == 0)
return;
chunk = get_chunk(interpreter, list, (UINTVAL *)&idx);
/* deleting beyond end? */
if (idx + n_items > (INTVAL)list->length)
n_items = list->length - idx;
list->length -= n_items;
list->cap -= n_items;
list->grow_policy = enum_grow_mixed;
while (n_items > 0) {
if (idx + n_items <= (INTVAL)chunk->items) {
/* chunk is bigger then we want to delete */
if (!(chunk->data.flags & sparse_flag)) {
chunk->data.flags = no_power_2;
if (idx + n_items <= (INTVAL)chunk->items) {
mem_sys_memmove(
(char *)chunk->data.bufstart +
idx * list->item_size,
(char *)chunk->data.bufstart +
(idx + n_items) * list->item_size,
(chunk->items - idx - n_items) * list->item_size);
}
}
chunk->items -= n_items;
break;
}
if (idx == 0 && n_items >= (INTVAL)chunk->items) {
/* delete this chunk */
n_items -= chunk->items;
/* rebuild_chunk_list will kill it because: */
chunk->items = 0;
if (!chunk->prev)
list->first = chunk->next;
}
else if (idx) {
/* else shrink chunk, it starts at idx then */
if (!(chunk->data.flags & sparse_flag))
chunk->data.flags = no_power_2;
n_items -= chunk->items - idx;
chunk->items = idx;
}
idx = 0;
chunk = chunk->next;
}
rebuild_chunk_list(interpreter, list);
}
void
list_push(Interp *interpreter, List *list, void *item, int type)
{
INTVAL idx = list->start + list->length++;
list_append(interpreter, list, item, type, idx);
}
void
list_unshift(Interp *interpreter, List *list, void *item, int type)
{
List_chunk * chunk;
if (list->start == 0) {
chunk = add_chunk(interpreter, list, enum_add_at_start, 0);
list->start = chunk->items;
}
else
chunk = list->first;
list_set(interpreter, list, item, type, --list->start);
list->length++;
}
void *
list_pop(Interp *interpreter, List *list, int type)
{
UINTVAL idx;
void *ret;
List_chunk * chunk = list->last;
if (list->length == 0) {
return 0;
}
idx = list->start + --list->length;
if (list->length == 0)
list->start = 0;
/* shrink array if necessary */
if (idx < list->cap - chunk->items) {
list->cap -= chunk->items;
chunk = list->last = chunk->prev;
chunk->next = 0;
if (list->n_chunks <= 2)
list->first = list->last;
rebuild_chunk_list(interpreter, list);
}
ret = list_item(interpreter, list, type, idx);
return ret;
}
void *
list_shift(Interp *interpreter, List *list, int type)
{
void * ret;
UINTVAL idx = list->start++;
List_chunk * chunk = list->first;
if (list->length == 0) {
return 0;
}
list->length--;
/* optimize push + shift on empty lists */
if (list->length == 0)
list->start = 0;
ret = list_item(interpreter,list, type, idx);
if (list->start >= chunk->items) {
list->cap -= chunk->items;
chunk = list->first = chunk->next ? chunk->next : list->last;
list->start = 0;
rebuild_chunk_list(interpreter, list);
if (list->n_chunks == 1)
list->last = list->first;
}
return ret;
}
void
list_assign(Interp *interpreter, List *list, INTVAL idx, void *item, int type)
{
INTVAL length = list->length;
if (idx < 0)
idx += length;
if (idx >= length) {
list_append(interpreter, list, item, type, list->start + idx);
list->length = idx + 1;
}
else {
list_set(interpreter, list, item, type, idx);
}
}
void *
list_get(Interp *interpreter, List *list, INTVAL idx, int type)
{
INTVAL length = list->length;
if (idx >= length || -idx > length) {
return 0;
}
if (idx < 0) idx += length;
idx += list->start;
return list_item( interpreter, list, type, idx);
}
#ifdef INTLIST_EMUL
/* getting data outside the array dimensions will
* return the value NULL, which will SIGSEGV, the intlist did
* an explicit exception, so there is not much difference.
* Of course, a check for valid pointers could be added here.
*/
PMC* intlist_mark(Interp*i, IntList*l, PMC* last) {
return list_mark(i, (List*) l, last);
}
IntList *intlist_new(Interp*i){
return (IntList *) list_new(i, enum_type_int);
}
INTVAL intlist_length(Interp* interpreter, IntList* list)
{
UNUSED(interpreter);
return ((List*)list)->length;
}
void intlist_assign(Interp*i, IntList*l, INTVAL idx, INTVAL val) {
list_assign(i, (List*)l, idx, INTVAL2PTR(void*,val), enum_type_int);
}
void intlist_push(Interp*i, IntList*l, INTVAL val) {
list_push(i,(List*)l,INTVAL2PTR(void*, val), enum_type_int);
}
INTVAL intlist_pop(Interp *i, IntList* l) {
int ret = *(INTVAL*) list_pop(i,(List*)l,enum_type_int);
return ret;
}
void intlist_unshift(Interp*i, IntList**l, INTVAL val) {
list_unshift(i, (List*)*l, INTVAL2PTR(void*, val), enum_type_int);
}
INTVAL intlist_shift(Interp *i, IntList**l) {
return *(INTVAL*) list_shift(i,(List*)*l,enum_type_int);
}
INTVAL intlist_get(Interp*i, IntList*l, INTVAL idx) {
return *(INTVAL*) list_get(i,(List*)l,idx, enum_type_int);
}
void intlist_dump(FILE* fp, IntList* list, int verbose) {
#ifdef LIST_DEBUG
list_dump(fp, (List*)list, verbose);
#endif
}
#endif
#ifdef LIST_TEST
int main(int argc, char* argv[]) {
int x, i, j;
char c;
short t;
FLOATVAL f;
STRING *s;
List* list, *list2;
PMC *p1, *p2;
Interp* interpreter = Parrot_new();
if (interpreter == NULL) return 1;
Parrot_init(interpreter, (void*) &interpreter);
list = list_new(interpreter, enum_type_int);
if (list == NULL) return 1;
for (i = 0, x = 32; x < 43; x++, i++) {
list_push(interpreter, list, INTVAL2PTR(void*, x) ,enum_type_int);
j = *(int*) list_get(interpreter, list, i, enum_type_int);
if (i < 10)
;
else
printf("The answer is %d.\n", j);
}
/* test various data types */
list = list_new(interpreter, enum_type_char);
list_assign(interpreter, list, 0 ,(void*) 'a', enum_type_char);
list_assign(interpreter, list, 1 ,(void*) 'b', enum_type_char);
list_assign(interpreter, list, 2 ,(void*) 'c', enum_type_char);
list_assign(interpreter, list, 3 ,(void*) 'd', enum_type_char);
c = *(char*) list_get(interpreter, list, 1, enum_type_char);
printf("char\t%c\n", c);
list = list_new(interpreter, enum_type_short);
list_assign(interpreter, list, 20 ,(void*) 15, enum_type_short);
list_assign(interpreter, list, 21 ,(void*) -15, enum_type_short);
list_assign(interpreter, list, 22 ,(void*) 99, enum_type_short);
t = *(short*) list_get(interpreter, list, 21, enum_type_short);
printf("short\t%d\n", t);
list = list_new(interpreter, enum_type_FLOATVAL);
f = 1234.56;
list_assign(interpreter, list, 20 ,(void*) &f, enum_type_FLOATVAL);
f = *(FLOATVAL*) list_get(interpreter, list, 20, enum_type_FLOATVAL);
printf("num\t" FLOATVAL_FMT "\n", f);
s = string_make(interpreter, "Seems ok\n", 9, 0, BUFFER_external_FLAG,0);
list = list_new(interpreter, enum_type_PMC);
p1 = pmc_new(interpreter, enum_class_PerlString);
p1->vtable->set_string_native(interpreter, p1, s);
list_push(interpreter, list, p1, enum_type_PMC);
p2 = list_shift(interpreter, list, enum_type_PMC);
s = p2->vtable->get_string(interpreter, p2);
printf("string\t%s", string_to_cstring(interpreter, s));
i = list_length(interpreter, list);
printf("len now %d\n", i);
s = string_make(interpreter, "list\n", 5, 0, BUFFER_external_FLAG,0);
p1 = pmc_new(interpreter, enum_class_PerlString);
p1->vtable->set_string_native(interpreter, p1, s);
list_assign(interpreter, list, 0, p1, enum_type_PMC);
/* clone */
list2 = list_clone(interpreter, list);
s = string_make(interpreter, "list 2\n", 7, 0, BUFFER_external_FLAG,0);
p1 = pmc_new(interpreter, enum_class_PerlString);
p1->vtable->set_string_native(interpreter, p1, s);
list_assign(interpreter, list2, 0, p1, enum_type_PMC);
p1 = list_shift(interpreter, list, enum_type_PMC);
s = p1->vtable->get_string(interpreter, p1);
printf("string\t%s", string_to_cstring(interpreter, s));
p2 = list_shift(interpreter, list2, enum_type_PMC);
s = p2->vtable->get_string(interpreter, p2);
printf("string\t%s", string_to_cstring(interpreter, s));
list = list_new(interpreter, enum_type_STRING);
s = string_make(interpreter, "list\n", 5, 0, BUFFER_external_FLAG,0);
list_assign(interpreter, list, 0, s, enum_type_STRING);
list2 = list_clone(interpreter, list);
s = string_make(interpreter, "list 2\n", 7, 0, BUFFER_external_FLAG,0);
list_assign(interpreter, list2, 0, s, enum_type_STRING);
s = list_shift(interpreter, list, enum_type_STRING);
printf("string\t%s", string_to_cstring(interpreter, s));
s = list_shift(interpreter, list2, enum_type_STRING);
printf("string\t%s", string_to_cstring(interpreter, s));
/* delete test */
printf("new list(0..19)\n");
list = list_new(interpreter, enum_type_char);
for (i = 0; i < 20; i++)
list_push(interpreter, list, (void*) 'a'+i, enum_type_char);
list_dump(0, list, 0);
printf("delete(1,1)\n");
list_delete(interpreter, list, 1, 1);
list_dump(0, list, 0);
printf("delete(1,4)\n");
list_delete(interpreter, list, 1, 4);
list_dump(0, list, 0);
j = *(char*) list_get(interpreter, list, 1, enum_type_char);
assert(j == 6+'a');
printf("new list(0..25)\n");
list = list_new(interpreter, enum_type_char);
for (i = 0; i < 26; i++)
list_push(interpreter, list, (void*) 'a'+i, enum_type_char);
printf("delete(1,20)\n");
list_delete(interpreter, list, 1, 20);
list_dump(0, list, 0);
j = *(char*) list_get(interpreter, list, 1, enum_type_char);
assert(j == 21+'a');
printf("shift, push('X')\n");
list_shift(interpreter, list, enum_type_char);
list_push(interpreter, list, (void*) 'X', enum_type_char);
list_dump(0, list, 0);
printf("new list(0..25)\n");
list = list_new(interpreter, enum_type_char);
for (i = 0; i < 26; i++)
list_push(interpreter, list, (void*) 'a'+i, enum_type_char);
printf("delete(2,30)\n");
list_delete(interpreter, list, 2, 30);
list_dump(0, list, 0);
printf("push('A'..'Z')\n");
for (i = 0; i < 26; i++)
list_push(interpreter, list, (void*) 'A'+i, enum_type_char);
list_dump(0, list, 0);
j = *(char*) list_get(interpreter, list, 6, enum_type_char);
assert(j == 'E');
assert(list_length(interpreter, list) == 28);
printf("new list(0..2)\n");
list = list_new(interpreter, enum_type_char);
for (i = 0; i < 3; i++)
list_push(interpreter, list, (void*) 'a'+i, enum_type_char);
printf("list[2000]='Y'\n");
list_assign(interpreter, list, 2000 ,(void*)'Y', enum_type_char);
printf("list[4000]='Z'\n");
list_assign(interpreter, list, 4000 ,(void*)'Z', enum_type_char);
list_dump(0, list, 0);
printf("delete(3,3000)\n");
list_delete(interpreter, list, 3, 3000);
list_dump(0, list, 0);
printf("delete(2,996)\n");
list_delete(interpreter, list, 2, 996);
list_dump(0, list, 0);
assert(list_length(interpreter, list) == 5);
j = *(char*) list_get(interpreter, list, -1, enum_type_char);
assert(j == 'Z');
/* insert */
printf("new list(0..5)\n");
list = list_new(interpreter, enum_type_char);
for (i = 0; i < 6; i++)
list_push(interpreter, list, (void*) 'a'+i, enum_type_char);
list_dump(0, list, 0);
printf("insert(2, 5)\n");
list_insert(interpreter, list, 2, 5);
list_dump(0, list, 0);
printf("list(2..7) = 'A'..'F'\n");
for (i = 0; i < 6; i++)
list_assign(interpreter, list, 2+i ,(void*)'A'+i, enum_type_char);
list_dump(0, list, 0);
printf("new list(0..5)\n");
list = list_new(interpreter, enum_type_char);
for (i = 0; i < 6; i++)
list_push(interpreter, list, (void*) 'a'+i, enum_type_char);
list_dump(0, list, 0);
printf("insert(0, 3)\n");
list_insert(interpreter, list, 0, 3);
list_dump(0, list, 0);
printf("list(0..4) = 'A'..'E'\n");
for (i = 0; i < 5; i++)
list_assign(interpreter, list, i ,(void*)'A'+i, enum_type_char);
list_dump(0, list, 0);
printf("new list(0..5)\n");
list = list_new(interpreter, enum_type_char);
for (i = 0; i < 6; i++)
list_push(interpreter, list, (void*) 'a'+i, enum_type_char);
list_dump(0, list, 0);
printf("insert(5, 3)\n");
list_insert(interpreter, list, 5, 3);
list_dump(0, list, 0);
printf("list(5..9) = 'A'..'E'\n");
for (i = 0; i < 5; i++)
list_assign(interpreter, list, 5+i ,(void*)'A'+i, enum_type_char);
list_dump(0, list, 0);
printf("new list(0..5)\n");
list = list_new(interpreter, enum_type_char);
for (i = 0; i < 6; i++)
list_push(interpreter, list, (void*) 'a'+i, enum_type_char);
list_dump(0, list, 0);
printf("insert(6, 3)\n");
list_insert(interpreter, list, 6, 3);
list_dump(0, list, 0);
printf("list(5..9) = 'A'..'E'\n");
for (i = 0; i < 5; i++)
list_assign(interpreter, list, 5+i ,(void*)'A'+i, enum_type_char);
list_dump(0, list, 0);
printf("delete(0,1)\n");
list_delete(interpreter, list, 0, 1);
list_dump(0, list, 0);
printf("new list(0..5)\n");
list = list_new(interpreter, enum_type_char);
printf("insert(0, 3)\n");
list_insert(interpreter, list, 0, 3);
list_dump(0, list, 0);
return 0;
}
#endif
/*
* Local variables:
* c-indentation-style: bsd
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/
1.3 +188 -1 parrot/t/pmc/intlist.t
Index: intlist.t
===================================================================
RCS file: /cvs/public/parrot/t/pmc/intlist.t,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -w -r1.2 -r1.3
--- intlist.t 26 Sep 2002 08:16:30 -0000 1.2
+++ intlist.t 10 Oct 2002 13:42:38 -0000 1.3
@@ -1,6 +1,6 @@
#! perl -w
-use Parrot::Test tests => 4;
+use Parrot::Test tests => 7;
use Test::More;
output_is(<<'CODE', <<'OUTPUT', "creation");
@@ -229,3 +229,190 @@
ok 2
OUTPUT
+output_is(<<'CODE', <<'OUTPUT', "direct access 2");
+ new P0, .IntList
+ set I10, 1100000
+ set I0, 1
+lp1:
+ add I1, I0, 5
+ set P0[I0], I1
+ add I3, I1, I0
+ push P0, I3
+ shl I0, I0, 1
+ inc I0
+ le I0, I10, lp1
+
+ set I0, 1
+lp2:
+ add I1, I0, 5
+ # check at I0
+ set I2, P0[I0]
+ ne I2, I1, err
+ add I4, I0, 1
+ # and pushed value at I0+1
+ set I4, P0[I4]
+ add I3, I1, I0
+ ne I3, I4, err
+
+ shl I0, I0, 1
+ inc I0
+ le I0, I10, lp2
+ print "ok\n"
+ end
+err:
+ print "not ok "
+ print I0
+ print " "
+ print I1
+ print " "
+ print I2
+ print " "
+ print I3
+ print " "
+ print I4
+ print " "
+ print I5
+ print " "
+ print I6
+ print " "
+ print I7
+ print "\n"
+
+ end
+CODE
+ok
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "sparse access");
+ new P0, .IntList
+ set I10, 110000
+ set I0, 1
+lp1:
+ add I1, I0, 5
+ set P0[I0], I1
+ add I3, I1, I0
+ push P0, I3
+ shl I0, I0, 1
+ inc I0
+ le I0, I10, lp1
+
+ set I0, 1
+lp2:
+ add I1, I0, 5
+ # check at I0
+ set I2, P0[I0]
+ ne I2, I1, err
+ add I4, I0, 1
+ # and pushed value at I0+1
+ set I4, P0[I4]
+ add I3, I1, I0
+ ne I3, I4, err
+
+ shl I0, I0, 1
+ inc I0
+ le I0, I10, lp2
+ print "ok 1\n"
+
+ # now repeat and fill some holes
+
+ set I0, 777
+lp3:
+ add I1, I0, 5
+ set P0[I0], I1
+ add I0, I0, 666
+ le I0, I10, lp3
+
+ set I0, 777
+lp4:
+ add I1, I0, 5
+ # check at I0
+ set I2, P0[I0]
+ ne I2, I1, err
+
+ add I0, I0, 666
+ le I0, I10, lp4
+ print "ok 2\n"
+ end
+err:
+ print "not ok "
+ print I0
+ print " "
+ print I1
+ print " "
+ print I2
+ print " "
+ print I3
+ print " "
+ print I4
+ print "\n"
+
+ end
+CODE
+ok 1
+ok 2
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "pop into sparse");
+ new P0, .IntList
+ set I10, 100
+ set I0, 0
+ # push some values at start
+lp1:
+ push P0, I0
+ inc I0
+ lt I0, I10, lp1
+
+ # create sparse
+ set I0, 100000
+ set I1, 1000
+ set P0[I0], I1
+ inc I1
+lp2:
+ # push some values after hole
+ push P0, I1
+ inc I1
+ le I1, 1100, lp2
+ dec I1
+
+ set I3, P0
+lp3:
+ set I4, P0
+ ne I3, I4, err1
+ pop I2, P0
+ dec I3
+ ne I2, I1, err2
+ gt I3, I0, cont1
+ lt I3, I10, cont1
+ set I1, 0
+
+ gt I3, I10, lp3
+ set I1, I10
+
+cont1:
+ dec I1
+ eq I1, 0, ok
+ branch lp3
+ok:
+ print "ok\n"
+ end
+err1: set S0, "len"
+ branch err
+err2:
+ set S0, "val"
+err:
+ print "nok "
+ print S0
+ print " "
+ print I0
+ print " "
+ print I1
+ print " "
+ print I2
+ print " "
+ print I3
+ print " "
+ print I4
+ end
+CODE
+ok
+OUTPUT