Tom Hughes wrote: > In message <[EMAIL PROTECTED]> > Leopold Toetsch <[EMAIL PROTECTED]> wrote:
> I applied this to my checkout (with _intlist_new renamed to > allocate_chunk because names starting with _ are reserved). Ah, didn't know that - ok changed too. > Unfortunately it doesn't test clean afterwards: > > dunsmere [~/src/parrot] % perl t/harness t/pmc/intlist.t > t/pmc/intlist....NOK 3# Failed test (t/pmc/intlist.t at line 149) > # got: '' Ah, dumps core, aha GC, ahaaha junk_list moved. I ran the tests with my Lea allocator in place, which doesn't suffer from this problem ;-) Anyway here is an update, tested with CVS GC. Additionally indexed access is simplified by a view lines. Thanks for testing and sorry, leo
--- parrot/intlist.c Thu Sep 26 18:30:29 2002 +++ parrot-leo/intlist.c Fri Sep 27 16:32:26 2002 @@ -70,6 +70,24 @@ * shift: read element, discard chunk and advance if necessary * unshift: unshift a chunk if necessary, write element * + * Direct aka indexed access of intlist data: + * + * The classic method would be to walk the intlist->next pointers + * (or optimized, the ->prev pointers if an index near the end is + * requested) and locate the chunk, that holds the wanted list + * item. + * To speed things up, especially for bigger lists, there are + * additional fields in the 'list' (the head chunk): + * chunk_list ... holds pointers to individual chunks + * collect_runs ... collect_runs counter, when chunk_list was + * rebuilt last. + * n_chunks ... used length in chunk_list + * + * If on any indexed access interpreter's collect_runs is + * different, the chunks might have been moved, so the chunk_list + * has to be rebuilt. + * + * * History: * Notes: * References: */ @@ -78,9 +96,29 @@ #include "parrot/intlist.h" static size_t rebuild_chunk_list(Interp *interpreter, IntList *list); +static IntList* allocate_chunk(Interp *interpreter, int initial); +static size_t rebuild_chunk_list(Interp *interpreter, IntList *list); IntList* -intlist_new(Interp *interpreter, int initial) +intlist_new(Interp *interpreter) { + return allocate_chunk(interpreter, 1); +} + +/* growth increment of chunk_list, must be a power of 2 */ +#define CL_SIZE 16 + +/* Buffers store the used len in bytes in buflen + * so, the len in entries is: */ + +#define chunk_list_size(list) \ + (list->chunk_list.buflen / sizeof(IntList_Chunk *)) + +/* hide the ugly cast somehow: */ +#define chunk_list_ptr(list, idx) \ + ((IntList_Chunk**)list->chunk_list.bufstart)[idx] + +static IntList* +allocate_chunk(Interp *interpreter, int initial) { IntList* list; @@ -96,11 +134,8 @@ Parrot_allocate(interpreter, (Buffer*) list, INTLIST_CHUNK_SIZE * sizeof(INTVAL)); if (initial) { - /* XXX managed memory or custom destroy? */ - list->chunk_list = mem_sys_allocate(sizeof(IntList_Chunk *)); - list->n_chunks = 1; - list->collect_runs = interpreter->dod_runs; - list->chunk_list[0] = (IntList_Chunk*) list; + /* we have a cleared list, so no need to zero chunk_list */ + rebuild_chunk_list(interpreter, list); } interpreter->DOD_block_level--; interpreter->GC_block_level--; @@ -115,10 +150,11 @@ buffer_lives((Buffer *) chunk); chunk = chunk->next; } while (chunk != (IntList_Chunk*) list); - + buffer_lives(&list->chunk_list); return last; } +#ifdef INTLIST_DEBUG void intlist_dump(FILE* fp, IntList* list, int verbose) { @@ -144,6 +180,7 @@ fprintf(fp, "\n"); } +#endif static size_t rebuild_chunk_list(Interp *interpreter, IntList *list) @@ -151,16 +188,25 @@ IntList_Chunk* chunk = (IntList_Chunk*) list; IntList_Chunk* lastChunk = list->prev; size_t len = 0; + /* allocate a new chunk_list buffer, old one my have moved + * firsr, count chunks */ while (1) { - if (len >= list->n_chunks) - list->chunk_list = mem_sys_realloc(list->chunk_list, - (len + 1)* sizeof(IntList_Chunk *)); - list->chunk_list[len] = chunk; len++; if (chunk == lastChunk) break; chunk = chunk->next; } - list->collect_runs = interpreter->dod_runs; + Parrot_allocate(interpreter, &list->chunk_list, + (len+1) * sizeof(IntList_Chunk *)); + len = 0; + chunk = list; + /* then fill list */ + while (1) { + chunk_list_ptr(list, len) = (IntList_Chunk*) chunk; + len++; + if (chunk == lastChunk) break; + chunk = chunk->next; + } + list->collect_runs = interpreter->collect_runs; list->n_chunks = len; return len; } @@ -172,7 +218,7 @@ if (chunk->next == list) { /* Need to add a new chunk */ - IntList_Chunk* new_chunk = intlist_new(interpreter, 0); + IntList_Chunk* new_chunk = allocate_chunk(interpreter, 0); new_chunk->next = list; new_chunk->prev = chunk; chunk->next = new_chunk; @@ -190,7 +236,17 @@ add_chunk(interpreter, list); list->prev->start = 0; list->prev->end = 0; + /* optimization, add new chunk directly, if still space + * but only, if no collections was done in between + */ + if (list->n_chunks >= chunk_list_size(list) || + list->collect_runs != interpreter->collect_runs) rebuild_chunk_list(interpreter, list); + else { + /* add the appended = last chunk = list->prev to chunk_list */ + chunk_list_ptr(list, list->n_chunks) = list->prev; + list->n_chunks++; + } } static void @@ -223,15 +279,15 @@ INTVAL length = chunk->length + 1; INTVAL offset; IntList_Chunk * o = chunk; - size_t n = chunk->n_chunks; /* Add on a new chunk if necessary */ if (chunk->start == 0) { unshift_chunk(interpreter, *list); chunk = chunk->prev; *list = chunk; + /* move chunk_list to new list head */ (*list)->chunk_list = o->chunk_list; - (*list)->n_chunks = n; + /* and rebuild it from scratch */ rebuild_chunk_list(interpreter, *list); } @@ -247,7 +303,6 @@ INTVAL length = chunk->length - 1; INTVAL value; IntList_Chunk * o = chunk; - size_t n = chunk->n_chunks; if (chunk->start >= chunk->end) { internal_exception(OUT_OF_BOUNDS, "No entries on list!\n"); @@ -262,8 +317,8 @@ chunk->next->prev = chunk->prev; chunk->prev->next = chunk; *list = chunk->next; + /* like above */ (*list)->chunk_list = o->chunk_list; - (*list)->n_chunks = n; rebuild_chunk_list(interpreter, *list); } @@ -285,6 +340,7 @@ chunk->next = list; list->prev = chunk->prev; chunk = chunk->prev; + /* chunk_list hold one less valid entry now */ list->n_chunks--; } @@ -306,23 +362,9 @@ IntList_Chunk* chunk = list; UNUSED(interpreter); -#if 1 - if (list->collect_runs != interpreter->dod_runs) + if (list->collect_runs != interpreter->collect_runs) rebuild_chunk_list(interpreter, list); - idx += chunk->start; - - return list->chunk_list[idx / INTLIST_CHUNK_SIZE]; -#else - /* Possible optimization: start from the closer end of the chunk list */ - - /* Find the chunk containing the requested element */ - while (idx >= chunk->end - chunk->start) { - idx -= chunk->end - chunk->start; - chunk = chunk->next; - } - - return chunk; -#endif + return chunk_list_ptr(list, idx / INTLIST_CHUNK_SIZE); } INTVAL @@ -339,13 +381,13 @@ } if (idx < 0) idx += length; + idx += list->start; chunk = find_chunk(interpreter, list, idx); - if (idx >= list->end - list->start) idx -= list->end - list->start; idx = idx % INTLIST_CHUNK_SIZE; - return ((INTVAL*)chunk->buffer.bufstart)[idx + chunk->start]; + return ((INTVAL*)chunk->buffer.bufstart)[idx]; } static void @@ -394,11 +436,11 @@ intlist_extend(interpreter, list, idx + 1); } + idx += list->start; chunk = find_chunk(interpreter, list, idx); - if (idx >= list->end - list->start) idx -= list->end - list->start; idx = idx % INTLIST_CHUNK_SIZE; - ((INTVAL*)chunk->buffer.bufstart)[idx + chunk->start] = val; + ((INTVAL*)chunk->buffer.bufstart)[idx] = val; } /* --- parrot/include/parrot/intlist.h Thu Sep 26 18:30:30 2002 +++ parrot-leo/include/parrot/intlist.h Fri Sep 27 12:10:47 2002 @@ -24,10 +24,12 @@ struct IntList_chunk_t { Buffer buffer; /* This struct is a Buffer header subclass! */ - INTVAL length; /* Only valid for the "head" chunk (1) */ - size_t collect_runs; /* when chunklist was built (1) */ - IntList_Chunk ** chunk_list; /* list of chunks for fast access (1) */ - size_t n_chunks; /* number of chunks in chunk_list */ + INTVAL length; /* number of items in list (1) */ + size_t collect_runs; /* counter, when chunklist was built (1) */ + Buffer chunk_list; /* holding list of chunks for fast access (1) */ + size_t n_chunks; /* number of used chunks in chunk_list (1) */ + /* all above items, marked (1) are only valid in the head junk + * s. intlist.c for a detailled description */ INTVAL start; INTVAL end; IntList_Chunk* next; @@ -38,7 +40,7 @@ PMC* intlist_mark(Interp*, IntList*, PMC* last); -IntList *intlist_new(Interp*, int initial); +IntList *intlist_new(Interp*); static INTVAL intlist_length(Interp* interpreter, IntList* list) { --- parrot/classes/intlist.pmc Thu Sep 26 18:30:30 2002 +++ parrot-leo/classes/intlist.pmc Fri Sep 27 11:55:15 2002 @@ -30,7 +30,7 @@ } void init () { - SELF->data = intlist_new(INTERP, 1); + SELF->data = intlist_new(INTERP); SELF->cache.int_val = 0; SELF->flags |= PMC_custom_mark_FLAG; } --- parrot/t/src/intlist.t Thu Sep 26 18:30:36 2002 +++ parrot-leo/t/src/intlist.t Fri Sep 27 15:42:25 2002 @@ -15,7 +15,7 @@ if (interpreter == NULL) return 1; Parrot_init(interpreter, (void*) &interpreter); - list = intlist_new(interpreter, 1); + list = intlist_new(interpreter); if (list == NULL) return 1; intlist_push(interpreter, list, 42); @@ -44,7 +44,7 @@ if (interpreter == NULL) return "create interpreter"; Parrot_init(interpreter, (void*) &interpreter); - list = intlist_new(interpreter, 1); + list = intlist_new(interpreter); if (list == NULL) return "create list"; /* Push 3, then pop 2. Repeat N times. */ @@ -177,7 +177,7 @@ if (interpreter == NULL) return 1; Parrot_init(interpreter, (void*) &interpreter); - list = intlist_new(interpreter, 1); + list = intlist_new(interpreter); if (list == NULL) return 1; printf("Step 1: 0\n"); @@ -282,7 +282,7 @@ if (interpreter == NULL) return 1; Parrot_init(interpreter, (void*) &interpreter); - list = intlist_new(interpreter, 1); + list = intlist_new(interpreter); if (list == NULL) return 1; for (i = 0; i < INTLIST_CHUNK_SIZE * 2.5; i++) {