1 /*-------------------------------------------------------------------------
2 *
3 * linebuffer.c
4 * a routines for iteration over stored lines
5 *
6 * Portions Copyright (c) 2017-2021 Pavel Stehule
7 *
8 * IDENTIFICATION
9 * src/linebuffer.c
10 *
11 *-------------------------------------------------------------------------
12 */
13
14 #include "pspg.h"
15
16 #include <stdlib.h>
17
18 /*
19 * Initialize line buffer iterator
20 */
21 inline void
init_lbi(LineBufferIter * lbi,LineBuffer * lb,MappedLine * order_map,int order_map_items,int init_pos)22 init_lbi(LineBufferIter *lbi,
23 LineBuffer *lb,
24 MappedLine *order_map,
25 int order_map_items,
26 int init_pos)
27 {
28 lbi->start_lb = lb;
29
30 lbi->order_map = order_map;
31 lbi->order_map_items = order_map_items;
32
33 lbi_set_lineno(lbi, init_pos);
34 }
35
36 /*
37 * Common case - initialize line buffer iterator
38 * for stored data.
39 */
40 inline void
init_lbi_ddesc(LineBufferIter * lbi,DataDesc * desc,int init_pos)41 init_lbi_ddesc(LineBufferIter *lbi,
42 DataDesc *desc,
43 int init_pos)
44 {
45 init_lbi(lbi,
46 &desc->rows,
47 desc->order_map,
48 desc->order_map_items,
49 init_pos);
50 }
51
52 /*
53 * Set iterator to absolute position in line buffer
54 */
55 bool
lbi_set_lineno(LineBufferIter * lbi,int pos)56 lbi_set_lineno(LineBufferIter *lbi, int pos)
57 {
58 lbi->lineno = pos;
59
60 if (lbi->order_map)
61 {
62 if (lbi->order_map_items > pos)
63 {
64 MappedLine *mpl = &lbi->order_map[pos];
65
66 lbi->current_lb = mpl->lnb;
67 lbi->current_lb_rowno = mpl->lnb_row;
68
69 return true;
70 }
71
72 /* set max lineno */
73 lbi->lineno = lbi->order_map_items;
74 }
75 else
76 {
77 int lineno_offset = 0;
78
79 lbi->current_lb = lbi->start_lb;
80
81 while (lbi->current_lb && pos >= LINEBUFFER_LINES)
82 {
83 pos -= LINEBUFFER_LINES;
84 lineno_offset += lbi->current_lb->nrows;
85
86 lbi->current_lb = lbi->current_lb->next;
87 }
88
89 if (lbi->current_lb)
90 {
91 if (pos < lbi->current_lb->nrows)
92 {
93 lbi->current_lb_rowno = pos;
94
95 return true;
96 }
97 else
98 lbi->lineno = lineno_offset + lbi->current_lb->nrows;
99 }
100 else
101 lbi->lineno = lineno_offset;
102 }
103
104 lbi->current_lb = NULL;
105 lbi->current_lb_rowno = 0;
106
107 return false;
108 }
109
110 /*
111 * Initialize line buffer mark to current position in
112 * line buffer.
113 */
114 inline void
lbi_set_mark(LineBufferIter * lbi,LineBufferMark * lbm)115 lbi_set_mark(LineBufferIter *lbi, LineBufferMark *lbm)
116 {
117 lbm->lb = lbi->current_lb;
118 lbm->lb_rowno = lbi->current_lb_rowno;
119 lbm->lineno = lbi->lineno;
120 }
121
122 /*
123 * Initialize line buffer mark to current position in line
124 * buffer. Increase current position in line buffer. Returns
125 * true if line buffer mark is valid.
126 */
127 bool
lbi_set_mark_next(LineBufferIter * lbi,LineBufferMark * lbm)128 lbi_set_mark_next(LineBufferIter *lbi, LineBufferMark *lbm)
129 {
130 lbi_set_mark(lbi, lbm);
131 (void) lbi_next(lbi);
132
133 return lbm->lb && lbm->lb_rowno < lbm->lb->nrows;
134 }
135
136 /*
137 * Sets mark to line buffer specified by position. When false,
138 * when position is not valid.
139 */
140 bool
ddesc_set_mark(LineBufferMark * lbm,DataDesc * desc,int pos)141 ddesc_set_mark(LineBufferMark *lbm, DataDesc *desc, int pos)
142 {
143 lbm->lb = NULL;
144 lbm->lineno = pos;
145
146 if (desc->order_map)
147 {
148 if (pos >= 0 && pos < desc->order_map_items)
149 {
150 lbm->lb = desc->order_map[pos].lnb;
151 lbm->lb_rowno = desc->order_map[pos].lnb_row;
152 lbm->lineno = pos;
153
154 return true;
155 }
156 }
157 else
158 {
159 LineBuffer *lb = &desc->rows;
160
161 while (lb && pos >= LINEBUFFER_LINES)
162 {
163 lb = lb->next;
164 pos -= LINEBUFFER_LINES;
165 }
166
167 if (lb && pos < lb->nrows)
168 {
169 lbm->lb = lb;
170 lbm->lb_rowno = pos;
171
172 return true;
173 }
174 }
175
176 return false;
177 }
178
179 void
lbm_xor_mask(LineBufferMark * lbm,char mask)180 lbm_xor_mask(LineBufferMark *lbm, char mask)
181 {
182 if (!lbm->lb->lineinfo)
183 {
184 /* smalloc returns zero fill memory already */
185 lbm->lb->lineinfo = smalloc(LINEBUFFER_LINES * sizeof(LineInfo));
186 }
187
188 lbm->lb->lineinfo[lbm->lb_rowno].mask ^= mask;
189 }
190
191 /*
192 * Working horse of lbm_get_line and lbi_get_line routines
193 */
194 static bool
lb_get_line(LineBuffer * lb,int rowno,int lineno,char ** line,LineInfo ** linfo,int * linenoptr)195 lb_get_line(LineBuffer *lb,
196 int rowno,
197 int lineno,
198 char **line,
199 LineInfo **linfo,
200 int *linenoptr)
201 {
202 if (linenoptr)
203 *linenoptr = lineno;
204
205 if (lb && rowno >= 0 && rowno < lb->nrows)
206 {
207 if (line)
208 *line = lb->rows[rowno];
209
210 if (linfo)
211 *linfo = lb->lineinfo ? &lb->lineinfo[rowno] : NULL;
212
213 return true;
214 }
215
216 if (line)
217 *line = NULL;
218
219 if (linfo)
220 *linfo = NULL;
221
222 return false;
223 }
224
225 /*
226 * Returns line related to line buffer mark
227 */
228 bool
lbm_get_line(LineBufferMark * lbm,char ** line,LineInfo ** linfo,int * lineno)229 lbm_get_line(LineBufferMark *lbm,
230 char **line,
231 LineInfo **linfo,
232 int *lineno)
233 {
234 return lb_get_line(lbm->lb,
235 lbm->lb_rowno,
236 lbm->lineno,
237 line,
238 linfo,
239 lineno);
240 }
241
242 /*
243 * Returns true, when returns valid line from line buffer.
244 */
245 inline bool
lbi_get_line(LineBufferIter * lbi,char ** line,LineInfo ** linfo,int * lineno)246 lbi_get_line(LineBufferIter *lbi,
247 char **line,
248 LineInfo **linfo,
249 int *lineno)
250 {
251 return lb_get_line(lbi->current_lb,
252 lbi->current_lb_rowno,
253 lbi->lineno,
254 line,
255 linfo,
256 lineno);
257 }
258
259 /*
260 * Returns true, when returns valid line from line buffer.
261 * Increments position in linebuffer.
262 */
263 inline bool
lbi_get_line_next(LineBufferIter * lbi,char ** line,LineInfo ** linfo,int * lineno)264 lbi_get_line_next(LineBufferIter *lbi,
265 char **line,
266 LineInfo **linfo,
267 int *lineno)
268 {
269 bool result;
270
271 result = lbi_get_line(lbi, line, linfo, lineno);
272
273 (void) lbi_next(lbi);
274
275 return result;
276 }
277
278
279 /*
280 * Returns true, when returns valid line from line buffer.
281 * Decreases position in linebuffer.
282 */
283 inline bool
lbi_get_line_prev(LineBufferIter * lbi,char ** line,LineInfo ** linfo,int * lineno)284 lbi_get_line_prev(LineBufferIter *lbi,
285 char **line,
286 LineInfo **linfo,
287 int *lineno)
288 {
289 bool result;
290
291 result = lbi_get_line(lbi, line, linfo, lineno);
292
293 (void) lbi_prev(lbi);
294
295 return result;
296 }
297
298 /*
299 * Move to prev line in line buffer. Returns false, when there
300 * is not valid line in buffer.
301 */
302 bool
lbi_prev(LineBufferIter * lbi)303 lbi_prev(LineBufferIter *lbi)
304 {
305 if (lbi->order_map)
306 {
307 if (lbi->lineno > 0)
308 {
309 MappedLine *mpl;
310
311 lbi->lineno -= 1;
312
313 mpl = &lbi->order_map[lbi->lineno];
314
315 lbi->current_lb = mpl->lnb;
316 lbi->current_lb_rowno = mpl->lnb_row;
317
318 return true;
319 }
320 else
321 lbi->lineno = -1;
322 }
323 else
324 {
325 if (lbi->current_lb)
326 {
327 lbi->lineno -= 1;
328
329 lbi->current_lb_rowno -= 1;
330 if (lbi->current_lb_rowno >= 0)
331 return true;
332
333 if (lbi->current_lb->prev)
334 {
335 lbi->current_lb = lbi->current_lb->prev;
336 lbi->current_lb_rowno = LINEBUFFER_LINES - 1;
337
338 return true;
339 }
340 }
341 }
342
343 lbi->current_lb = NULL;
344 lbi->current_lb_rowno = 0;
345
346 return false;
347 }
348
349 /*
350 * Move on next line in line buffer. Returns false, when there
351 * is not valid line in buffer.
352 */
353 bool
lbi_next(LineBufferIter * lbi)354 lbi_next(LineBufferIter *lbi)
355 {
356 if (lbi->order_map)
357 {
358 if (lbi->lineno + 1 < lbi->order_map_items)
359 {
360 MappedLine *mpl;
361
362 lbi->lineno += 1;
363
364 mpl = &lbi->order_map[lbi->lineno];
365
366 lbi->current_lb = mpl->lnb;
367 lbi->current_lb_rowno = mpl->lnb_row;
368
369 return true;
370 }
371 else
372 lbi->lineno = lbi->order_map_items;
373 }
374 else
375 {
376 if (lbi->current_lb)
377 {
378 /*
379 * Previous row must be valid, so we can increase
380 * lineno without creating gap after last line lineno.
381 */
382 lbi->lineno += 1;
383
384 lbi->current_lb_rowno += 1;
385 if (lbi->current_lb_rowno < lbi->current_lb->nrows)
386 return true;
387
388 if (lbi->current_lb->next)
389 {
390 lbi->current_lb = lbi->current_lb->next;
391 lbi->current_lb_rowno = 0;
392
393 return true;
394 }
395 }
396 }
397
398 lbi->current_lb = NULL;
399 lbi->current_lb_rowno = 0;
400
401 return false;
402 }
403
404 /*
405 * Simple line buffer iterator allows just only forward
406 * scan.
407 */
408 SimpleLineBufferIter *
init_slbi_ddesc(SimpleLineBufferIter * slbi,DataDesc * desc)409 init_slbi_ddesc(SimpleLineBufferIter *slbi, DataDesc *desc)
410 {
411 slbi->lb = &desc->rows;
412 slbi->lb_rowno = 0;
413
414 if (slbi->lb->nrows > 0)
415 return slbi;
416 else
417 return NULL;
418
419 }
420
421 SimpleLineBufferIter *
slbi_get_line_next(SimpleLineBufferIter * slbi,char ** line,LineInfo ** linfo)422 slbi_get_line_next(SimpleLineBufferIter *slbi,
423 char **line,
424 LineInfo **linfo)
425 {
426 if (slbi)
427 {
428 LineBuffer *lb = slbi->lb;
429
430 /*
431 * one line should be available every time. The possibility
432 * is checked before
433 */
434 if (linfo)
435 *linfo = lb->lineinfo ? &lb->lineinfo[slbi->lb_rowno] : NULL;
436
437 if (line)
438 *line = lb->rows[slbi->lb_rowno];
439
440 slbi->lb_rowno += 1;
441
442 /* check an possibility of next read */
443 if (slbi->lb_rowno < lb->nrows)
444 return slbi;
445
446 if (lb->next)
447 {
448 slbi->lb = lb->next;
449 slbi->lb_rowno = 0;
450
451 /* should not be possible */
452 if (slbi->lb->nrows == 0)
453 return NULL;
454 }
455 else
456 return NULL;
457 }
458 else
459 *line = NULL;
460
461 return slbi;
462 }
463
464 /*
465 * Free all lines stored in line buffer. An argument is data desc,
466 * because first chunk of line buffer is owned by data desc.
467 */
468 void
lb_free(DataDesc * desc)469 lb_free(DataDesc *desc)
470 {
471 LineBuffer *lb = &desc->rows;
472 LineBuffer *next;
473 int i;
474
475 while (lb)
476 {
477 for (i = 0; i < lb->nrows; i++)
478 free(lb->rows[i]);
479
480 free(lb->lineinfo);
481 next = lb->next;
482
483 if (lb != &desc->rows)
484 free(lb);
485
486 lb = next;
487 }
488 }
489
490 /*
491 * Print all lines to stream
492 */
493 void
lb_print_all_ddesc(DataDesc * desc,FILE * f)494 lb_print_all_ddesc(DataDesc *desc, FILE *f)
495 {
496 SimpleLineBufferIter slbi, *_slbi;
497 int res;
498
499 _slbi = init_slbi_ddesc(&slbi, desc);
500
501 while (_slbi)
502 {
503 char *line;
504
505 _slbi = slbi_get_line_next(_slbi, &line, NULL);
506
507 res = fprintf(f, "%s\n", line);
508 if (res < 0)
509 break;
510 }
511 }
512