0
|
1 #include "structs.h"
|
|
2 #include "datum.h"
|
|
3 #include "interp.h"
|
|
4 #include <stdlib.h>
|
|
5 #include <string.h>
|
|
6
|
|
7 datum * create_list(program * prog)
|
|
8 {
|
|
9 short i;
|
|
10 datum * dat = new_datum(BUILTIN_TYPE_LIST, 1, sizeof(list_data) + sizeof(datum *)*7, prog);
|
|
11 dat->c.generic.len = 8;
|
|
12 ((list_data *)dat->c.generic.data)->num_entries = 0;
|
|
13 return dat;
|
|
14 }
|
|
15
|
|
16 int vis_list_new(datum ** inputlist, queue_entry * worker_entry)
|
|
17 {
|
|
18 inputlist[0] = create_list(worker_entry->instance->def->program);
|
|
19 return 0;
|
|
20 }
|
|
21
|
|
22 int vis_list_append(datum ** inputlist, queue_entry * worker_entry)
|
|
23 {
|
|
24 int ref_count, new_entry_count;
|
|
25 list_data * list, * new_list;
|
|
26 datum * output;
|
|
27 int i;
|
|
28
|
|
29 VIS_EnterCriticalSection(inputlist[0]->lock);
|
|
30 ref_count = inputlist[0]->ref_count;
|
|
31 VIS_LeaveCriticalSection(inputlist[0]->lock);
|
|
32 list = ((list_data *)inputlist[0]->c.generic.data);
|
|
33 DEBUGPRINTF("append: generic.len = %d, list->num_entries = %d, ref_count = %d\n", inputlist[0]->c.generic.len, list->num_entries, ref_count);
|
|
34 if(ref_count == 1)
|
|
35 {
|
|
36 if(inputlist[0]->c.generic.len > list->num_entries)
|
|
37 {
|
|
38 DEBUGPUTS("Fast append\n");
|
|
39 list->entries[list->num_entries] = inputlist[1]; //No need to add_ref because we're consuming the ref we wer passed
|
|
40 ++(list->num_entries);
|
|
41 }
|
|
42 else
|
|
43 {
|
|
44 DEBUGPUTS("malloc append\n");
|
|
45 new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
|
|
46 new_list = malloc((new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
|
|
47 new_list->num_entries = list->num_entries+1;
|
|
48 inputlist[0]->c.generic.len = new_entry_count;
|
|
49 memcpy(new_list->entries, list->entries, list->num_entries * sizeof(datum *));
|
|
50 new_list->entries[list->num_entries] = inputlist[1];
|
|
51 inputlist[0]->c.generic.data = new_list;
|
|
52 VIS_FREE(list, "List object");
|
|
53 }
|
|
54 }
|
|
55 else
|
|
56 {
|
|
57 DEBUGPUTS("datum copy append\n");
|
|
58
|
|
59 if(inputlist[0]->c.generic.len > list->num_entries)
|
|
60 new_entry_count = inputlist[0]->c.generic.len;
|
|
61 else
|
|
62 new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
|
|
63 output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
|
|
64 new_list = output->c.generic.data;
|
|
65 new_list->num_entries = list->num_entries+1;
|
|
66 output->c.generic.len = new_entry_count;
|
|
67 for(i = 0; i < list->num_entries; ++i)
|
|
68 new_list->entries[i] = add_ref(list->entries[i]);
|
|
69 new_list->entries[list->num_entries] = inputlist[1];
|
|
70 release_ref(inputlist[0]);
|
|
71 inputlist[0] = output;
|
|
72 }
|
|
73 DEBUGPRINTF("append: generic.len = %d, list->num_entries = %d\n", inputlist[0]->c.generic.len, ((list_data *)inputlist[0]->c.generic.data)->num_entries);
|
|
74 return 0;
|
|
75 }
|
|
76
|
|
77 int vis_list_swap(datum ** inputlist, queue_entry * worker_entry)
|
|
78 {
|
|
79 //TODO: Throw error if indices out of bounds
|
|
80 list_data * list;
|
|
81 datum * temp;
|
|
82 inputlist[0] = copy_datum(inputlist[0], 0);
|
|
83 list = ((list_data *)inputlist[0]->c.generic.data);
|
|
84
|
|
85 temp = list->entries[inputlist[1]->c.integers.num_a];
|
|
86 list->entries[inputlist[1]->c.integers.num_a] = list->entries[inputlist[2]->c.integers.num_a];
|
|
87 list->entries[inputlist[2]->c.integers.num_a] = temp;
|
|
88 release_ref(inputlist[1]);
|
|
89 release_ref(inputlist[2]);
|
|
90 return 0;
|
|
91 }
|
|
92
|
|
93 int vis_list_index(datum ** inputlist, queue_entry * worker_entry)
|
|
94 {
|
|
95 //TODO: Throw error if indices out of bounds
|
|
96 list_data * list = ((list_data *)inputlist[0]->c.generic.data);
|
|
97 datum * output;
|
|
98 DEBUGPRINTF("index: generic.len = %d, list->num_entries = %d, requested index: %d\n", inputlist[0]->c.generic.len, list->num_entries, inputlist[1]->c.integers.num_a);
|
|
99 DEBUGPRINTF("list->entries[%d] = %X\n", inputlist[1]->c.integers.num_a, list->entries[inputlist[1]->c.integers.num_a]);
|
|
100 if(inputlist[1]->c.integers.num_a < list->num_entries && list->entries[inputlist[1]->c.integers.num_a])
|
|
101 {
|
|
102 output = add_ref(list->entries[inputlist[1]->c.integers.num_a]);
|
|
103 release_ref(inputlist[1]);
|
|
104 inputlist[1] = NULL;
|
|
105 }
|
|
106 else
|
|
107 {
|
|
108 output = NULL;
|
|
109 inputlist[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program);
|
|
110 inputlist[1]->c.integers.num_a = 0;
|
|
111 }
|
|
112
|
|
113 release_ref(inputlist[0]);
|
|
114 inputlist[0] = output;
|
|
115 return 0;
|
|
116 }
|
|
117
|
|
118 int vis_list_insert(datum ** inputlist, queue_entry * worker_entry)
|
|
119 {
|
|
120 int ref_count, new_entry_count;
|
|
121 list_data * list, * new_list;
|
|
122 datum * output;
|
|
123 int i;
|
|
124 VIS_EnterCriticalSection(inputlist[0]->lock);
|
|
125 ref_count = inputlist[0]->ref_count;
|
|
126 VIS_LeaveCriticalSection(inputlist[0]->lock);
|
|
127 list = ((list_data *)inputlist[0]->c.generic.data);
|
|
128 if(ref_count == 1)
|
|
129 {
|
|
130 if(inputlist[0]->c.generic.len > list->num_entries)
|
|
131 {
|
|
132 memmove(list->entries + inputlist[1]->c.integers.num_a + 1, list->entries + inputlist[1]->c.integers.num_a, sizeof(datum *) * (list->num_entries-inputlist[1]->c.integers.num_a));
|
|
133 list->entries[inputlist[1]->c.integers.num_a] = inputlist[2]; //No need to add_ref because we're consuming the ref we wer passed
|
|
134 ++(list->num_entries);
|
|
135 }
|
|
136 else
|
|
137 {
|
|
138 new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
|
|
139 new_list = malloc((new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
|
|
140 new_list->num_entries = list->num_entries+1;
|
|
141 inputlist[0]->c.generic.len = new_entry_count;
|
|
142 memcpy(new_list->entries, list->entries, list->num_entries * sizeof(datum *));
|
|
143 new_list->entries[list->num_entries] = inputlist[1];
|
|
144 inputlist[0]->c.generic.data = new_list;
|
|
145 VIS_FREE(list, "List object");
|
|
146 }
|
|
147 }
|
|
148 else
|
|
149 {
|
|
150 new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
|
|
151 output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
|
|
152 new_list = output->c.generic.data;
|
|
153 new_list->num_entries = list->num_entries+1;
|
|
154 output->c.generic.len = new_entry_count;
|
|
155 for(i = 0; i < inputlist[1]->c.integers.num_a; ++i)
|
|
156 new_list->entries[i] = add_ref(list->entries[i]);
|
|
157 for(i = inputlist[1]->c.integers.num_a; i < list->num_entries; ++i)
|
|
158 new_list->entries[i+1] = add_ref(list->entries[i]);
|
|
159 release_ref(inputlist[0]);
|
|
160 new_list->entries[list->num_entries] = inputlist[2];
|
|
161 inputlist[0] = output;
|
|
162 }
|
|
163 release_ref(inputlist[1]);
|
|
164 return 0;
|
|
165 }
|
|
166
|
|
167 int vis_list_remove(datum ** inputlist, queue_entry * worker_entry)
|
|
168 {
|
|
169 int ref_count, new_entry_count;
|
|
170 list_data * list, * new_list;
|
|
171 int i;
|
|
172 datum * output;
|
|
173 VIS_EnterCriticalSection(inputlist[0]->lock);
|
|
174 ref_count = inputlist[0]->ref_count;
|
|
175 VIS_LeaveCriticalSection(inputlist[0]->lock);
|
|
176 list = ((list_data *)inputlist[0]->c.generic.data);
|
|
177 if(ref_count == 1)
|
|
178 {
|
|
179 release_ref(list->entries[inputlist[1]->c.integers.num_a]);
|
|
180 memmove(list->entries + inputlist[1]->c.integers.num_a, list->entries + inputlist[1]->c.integers.num_a + 1, sizeof(datum *) * (list->num_entries-(inputlist[1]->c.integers.num_a+1)));
|
|
181 --(list->num_entries);
|
|
182 }
|
|
183 else
|
|
184 {
|
|
185 new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size
|
|
186 output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data));
|
|
187 new_list = output->c.generic.data;
|
|
188 new_list->num_entries = list->num_entries+1;
|
|
189 output->c.generic.len = new_entry_count;
|
|
190 for(i = 0; i < inputlist[1]->c.integers.num_a; ++i)
|
|
191 new_list->entries[i] = add_ref(list->entries[i]);
|
|
192 for(i = inputlist[1]->c.integers.num_a+1; i < list->num_entries; ++i)
|
|
193 new_list->entries[i-1] = add_ref(list->entries[i]);
|
|
194 release_ref(inputlist[0]);
|
|
195 inputlist[0] = output;
|
|
196 }
|
|
197 release_ref(inputlist[1]);
|
|
198 return 0;
|
|
199 }
|
|
200
|
|
201 int vis_list_set(datum ** inputlist, queue_entry * worker_entry)
|
|
202 {
|
|
203 int new_num_entries, new_generic_len, i;
|
|
204 list_data * list;
|
|
205 DEBUGPUTS("vis_list_set\n");
|
|
206 if(((list_data *)inputlist[0]->c.generic.data)->num_entries <= inputlist[1]->c.integers.num_a)
|
|
207 {
|
|
208 new_num_entries = inputlist[1]->c.integers.num_a + 1;
|
|
209 new_generic_len = (new_num_entries + (new_num_entries>>1)-1)*sizeof(datum*) + sizeof(list_data);
|
|
210 }
|
|
211 else
|
|
212 {
|
|
213 new_num_entries = ((list_data *)inputlist[0]->c.generic.data)->num_entries;
|
|
214 new_generic_len = 0;
|
|
215 }
|
|
216 DEBUGPRINTF("new_generic_len: %d, new num_entries: %d\n", new_generic_len, new_num_entries);
|
|
217 inputlist[0] = copy_datum(inputlist[0], new_generic_len);
|
|
218 if(new_generic_len) {
|
|
219 inputlist[0]->c.generic.len = (new_num_entries + (new_num_entries>>1));
|
|
220 }
|
|
221 DEBUGPUTS("Datum copy done\n");
|
|
222 list = ((list_data *)inputlist[0]->c.generic.data);
|
|
223 DEBUGPUTS("before Null fill loop\n");
|
|
224 for(i = list->num_entries; i < new_num_entries; ++i)
|
|
225 list->entries[i] = NULL;
|
|
226 DEBUGPUTS("Before existing entry release_ref\n");
|
|
227 if(inputlist[1]->c.integers.num_a < list->num_entries)
|
|
228 release_ref(list->entries[inputlist[1]->c.integers.num_a]);
|
|
229 DEBUGPRINTF("Setting index %d to %X\n", inputlist[1]->c.integers.num_a, inputlist[2]);
|
|
230 list->entries[inputlist[1]->c.integers.num_a] = inputlist[2];
|
|
231 release_ref(inputlist[1]);
|
|
232 list->num_entries = new_num_entries;
|
|
233 DEBUGPUTS("vis_list_set done\n");
|
|
234 return 0;
|
|
235
|
|
236 }
|
|
237
|
|
238 int vis_list_length(datum ** inputlist, queue_entry * worker_entry)
|
|
239 {
|
|
240 datum * output;
|
|
241 list_data * list = ((list_data *)inputlist[0]->c.generic.data);
|
|
242 output = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
|
|
243 output->c.integers.num_a = list->num_entries;
|
|
244 release_ref(inputlist[0]);
|
|
245 inputlist[0] = output;
|
|
246 return 0;
|
|
247 }
|
|
248
|
|
249 int vis_list_first(datum ** inputlist, queue_entry * worker_entry)
|
|
250 {
|
|
251 int i;
|
|
252 list_data * list = inputlist[0]->c.generic.data;
|
|
253 if(!list->num_entries)
|
|
254 {
|
|
255 inputlist[1] = inputlist[0];
|
|
256 inputlist[0] = NULL;
|
|
257 }
|
|
258 else
|
|
259 {
|
|
260 i = 0;
|
|
261 while(!list->entries[i] && i < list->num_entries)
|
|
262 ++i;
|
|
263 release_ref(inputlist[0]);
|
|
264 inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program);
|
|
265 inputlist[0]->c.integers.num_a = i;
|
|
266 inputlist[1] = NULL;
|
|
267 }
|
|
268 return 0;
|
|
269 }
|
|
270
|
|
271 int vis_list_next(datum ** inputlist, queue_entry * worker_entry)
|
|
272 {
|
|
273 int i;
|
|
274 list_data * list = inputlist[0]->c.generic.data;
|
|
275 i = inputlist[1]->c.integers.num_a + 1;
|
|
276 while(i < list->num_entries && !list->entries[i])
|
|
277 ++i;
|
|
278 if(i < list->num_entries)
|
|
279 {
|
|
280 release_ref(inputlist[0]);
|
|
281 inputlist[0] = copy_datum(inputlist[1], 0);
|
|
282 inputlist[1] = NULL;
|
|
283 inputlist[0]->c.integers.num_a = i;
|
|
284 } else {
|
|
285 release_ref(inputlist[1]);
|
|
286 inputlist[1] = inputlist[0];
|
|
287 inputlist[0] = NULL;
|
|
288 }
|
|
289 return 0;
|
|
290 }
|