2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/intlists.c - Regex stack handling routines
11 intlist emulation code, calls routines in F<src/list.c>.
13 Here is the original documentation for intlist:
15 The basic data structure is a variant of a doubly-linked list
16 of 'chunks', where a chunk is a C<Buffer> header subclass
17 containing the link pointers and other metadata for the chunk.
18 As expected from it being a C<Buffer> header, the C<PObj_bufstart>
19 field points to the actual array of C<INTVAL>s. The handle used by
20 external code for one of these IntLists is just a pointer to a
21 chunk, always called 'list' in this code.
23 For now, all of the chunks are fixed-length in size. (That
24 could easily be changed, at the cost of another integer in each
27 Notice that I said 'variant' of a doubly-linked list. That is
28 because if you start at 'list' and follow prev pointers, you
29 will loop through all the used nodes of the list, as usual. But
30 if you follow next pointers instead, you might find a spare
31 node hanging off the last node in the list (the last node is
32 always C<< list->prev >>, so if there is a spare node, it will be at
33 C<< list->prev->next >>. If no spare exists, then
34 C<< list->prev->next==list >>.)
36 The first node in the list may be partly full; the intermediate
37 nodes are always completely full; and the last node may be
38 partly full. Each node has a C<.start> field, giving the offset of
39 the first valid element (always zero except for possibly the
40 first node), and a C<.end> field, giving one past the offset of
41 the last valid element (always equal to C<INTLIST_CHUNK_SIZE>
42 except for possibly the last node).
44 To make it concrete, let's walk through some sample operations.
45 To push onto the end of the list, first find the last chunk:
46 C<< list->prev >>. Then if C<< chunk->end < INTLIST_CHUNK_SIZE >>, there is
47 space to fit another element and so just stick it in. If not,
48 we must add a chunk to the end of the list. If there is a
49 spare, just link it fully into the list (forming a conventional
50 doubly-linked list). Otherwise, create a new chunk and link it
51 fully into the list. Easy enough.
53 To pop something off the end, first go to the end chunk
54 (C<< list->prev >>). Pop off an element and decrement C<.end> if the
55 chunk is nonempty. If it is empty, make that last chunk into
56 the spare (discarding the previous spare). Then go to the
57 previous chunk, which is guaranteed to have C<.end> set to
58 C<INTLIST_CHUNK_SIZE>, and return C<data[.end--]>.
60 The length of the list is always cached in the overall header
61 chunk. If an operation changes which chunk is the header (i.e.,
62 shift or unshift), then the length is copied to the new header.
66 There is always space in C<< list->prev >> to insert an element.
68 The 'list' chunk is never empty unless the entire list is
71 In combination, the above invariants imply that the various
72 operations are implemented as:
78 Write element, push a new chunk if necessary.
82 Check to see if we have to back up a chunk, read element.
86 Read element, discard chunk and advance if necessary.
90 Unshift a chunk if necessary, write element.
94 Direct aka indexed access of intlist data:
96 The classic method would be to walk the C<< intlist->next >> pointers
97 (or optimized, the C<< ->prev >> pointers if an index near the end is
98 requested) and locate the chunk, that holds the wanted list
101 To speed things up, especially for bigger lists, there are
102 additional fields in the 'list' (the head chunk):
108 Holds pointers to individual chunks.
110 =item C<collect_runs>
112 C<collect_runs> counter, when C<chunk_list> was rebuilt last.
116 Used length in C<chunk_list>
120 If on any indexed access interpreter's collect_runs is
121 different, the chunks might have been moved, so the chunk_list
124 Getting data outside the array dimensions will
125 return the value C<NULL>, which will C<SIGSEGV>, the intlist did
126 an explicit exception, so there is not much difference.
127 Of course, a check for valid pointers could be added here.
137 #include "parrot/parrot.h"
139 /* HEADERIZER HFILE: include/parrot/intlist.h */
143 =item C<void intlist_mark>
145 Marks the list as live.
152 intlist_mark(PARROT_INTERP
, ARGMOD(IntList
*l
))
154 list_mark(interp
, (List
*)l
);
159 =item C<IntList * intlist_clone>
161 Returns a clone of the list.
167 PARROT_WARN_UNUSED_RESULT
168 PARROT_CANNOT_RETURN_NULL
170 intlist_clone(PARROT_INTERP
, ARGIN(const IntList
*list
))
172 return (IntList
*)list_clone(interp
, (const List
*)list
);
177 =item C<IntList * intlist_new>
185 PARROT_WARN_UNUSED_RESULT
186 PARROT_CANNOT_RETURN_NULL
188 intlist_new(PARROT_INTERP
)
190 return (IntList
*)list_new(interp
, enum_type_INTVAL
);
195 =item C<INTVAL intlist_length>
197 Returns the length of the list.
203 PARROT_WARN_UNUSED_RESULT
206 intlist_length(SHIM_INTERP
, ARGIN(const IntList
*list
))
208 return ((const List
*)list
)->length
;
213 =item C<void intlist_assign>
215 Assigns <val> to the item at C<idx>.
222 intlist_assign(PARROT_INTERP
, ARGMOD(IntList
*l
), INTVAL idx
, INTVAL val
)
224 list_assign(interp
, (List
*)l
, idx
, INTVAL2PTR(void *, val
), enum_type_INTVAL
);
229 =item C<void intlist_push>
231 Pushes C<val> on the end of the list.
238 intlist_push(PARROT_INTERP
, ARGMOD(IntList
*l
), INTVAL val
)
240 list_push(interp
, (List
*)l
, INTVAL2PTR(void *, val
), enum_type_INTVAL
);
245 =item C<void intlist_unshift>
247 Pushes C<val> on the front of the list.
254 intlist_unshift(PARROT_INTERP
, ARGMOD(IntList
**l
), INTVAL val
)
256 list_unshift(interp
, (List
*)*l
, INTVAL2PTR(void *, val
), enum_type_INTVAL
);
261 =item C<INTVAL intlist_pop>
263 Popping/shifting into a sparse hole returns 0.
270 intlist_pop(PARROT_INTERP
, ARGMOD(IntList
*l
))
272 void * const ret
= list_pop(interp
, (List
*)l
, enum_type_INTVAL
);
273 const INTVAL retval
= ret
== (void *)-1 ? 0 : *(INTVAL
*)ret
;
279 =item C<INTVAL intlist_shift>
281 Removes and returns the first item on the list.
288 intlist_shift(PARROT_INTERP
, ARGMOD(IntList
**l
))
290 void * const ret
= list_shift(interp
, (List
*)*l
, enum_type_INTVAL
);
291 const INTVAL retval
= ret
== (void *)-1 ? 0 : *(INTVAL
*)ret
;
297 =item C<INTVAL intlist_get>
299 Returns the item at C<idx>.
305 PARROT_WARN_UNUSED_RESULT
307 intlist_get(PARROT_INTERP
, ARGMOD(IntList
*list
), INTVAL idx
)
309 void * const ret
= list_get(interp
, (List
*)list
, idx
, enum_type_INTVAL
);
311 return *(INTVAL
*)ret
;
322 F<include/parrot/intlist.h>, F<src/list.c> and F<include/parrot/list.h>.
331 * c-file-style: "parrot"
333 * vim: expandtab shiftwidth=4: