Starting release 0.7.0
[parrot.git] / src / intlist.c
blob70433d445e99e83acd2e8a275352bd7f6611dd20
1 /*
2 Copyright (C) 2001-2008, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/intlists.c - Regex stack handling routines
9 =head1 DESCRIPTION
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
25 header.)
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.
64 Invariants:
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
69 empty.
71 In combination, the above invariants imply that the various
72 operations are implemented as:
74 =over 4
76 =item C<push>
78 Write element, push a new chunk if necessary.
80 =item C<pop>
82 Check to see if we have to back up a chunk, read element.
84 =item C<shift>
86 Read element, discard chunk and advance if necessary.
88 =item C<unshift>
90 Unshift a chunk if necessary, write element.
92 =back
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
99 item.
101 To speed things up, especially for bigger lists, there are
102 additional fields in the 'list' (the head chunk):
104 =over 4
106 =item C<chunk_list>
108 Holds pointers to individual chunks.
110 =item C<collect_runs>
112 C<collect_runs> counter, when C<chunk_list> was rebuilt last.
114 =item C<n_chunks>
116 Used length in C<chunk_list>
118 =back
120 If on any indexed access interpreter's collect_runs is
121 different, the chunks might have been moved, so the chunk_list
122 has to be rebuilt.
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.
129 =head2 Functions
131 =over 4
133 =cut
137 #include "parrot/parrot.h"
139 /* HEADERIZER HFILE: include/parrot/intlist.h */
143 =item C<void intlist_mark>
145 Marks the list as live.
147 =cut
151 void
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.
163 =cut
167 PARROT_WARN_UNUSED_RESULT
168 PARROT_CANNOT_RETURN_NULL
169 IntList *
170 intlist_clone(PARROT_INTERP, ARGIN(const IntList *list))
172 return (IntList *)list_clone(interp, (const List *)list);
177 =item C<IntList * intlist_new>
179 Returns a new list.
181 =cut
185 PARROT_WARN_UNUSED_RESULT
186 PARROT_CANNOT_RETURN_NULL
187 IntList *
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.
199 =cut
203 PARROT_WARN_UNUSED_RESULT
204 PARROT_PURE_FUNCTION
205 INTVAL
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>.
217 =cut
221 void
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.
233 =cut
237 void
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.
249 =cut
253 void
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.
265 =cut
269 INTVAL
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;
274 return retval;
279 =item C<INTVAL intlist_shift>
281 Removes and returns the first item on the list.
283 =cut
287 INTVAL
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;
292 return retval;
297 =item C<INTVAL intlist_get>
299 Returns the item at C<idx>.
301 =cut
305 PARROT_WARN_UNUSED_RESULT
306 INTVAL
307 intlist_get(PARROT_INTERP, ARGMOD(IntList *list), INTVAL idx)
309 void * const ret = list_get(interp, (List *)list, idx, enum_type_INTVAL);
310 if (ret)
311 return *(INTVAL *)ret;
313 return (INTVAL)0;
318 =back
320 =head1 SEE ALSO
322 F<include/parrot/intlist.h>, F<src/list.c> and F<include/parrot/list.h>.
324 =cut
330 * Local variables:
331 * c-file-style: "parrot"
332 * End:
333 * vim: expandtab shiftwidth=4: