rural 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/vlerq.c ADDED
@@ -0,0 +1,4531 @@
1
+ /* vlerq.c - this is the single-source-file version of Vlerq for Ruby */
2
+
3
+ /* %includeDir<../src>% */
4
+ /* %includeDir<../_ruby>% */
5
+
6
+ /* %include<bits.c>% */
7
+ /*
8
+ * bits.c - Implementation of bitwise operations.
9
+ */
10
+
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+
14
+ /*
15
+ * defs.h - Binding-specific definitions needed by the general code.
16
+ */
17
+
18
+ typedef unsigned long Object_p;
19
+
20
+ struct Shared *(GetShared) (void);
21
+ /*
22
+ * column.h - Definition of sequences, columns, and items.
23
+ */
24
+
25
+ #include <stdint.h>
26
+ /* on OpenBSD, use this line instead: typedef int intptr_t; */
27
+
28
+ #ifdef __sparc__
29
+ #define VALUES_MUST_BE_ALIGNED 1
30
+ #endif
31
+
32
+ #if WORDS_BIGENDIAN
33
+ #define _BIG_ENDIAN 1
34
+ #endif
35
+
36
+ #if DEBUG
37
+ #define Assert(x) do if (!(x)) FailedAssert(#x, __FILE__, __LINE__); while (0)
38
+ #else
39
+ #define Assert(x)
40
+ #endif
41
+
42
+ #define INVALID_COUNT (-1)
43
+
44
+ #define PUSH_KEEP_REFS \
45
+ { Buffer keep, *prevkeeps = GetShared()->keeps; \
46
+ InitBuffer(&keep); \
47
+ GetShared()->keeps = &keep;
48
+ #define POP_KEEP_REFS \
49
+ ReleaseSequences((Sequence_p*) BufferAsPtr(&keep, 1), \
50
+ BufferFill(keep) / sizeof(Sequence_p)); \
51
+ ReleaseBuffer(&keep, 0); \
52
+ GetShared()->keeps = prevkeeps; \
53
+ }
54
+
55
+ /* keep in sync with CharAsItemType() in column.c */
56
+ typedef enum ItemTypes {
57
+ IT_unknown,
58
+ IT_int,
59
+ IT_wide,
60
+ IT_float,
61
+ IT_double,
62
+ IT_string,
63
+ IT_bytes,
64
+ IT_object,
65
+ IT_column,
66
+ IT_view,
67
+ IT_error
68
+ } ItemTypes;
69
+
70
+ typedef enum ErrorCodes {
71
+ EC_cioor,
72
+ EC_rioor,
73
+ EC_cizwv,
74
+ EC_nmcw,
75
+ EC_rambe,
76
+ EC_nalor,
77
+ EC_wnoa
78
+ } ErrorCodes;
79
+
80
+ typedef struct Shared {
81
+ struct SharedInfo *info; /* ext_tcl.c */
82
+ int refs; /* ext_tcl.c */
83
+ struct Buffer *keeps; /* column.c */
84
+ intptr_t position; /* emit.c: current file emit offset */
85
+ struct Buffer *itembuf; /* emit.c: current item buffer */
86
+ struct Buffer *colbuf; /* emit.c: current column buffer */
87
+ struct Sequence *empty; /* view.c */
88
+ } Shared, *Shared_p;
89
+
90
+ typedef struct RefCounted *RefCounted_p;
91
+ typedef struct Sequence *Sequence_p;
92
+ typedef struct Column *Column_p;
93
+ typedef union Item *Item_p;
94
+ typedef Sequence_p View_p;
95
+
96
+ typedef int (*Sizer) (Sequence_p seq);
97
+ typedef ItemTypes (*Getter) (int row, Item_p item);
98
+ typedef void (*Cleaner) (RefCounted_p seq);
99
+
100
+ typedef struct RefCounted {
101
+ Cleaner cleaner; /* called during cleanup */
102
+ int refcount; /* reference count */
103
+ int filler; /* needed for 64b alignment, can reuse for any purpose */
104
+ } RefCounted;
105
+
106
+ typedef struct Sequence {
107
+ RefCounted head; /* manages ref counts, must be first is struct */
108
+ Getter getter; /* function to access a single item */
109
+ union { int i; void *p; } data[4]; /* getter-specific use */
110
+ } Sequence;
111
+
112
+ #define S_Count(seq) ((seq)->head.filler)
113
+
114
+ #define IncRefCount(seq) AdjustSeqRefs(seq, 1)
115
+ #define DecRefCount(seq) AdjustSeqRefs(seq, -1)
116
+
117
+ typedef struct Column {
118
+ Sequence_p seq; /* the sequence which will handle accesses */
119
+ int pos; /* position of this column in the view */
120
+ } Column;
121
+
122
+ typedef union Item {
123
+ char b [8]; /* used for raw access and byte-swapping */
124
+ int q [2]; /* used for hash calculation of wides and doubles */
125
+ int i; /* IT_int */
126
+ int64_t w; /* IT_wide */
127
+ float f; /* IT_float */
128
+ double d; /* IT_double */
129
+ const void *p; /* used to convert pointers */
130
+ const char *s; /* IT_string */
131
+ struct { const uint8_t *ptr; int len; } u; /* IT_bytes */
132
+ Object_p o; /* IT_object */
133
+ Column c; /* IT_column */
134
+ View_p v; /* IT_view */
135
+ ErrorCodes e; /* IT_error */
136
+ } Item;
137
+
138
+ void *(AdjustSeqRefs) (void *refs, int count);
139
+ void (AppendToStringColumn) (const void *s, int bytes, Column_p column);
140
+ int (CastObjToItem) (char type, Item_p item);
141
+ ItemTypes (CharAsItemType) (char type);
142
+ Column (CoerceCmd) (Object_p obj, const char *str);
143
+ void (FailedAssert) (const char *msg, const char *file, int line);
144
+ Column (ForceStringColumn) (Column column);
145
+ ItemTypes (GetItem) (int row, Item_p item);
146
+ Item (GetTypedItem) (int row, Column column, ItemTypes type);
147
+ Column (InitColumn) (int count, Getter proc, int auxbytes);
148
+ Sequence_p (KeepRef) (Sequence_p seq);
149
+ Column (NewCountsColumn) (Column column);
150
+ Column (NewIntVec) (int count, int **dataptr);
151
+ Column (NewIotaColumn) (int count);
152
+ Column (NewPtrVec) (int count, intptr_t **dataptr);
153
+ Column (NewSequenceColumn) (ItemTypes type, const Sequence_p *p, int n);
154
+ Column (NewStringColumn) (int maxitems, int maxbytes, int istext);
155
+ Column (OmitColumn) (Column omit, int size);
156
+ void (ReleaseSequences) (Sequence_p *refs, int count);
157
+
158
+ /* the following must be supplied in the language binding */
159
+ Column (CoerceColumn) (ItemTypes type, Object_p obj);
160
+ int (ColumnByName) (View_p meta, Object_p obj);
161
+ Object_p (ItemAsObj) (ItemTypes type, Item_p item);
162
+ Column (ObjAsColumn) (Object_p obj);
163
+ int (ObjToItem) (ItemTypes type, Item_p item);
164
+ /*
165
+ * buffer.h - Definition of a simple temporary buffer.
166
+ */
167
+
168
+ typedef struct Buffer *Buffer_p;
169
+ typedef struct Overflow *Overflow_p;
170
+
171
+ typedef struct Buffer {
172
+ union { char *c; int *i; const void **p; } fill;
173
+ char *limit;
174
+ Overflow_p head;
175
+ char *ofill;
176
+ intptr_t ocount;
177
+ char *result;
178
+ char buf [128];
179
+ char slack [8];
180
+ } Buffer;
181
+
182
+ #define ADD_CHAR_TO_BUF(b,x) \
183
+ { char _c = x; \
184
+ if ((b).fill.c < (b).limit) *(b).fill.c++ = _c; \
185
+ else AddToBuffer(&(b), &_c, sizeof _c); }
186
+
187
+ #define ADD_INT_TO_BUF(b,x) \
188
+ { int _i = x; \
189
+ if ((b).fill.c < (b).limit) *(b).fill.i++ = _i; \
190
+ else AddToBuffer(&(b), &_i, sizeof _i); }
191
+
192
+ #define ADD_PTR_TO_BUF(b,x) \
193
+ { const void *_p = x; \
194
+ if ((b).fill.c < (b).limit) *(b).fill.p++ = _p; \
195
+ else AddToBuffer(&(b), &_p, sizeof _p); }
196
+
197
+ #define BufferFill(b) ((b).ocount + ((b).fill.c - (b).buf))
198
+
199
+ void InitBuffer(Buffer_p bp);
200
+ void ReleaseBuffer(Buffer_p bp, int keep);
201
+ void AddToBuffer(Buffer_p bp, const void *data, intptr_t len);
202
+ char *BufferAsPtr(Buffer_p bp, int fast);
203
+ Column BufferAsIntCol(Buffer_p bp);
204
+ /*
205
+ * bits.h - Definition of bitwise operations.
206
+ */
207
+
208
+ int (BitTest) (const uint8_t *bitmap, int row);
209
+ void (BitSet) (uint8_t *bitmap, int row);
210
+
211
+ int BitTest (const uint8_t *bitmap, int row) {
212
+ return bitmap[row/8] & (1 << row % 8);
213
+ }
214
+
215
+ void BitSet (uint8_t *bitmap, int row) {
216
+ bitmap[row/8] |= 1 << row % 8;
217
+ }
218
+ /* %include<buffer.c>% */
219
+ /*
220
+ * buffer.c - Implementation of a simple temporary buffer.
221
+ */
222
+
223
+ #include <stdlib.h>
224
+ #include <string.h>
225
+
226
+
227
+ typedef struct Overflow {
228
+ Overflow_p p;
229
+ char b[4096];
230
+ } Overflow;
231
+
232
+ void InitBuffer(Buffer_p bp) {
233
+ bp->fill.c = bp->buf;
234
+ bp->limit = bp->buf + sizeof bp->buf;
235
+ bp->head = 0;
236
+ bp->ofill = 0;
237
+ bp->ocount = 0;
238
+ bp->result = 0;
239
+ }
240
+
241
+ void ReleaseBuffer(Buffer_p bp, int keep) {
242
+ while (bp->head != 0) {
243
+ Overflow_p op = bp->head;
244
+ bp->head = op->p;
245
+ free(op);
246
+ }
247
+ if (!keep && bp->result != 0)
248
+ free(bp->result);
249
+ }
250
+
251
+ void AddToBuffer(Buffer_p bp, const void *data, intptr_t len) {
252
+ intptr_t n;
253
+ while (len > 0) {
254
+ if (bp->fill.c >= bp->limit) {
255
+ if (bp->head == 0 || bp->ofill >= bp->head->b + sizeof bp->head->b) {
256
+ Overflow_p op = (Overflow_p) malloc(sizeof(Overflow));
257
+ op->p = bp->head;
258
+ bp->head = op;
259
+ bp->ofill = op->b;
260
+ }
261
+ memcpy(bp->ofill, bp->buf, sizeof bp->buf);
262
+ bp->ofill += sizeof bp->buf;
263
+ bp->ocount += sizeof bp->buf;
264
+ n = bp->fill.c - bp->slack;
265
+ memcpy(bp->buf, bp->slack, n);
266
+ bp->fill.c = bp->buf + n;
267
+ }
268
+ n = len;
269
+ if (n > bp->limit - bp->fill.c)
270
+ n = bp->limit - bp->fill.c; /* TODO: copy big chunks to overflow */
271
+ memcpy(bp->fill.c, data, n);
272
+ bp->fill.c += n;
273
+ data = (const char*) data + n;
274
+ len -= n;
275
+ }
276
+ }
277
+
278
+ char *BufferAsPtr(Buffer_p bp, int fast) {
279
+ intptr_t n = bp->fill.c - bp->buf, len = bp->ocount + n;
280
+ if (fast && n == len)
281
+ return bp->buf;
282
+ if (bp->result == 0)
283
+ bp->result = malloc(len);
284
+ len -= n;
285
+ memcpy(bp->result + len, bp->buf, n);
286
+ if (bp->head != 0) {
287
+ Overflow_p curr = bp->head;
288
+ n = bp->ofill - curr->b;
289
+ do {
290
+ len -= n;
291
+ memcpy(bp->result + len, curr->b, n);
292
+ curr = curr->p;
293
+ n = sizeof bp->head->b;
294
+ } while (curr != 0);
295
+ }
296
+ return bp->result;
297
+ }
298
+
299
+ Column BufferAsIntCol(Buffer_p bp) {
300
+ int count, *data;
301
+ Column result;
302
+
303
+ count = BufferFill(*bp) / sizeof(int);
304
+ result = NewIntVec(count, &data);
305
+ memcpy(data, BufferAsPtr(bp, 1), BufferFill(*bp));
306
+ ReleaseBuffer(bp, 0); /* TODO: try to avoid extra alloc + copy */
307
+
308
+ return result;
309
+ }
310
+ /* %include<column.c>% */
311
+ /*
312
+ * column.c - Implementation of sequences, columns, and items.
313
+ */
314
+
315
+ #include <stdlib.h>
316
+ #include <string.h>
317
+ #include <unistd.h>
318
+
319
+ /*
320
+ * view.h - Definition of views.
321
+ */
322
+
323
+ typedef enum MetaCols {
324
+ MC_name, MC_type, MC_subv, MC_limit
325
+ } MetaCols;
326
+
327
+ #define V_Cols(view) ((Column_p) ((view) + 1))
328
+ #define V_Types(view) (*(char**) ((view)->data))
329
+ #define V_Meta(view) (*(View_p*) ((view)->data+1))
330
+
331
+ #define ViewWidth(view) ViewSize(V_Meta(view))
332
+ #define ViewCol(view,col) (V_Cols(view)[col])
333
+ #define ViewColType(view,col) ((ItemTypes) V_Types(view)[col])
334
+ #define ViewCompat(view1,view2) MetaIsCompatible(V_Meta(view1), V_Meta(view2))
335
+
336
+ View_p (CloneView) (View_p view);
337
+ View_p (ColMapView) (View_p view, Column mapcol);
338
+ View_p (ColOmitView) (View_p view, Column mapcol);
339
+ View_p (DescAsMeta) (const char** desc, const char* end);
340
+ View_p (DescToMeta) (const char *desc);
341
+ View_p (EmptyMetaView) (void);
342
+ View_p (FirstView) (View_p view, int count);
343
+ char (GetColType) (View_p meta, int col);
344
+ View_p (IndirectView) (View_p meta, Sequence_p seq);
345
+ View_p (LastView) (View_p view, int count);
346
+ View_p (NameColView) (View_p view);
347
+ View_p (NewView) (View_p meta);
348
+ View_p (NoColumnView) (int rows);
349
+ View_p (PairView) (View_p view1, View_p view2);
350
+ View_p (TakeView) (View_p view, int count);
351
+ int (MetaIsCompatible) (View_p meta1, View_p meta2);
352
+ Column (ViewAsCol) (View_p view);
353
+ int (ViewCompare) (View_p view1, View_p view2);
354
+ int (ViewSize) (View_p view);
355
+ void (ViewStructure) (View_p meta, Buffer_p buffer);
356
+ void (ReleaseUnusedViews) (void);
357
+ void (SetViewColumns) (View_p view, int first, int count, Column src);
358
+ View_p (TagView) (View_p view, const char* name);
359
+ /*
360
+ * getters.h - Definition of several simple getter functions.
361
+ */
362
+
363
+ Getter (PickIntGetter) (int bits);
364
+ Getter (FixedGetter) (int bytes, int rows, int real, int flip);
365
+
366
+ void *AdjustSeqRefs (void *refs, int count) {
367
+ if (refs != NULL) {
368
+ RefCounted_p ptr = refs;
369
+ ptr->refcount += count;
370
+ if (ptr->refcount <= 0) {
371
+ if (ptr->cleaner != NULL)
372
+ ptr->cleaner(ptr);
373
+ free(refs);
374
+ refs = NULL;
375
+ }
376
+ }
377
+ return refs;
378
+ }
379
+
380
+ Sequence_p KeepRef (Sequence_p seq) {
381
+ Shared_p sh = GetShared();
382
+
383
+ ADD_PTR_TO_BUF(*sh->keeps, seq);
384
+ return IncRefCount(seq);
385
+ }
386
+
387
+ Column InitColumn (int count, Getter proc, int auxbytes) {
388
+ Column column;
389
+
390
+ column.seq = KeepRef((Sequence_p) calloc(1, sizeof(Sequence) + auxbytes));
391
+ S_Count(column.seq) = count;
392
+ column.seq->getter = proc;
393
+
394
+ /* default for data[0] is to point to the aux bytes after the sequence */
395
+ column.seq->data[0].p = column.seq + 1;
396
+
397
+ /* make sure 64-bit values have a "native" 8-byte alignment */
398
+ Assert(((intptr_t) column.seq->data[0].p) % 8 == 0);
399
+
400
+ column.pos = INVALID_COUNT;
401
+ return column;
402
+ }
403
+
404
+ void ReleaseSequences (Sequence_p *refs, int count) {
405
+ while (--count >= 0)
406
+ DecRefCount(refs[count]);
407
+ }
408
+
409
+ Column NewIntVec (int count, int **dataptr) {
410
+ const int w = sizeof(int);
411
+ Column result = InitColumn(count, PickIntGetter(8 * w), w * count);
412
+ if (dataptr != NULL)
413
+ *dataptr = result.seq->data[0].p;
414
+ return result;
415
+ }
416
+
417
+ Column NewPtrVec (int count, intptr_t **dataptr) {
418
+ const int w = sizeof(intptr_t);
419
+ Column result = InitColumn(count, PickIntGetter(8 * w), w * count);
420
+ if (dataptr != NULL)
421
+ *dataptr = result.seq->data[0].p;
422
+ return result;
423
+ }
424
+
425
+ ItemTypes GetItem (int row, Item_p item) {
426
+ if (row < 0 || row >= S_Count(item->c.seq)) {
427
+ item->e = EC_rioor;
428
+ return IT_error;
429
+ }
430
+
431
+ return item->c.seq->getter(row, item);
432
+ }
433
+
434
+ Item GetTypedItem (int row, Column column, ItemTypes type) {
435
+ Item item;
436
+ ItemTypes got;
437
+
438
+ item.c = column;
439
+ got = GetItem(row, &item);
440
+ Assert(got == type);
441
+
442
+ return item;
443
+ }
444
+
445
+ #if 0 /* unused */
446
+ const char *ItemTypeAsString (ItemTypes type) {
447
+ static const char *typeTable[] = {
448
+ "", /* IT_unknown */
449
+ "I", /* IT_int */
450
+ "L", /* IT_wide */
451
+ "D", /* IT_double */
452
+ "S", /* IT_string */
453
+ "O", /* IT_object */
454
+ "C", /* IT_column */
455
+ "V", /* IT_view */
456
+ "E", /* IT_error */
457
+ };
458
+
459
+ return typeTable[type];
460
+ }
461
+ #endif
462
+
463
+ ItemTypes CharAsItemType (char type) {
464
+ switch (type) {
465
+ case 0: return IT_unknown;
466
+ case 'I': return IT_int;
467
+ case 'L': return IT_wide;
468
+ case 'F': return IT_float;
469
+ case 'D': return IT_double;
470
+ case 'S': return IT_string;
471
+ case 'B': return IT_bytes;
472
+ case 'O': return IT_object;
473
+ case 'C': return IT_column;
474
+ case 'V': return IT_view;
475
+ }
476
+ return IT_error;
477
+ }
478
+
479
+ static void StringCleaner (Sequence_p seq) {
480
+ DecRefCount(seq->data[2].p);
481
+ }
482
+
483
+ static ItemTypes StringGetter (int row, Item_p item) {
484
+ char **ptrs = (char**) item->c.seq->data[0].p;
485
+ item->s = ptrs[row];
486
+ return IT_string;
487
+ }
488
+
489
+ static ItemTypes BytesGetter (int row, Item_p item) {
490
+ char **ptrs = (char**) item->c.seq->data[0].p;
491
+ item->u.ptr = (const uint8_t*) ptrs[row];
492
+ item->u.len = ptrs[row+1] - ptrs[row];
493
+ return IT_bytes;
494
+ }
495
+
496
+ Column NewStringColumn (int maxitems, int maxbytes, int istext) {
497
+ int ptrbytes;
498
+ char **ptrs;
499
+ Column result;
500
+
501
+ ptrbytes = (maxitems + 1) * sizeof(char*);
502
+ result = InitColumn(0, istext ? StringGetter : BytesGetter,
503
+ ptrbytes + maxbytes);
504
+ result.seq->head.cleaner = (Cleaner) StringCleaner;
505
+ /* data[0] is a vector of string pointers */
506
+ /* data[1] is not used */
507
+ /* data[2] is an optional pointer to a hash map sequence, see StringLookup */
508
+ /* data[3] is the optional prime factor used in hash map, see StringLookup */
509
+ result.seq->data[1].i = 0;
510
+
511
+ /* last pointer points to first unused byte */
512
+ ptrs = (char**) result.seq->data[0].p;
513
+ ptrs[0] = (char*) ptrs + ptrbytes;
514
+ return result;
515
+ }
516
+
517
+ void AppendToStringColumn (const void *string, int bytes, Column_p column) {
518
+ char **ptrs = (char**) column->seq->data[0].p;
519
+ char *bufend = ptrs[S_Count(column->seq)];
520
+
521
+ if (bytes < 0)
522
+ bytes = strlen((const char*) string) + 1;
523
+ memcpy(bufend, string, bytes);
524
+ ptrs[++S_Count(column->seq)] = bufend + bytes;
525
+ }
526
+
527
+ static int PreflightStringLengths (Column column) {
528
+ int i, count = S_Count(column.seq), total = 0;
529
+
530
+ for (i = 0; i < count; ++i)
531
+ total += strlen(GetTypedItem(i, column, IT_string).s) + 1;
532
+
533
+ return total;
534
+ }
535
+
536
+ Column ForceStringColumn (Column column) {
537
+ int r, rows;
538
+ Column result;
539
+
540
+ /* this code is needed to always make name column of meta views string cols */
541
+
542
+ if (column.seq == NULL || column.seq->getter == StringGetter)
543
+ return column;
544
+
545
+ rows = S_Count(column.seq);
546
+ result = NewStringColumn(rows, PreflightStringLengths(column), 1);
547
+
548
+ for (r = 0; r < rows; ++r)
549
+ AppendToStringColumn(GetTypedItem(r, column, IT_string).s, -1, &result);
550
+
551
+ return result;
552
+ }
553
+
554
+ static ItemTypes IotaGetter (int row, Item_p item) {
555
+ item->i = row;
556
+ return IT_int;
557
+ }
558
+
559
+ Column NewIotaColumn (int count) {
560
+ return InitColumn(count, IotaGetter, 0);
561
+ }
562
+
563
+ static void SequenceCleaner (Sequence_p seq) {
564
+ int i;
565
+ View_p *items = seq->data[0].p;
566
+
567
+ for (i = 0; i < S_Count(seq); ++i)
568
+ DecRefCount(items[i]);
569
+ }
570
+
571
+ static ItemTypes SequenceGetter (int row, Item_p item) {
572
+ void **items = (void**) item->c.seq->data[0].p;
573
+ ItemTypes type = item->c.seq->data[1].i;
574
+
575
+ switch (type) {
576
+
577
+ case IT_view:
578
+ item->v = items[row];
579
+ return IT_view;
580
+
581
+ case IT_column:
582
+ item->c.seq = items[row];
583
+ item->c.pos = INVALID_COUNT;
584
+ return IT_column;
585
+
586
+ default:
587
+ return IT_unknown;
588
+ }
589
+ }
590
+
591
+ Column NewSequenceColumn (ItemTypes type, const Sequence_p *items, int count) {
592
+ int i, bytes;
593
+ Column result;
594
+
595
+ bytes = count * sizeof(View_p);
596
+ result = InitColumn(count, SequenceGetter, bytes);
597
+ result.seq->head.cleaner = (Cleaner) SequenceCleaner;
598
+
599
+ /* data[0] points a list of pointers */
600
+ /* data[1] is the type of the returned items */
601
+ result.seq->data[1].i = type;
602
+
603
+ if (items != NULL) {
604
+ memcpy(result.seq->data[0].p, items, bytes);
605
+ for (i = 0; i < count; ++i)
606
+ IncRefCount(items[i]);
607
+ }
608
+
609
+ return result;
610
+ }
611
+
612
+ static ItemTypes CountsGetter (int row, Item_p item) {
613
+ const View_p *items = (const View_p*) item->c.seq->data[0].p;
614
+
615
+ item->i = ViewSize(items[row]);
616
+ return IT_int;
617
+ }
618
+
619
+ Column NewCountsColumn (Column column) {
620
+ int r, rows;
621
+ View_p *items;
622
+ Column result;
623
+
624
+ rows = S_Count(column.seq);
625
+ result = NewSequenceColumn(IT_view, NULL, rows);
626
+ result.seq->getter = CountsGetter;
627
+
628
+ items = result.seq->data[0].p;
629
+ for (r = 0; r < rows; ++r)
630
+ items[r] = IncRefCount(GetTypedItem(r, column, IT_view).v);
631
+
632
+ return result;
633
+ }
634
+
635
+ Column OmitColumn (Column omit, int size) {
636
+ int i, *data, next = 0, omitcount = S_Count(omit.seq), limit;
637
+ Column result;
638
+
639
+ result = NewIntVec(size - omitcount, &data);
640
+ for (i = 0; i < omitcount; ++i) {
641
+ limit = GetTypedItem(i, omit, IT_int).i;
642
+ while (next < limit)
643
+ *data++ = next++;
644
+ ++next;
645
+ }
646
+ while (next < size)
647
+ *data++ = next++;
648
+
649
+ return result;
650
+ }
651
+
652
+ static int StringTotals (Column column, int text) {
653
+ int i, count, bytes, total = 0;
654
+ Item item;
655
+
656
+ count = S_Count(column.seq);
657
+
658
+ for (i = 0; i < count; ++i) {
659
+ item.c = column;
660
+ ItemAsObj(GetItem(i, &item), &item);
661
+ if (text) {
662
+ if (!ObjToItem(IT_string, &item))
663
+ Assert(0);
664
+ bytes = strlen(item.s) + 1;
665
+ } else {
666
+ if (!ObjToItem(IT_bytes, &item))
667
+ Assert(0);
668
+ bytes = item.u.len;
669
+ }
670
+ total += bytes;
671
+ }
672
+
673
+ return total;
674
+ }
675
+
676
+ static Column CoerceColType (ItemTypes from, ItemTypes to, Column column) {
677
+ int i, n;
678
+ void *data;
679
+ Item item;
680
+ Column out;
681
+
682
+ if (from == to)
683
+ return column;
684
+
685
+ Assert(from == IT_object); /* not sure why this is always the case... */
686
+
687
+ n = S_Count(column.seq);
688
+
689
+ switch (to) {
690
+ case IT_int: out = NewIntVec(n, (int**) &data); break;
691
+ case IT_wide: out = InitColumn(n, PickIntGetter(64), 8 * n); break;
692
+ case IT_float: out = InitColumn(n, FixedGetter(4, 1, 1, 0), 4 * n); break;
693
+ case IT_double: out = InitColumn(n, FixedGetter(8, 1, 1, 0), 8 * n); break;
694
+ case IT_string: out = NewStringColumn(n, StringTotals(column, 1), 1); break;
695
+ case IT_bytes: out = NewStringColumn(n, StringTotals(column, 0), 0); break;
696
+ case IT_view: out = NewSequenceColumn(IT_view, NULL, n); break;
697
+ default: out.seq = NULL; out.pos = -1; return out;
698
+ }
699
+
700
+ data = out.seq->data[0].p;
701
+
702
+ for (i = 0; i < n; ++i) {
703
+ item.o = GetTypedItem(i, column, IT_object).o;
704
+ if (!ObjToItem(to, &item)) {
705
+ out.seq = NULL;
706
+ out.pos = i;
707
+ }
708
+
709
+ switch (to) {
710
+ case IT_int: ((int*) data)[i] = item.i; break;
711
+ case IT_wide: ((int64_t*) data)[i] = item.w; break;
712
+ case IT_float: ((float*) data)[i] = item.f; break;
713
+ case IT_double: ((double*) data)[i] = item.d; break;
714
+ case IT_string: AppendToStringColumn(item.s, -1, &out); break;
715
+ case IT_bytes: AppendToStringColumn(item.u.ptr, item.u.len, &out); break;
716
+ case IT_view: ((Sequence_p*) data)[i] = IncRefCount(item.v); break;
717
+ default: ;
718
+ }
719
+ }
720
+
721
+ return out;
722
+ }
723
+
724
+ Column CoerceColumn (ItemTypes type, Object_p obj) {
725
+ Item item;
726
+ Column column = ObjAsColumn(obj);
727
+
728
+ /* determine the input column type by fetching one item */
729
+ if (column.seq != NULL && S_Count(column.seq) > 0) {
730
+ item.c = column;
731
+ return CoerceColType(GetItem(0, &item), type, column);
732
+ }
733
+
734
+ return column;
735
+ }
736
+
737
+ Column CoerceCmd (Object_p obj, const char *str) {
738
+ return CoerceColumn(CharAsItemType(str[0]), obj);
739
+ }
740
+
741
+ int CastObjToItem (char type, Item_p item) {
742
+ switch (type) {
743
+
744
+ case 'N':
745
+ item->i = ColumnByName(V_Meta(item[-1].v), item->o);
746
+ return item->i >= 0;
747
+
748
+ case 'n': {
749
+ int *data, r, rows;
750
+ View_p meta;
751
+ Column column, result;
752
+
753
+ column = ObjAsColumn(item->o);
754
+ if (column.seq == NULL)
755
+ return 0;
756
+
757
+ rows = S_Count(column.seq);
758
+ result = NewIntVec(rows, &data);
759
+ meta = V_Meta(item[-1].v);
760
+
761
+ for (r = 0; r < rows; ++r) {
762
+ item->c = column;
763
+ data[r] = ColumnByName(meta, ItemAsObj(GetItem(r, item), item));
764
+ if (data[r] < 0)
765
+ return 0;
766
+ }
767
+
768
+ item->c = result;
769
+ break;
770
+ }
771
+
772
+ default:
773
+ if (type < 'a' || type > 'z')
774
+ return ObjToItem(CharAsItemType(type), item);
775
+
776
+ item->c = CoerceColumn(CharAsItemType(type +'A'-'a'), item->o);
777
+ break;
778
+ }
779
+
780
+ return 1; /* cast succeeded */
781
+ }
782
+ /* %include<emit.c>% */
783
+ /*
784
+ * emit.c - Implementation of file output commands.
785
+ */
786
+
787
+ #include <stdlib.h>
788
+ #include <string.h>
789
+ #include <unistd.h>
790
+
791
+ /*
792
+ * emit.h - Definition of file output commands.
793
+ */
794
+
795
+ typedef enum EmitTypes {
796
+ ET_mem
797
+ } EmitTypes;
798
+
799
+ typedef struct EmitItem {
800
+ EmitTypes type;
801
+ intptr_t size;
802
+ const void *data;
803
+ } EmitItem, *EmitItem_p;
804
+
805
+ intptr_t (EmitFull) (View_p view, Buffer_p buffer);
806
+ void (EmitView) (View_p view, int describe);
807
+ void (MetaAsDesc) (View_p meta, Buffer_p buffer);
808
+
809
+ static void EmitBlock (const void* data, int size) {
810
+ if (size > 0) {
811
+ EmitItem item;
812
+ Shared_p sh = GetShared();
813
+
814
+ item.type = ET_mem;
815
+ item.size = size;
816
+ item.data = data;
817
+ AddToBuffer(sh->itembuf, &item, sizeof item);
818
+
819
+ sh->position += size;
820
+ }
821
+ }
822
+
823
+ static void *EmitCopy (const void* data, int size) {
824
+ void *buf = NULL;
825
+ if (size > 0) {
826
+ buf = memcpy(malloc(size), data, size);
827
+ EmitBlock(buf, size);
828
+ }
829
+ return buf;
830
+ }
831
+
832
+ static intptr_t EmitAlign (void) {
833
+ Shared_p sh = GetShared();
834
+ if (sh->position >= 1024 * 1024)
835
+ EmitCopy("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 15 & - sh->position);
836
+ return sh->position;
837
+ }
838
+
839
+ void MetaAsDesc (View_p meta, Buffer_p buffer) {
840
+ int r, rows = ViewSize(meta);
841
+ Column names, types, subvs;
842
+ char type;
843
+ const char *name;
844
+ View_p subv;
845
+
846
+ names = ViewCol(meta, MC_name);
847
+ types = ViewCol(meta, MC_type);
848
+ subvs = ViewCol(meta, MC_subv);
849
+
850
+ for (r = 0; r < rows; ++r) {
851
+ if (r > 0)
852
+ ADD_CHAR_TO_BUF(*buffer, ',');
853
+
854
+ name = GetTypedItem(r, names, IT_string).s;
855
+ type = *GetTypedItem(r, types, IT_string).s;
856
+ subv = GetTypedItem(r, subvs, IT_view).v;
857
+
858
+ AddToBuffer(buffer, name, strlen(name));
859
+ if (type == 'V' && ViewSize(subv) > 0) {
860
+ ADD_CHAR_TO_BUF(*buffer, '[');
861
+ MetaAsDesc(subv, buffer);
862
+ ADD_CHAR_TO_BUF(*buffer, ']');
863
+ } else {
864
+ ADD_CHAR_TO_BUF(*buffer, ':');
865
+ ADD_CHAR_TO_BUF(*buffer, type);
866
+ }
867
+ }
868
+ }
869
+
870
+ static void EmitVarInt (intptr_t value) {
871
+ int n;
872
+ Shared_p sh = GetShared();
873
+
874
+ #if 0
875
+ if (value < 0) {
876
+ ADD_CHAR_TO_BUF(*sh->colbuf, 0);
877
+ value = ~value;
878
+ }
879
+ #endif
880
+
881
+ Assert(value >= 0);
882
+ for (n = 7; (value >> n) > 0; n += 7)
883
+ ;
884
+ while (n > 7) {
885
+ n -= 7;
886
+ ADD_CHAR_TO_BUF(*sh->colbuf, (value >> n) & 0x7F);
887
+ }
888
+ ADD_CHAR_TO_BUF(*sh->colbuf, (value & 0x7F) | 0x80);
889
+ }
890
+
891
+ static void EmitPair (intptr_t offset) {
892
+ intptr_t size;
893
+ Shared_p sh = GetShared();
894
+
895
+ size = sh->position - offset;
896
+ EmitVarInt(size);
897
+ if (size > 0)
898
+ EmitVarInt(offset);
899
+ }
900
+
901
+ static int TopBit (int v) {
902
+ #define Vn(x) (v < (1<<x))
903
+ return Vn(16) ? Vn( 8) ? Vn( 4) ? Vn( 2) ? Vn( 1) ? v-1 : 1
904
+ : Vn( 3) ? 2 : 3
905
+ : Vn( 6) ? Vn( 5) ? 4 : 5
906
+ : Vn( 7) ? 6 : 7
907
+ : Vn(12) ? Vn(10) ? Vn( 9) ? 8 : 9
908
+ : Vn(11) ? 10 : 11
909
+ : Vn(14) ? Vn(13) ? 12 : 13
910
+ : Vn(15) ? 14 : 15
911
+ : Vn(24) ? Vn(20) ? Vn(18) ? Vn(17) ? 16 : 17
912
+ : Vn(19) ? 18 : 19
913
+ : Vn(22) ? Vn(21) ? 20 : 21
914
+ : Vn(23) ? 22 : 23
915
+ : Vn(28) ? Vn(26) ? Vn(25) ? 24 : 25
916
+ : Vn(27) ? 26 : 27
917
+ : Vn(30) ? Vn(29) ? 28 : 29
918
+ : Vn(31) ? 30 : 31;
919
+ #undef Vn
920
+ }
921
+
922
+ static int MinWidth (int lo, int hi) {
923
+ lo = lo > 0 ? 0 : "444444445555555566666666666666666"[TopBit(~lo)+1] & 7;
924
+ hi = hi < 0 ? 0 : "012334445555555566666666666666666"[TopBit(hi)+1] & 7;
925
+ return lo > hi ? lo : hi;
926
+ }
927
+
928
+ static int FixFudge (int n, int w) {
929
+ static char fudges[3][4] = { /* n: 1: 2: 3: 4: */
930
+ {3,3,4,5}, /* 1-bit entries: 1b 2b 3b 4b */
931
+ {5,5,1,1}, /* 2-bit entries: 2b 4b 6b 8b */
932
+ {6,1,2,2}, /* 4-bit entries: 4b 8b 12b 16b */
933
+ };
934
+ return n <= 4 && w <= 3 ? fudges[w-1][n-1] : ((n<<w)+14)>>4;
935
+ }
936
+
937
+ static int *PackedIntVec (int *data, int rows, intptr_t *outsize) {
938
+ int r, width, lo = 0, hi = 0, bits, *limit, *result;
939
+ intptr_t bytes;
940
+
941
+ for (r = 0; r < rows; ++r) {
942
+ if (data[r] < lo) lo = data[r];
943
+ if (data[r] > hi) hi = data[r];
944
+ }
945
+
946
+ width = MinWidth(lo, hi);
947
+
948
+ if (width >= 6) {
949
+ bytes = rows * (1 << (width-4));
950
+ result = malloc(bytes);
951
+ memcpy(result, data, bytes);
952
+ } else if (rows > 0 && width > 0) {
953
+ bytes = FixFudge(rows, width);
954
+ result = malloc(bytes);
955
+ memset(result, 0, bytes);
956
+
957
+ limit = data + rows;
958
+ bits = 0;
959
+
960
+ switch (width) {
961
+
962
+ case 1: { /* 1 bit, 8 per byte */
963
+ char* q = (char*) result;
964
+ while (data < limit) {
965
+ *q |= (*data++ & 1) << bits; ++bits; q += bits >> 3; bits &= 7;
966
+ }
967
+ break;
968
+ }
969
+
970
+ case 2: { /* 2 bits, 4 per byte */
971
+ char* q = (char*) result;
972
+ while (data < limit) {
973
+ *q |= (*data++ & 3) << bits; bits += 2; q += bits >> 3; bits &= 7;
974
+ }
975
+ break;
976
+ }
977
+
978
+ case 3: { /* 4 bits, 2 per byte */
979
+ char* q = (char*) result;
980
+ while (data < limit) {
981
+ *q |= (*data++ & 15) << bits; bits += 4; q += bits >> 3; bits &= 7;
982
+ }
983
+ break;
984
+ }
985
+
986
+ case 4: { /* 1-byte (char) */
987
+ char* q = (char*) result;
988
+ while (data < limit)
989
+ *q++ = (char) *data++;
990
+ break;
991
+ }
992
+
993
+ case 5: { /* 2-byte (short) */
994
+ short* q = (short*) result;
995
+ while (data < limit)
996
+ *q++ = (short) *data++;
997
+ break;
998
+ }
999
+ }
1000
+ } else {
1001
+ bytes = 0;
1002
+ result = NULL;
1003
+ }
1004
+
1005
+ *outsize = bytes;
1006
+ return result;
1007
+ }
1008
+
1009
+ static void EmitFixCol (Column column, ItemTypes type) {
1010
+ int r, rows, *tempvec;
1011
+ void *buffer;
1012
+ intptr_t basepos, bufsize;
1013
+ Shared_p sh = GetShared();
1014
+
1015
+ rows = S_Count(column.seq);
1016
+
1017
+ switch (type) {
1018
+
1019
+ case IT_int:
1020
+ bufsize = rows * sizeof(int);
1021
+ tempvec = malloc(bufsize);
1022
+ for (r = 0; r < rows; ++r)
1023
+ tempvec[r] = GetTypedItem(r, column, type).i;
1024
+ buffer = PackedIntVec(tempvec, rows, &bufsize);
1025
+ free((char*) tempvec); /* TODO: avoid extra copy & malloc */
1026
+ break;
1027
+
1028
+ case IT_wide:
1029
+ bufsize = rows * sizeof(int64_t);
1030
+ buffer = malloc(bufsize);
1031
+ for (r = 0; r < rows; ++r)
1032
+ ((int64_t*) buffer)[r] = GetTypedItem(r, column, type).w;
1033
+ break;
1034
+
1035
+ case IT_float:
1036
+ bufsize = rows * sizeof(float);
1037
+ buffer = malloc(bufsize);
1038
+ for (r = 0; r < rows; ++r)
1039
+ ((float*) buffer)[r] = GetTypedItem(r, column, type).f;
1040
+ break;
1041
+
1042
+ case IT_double:
1043
+ bufsize = rows * sizeof(double);
1044
+ buffer = malloc(bufsize);
1045
+ for (r = 0; r < rows; ++r)
1046
+ ((double*) buffer)[r] = GetTypedItem(r, column, type).d;
1047
+ break;
1048
+
1049
+ default: Assert(0); return;
1050
+ }
1051
+
1052
+ /* start using 16-byte alignment once the emitted data reaches 1 Mb */
1053
+ /* only do this for vectors >= 128 bytes, so worst-case waste is under 10% */
1054
+
1055
+ Assert(!(bufsize > 0 && rows == 0));
1056
+ if (bufsize >= 128 && bufsize / rows >= 2)
1057
+ EmitAlign();
1058
+
1059
+ basepos = sh->position;
1060
+ EmitBlock(buffer, bufsize);
1061
+ EmitPair(basepos);
1062
+ }
1063
+
1064
+ static void EmitVarCol (Column column, int istext) {
1065
+ int r, rows, bytes, *sizevec;
1066
+ intptr_t basepos;
1067
+ Item item;
1068
+ Buffer buffer;
1069
+ Column sizes;
1070
+ Shared_p sh = GetShared();
1071
+
1072
+ InitBuffer(&buffer);
1073
+ rows = S_Count(column.seq);
1074
+ sizes = NewIntVec(rows, &sizevec);
1075
+
1076
+ if (istext)
1077
+ for (r = 0; r < rows; ++r) {
1078
+ item = GetTypedItem(r, column, IT_string);
1079
+ bytes = strlen(item.s);
1080
+ if (bytes > 0)
1081
+ AddToBuffer(&buffer, item.s, ++bytes);
1082
+ sizevec[r] = bytes;
1083
+ }
1084
+ else
1085
+ for (r = 0; r < rows; ++r) {
1086
+ item = GetTypedItem(r, column, IT_bytes);
1087
+ AddToBuffer(&buffer, item.u.ptr, item.u.len);
1088
+ sizevec[r] = item.u.len;
1089
+ }
1090
+
1091
+ basepos = sh->position;
1092
+ EmitBlock(BufferAsPtr(&buffer, 0), BufferFill(buffer));
1093
+ EmitPair(basepos);
1094
+
1095
+ if (BufferFill(buffer) > 0)
1096
+ EmitFixCol(sizes, 1);
1097
+
1098
+ ReleaseBuffer(&buffer, 1);
1099
+ EmitVarInt(0); /* no memos */
1100
+ }
1101
+
1102
+ static void EmitSubCol (Column column, int describe) {
1103
+ int r, rows;
1104
+ intptr_t basepos;
1105
+ View_p view;
1106
+ Buffer newcolbuf;
1107
+ Buffer_p origcolbuf;
1108
+ Shared_p sh = GetShared();
1109
+
1110
+ origcolbuf = sh->colbuf;
1111
+ sh->colbuf = &newcolbuf;
1112
+ InitBuffer(sh->colbuf);
1113
+
1114
+ rows = S_Count(column.seq);
1115
+
1116
+ for (r = 0; r < rows; ++r) {
1117
+ view = GetTypedItem(r, column, IT_view).v;
1118
+ EmitView(view, describe);
1119
+ }
1120
+
1121
+ sh->colbuf = origcolbuf;
1122
+
1123
+ basepos = sh->position;
1124
+ EmitBlock(BufferAsPtr(&newcolbuf, 0), BufferFill(newcolbuf));
1125
+ EmitPair(basepos);
1126
+
1127
+ ReleaseBuffer(&newcolbuf, 1);
1128
+ }
1129
+
1130
+ void EmitView (View_p view, int describe) {
1131
+ int rows;
1132
+ Shared_p sh = GetShared();
1133
+
1134
+ EmitVarInt(0);
1135
+
1136
+ if (describe) {
1137
+ Buffer desc;
1138
+
1139
+ InitBuffer(&desc);
1140
+ MetaAsDesc(V_Meta(view), &desc);
1141
+
1142
+ EmitVarInt(BufferFill(desc));
1143
+ AddToBuffer(sh->colbuf, BufferAsPtr(&desc, 1), BufferFill(desc));
1144
+
1145
+ ReleaseBuffer(&desc, 0);
1146
+ }
1147
+
1148
+ rows = ViewSize(view);
1149
+ EmitVarInt(rows);
1150
+
1151
+ if (rows > 0) {
1152
+ int c, cols = ViewWidth(view);
1153
+ ItemTypes type;
1154
+ Column column;
1155
+ View_p subv, meta = V_Meta(view);
1156
+
1157
+ for (c = 0; c < cols; ++c) {
1158
+ column = ViewCol(view,c);
1159
+ type = ViewColType(view, c);
1160
+ switch (type) {
1161
+
1162
+ case IT_int:
1163
+ case IT_wide:
1164
+ case IT_float:
1165
+ case IT_double:
1166
+ EmitFixCol(column, type);
1167
+ break;
1168
+
1169
+ case IT_string:
1170
+ EmitVarCol(column, 1);
1171
+ break;
1172
+
1173
+ case IT_bytes:
1174
+ EmitVarCol(column, 0);
1175
+ break;
1176
+
1177
+ case IT_view:
1178
+ subv = GetTypedItem(c, ViewCol(meta, MC_subv), IT_view).v;
1179
+ EmitSubCol(column, ViewSize(subv) == 0);
1180
+ break;
1181
+
1182
+ default: Assert(0);
1183
+ }
1184
+ }
1185
+ }
1186
+ }
1187
+
1188
+ static void SetBigEndian32 (char* dest, intptr_t value) {
1189
+ dest[0] = (char) (value >> 24);
1190
+ dest[1] = (char) (value >> 16);
1191
+ dest[2] = (char) (value >> 8);
1192
+ dest[3] = (char) value;
1193
+ }
1194
+
1195
+ intptr_t EmitFull (View_p view, Buffer_p buffer) {
1196
+ int overflow;
1197
+ intptr_t rootpos, tailpos, endpos;
1198
+ char tail[16];
1199
+ struct Head { short a; char b; char c; char d[4]; } head, *fixup;
1200
+ Buffer newcolbuf;
1201
+ Shared_p sh = GetShared();
1202
+
1203
+ sh->position = 0;
1204
+ sh->itembuf = buffer;
1205
+
1206
+ head.a = 'J' + ('L' << 8);
1207
+ head.b = 0x1A;
1208
+ head.c = 0;
1209
+ fixup = EmitCopy(&head, sizeof head);
1210
+
1211
+ sh->colbuf = &newcolbuf;
1212
+ InitBuffer(sh->colbuf);
1213
+
1214
+ EmitView(view, 1);
1215
+
1216
+ rootpos = EmitAlign();
1217
+
1218
+ EmitBlock(BufferAsPtr(sh->colbuf, 0), BufferFill(*sh->colbuf));
1219
+
1220
+ ReleaseBuffer(sh->colbuf, 1);
1221
+
1222
+ sh->colbuf = NULL;
1223
+
1224
+ tailpos = EmitAlign();
1225
+ endpos = tailpos + sizeof tail;
1226
+
1227
+ /* large files will have bit 8 of head[3] and bit 8 of tail[12] set */
1228
+ overflow = (endpos >> 16) >> 15; /* careful on 32-bit machines */
1229
+
1230
+ /* for file sizes > 2 Gb, store bits 41..31 in tail[2..3] */
1231
+ SetBigEndian32(tail, 0x80000000 + overflow);
1232
+ SetBigEndian32(tail+4, tailpos);
1233
+ SetBigEndian32(tail+8, 0x80000000 + tailpos - rootpos);
1234
+ SetBigEndian32(tail+12, rootpos);
1235
+
1236
+ if (overflow)
1237
+ tail[12] |= 0x80;
1238
+
1239
+ EmitCopy(tail, sizeof tail);
1240
+
1241
+ if (overflow) {
1242
+ /* store bits 41..36 in head[3], and bits 35..4 in head[4..7] */
1243
+ Assert((endpos & 15) == 0);
1244
+ fixup->c = 0x80 | ((endpos >> 16) >> 20);
1245
+ SetBigEndian32(fixup->d, endpos >> 4);
1246
+ } else
1247
+ SetBigEndian32(fixup->d, endpos);
1248
+
1249
+ return endpos;
1250
+ }
1251
+ /* %include<file.c>% */
1252
+ /*
1253
+ * file.c - Implementation of memory-mapped file access.
1254
+ */
1255
+
1256
+ #include <stdlib.h>
1257
+ #include <string.h>
1258
+ #include <unistd.h>
1259
+
1260
+ #ifdef WIN32
1261
+ #define WIN32_LEAN_AND_MEAN
1262
+ #include <windows.h>
1263
+ #else
1264
+ #include <sys/mman.h>
1265
+ #include <sys/stat.h>
1266
+ #include <fcntl.h>
1267
+ #endif
1268
+
1269
+ /*
1270
+ * file.h - Definition of memory-mapped file access.
1271
+ */
1272
+
1273
+ typedef Sequence_p MappedFile_p;
1274
+
1275
+ #define MF_Data(map) ((const char*) ((map)->data[0].p))
1276
+ #define MF_Length(map) ((intptr_t) (map)->data[1].p)
1277
+
1278
+ MappedFile_p (InitMappedFile) (const char *data, intptr_t length, Cleaner fun);
1279
+ View_p (MappedToView) (MappedFile_p map);
1280
+ View_p (MapSubview) (MappedFile_p map, intptr_t offset, View_p meta);
1281
+ View_p (OpenDataFile) (const char *filename);
1282
+ MappedFile_p (OpenMappedFile) (const char *filename);
1283
+
1284
+ MappedFile_p InitMappedFile (const char *data, intptr_t length, Cleaner fun) {
1285
+ MappedFile_p map;
1286
+
1287
+ /* data[0] points to the current start of the mapped area */
1288
+ /* data[1] is the current length of the mapped area */
1289
+ /* data[2] points to the original mapped area */
1290
+ /* data[3] is available for storing an Object_p, see ext_tcl.c */
1291
+ map = InitColumn(0, NULL, 0).seq;
1292
+ map->data[0].p = (void*) data;
1293
+ map->data[1].p = (void*) length;
1294
+ map->data[2].p = (void*) data;
1295
+ map->head.cleaner = fun;
1296
+ return map;
1297
+ }
1298
+
1299
+ static void MappedFileCleaner (MappedFile_p map) {
1300
+ #if WIN32
1301
+ UnmapViewOfFile(map->data[2].p);
1302
+ #else
1303
+ int offset = (char*) map->data[0].p - (char*) map->data[2].p;
1304
+ munmap(map->data[2].p, (intptr_t) map->data[1].p + offset);
1305
+ #endif
1306
+ }
1307
+
1308
+ MappedFile_p OpenMappedFile (const char *filename) {
1309
+ const char *data = NULL;
1310
+ intptr_t length = -1;
1311
+
1312
+ #if WIN32
1313
+ {
1314
+ DWORD n;
1315
+ HANDLE h, f = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0,
1316
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1317
+ if (f != INVALID_HANDLE_VALUE) {
1318
+ h = CreateFileMapping(f, 0, PAGE_READONLY, 0, 0, 0);
1319
+ if (h != INVALID_HANDLE_VALUE) {
1320
+ n = GetFileSize(f, 0);
1321
+ data = MapViewOfFile(h, FILE_MAP_READ, 0, 0, n);
1322
+ if (data != NULL)
1323
+ length = n;
1324
+ CloseHandle(h);
1325
+ }
1326
+ CloseHandle(f);
1327
+ }
1328
+ }
1329
+ #else
1330
+ {
1331
+ struct stat sb;
1332
+ int fd = open(filename, O_RDONLY);
1333
+ if (fd != -1) {
1334
+ if (fstat(fd, &sb) == 0) {
1335
+ data = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
1336
+ if (data != MAP_FAILED)
1337
+ length = sb.st_size;
1338
+ }
1339
+ close(fd);
1340
+ }
1341
+ }
1342
+ #endif
1343
+
1344
+ if (length < 0)
1345
+ return NULL;
1346
+
1347
+ return InitMappedFile(data, length, (Cleaner) MappedFileCleaner);
1348
+ }
1349
+
1350
+ static void AdjustMappedFile (MappedFile_p map, int offset) {
1351
+ map->data[0].p = (void*) (MF_Data(map) + offset);
1352
+ map->data[1].p = (void*) (MF_Length(map) - offset);
1353
+ }
1354
+
1355
+ static int IsReversedEndian(MappedFile_p map) {
1356
+ #if _BIG_ENDIAN
1357
+ return *MF_Data(map) == 'J';
1358
+ #else
1359
+ return *MF_Data(map) == 'L';
1360
+ #endif
1361
+ }
1362
+
1363
+ static intptr_t GetVarInt (const char **cp) {
1364
+ int8_t b;
1365
+ intptr_t v = 0;
1366
+ do {
1367
+ b = *(*cp)++;
1368
+ v = (v << 7) + b;
1369
+ } while (b >= 0);
1370
+ return v + 128;
1371
+ }
1372
+
1373
+ static intptr_t GetVarPair(const char** cp) {
1374
+ intptr_t n = GetVarInt(cp);
1375
+ if (n > 0 && GetVarInt(cp) == 0)
1376
+ *cp += n;
1377
+ return n;
1378
+ }
1379
+
1380
+ static void MappedViewCleaner (Sequence_p seq) {
1381
+ int i, count;
1382
+ const View_p *subviews = seq->data[0].p;
1383
+
1384
+ count = S_Count((Sequence_p) seq->data[1].p);
1385
+ for (i = 0; i < count; ++i)
1386
+ DecRefCount(subviews[i]);
1387
+
1388
+ DecRefCount(seq->data[1].p);
1389
+ DecRefCount(seq->data[2].p);
1390
+ DecRefCount(seq->data[3].p);
1391
+ }
1392
+
1393
+ static ItemTypes MappedViewGetter (int row, Item_p item) {
1394
+ View_p *subviews = item->c.seq->data[0].p;
1395
+
1396
+ if (subviews[row] == NULL) {
1397
+ const intptr_t *offsets = ((Sequence_p) item->c.seq->data[1].p)->data[0].p;
1398
+ MappedFile_p map = item->c.seq->data[2].p;
1399
+ View_p meta = item->c.seq->data[3].p;
1400
+ subviews[row] = IncRefCount(MapSubview(map, offsets[row], meta));
1401
+ }
1402
+
1403
+ item->v = subviews[row];
1404
+ return IT_view;
1405
+ }
1406
+
1407
+ static Column MappedViewCol (MappedFile_p map, int rows, const char **nextp, View_p meta) {
1408
+ int r, c, cols, subcols;
1409
+ intptr_t colsize, colpos, *offsets;
1410
+ const char *next;
1411
+ Sequence_p offseq;
1412
+ Column result;
1413
+
1414
+ offseq = NewPtrVec(rows, &offsets).seq;
1415
+ cols = ViewSize(meta);
1416
+
1417
+ colsize = GetVarInt(nextp);
1418
+ colpos = colsize > 0 ? GetVarInt(nextp) : 0;
1419
+ next = MF_Data(map) + colpos;
1420
+
1421
+ for (r = 0; r < rows; ++r) {
1422
+ offsets[r] = next - MF_Data(map);
1423
+ GetVarInt(&next);
1424
+ if (cols == 0) {
1425
+ intptr_t desclen = GetVarInt(&next);
1426
+ const char *desc = next;
1427
+ next += desclen;
1428
+ meta = DescAsMeta(&desc, next);
1429
+ }
1430
+ if (GetVarInt(&next) > 0) {
1431
+ subcols = ViewSize(meta);
1432
+ for (c = 0; c < subcols; ++c)
1433
+ switch (GetColType(meta, c)) {
1434
+ case 'B': case 'S': if (GetVarPair(&next)) GetVarPair(&next);
1435
+ /* fall through */
1436
+ default: GetVarPair(&next);
1437
+ }
1438
+ }
1439
+ }
1440
+
1441
+ /* data[0] points to a subview cache */
1442
+ /* data[1] points to a sequence owning the offest vector */
1443
+ /* data[2] points to the mapped file */
1444
+ /* data[3] points to the meta view */
1445
+ result = InitColumn(rows, MappedViewGetter, rows * sizeof(View_p));
1446
+ result.seq->head.cleaner = (Cleaner) MappedViewCleaner;
1447
+ result.seq->data[1].p = IncRefCount(offseq);
1448
+ result.seq->data[2].p = IncRefCount(map);
1449
+ result.seq->data[3].p = IncRefCount(cols > 0 ? meta : EmptyMetaView());
1450
+
1451
+ /* TODO: could combine subview cache and offsets vector */
1452
+
1453
+ return result;
1454
+ }
1455
+
1456
+ static void MappedFixedCleaner (Sequence_p seq) {
1457
+ DecRefCount(seq->data[1].p);
1458
+ }
1459
+
1460
+ static Column MappedFixedCol (MappedFile_p map, int rows, const char **nextp, int isreal) {
1461
+ intptr_t colsize, colpos;
1462
+ Getter getter;
1463
+ Column result;
1464
+
1465
+ colsize = GetVarInt(nextp);
1466
+ colpos = colsize > 0 ? GetVarInt(nextp) : 0;
1467
+ getter = FixedGetter(colsize, rows, isreal, IsReversedEndian(map));
1468
+
1469
+ /* data[0] points to the mapped data */
1470
+ /* data[1] points to the mapped file */
1471
+ result = InitColumn(rows, getter, 0);
1472
+ result.seq->head.cleaner = (Cleaner) MappedFixedCleaner;
1473
+ result.seq->data[0].p = (void*) (MF_Data(map) + colpos);
1474
+ result.seq->data[1].p = IncRefCount(map);
1475
+
1476
+ return result;
1477
+ }
1478
+
1479
+ static void MappedStringCleaner (Sequence_p seq) {
1480
+ DecRefCount(seq->data[0].p);
1481
+ DecRefCount(seq->data[2].p);
1482
+ DecRefCount(seq->data[3].p);
1483
+ }
1484
+
1485
+ static ItemTypes MappedStringGetter (int row, Item_p item) {
1486
+ const intptr_t *offsets = item->c.seq->data[1].p;
1487
+ MappedFile_p map = item->c.seq->data[2].p;
1488
+
1489
+ if (offsets[row] == 0)
1490
+ item->s = "";
1491
+ else if (offsets[row] > 0)
1492
+ item->s = MF_Data(map) + offsets[row];
1493
+ else {
1494
+ const char *next = MF_Data(map) - offsets[row];
1495
+ if (GetVarInt(&next) > 0)
1496
+ item->s = MF_Data(map) + GetVarInt(&next);
1497
+ else
1498
+ item->s = "";
1499
+ }
1500
+
1501
+ return IT_string;
1502
+ }
1503
+
1504
+ static ItemTypes MappedBytesGetter (int row, Item_p item) {
1505
+ const intptr_t *offsets = item->c.seq->data[1].p;
1506
+ MappedFile_p map = item->c.seq->data[2].p;
1507
+ Sequence_p sizes = item->c.seq->data[3].p;
1508
+ Column column;
1509
+
1510
+ column.seq = sizes;
1511
+ column.pos = -1;
1512
+ item->u.len = GetTypedItem(row, column, IT_int).i;
1513
+
1514
+ if (offsets[row] >= 0)
1515
+ item->u.ptr = (const uint8_t*) MF_Data(map) + offsets[row];
1516
+ else {
1517
+ const char *next = MF_Data(map) - offsets[row];
1518
+ item->u.len = GetVarInt(&next);
1519
+ item->u.ptr = (const uint8_t*) MF_Data(map) + GetVarInt(&next);
1520
+ }
1521
+
1522
+ return IT_bytes;
1523
+ }
1524
+
1525
+ static Column MappedStringCol (MappedFile_p map, int rows, const char **nextp, int istext) {
1526
+ int r, len, memopos;
1527
+ intptr_t colsize, colpos, *offsets;
1528
+ const char *next, *limit;
1529
+ Sequence_p offseq;
1530
+ Column sizes, result;
1531
+
1532
+ offseq = NewPtrVec(rows, &offsets).seq;
1533
+
1534
+ colsize = GetVarInt(nextp);
1535
+ colpos = colsize > 0 ? GetVarInt(nextp) : 0;
1536
+
1537
+ if (colsize > 0) {
1538
+ sizes = MappedFixedCol(map, rows, nextp, 0);
1539
+ for (r = 0; r < rows; ++r) {
1540
+ len = GetTypedItem(r, sizes, IT_int).i;
1541
+ if (len > 0) {
1542
+ offsets[r] = colpos;
1543
+ colpos += len;
1544
+ }
1545
+ }
1546
+ } else
1547
+ sizes = InitColumn(rows, FixedGetter(0, rows, 0, 0), 0);
1548
+
1549
+ colsize = GetVarInt(nextp);
1550
+ memopos = colsize > 0 ? GetVarInt(nextp) : 0;
1551
+ next = MF_Data(map) + memopos;
1552
+ limit = next + colsize;
1553
+
1554
+ /* negated offsets point to the size/pos pair in the map */
1555
+ for (r = 0; next < limit; ++r) {
1556
+ r += (int) GetVarInt(&next);
1557
+ offsets[r] = MF_Data(map) - next; /* always < 0 */
1558
+ GetVarPair(&next);
1559
+ }
1560
+
1561
+ /* data[0] points to a sequence owning the offset vector */
1562
+ /* data[1] points to that vector of subview offsets */
1563
+ /* data[2] points to the mapped file */
1564
+ /* data[3] points to the sizes seq if binary or is null if zero-terminated */
1565
+ result = InitColumn(rows, istext ? MappedStringGetter : MappedBytesGetter, 0);
1566
+ result.seq->head.cleaner = (Cleaner) MappedStringCleaner;
1567
+ result.seq->data[0].p = IncRefCount(offseq);
1568
+ result.seq->data[1].p = offsets;
1569
+ result.seq->data[2].p = IncRefCount(map);
1570
+ result.seq->data[3].p = istext ? NULL : IncRefCount(sizes.seq);
1571
+
1572
+ return result;
1573
+ }
1574
+
1575
+ View_p MapSubview (MappedFile_p map, intptr_t offset, View_p meta) {
1576
+ int c, cols, rows;
1577
+ const char *next;
1578
+ Column column;
1579
+ View_p result, subview;
1580
+
1581
+ next = MF_Data(map) + offset;
1582
+ GetVarInt(&next);
1583
+
1584
+ if (ViewSize(meta) == 0) {
1585
+ intptr_t desclen = GetVarInt(&next);
1586
+ const char *desc = next;
1587
+ next += desclen;
1588
+ meta = DescAsMeta(&desc, next);
1589
+ }
1590
+
1591
+ rows = (int) GetVarInt(&next);
1592
+ cols = ViewSize(meta);
1593
+
1594
+ if (cols == 0)
1595
+ return NoColumnView(rows);
1596
+
1597
+ result = NewView(meta);
1598
+
1599
+ if (rows > 0)
1600
+ for (c = 0; c < cols; ++c) {
1601
+ switch (ViewColType(result, c)) {
1602
+
1603
+ case IT_int:
1604
+ case IT_wide:
1605
+ column = MappedFixedCol(map, rows, &next, 0);
1606
+ break;
1607
+
1608
+ case IT_float:
1609
+ case IT_double:
1610
+ column = MappedFixedCol(map, rows, &next, 1);
1611
+ break;
1612
+
1613
+ case IT_string:
1614
+ column = MappedStringCol(map, rows, &next, 1);
1615
+ break;
1616
+
1617
+ case IT_bytes:
1618
+ column = MappedStringCol(map, rows, &next, 0);
1619
+ break;
1620
+
1621
+ case IT_view:
1622
+ subview = GetTypedItem(c, ViewCol(meta, MC_subv), IT_view).v;
1623
+ column = MappedViewCol(map, rows, &next, subview);
1624
+ break;
1625
+
1626
+ default:
1627
+ Assert(0);
1628
+ return result;
1629
+ }
1630
+ SetViewColumns(result, c, 1, column);
1631
+ }
1632
+
1633
+ return result;
1634
+ }
1635
+
1636
+ static int BigEndianInt32 (const char *p) {
1637
+ const uint8_t *up = (const uint8_t*) p;
1638
+ return (p[0] << 24) | (up[1] << 16) | (up[2] << 8) | up[3];
1639
+ }
1640
+
1641
+ View_p MappedToView (MappedFile_p map) {
1642
+ int i, t[4];
1643
+ intptr_t datalen, rootoff;
1644
+
1645
+ if (MF_Length(map) < 24 || *(MF_Data(map) + MF_Length(map) - 8) != '\x80')
1646
+ return NULL;
1647
+
1648
+ for (i = 0; i < 4; ++i)
1649
+ t[i] = BigEndianInt32(MF_Data(map) + MF_Length(map) - 16 + i * 4);
1650
+
1651
+ datalen = t[1] + 16;
1652
+ rootoff = t[3];
1653
+
1654
+ if (rootoff < 0) {
1655
+ const intptr_t mask = 0x7FFFFFFF;
1656
+ datalen = (datalen & mask) + ((intptr_t) ((t[0] & 0x7FF) << 16) << 15);
1657
+ rootoff = (rootoff & mask) + (datalen & ~mask);
1658
+ }
1659
+
1660
+ AdjustMappedFile(map, MF_Length(map) - datalen);
1661
+ return MapSubview(map, rootoff, EmptyMetaView());
1662
+ }
1663
+
1664
+ View_p OpenDataFile (const char *filename) {
1665
+ MappedFile_p map;
1666
+
1667
+ map = OpenMappedFile(filename);
1668
+ if (map == NULL)
1669
+ return NULL;
1670
+
1671
+ return MappedToView(map);
1672
+ }
1673
+ /* %include<getters.c>% */
1674
+ /*
1675
+ * getters.c - Implementation of several simple getter functions.
1676
+ */
1677
+
1678
+ #include <stdlib.h>
1679
+
1680
+
1681
+ static ItemTypes Getter_i0 (int row, Item_p item) {
1682
+ item->i = 0;
1683
+ return IT_int;
1684
+ }
1685
+
1686
+ static ItemTypes Getter_i1 (int row, Item_p item) {
1687
+ const char *ptr = item->c.seq->data[0].p;
1688
+ item->i = (ptr[row>>3] >> (row&7)) & 1;
1689
+ return IT_int;
1690
+ }
1691
+
1692
+ static ItemTypes Getter_i2 (int row, Item_p item) {
1693
+ const char *ptr = item->c.seq->data[0].p;
1694
+ item->i = (ptr[row>>2] >> 2*(row&3)) & 3;
1695
+ return IT_int;
1696
+ }
1697
+
1698
+ static ItemTypes Getter_i4 (int row, Item_p item) {
1699
+ const char *ptr = item->c.seq->data[0].p;
1700
+ item->i = (ptr[row>>1] >> 4*(row&1)) & 15;
1701
+ return IT_int;
1702
+ }
1703
+
1704
+ static ItemTypes Getter_i8 (int row, Item_p item) {
1705
+ const char *ptr = item->c.seq->data[0].p;
1706
+ item->i = (int8_t) ptr[row];
1707
+ return IT_int;
1708
+ }
1709
+
1710
+ #if VALUES_MUST_BE_ALIGNED
1711
+
1712
+ static ItemTypes Getter_i16 (int row, Item_p item) {
1713
+ const uint8_t *ptr = (const uint8_t*) item->c.seq->data[0].p + row * 2;
1714
+ #if _BIG_ENDIAN
1715
+ item->i = (((int8_t) ptr[0]) << 8) | ptr[1];
1716
+ #else
1717
+ item->i = (((int8_t) ptr[1]) << 8) | ptr[0];
1718
+ #endif
1719
+ return IT_int;
1720
+ }
1721
+
1722
+ static ItemTypes Getter_i32 (int row, Item_p item) {
1723
+ const char *ptr = (const char*) item->c.seq->data[0].p + row * 4;
1724
+ int i;
1725
+ for (i = 0; i < 4; ++i)
1726
+ item->b[i] = ptr[i];
1727
+ return IT_int;
1728
+ }
1729
+
1730
+ static ItemTypes Getter_i64 (int row, Item_p item) {
1731
+ const char *ptr = (const char*) item->c.seq->data[0].p + row * 8;
1732
+ int i;
1733
+ for (i = 0; i < 8; ++i)
1734
+ item->b[i] = ptr[i];
1735
+ return IT_wide;
1736
+ }
1737
+
1738
+ static ItemTypes Getter_f32 (int row, Item_p item) {
1739
+ Getter_i32(row, item);
1740
+ return IT_float;
1741
+ }
1742
+
1743
+ static ItemTypes Getter_f64 (int row, Item_p item) {
1744
+ Getter_i64(row, item);
1745
+ return IT_double;
1746
+ }
1747
+
1748
+ #else
1749
+
1750
+ static ItemTypes Getter_i16 (int row, Item_p item) {
1751
+ const char *ptr = item->c.seq->data[0].p;
1752
+ item->i = ((short*) ptr)[row];
1753
+ return IT_int;
1754
+ }
1755
+
1756
+ static ItemTypes Getter_i32 (int row, Item_p item) {
1757
+ const char *ptr = item->c.seq->data[0].p;
1758
+ item->i = ((const int*) ptr)[row];
1759
+ return IT_int;
1760
+ }
1761
+
1762
+ static ItemTypes Getter_i64 (int row, Item_p item) {
1763
+ const char *ptr = item->c.seq->data[0].p;
1764
+ item->w = ((const int64_t*) ptr)[row];
1765
+ return IT_wide;
1766
+ }
1767
+
1768
+ static ItemTypes Getter_f32 (int row, Item_p item) {
1769
+ const char *ptr = item->c.seq->data[0].p;
1770
+ item->f = ((const float*) ptr)[row];
1771
+ return IT_float;
1772
+ }
1773
+
1774
+ static ItemTypes Getter_f64 (int row, Item_p item) {
1775
+ const char *ptr = item->c.seq->data[0].p;
1776
+ item->d = ((const double*) ptr)[row];
1777
+ return IT_double;
1778
+ }
1779
+
1780
+ #endif
1781
+
1782
+ static ItemTypes Getter_i16r (int row, Item_p item) {
1783
+ const uint8_t *ptr = (const uint8_t*) item->c.seq->data[0].p + row * 2;
1784
+ #if _BIG_ENDIAN
1785
+ item->i = (((int8_t) ptr[1]) << 8) | ptr[0];
1786
+ #else
1787
+ item->i = (((int8_t) ptr[0]) << 8) | ptr[1];
1788
+ #endif
1789
+ return IT_int;
1790
+ }
1791
+
1792
+ static ItemTypes Getter_i32r (int row, Item_p item) {
1793
+ const char *ptr = (const char*) item->c.seq->data[0].p + row * 4;
1794
+ int i;
1795
+ for (i = 0; i < 4; ++i)
1796
+ item->b[i] = ptr[3-i];
1797
+ return IT_int;
1798
+ }
1799
+
1800
+ static ItemTypes Getter_i64r (int row, Item_p item) {
1801
+ const char *ptr = (const char*) item->c.seq->data[0].p + row * 8;
1802
+ int i;
1803
+ for (i = 0; i < 8; ++i)
1804
+ item->b[i] = ptr[7-i];
1805
+ return IT_wide;
1806
+ }
1807
+
1808
+ static ItemTypes Getter_f32r (int row, Item_p item) {
1809
+ Getter_i32r(row, item);
1810
+ return IT_float;
1811
+ }
1812
+
1813
+ static ItemTypes Getter_f64r (int row, Item_p item) {
1814
+ Getter_i64r(row, item);
1815
+ return IT_double;
1816
+ }
1817
+
1818
+ Getter PickIntGetter (int bits) {
1819
+ switch (bits) {
1820
+ default: Assert(0); /* fall through */
1821
+ case 0: return Getter_i0;
1822
+ case 1: return Getter_i1;
1823
+ case 2: return Getter_i2;
1824
+ case 4: return Getter_i4;
1825
+ case 8: return Getter_i8;
1826
+ case 16: return Getter_i16;
1827
+ case 32: return Getter_i32;
1828
+ case 64: return Getter_i64;
1829
+ }
1830
+ }
1831
+
1832
+ Getter FixedGetter (int bytes, int rows, int real, int flip) {
1833
+ int bits;
1834
+
1835
+ static char widths[8][7] = {
1836
+ {0,-1,-1,-1,-1,-1,-1},
1837
+ {0, 8,16, 1,32, 2, 4},
1838
+ {0, 4, 8, 1,16, 2,-1},
1839
+ {0, 2, 4, 8, 1,-1,16},
1840
+ {0, 2, 4,-1, 8, 1,-1},
1841
+ {0, 1, 2, 4,-1, 8,-1},
1842
+ {0, 1, 2, 4,-1,-1, 8},
1843
+ {0, 1, 2,-1, 4,-1,-1},
1844
+ };
1845
+
1846
+ bits = rows < 8 && bytes < 7 ? widths[rows][bytes] : (bytes << 3) / rows;
1847
+
1848
+ switch (bits) {
1849
+ case 16: return flip ? Getter_i16r : Getter_i16;
1850
+ case 32: return real ? flip ? Getter_f32r : Getter_f32
1851
+ : flip ? Getter_i32r : Getter_i32;
1852
+ case 64: return real ? flip ? Getter_f64r : Getter_f64
1853
+ : flip ? Getter_i64r : Getter_i64;
1854
+ }
1855
+
1856
+ return PickIntGetter(bits);
1857
+ }
1858
+ /* %include<hash.c>% */
1859
+ /*
1860
+ * hash.c - Implementation of hashing functions.
1861
+ */
1862
+
1863
+ #include <stdlib.h>
1864
+ #include <string.h>
1865
+
1866
+ /*
1867
+ * hash.h - Definition of hashing functions.
1868
+ */
1869
+
1870
+ Column (HashCol) (ItemTypes type, Column column);
1871
+ int (HashDoFind) (View_p view, int row, View_p w, Column, Column, Column);
1872
+ Column (GetHashInfo) (View_p left, View_p right, int type);
1873
+ View_p (GroupCol) (View_p view, Column cols, const char *name);
1874
+ Column (HashValues) (View_p view);
1875
+ View_p (IjoinView) (View_p left, View_p right);
1876
+ Column (IntersectMap) (View_p keys, View_p view);
1877
+ View_p (JoinView) (View_p left, View_p right, const char *name);
1878
+ int (RowHash) (View_p view, int row);
1879
+ int (StringLookup) (const char *key, Column values);
1880
+ Column (UniqMap) (View_p view);
1881
+ /*
1882
+ * sorted.h - Definition of sorting functions.
1883
+ */
1884
+
1885
+ int (RowCompare) (int r1, View_p v1, int r2, View_p v2);
1886
+ int (RowEqual) (int r1, View_p v1, int r2, View_p v2);
1887
+ Column (SortMap) (View_p view);
1888
+ /*
1889
+ * indirect.h - Definition of some virtual views.
1890
+ */
1891
+
1892
+ View_p (BlockedView) (View_p view);
1893
+ View_p (ConcatView) (View_p view1, View_p view2);
1894
+ View_p (GroupedView) (View_p view, Column scol, Column gcol, const char *name);
1895
+ View_p (RemapSubview) (View_p view, Column mapcol, int start, int count);
1896
+ View_p (StepView) (View_p view, int count, int offset, int rate, int step);
1897
+ View_p (UngroupView) (View_p view, int col);
1898
+ /* wrap_gen.h - generated code, do not edit */
1899
+
1900
+ ItemTypes (AppendCmd_VV) (Item_p a);
1901
+ ItemTypes (AtRowCmd_OI) (Item_p a);
1902
+ ItemTypes (BlockedCmd_V) (Item_p a);
1903
+ ItemTypes (CloneCmd_V) (Item_p a);
1904
+ ItemTypes (CoerceCmd_OS) (Item_p a);
1905
+ ItemTypes (ColConvCmd_C) (Item_p a);
1906
+ ItemTypes (ColMapCmd_Vn) (Item_p a);
1907
+ ItemTypes (ColOmitCmd_Vn) (Item_p a);
1908
+ ItemTypes (CompareCmd_VV) (Item_p a);
1909
+ ItemTypes (CompatCmd_VV) (Item_p a);
1910
+ ItemTypes (ConcatCmd_VV) (Item_p a);
1911
+ ItemTypes (CountsCmd_VN) (Item_p a);
1912
+ ItemTypes (CountsColCmd_C) (Item_p a);
1913
+ ItemTypes (CountViewCmd_I) (Item_p a);
1914
+ ItemTypes (DataCmd_VX) (Item_p a);
1915
+ ItemTypes (DefCmd_OO) (Item_p a);
1916
+ ItemTypes (DeleteCmd_VII) (Item_p a);
1917
+ ItemTypes (EmitCmd_V) (Item_p a);
1918
+ ItemTypes (ExceptCmd_VV) (Item_p a);
1919
+ ItemTypes (ExceptMapCmd_VV) (Item_p a);
1920
+ ItemTypes (FirstCmd_VI) (Item_p a);
1921
+ ItemTypes (GetCmd_VX) (Item_p a);
1922
+ ItemTypes (GetColCmd_VN) (Item_p a);
1923
+ ItemTypes (GetInfoCmd_VVI) (Item_p a);
1924
+ ItemTypes (GroupCmd_VnS) (Item_p a);
1925
+ ItemTypes (GroupedCmd_ViiS) (Item_p a);
1926
+ ItemTypes (GroupInfoCmd_V) (Item_p a);
1927
+ ItemTypes (HashColCmd_SO) (Item_p a);
1928
+ ItemTypes (HashFindCmd_VIViii) (Item_p a);
1929
+ ItemTypes (HashInfoCmd_V) (Item_p a);
1930
+ ItemTypes (HashViewCmd_V) (Item_p a);
1931
+ ItemTypes (IjoinCmd_VV) (Item_p a);
1932
+ ItemTypes (InsertCmd_VIV) (Item_p a);
1933
+ ItemTypes (IntersectCmd_VV) (Item_p a);
1934
+ ItemTypes (IotaCmd_I) (Item_p a);
1935
+ ItemTypes (IsectMapCmd_VV) (Item_p a);
1936
+ ItemTypes (JoinCmd_VVS) (Item_p a);
1937
+ ItemTypes (JoinInfoCmd_VV) (Item_p a);
1938
+ ItemTypes (LastCmd_VI) (Item_p a);
1939
+ ItemTypes (LoadCmd_O) (Item_p a);
1940
+ ItemTypes (LoopCmd_X) (Item_p a);
1941
+ ItemTypes (MaxCmd_VN) (Item_p a);
1942
+ ItemTypes (MdefCmd_O) (Item_p a);
1943
+ ItemTypes (MdescCmd_S) (Item_p a);
1944
+ ItemTypes (MetaCmd_V) (Item_p a);
1945
+ ItemTypes (MinCmd_VN) (Item_p a);
1946
+ ItemTypes (NameColCmd_V) (Item_p a);
1947
+ ItemTypes (NamesCmd_V) (Item_p a);
1948
+ ItemTypes (OmitMapCmd_iI) (Item_p a);
1949
+ ItemTypes (OpenCmd_S) (Item_p a);
1950
+ ItemTypes (PairCmd_VV) (Item_p a);
1951
+ ItemTypes (ProductCmd_VV) (Item_p a);
1952
+ ItemTypes (RefCmd_OX) (Item_p a);
1953
+ ItemTypes (RefsCmd_O) (Item_p a);
1954
+ ItemTypes (RemapCmd_Vi) (Item_p a);
1955
+ ItemTypes (RemapSubCmd_ViII) (Item_p a);
1956
+ ItemTypes (RenameCmd_VO) (Item_p a);
1957
+ ItemTypes (RepeatCmd_VI) (Item_p a);
1958
+ ItemTypes (ReplaceCmd_VIIV) (Item_p a);
1959
+ ItemTypes (ReverseCmd_V) (Item_p a);
1960
+ ItemTypes (RowEqCmd_IVIV) (Item_p a);
1961
+ ItemTypes (RowHashCmd_VI) (Item_p a);
1962
+ ItemTypes (SaveCmd_VS) (Item_p a);
1963
+ ItemTypes (SetCmd_VIX) (Item_p a);
1964
+ ItemTypes (SizeCmd_V) (Item_p a);
1965
+ ItemTypes (SliceCmd_VIII) (Item_p a);
1966
+ ItemTypes (SortCmd_V) (Item_p a);
1967
+ ItemTypes (SortMapCmd_V) (Item_p a);
1968
+ ItemTypes (SpreadCmd_VI) (Item_p a);
1969
+ ItemTypes (StepCmd_VIIII) (Item_p a);
1970
+ ItemTypes (StrLookupCmd_Ss) (Item_p a);
1971
+ ItemTypes (StructDescCmd_V) (Item_p a);
1972
+ ItemTypes (StructureCmd_V) (Item_p a);
1973
+ ItemTypes (SumCmd_VN) (Item_p a);
1974
+ ItemTypes (TagCmd_VS) (Item_p a);
1975
+ ItemTypes (TakeCmd_VI) (Item_p a);
1976
+ ItemTypes (ToCmd_OO) (Item_p a);
1977
+ ItemTypes (TypeCmd_O) (Item_p a);
1978
+ ItemTypes (TypesCmd_V) (Item_p a);
1979
+ ItemTypes (UngroupCmd_VN) (Item_p a);
1980
+ ItemTypes (UnionCmd_VV) (Item_p a);
1981
+ ItemTypes (UnionMapCmd_VV) (Item_p a);
1982
+ ItemTypes (UniqueCmd_V) (Item_p a);
1983
+ ItemTypes (UniqueMapCmd_V) (Item_p a);
1984
+ ItemTypes (ViewCmd_X) (Item_p a);
1985
+ ItemTypes (ViewAsColCmd_V) (Item_p a);
1986
+ ItemTypes (ViewConvCmd_V) (Item_p a);
1987
+ ItemTypes (WidthCmd_V) (Item_p a);
1988
+ ItemTypes (WriteCmd_VS) (Item_p a);
1989
+
1990
+ /* end of generated code */
1991
+
1992
+ typedef struct HashInfo *HashInfo_p;
1993
+
1994
+ typedef struct HashInfo {
1995
+ View_p view; /* input view */
1996
+ int prime; /* prime used for hashing */
1997
+ int fill; /* used to fill map */
1998
+ int *map; /* map of unique rows */
1999
+ Column mapcol; /* owner of map */
2000
+ int *hvec; /* hash probe vector */
2001
+ Column veccol; /* owner of hvec */
2002
+ int *hashes; /* hash values, one per view row */
2003
+ Column hashcol; /* owner of hashes */
2004
+ } HashInfo;
2005
+
2006
+ static int StringHash (const char *s, int n) {
2007
+ /* similar to Python's stringobject.c */
2008
+ int i, h = (*s * 0xFF) << 7;
2009
+ if (n == INVALID_COUNT)
2010
+ n = strlen(s);
2011
+ for (i = 0; i < n; ++i)
2012
+ h = (1000003 * h) ^ s[i];
2013
+ return h ^ i;
2014
+ }
2015
+
2016
+ Column HashCol (ItemTypes type, Column column) {
2017
+ int i, count, *data;
2018
+ Column result;
2019
+ Item item;
2020
+
2021
+ /* the folowing is not possible: the result may be xor-ed into!
2022
+ if (type == IT_int && column.seq->getter == PickIntGetter(32))
2023
+ return column;
2024
+ */
2025
+
2026
+ count = S_Count(column.seq);
2027
+ result = NewIntVec(count, &data);
2028
+
2029
+ switch (type) {
2030
+
2031
+ case IT_int:
2032
+ for (i = 0; i < count; ++i)
2033
+ data[i] = GetTypedItem(i, column, IT_int).i;
2034
+ break;
2035
+
2036
+ case IT_wide:
2037
+ for (i = 0; i < count; ++i) {
2038
+ item = GetTypedItem(i, column, IT_wide);
2039
+ data[i] = item.q[0] ^ item.q[1];
2040
+ }
2041
+ break;
2042
+
2043
+ case IT_float:
2044
+ for (i = 0; i < count; ++i)
2045
+ data[i] = GetTypedItem(i, column, IT_float).i;
2046
+ break;
2047
+
2048
+ case IT_double:
2049
+ for (i = 0; i < count; ++i) {
2050
+ item = GetTypedItem(i, column, IT_double);
2051
+ data[i] = item.q[0] ^ item.q[1];
2052
+ }
2053
+ break;
2054
+
2055
+ case IT_string:
2056
+ for (i = 0; i < count; ++i) {
2057
+ item = GetTypedItem(i, column, IT_string);
2058
+ data[i] = StringHash(item.s, INVALID_COUNT);
2059
+ }
2060
+ break;
2061
+
2062
+ case IT_bytes:
2063
+ for (i = 0; i < count; ++i) {
2064
+ item = GetTypedItem(i, column, IT_bytes);
2065
+ data[i] = StringHash((const char*) item.u.ptr, item.u.len);
2066
+ }
2067
+ break;
2068
+
2069
+ case IT_view:
2070
+ for (i = 0; i < count; ++i) {
2071
+ int j, hcount, hval = 0;
2072
+ const int *hvec;
2073
+ Column hashes;
2074
+
2075
+ item = GetTypedItem(i, column, IT_view);
2076
+ hashes = HashValues(item.v);
2077
+ hvec = (const int*) hashes.seq->data[0].p;
2078
+ hcount = S_Count(hashes.seq);
2079
+
2080
+ for (j = 0; j < hcount; ++j)
2081
+ hval ^= hvec[j];
2082
+ /* TODO: release hashes right now */
2083
+
2084
+ data[i] = hval ^ hcount;
2085
+ }
2086
+ break;
2087
+
2088
+ default: Assert(0);
2089
+ }
2090
+
2091
+ return result;
2092
+ }
2093
+
2094
+ ItemTypes HashColCmd_SO (Item args[]) {
2095
+ ItemTypes type;
2096
+ Column column;
2097
+
2098
+ type = CharAsItemType(args[0].s[0]);
2099
+ column = CoerceColumn(type, args[1].o);
2100
+ if (column.seq == NULL)
2101
+ return IT_unknown;
2102
+
2103
+ args[0].c = HashCol(type, column);
2104
+ return IT_column;
2105
+ }
2106
+
2107
+ int RowHash (View_p view, int row) {
2108
+ int c, cols = ViewWidth(view), hash = 0;
2109
+ Item item;
2110
+
2111
+ for (c = 0; c < cols; ++c) {
2112
+ item.c = V_Cols(view)[c];
2113
+ switch (GetItem(row, &item)) {
2114
+
2115
+ case IT_int:
2116
+ hash ^= item.i;
2117
+ break;
2118
+
2119
+ case IT_string:
2120
+ hash ^= StringHash(item.s, INVALID_COUNT);
2121
+ break;
2122
+
2123
+ case IT_bytes:
2124
+ hash ^= StringHash((const char*) item.u.ptr, item.u.len);
2125
+ break;
2126
+
2127
+ default: {
2128
+ View_p rview = StepView(view, 1, row, 1, 1);
2129
+ Column rcol = HashValues(rview);
2130
+ hash = *(const int*) rcol.seq->data[0].p;
2131
+ break;
2132
+ }
2133
+ }
2134
+ }
2135
+
2136
+ return hash;
2137
+ }
2138
+
2139
+ static void XorWithIntCol (Column src, Column_p dest) {
2140
+ const int *srcdata = (const int*) src.seq->data[0].p;
2141
+ int i, count = S_Count(src.seq), *destdata = (int*) dest->seq->data[0].p;
2142
+
2143
+ for (i = 0; i < count; ++i)
2144
+ destdata[i] ^= srcdata[i];
2145
+ }
2146
+
2147
+ Column HashValues (View_p view) {
2148
+ int c, rows = ViewSize(view), cols = ViewWidth(view);
2149
+ Column result;
2150
+
2151
+ if (cols == 0 || rows == 0)
2152
+ return NewIntVec(rows, NULL);
2153
+
2154
+ result = HashCol(ViewColType(view, 0), V_Cols(view)[0]);
2155
+ for (c = 1; c < cols; ++c) {
2156
+ Column auxcol = HashCol(ViewColType(view, c), V_Cols(view)[c]);
2157
+ /* TODO: get rid of the separate xor step by xoring in HashCol */
2158
+ XorWithIntCol(auxcol, &result);
2159
+ }
2160
+ return result;
2161
+ }
2162
+
2163
+ static int HashFind (View_p keyview, int keyrow, int keyhash, HashInfo_p data) {
2164
+ int probe, datarow, mask, step;
2165
+
2166
+ mask = S_Count(data->veccol.seq) - 1;
2167
+ probe = ~keyhash & mask;
2168
+
2169
+ step = (keyhash ^ (keyhash >> 3)) & mask;
2170
+ if (step == 0)
2171
+ step = mask;
2172
+
2173
+ for (;;) {
2174
+ probe = (probe + step) & mask;
2175
+ if (data->hvec[probe] == 0)
2176
+ break;
2177
+
2178
+ datarow = data->map[data->hvec[probe]-1];
2179
+ if (keyhash == data->hashes[datarow] &&
2180
+ RowEqual(keyrow, keyview, datarow, data->view))
2181
+ return data->hvec[probe] - 1;
2182
+
2183
+ step <<= 1;
2184
+ if (step > mask)
2185
+ step ^= data->prime;
2186
+ }
2187
+
2188
+ if (keyview == data->view) {
2189
+ data->hvec[probe] = data->fill + 1;
2190
+ data->map[data->fill++] = keyrow;
2191
+ }
2192
+
2193
+ return -1;
2194
+ }
2195
+
2196
+ static int StringHashFind (const char *key, Sequence_p hseq, int prime, Column values) {
2197
+ int probe, datarow, mask, step, keyhash;
2198
+ const int *hvec = (const int*) hseq->data[0].p;
2199
+
2200
+ keyhash = StringHash(key, INVALID_COUNT);
2201
+ mask = S_Count(hseq) - 1;
2202
+ probe = ~keyhash & mask;
2203
+
2204
+ step = (keyhash ^ (keyhash >> 3)) & mask;
2205
+ if (step == 0)
2206
+ step = mask;
2207
+
2208
+ for (;;) {
2209
+ probe = (probe + step) & mask;
2210
+ datarow = hvec[probe] - 1;
2211
+ if (datarow < 0)
2212
+ break;
2213
+
2214
+ /* These string hashes are much simpler than the standard HashFind:
2215
+ no hashes vector, no indirect map, compute all hashes on-the-fly */
2216
+
2217
+ if (strcmp(key, GetTypedItem(datarow, values, IT_string).s) == 0)
2218
+ return datarow;
2219
+
2220
+ step <<= 1;
2221
+ if (step > mask)
2222
+ step ^= prime;
2223
+ }
2224
+
2225
+ return ~probe;
2226
+ }
2227
+
2228
+ static int Log2bits (int n) {
2229
+ int bits = 0;
2230
+ while ((1 << bits) < n)
2231
+ ++bits;
2232
+ return bits;
2233
+ }
2234
+
2235
+ static Column HashVector (int rows) {
2236
+ int bits = Log2bits((4 * rows) / 3);
2237
+ if (bits < 2)
2238
+ bits = 2;
2239
+ return NewIntVec(1 << bits, NULL);
2240
+ }
2241
+
2242
+ static void InitHashInfo (HashInfo_p info, View_p view, Column hmap, Column hvec, Column hashes) {
2243
+ int size = S_Count(hvec.seq);
2244
+
2245
+ static char slack [] = {
2246
+ 0, 0, 3, 3, 3, 5, 3, 3, 29, 17, 9, 5, 83, 27, 43, 3,
2247
+ 45, 9, 39, 39, 9, 5, 3, 33, 27, 9, 71, 39, 9, 5, 83, 0
2248
+ };
2249
+
2250
+ info->view = view;
2251
+ info->prime = size + slack[Log2bits(size-1)];
2252
+ info->fill = 0;
2253
+
2254
+ info->mapcol = hmap;
2255
+ info->map = (int*) hmap.seq->data[0].p;
2256
+
2257
+ info->veccol = hvec;
2258
+ info->hvec = (int*) hvec.seq->data[0].p;
2259
+
2260
+ info->hashcol = hashes;
2261
+ info->hashes = (int*) hashes.seq->data[0].p;
2262
+ }
2263
+
2264
+ int StringLookup (const char *key, Column values) {
2265
+ int h, r, rows, *hptr;
2266
+ const char *string;
2267
+ Column hvec;
2268
+ HashInfo info;
2269
+
2270
+ /* adjust data[2] and data[3], this assumes values is a string column */
2271
+
2272
+ if (values.seq->data[2].p == NULL) {
2273
+ rows = S_Count(values.seq);
2274
+ hvec = HashVector(rows);
2275
+ hptr = (int*) hvec.seq->data[0].p;
2276
+
2277
+ /* use InitHashInfo to get at the prime number, bit of a hack */
2278
+ InitHashInfo(&info, NULL, hvec, hvec, hvec);
2279
+
2280
+ for (r = 0; r < rows; ++r) {
2281
+ string = GetTypedItem(r, values, IT_string).s;
2282
+ h = StringHashFind(string, hvec.seq, info.prime, values);
2283
+ if (h < 0) /* silently ignore duplicates */
2284
+ hptr[~h] = r + 1;
2285
+ }
2286
+
2287
+ values.seq->data[2].p = IncRefCount(hvec.seq);
2288
+ values.seq->data[3].i = info.prime;
2289
+ }
2290
+
2291
+ h = StringHashFind(key, (Sequence_p) values.seq->data[2].p,
2292
+ values.seq->data[3].i, values);
2293
+ return h >= 0 ? h : -1;
2294
+ }
2295
+
2296
+ static void FillHashInfo (HashInfo_p info, View_p view) {
2297
+ int r, rows;
2298
+ Column mapcol;
2299
+
2300
+ rows = ViewSize(view);
2301
+ mapcol = NewIntVec(rows, NULL); /* worst-case, don't know #groups yet */
2302
+
2303
+ InitHashInfo(info, view, mapcol, HashVector(rows), HashValues(view));
2304
+
2305
+ for (r = 0; r < rows; ++r)
2306
+ HashFind(view, r, info->hashes[r], info);
2307
+
2308
+ /* TODO: reclaim unused entries at end of map */
2309
+ S_Count(mapcol.seq) = info->fill;
2310
+ }
2311
+
2312
+ static void ChaseLinks (HashInfo_p info, int count, const int *hmap, const int *lmap) {
2313
+ int groups = info->fill, *smap = info->hvec, *gmap = info->hashes;
2314
+
2315
+ while (--groups >= 0) {
2316
+ int head = hmap[groups] - 1;
2317
+ smap[groups] = count;
2318
+ while (head >= 0) {
2319
+ gmap[--count] = head;
2320
+ head = lmap[head];
2321
+ }
2322
+ }
2323
+ /* assert(count == 0); */
2324
+ }
2325
+
2326
+ void FillGroupInfo (HashInfo_p info, View_p view) {
2327
+ int g, r, rows, *hmap, *lmap;
2328
+ Column mapcol, headmap, linkmap;
2329
+
2330
+ rows = ViewSize(view);
2331
+ mapcol = NewIntVec(rows, NULL); /* worst-case, don't know #groups yet */
2332
+ headmap = NewIntVec(rows, &hmap); /* worst-case, don't know #groups yet */
2333
+ linkmap = NewIntVec(rows, &lmap);
2334
+
2335
+ InitHashInfo(info, view, mapcol, HashVector(rows), HashValues(view));
2336
+
2337
+ for (r = 0; r < rows; ++r) {
2338
+ g = HashFind(view, r, info->hashes[r], info);
2339
+ if (g < 0)
2340
+ g = info->fill - 1;
2341
+ lmap[r] = hmap[g] - 1;
2342
+ hmap[g] = r + 1;
2343
+ }
2344
+
2345
+ /* TODO: reclaim unused entries at end of map and hvec */
2346
+ S_Count(info->mapcol.seq) = S_Count(info->veccol.seq) = info->fill;
2347
+
2348
+ ChaseLinks(info, rows, hmap, lmap);
2349
+
2350
+ /* TODO: could release headmap and linkmap but that's a no-op here */
2351
+
2352
+ /* There's probably an opportunity to reduce space usage further,
2353
+ since the grouping map points to the starting row of each group:
2354
+ map[i] == gmap[smap[i]]
2355
+ Perhaps "map" (which starts out with #rows entries) can be re-used
2356
+ to append the gmap entries (if we can reduce it by #groups items).
2357
+ Or just release map[x] for grouping views, and use gmap[smap[x]].
2358
+ */
2359
+ }
2360
+
2361
+ void GroupInfo (View_p view, Column_p mcol, Column_p scol, Column_p gcol) {
2362
+ /* TODO: get rid of this silly wrapper (due to HashInfo being private) */
2363
+ HashInfo info;
2364
+ FillGroupInfo(&info, view);
2365
+ *mcol = info.mapcol;
2366
+ *scol = info.veccol;
2367
+ *gcol = info.hashcol;
2368
+ }
2369
+
2370
+ View_p GroupCol (View_p view, Column cols, const char *name) {
2371
+ View_p vkey, vres, gview;
2372
+ HashInfo info;
2373
+
2374
+ vkey = ColMapView(view, cols);
2375
+ vres = ColMapView(view, OmitColumn(cols, ViewWidth(view)));
2376
+
2377
+ FillGroupInfo(&info, vkey);
2378
+ gview = GroupedView(vres, info.veccol, info.hashcol, name);
2379
+ return PairView(RemapSubview(vkey, info.mapcol, 0, -1), gview);
2380
+ }
2381
+
2382
+ static void FillJoinInfo (HashInfo_p info, View_p left, View_p right) {
2383
+ int g, r, gleft, nleft, nright, nused = 0, *hmap, *lmap, *jmap;
2384
+ Column mapcol, headmap, linkmap, joincol;
2385
+
2386
+ nleft = ViewSize(left);
2387
+ mapcol = NewIntVec(nleft, NULL); /* worst-case, don't know #groups yet */
2388
+ joincol = NewIntVec(nleft, &jmap);
2389
+
2390
+ InitHashInfo(info, left, mapcol, HashVector(nleft), HashValues(left));
2391
+
2392
+ for (r = 0; r < nleft; ++r) {
2393
+ g = HashFind(left, r, info->hashes[r], info);
2394
+ if (g < 0)
2395
+ g = info->fill - 1;
2396
+ jmap[r] = g;
2397
+ }
2398
+
2399
+ /* TODO: reclaim unused entries at end of map */
2400
+ S_Count(mapcol.seq) = info->fill;
2401
+
2402
+ gleft = S_Count(info->mapcol.seq);
2403
+ nleft = S_Count(info->hashcol.seq);
2404
+ nright = ViewSize(right);
2405
+
2406
+ headmap = NewIntVec(gleft, &hmap); /* worst-case, don't know #groups yet */
2407
+ linkmap = NewIntVec(nright, &lmap);
2408
+
2409
+ for (r = 0; r < nright; ++r) {
2410
+ g = HashFind(right, r, RowHash(right, r), info);
2411
+ if (g >= 0) {
2412
+ lmap[r] = hmap[g] - 1;
2413
+ hmap[g] = r + 1;
2414
+ ++nused;
2415
+ }
2416
+ }
2417
+
2418
+ /* we're reusing veccol, but it might not be large enough to start with */
2419
+ /* TODO: reclaim unused entries at end of hvec */
2420
+ if (S_Count(info->veccol.seq) < nused)
2421
+ info->veccol = NewIntVec(nused, &info->hvec);
2422
+ else
2423
+ S_Count(info->veccol.seq) = nused;
2424
+
2425
+ /* reorder output to match results from FillHashInfo and FillGroupInfo */
2426
+ info->hashcol = info->veccol;
2427
+ info->hashes = info->hvec;
2428
+ info->veccol = info->mapcol;
2429
+ info->hvec = info->map;
2430
+ info->mapcol = joincol;
2431
+ info->map = jmap;
2432
+
2433
+ ChaseLinks(info, nused, hmap, lmap);
2434
+
2435
+ /* As with FillGroupInfo, this is most likely not quite optimal yet.
2436
+ All zero-length groups in smap (info->map, now info->hvec) could be
2437
+ coalesced into one, and joinmap indices into it adjusted down a bit.
2438
+ Would reduce the size of smap when there are lots of failed matches.
2439
+ Also: FillJoinInfo needs quite a lot of temp vector space right now.
2440
+ */
2441
+ }
2442
+
2443
+ View_p JoinView (View_p left, View_p right, const char *name) {
2444
+ View_p lnames, rnames, lkey, rkey, rres, gview;
2445
+ Column lmap, rmap;
2446
+ HashInfo info;
2447
+
2448
+ lnames = NameColView(left);
2449
+ rnames = NameColView(right);
2450
+ lmap = IntersectMap(rnames, lnames);
2451
+ rmap = IntersectMap(lnames, rnames);
2452
+
2453
+ lkey = ColMapView(left, lmap);
2454
+ rkey = ColMapView(right, rmap);
2455
+ rres = ColMapView(right, OmitColumn(rmap, ViewWidth(right)));
2456
+
2457
+ FillJoinInfo(&info, lkey, rkey);
2458
+ gview = GroupedView(rres, info.veccol, info.hashcol, name);
2459
+ return PairView(left, RemapSubview(gview, info.mapcol, 0, -1));
2460
+ }
2461
+
2462
+ Column UniqMap (View_p view) {
2463
+ HashInfo info;
2464
+ FillHashInfo(&info, view);
2465
+ return info.mapcol;
2466
+ }
2467
+
2468
+ Column IntersectMap (View_p keys, View_p view) {
2469
+ int r, rows, *output, fill = 0;
2470
+ HashInfo info;
2471
+ Column result;
2472
+
2473
+ FillHashInfo(&info, view);
2474
+
2475
+ rows = ViewSize(keys);
2476
+ result = NewIntVec(rows, &output);
2477
+
2478
+ for (r = 0; r < rows; ++r)
2479
+ if (HashFind(keys, r, RowHash(keys, r), &info) >= 0)
2480
+ output[fill++] = r;
2481
+
2482
+ /* TODO: reclaim unused entries at end of map */
2483
+ S_Count(result.seq) = fill;
2484
+ return result;
2485
+ }
2486
+
2487
+ int HashDoFind (View_p view, int row, View_p w, Column a, Column b, Column c) {
2488
+ HashInfo info;
2489
+ /* TODO: avoid Log2bits call in InitHashInfo, since it's done on each find */
2490
+ InitHashInfo(&info, w, a, b, c);
2491
+ return HashFind(view, row, RowHash(view, row), &info);
2492
+ }
2493
+
2494
+ Column GetHashInfo (View_p left, View_p right, int type) {
2495
+ HashInfo info;
2496
+ Sequence_p seqvec[3];
2497
+
2498
+ switch (type) {
2499
+ case 0: FillHashInfo(&info, left); break;
2500
+ case 1: FillGroupInfo(&info, left); break;
2501
+ default: FillJoinInfo(&info, left, right); break;
2502
+ }
2503
+
2504
+ seqvec[0] = info.mapcol.seq;
2505
+ seqvec[1] = info.veccol.seq;
2506
+ seqvec[2] = info.hashcol.seq;
2507
+
2508
+ return NewSequenceColumn(IT_column, seqvec, 3);
2509
+ }
2510
+
2511
+ View_p IjoinView (View_p left, View_p right) {
2512
+ View_p view = JoinView(left, right, "?");
2513
+ return UngroupView(view, ViewWidth(view)-1);
2514
+ }
2515
+ /* %include<indirect.c>% */
2516
+ /*
2517
+ * indirect.c - Implementation of some virtual views.
2518
+ */
2519
+
2520
+ #include <stdlib.h>
2521
+ #include <string.h>
2522
+
2523
+ /*
2524
+ * mutable.h - Definition of mutable views.
2525
+ */
2526
+
2527
+ View_p (ViewReplace) (View_p view, int row, int count, View_p data);
2528
+ View_p (ViewSet) (View_p view, int row, int col, Item_p value);
2529
+
2530
+ static void RemapCleaner (Sequence_p seq) {
2531
+ DecRefCount(seq->data[0].p);
2532
+ DecRefCount(seq->data[1].p);
2533
+ }
2534
+
2535
+ static ItemTypes RemapGetter (int row, Item_p item) {
2536
+ int start;
2537
+ const int* data;
2538
+ View_p parent;
2539
+
2540
+ parent = (View_p) item->c.seq->data[0].p;
2541
+ data = (const int*) ((Sequence_p) item->c.seq->data[1].p)->data[0].p;
2542
+ start = item->c.seq->data[2].i;
2543
+
2544
+ item->c = V_Cols(parent)[item->c.pos];
2545
+ row += start;
2546
+ if (data[row] < 0)
2547
+ row += data[row];
2548
+ return GetItem(data[row], item);
2549
+ }
2550
+
2551
+ View_p RemapSubview (View_p view, Column mapcol, int start, int count) {
2552
+ Sequence_p seq;
2553
+
2554
+ if (count < 0)
2555
+ count = S_Count(mapcol.seq);
2556
+
2557
+ if (ViewWidth(view) == 0)
2558
+ return NoColumnView(count);
2559
+
2560
+ seq = InitColumn(count, RemapGetter, 0).seq;
2561
+ seq->head.cleaner = (Cleaner) RemapCleaner;
2562
+ /* data[0] is the parent view to which the map applies */
2563
+ /* data[1] is the map, as a sequence */
2564
+ /* data[2] is the index offset */
2565
+ seq->data[0].p = IncRefCount(view);
2566
+ seq->data[1].p = IncRefCount(mapcol.seq);
2567
+ seq->data[2].i = start;
2568
+
2569
+ return IndirectView(V_Meta(view), seq);
2570
+ }
2571
+
2572
+ static View_p MakeMetaSubview (const char *name, View_p view) {
2573
+ View_p meta, result;
2574
+ Column namecol, typecol, subvcol;
2575
+
2576
+ namecol = NewStringColumn(1, strlen(name) + 1, 1);
2577
+ AppendToStringColumn(name, -1, &namecol);
2578
+
2579
+ typecol = NewStringColumn(1, 2, 1);
2580
+ AppendToStringColumn("V", -1, &typecol);
2581
+
2582
+ meta = V_Meta(view);
2583
+ subvcol = NewSequenceColumn(IT_view, &meta, 1);
2584
+
2585
+ result = NewView(V_Meta(meta));
2586
+ SetViewColumns(result, MC_name, 1, namecol);
2587
+ SetViewColumns(result, MC_type, 1, typecol);
2588
+ SetViewColumns(result, MC_subv, 1, subvcol);
2589
+ return result;
2590
+ }
2591
+
2592
+ static void GroupedCleaner (Sequence_p seq) {
2593
+ DecRefCount(seq->data[0].p);
2594
+ DecRefCount(seq->data[1].p);
2595
+ DecRefCount(seq->data[2].p);
2596
+ DecRefCount(seq->data[3].p);
2597
+ }
2598
+
2599
+ static ItemTypes GroupedGetter (int row, Item_p item) {
2600
+ View_p *subviews = ((Sequence_p) item->c.seq->data[3].p)->data[0].p;
2601
+
2602
+ if (subviews[row] == NULL) {
2603
+ int start;
2604
+ const int *sptr;
2605
+ View_p parent;
2606
+ Sequence_p gmap;
2607
+
2608
+ parent = item->c.seq->data[0].p;
2609
+ sptr = ((Sequence_p) item->c.seq->data[1].p)->data[0].p;
2610
+ gmap = item->c.seq->data[2].p;
2611
+
2612
+ start = row > 0 ? sptr[row-1] : 0;
2613
+ item->c.seq = gmap;
2614
+ subviews[row] = IncRefCount(RemapSubview(parent, item->c,
2615
+ start, sptr[row] - start));
2616
+ }
2617
+
2618
+ item->v = subviews[row];
2619
+ return IT_view;
2620
+ }
2621
+
2622
+ View_p GroupedView (View_p view, Column startcol, Column groupcol, const char *name) {
2623
+ int groups;
2624
+ Sequence_p seq;
2625
+ Column subviewcol;
2626
+
2627
+ groups = S_Count(startcol.seq);
2628
+ subviewcol = NewSequenceColumn(IT_view, NULL, groups);
2629
+
2630
+ seq = InitColumn(groups, GroupedGetter, 0).seq;
2631
+ seq->head.cleaner = (Cleaner) GroupedCleaner;
2632
+ /* data[0] is the parent view to which the grouping applies */
2633
+ /* data[1] is the start map, as a sequence */
2634
+ /* data[2] is the group map, as a sequence */
2635
+ /* data[3] is a cache of subviews, as a pointer vector in a sequence */
2636
+ seq->data[0].p = IncRefCount(view);
2637
+ seq->data[1].p = IncRefCount(startcol.seq);
2638
+ seq->data[2].p = IncRefCount(groupcol.seq);
2639
+ seq->data[3].p = IncRefCount(subviewcol.seq);
2640
+
2641
+ return IndirectView(MakeMetaSubview(name, view), seq);
2642
+ }
2643
+
2644
+ static void UnaryCleaner (Sequence_p seq) {
2645
+ DecRefCount(seq->data[0].p);
2646
+ }
2647
+
2648
+ static ItemTypes StepGetter (int row, Item_p item) {
2649
+ int rows, offs, rate, step;
2650
+ View_p parent;
2651
+ Sequence_p seq;
2652
+
2653
+ seq = item->c.seq;
2654
+ parent = (View_p) seq->data[0].p;
2655
+ offs = seq->data[1].i;
2656
+ rate = seq->data[2].i;
2657
+ step = seq->data[3].i;
2658
+ rows = ViewSize(parent);
2659
+
2660
+ item->c = V_Cols(parent)[item->c.pos];
2661
+ row = (offs + (row / rate) * step) % rows;
2662
+ if (row < 0)
2663
+ row += rows;
2664
+ return GetItem(row, item);
2665
+ }
2666
+
2667
+ View_p StepView (View_p view, int count, int offset, int rate, int step) {
2668
+ Sequence_p seq;
2669
+
2670
+ /* prevent division by zero if input view is empty */
2671
+ if (ViewSize(view) == 0)
2672
+ return view;
2673
+
2674
+ seq = InitColumn(count * rate, StepGetter, 0).seq;
2675
+ seq->head.cleaner = (Cleaner) UnaryCleaner;
2676
+ /* data[0] is the parent view to which the changes apply */
2677
+ /* data[1] is the starting offset */
2678
+ /* data[2] is the rate to repeat an item */
2679
+ /* data[3] is the step to the next item */
2680
+ seq->data[0].p = IncRefCount(view);
2681
+ seq->data[1].i = offset;
2682
+ seq->data[2].i = rate;
2683
+ seq->data[3].i = step;
2684
+
2685
+ return IndirectView(V_Meta(view), seq);
2686
+ }
2687
+
2688
+ static void BinaryCleaner (Sequence_p seq) {
2689
+ DecRefCount(seq->data[0].p);
2690
+ DecRefCount(seq->data[1].p);
2691
+ }
2692
+
2693
+ static ItemTypes ConcatGetter (int row, Item_p item) {
2694
+ int rows;
2695
+ View_p view;
2696
+
2697
+ view = (View_p) item->c.seq->data[0].p;
2698
+ rows = ViewSize(view);
2699
+ if (row >= rows) {
2700
+ row -= rows;
2701
+ view = (View_p) item->c.seq->data[1].p;
2702
+ }
2703
+
2704
+ item->c = V_Cols(view)[item->c.pos];
2705
+ return GetItem(row, item);
2706
+ }
2707
+
2708
+ View_p ConcatView (View_p view1, View_p view2) {
2709
+ int rows1, rows2;
2710
+ Sequence_p seq;
2711
+
2712
+ rows1 = ViewSize(view1);
2713
+ if (rows1 == 0)
2714
+ return view2;
2715
+
2716
+ rows2 = ViewSize(view2);
2717
+ if (rows2 == 0)
2718
+ return view1;
2719
+
2720
+ seq = InitColumn(rows1 + rows2, ConcatGetter, 0).seq;
2721
+ seq->head.cleaner = (Cleaner) BinaryCleaner;
2722
+ /* data[0] is the left-hand view */
2723
+ /* data[1] is the right-hand view */
2724
+ seq->data[0].p = IncRefCount(view1);
2725
+ seq->data[1].p = IncRefCount(view2);
2726
+
2727
+ return IndirectView(V_Meta(view1), seq);
2728
+ }
2729
+
2730
+ static void UngroupCleaner (Sequence_p seq) {
2731
+ DecRefCount(seq->data[0].p);
2732
+ DecRefCount(seq->data[1].p);
2733
+ }
2734
+
2735
+ static ItemTypes UngroupGetter (int row, Item_p item) {
2736
+ int col, subcol, subwidth, parentrow;
2737
+ const int *data;
2738
+ View_p view;
2739
+
2740
+ view = (View_p) item->c.seq->data[0].p;
2741
+ data = (const int*) ((Sequence_p) item->c.seq->data[1].p)->data[0].p;
2742
+ subcol = item->c.seq->data[2].i;
2743
+ subwidth = item->c.seq->data[3].i;
2744
+
2745
+ parentrow = data[row];
2746
+ if (parentrow < 0) {
2747
+ parentrow = data[row+parentrow];
2748
+ row = -data[row];
2749
+ } else
2750
+ row = 0;
2751
+
2752
+ col = item->c.pos;
2753
+
2754
+ if (subcol <= col && col < subcol + subwidth) {
2755
+ view = GetTypedItem(parentrow, ViewCol(view, subcol), IT_view).v;
2756
+ col -= subcol;
2757
+ } else {
2758
+ if (col >= subcol)
2759
+ col -= subwidth - 1;
2760
+ row = parentrow;
2761
+ }
2762
+
2763
+ item->c = ViewCol(view, col);
2764
+ return GetItem(row, item);
2765
+ }
2766
+
2767
+ View_p UngroupView (View_p view, int col) {
2768
+ int i, n, r, rows;
2769
+ Buffer buffer;
2770
+ View_p subview, meta, submeta, newmeta;
2771
+ Sequence_p seq;
2772
+ Column column, map;
2773
+
2774
+ InitBuffer(&buffer);
2775
+
2776
+ column = ViewCol(view, col);
2777
+ rows = S_Count(column.seq);
2778
+
2779
+ for (r = 0; r < rows; ++r) {
2780
+ subview = GetTypedItem(r, column, IT_view).v;
2781
+ n = ViewSize(subview);
2782
+ if (n > 0) {
2783
+ ADD_INT_TO_BUF(buffer, r);
2784
+ for (i = 1; i < n; ++i)
2785
+ ADD_INT_TO_BUF(buffer, -i);
2786
+ }
2787
+ }
2788
+
2789
+ map = BufferAsIntCol(&buffer);
2790
+
2791
+ /* result meta view replaces subview column with its actual meta view */
2792
+ meta = V_Meta(view);
2793
+ submeta = GetTypedItem(col, ViewCol(meta, MC_subv), IT_view).v;
2794
+ newmeta = ConcatView(FirstView(meta, col), submeta);
2795
+ newmeta = ConcatView(newmeta, LastView(meta, ViewSize(meta) - (col + 1)));
2796
+
2797
+ seq = InitColumn(S_Count(map.seq), UngroupGetter, 0).seq;
2798
+ seq->head.cleaner = (Cleaner) UngroupCleaner;
2799
+ /* data[0] is the parent view */
2800
+ /* data[1] is ungroup map as a sequence */
2801
+ /* data[2] is the subview column */
2802
+ /* data[3] is the subview width */
2803
+ seq->data[0].p = IncRefCount(view);
2804
+ seq->data[1].p = IncRefCount(map.seq);
2805
+ seq->data[2].i = col;
2806
+ seq->data[3].i = ViewSize(submeta);
2807
+
2808
+ return IndirectView(newmeta, seq);
2809
+ }
2810
+
2811
+ static void BlockedCleaner (Sequence_p seq) {
2812
+ DecRefCount(seq->data[0].p);
2813
+ DecRefCount(seq->data[1].p);
2814
+ }
2815
+
2816
+ static ItemTypes BlockedGetter (int row, Item_p item) {
2817
+ int block;
2818
+ const int* data;
2819
+ View_p parent, subv;
2820
+
2821
+ parent = (View_p) item->c.seq->data[0].p;
2822
+ data = (const int*) ((Sequence_p) item->c.seq->data[1].p)->data[0].p;
2823
+
2824
+ for (block = 0; block + data[block] < row; ++block)
2825
+ ;
2826
+
2827
+ if (row == block + data[block]) {
2828
+ row = block;
2829
+ block = ViewSize(parent) - 1;
2830
+ } else if (block > 0)
2831
+ row -= block + data[block-1];
2832
+
2833
+ subv = GetTypedItem(block, ViewCol(parent, 0), IT_view).v;
2834
+ item->c = ViewCol(subv, item->c.pos);
2835
+ return GetItem(row, item);
2836
+ }
2837
+
2838
+ View_p BlockedView (View_p view) {
2839
+ int r, rows, *limits, tally = 0;
2840
+ View_p submeta;
2841
+ Sequence_p seq;
2842
+ Column blocks, offsets;
2843
+
2844
+ /* view must have exactly one subview column */
2845
+ if (ViewWidth(view) != 1)
2846
+ return NULL;
2847
+
2848
+ blocks = ViewCol(view, 0);
2849
+ rows = ViewSize(view);
2850
+
2851
+ offsets = NewIntVec(rows, &limits);
2852
+ for (r = 0; r < rows; ++r) {
2853
+ tally += ViewSize(GetTypedItem(r, blocks, IT_view).v);
2854
+ limits[r] = tally;
2855
+ }
2856
+
2857
+ seq = InitColumn(tally, BlockedGetter, 0).seq;
2858
+ seq->head.cleaner = (Cleaner) BlockedCleaner;
2859
+ /* data[0] is the parent view */
2860
+ /* data[1] is a cumulative row count, as a sequence */
2861
+ seq->data[0].p = IncRefCount(view);
2862
+ seq->data[1].p = IncRefCount(offsets.seq);
2863
+
2864
+ submeta = GetTypedItem(0, ViewCol(V_Meta(view), MC_subv), IT_view).v;
2865
+ return IndirectView(submeta, seq);
2866
+ }
2867
+ /* %include<mutable.c>% */
2868
+ /*
2869
+ * mutable.c - Implementation of mutable views.
2870
+ */
2871
+
2872
+ #include <stdlib.h>
2873
+ #include <string.h>
2874
+
2875
+
2876
+ static void SettableCleaner (Sequence_p seq) {
2877
+ int r, rows;
2878
+ ItemTypes type;
2879
+
2880
+ type = seq->data[3].i;
2881
+ rows = S_Count(seq);
2882
+
2883
+ switch (type) {
2884
+
2885
+ case IT_string: {
2886
+ const char **p = (const char**) seq->data[0].p;
2887
+ for (r = 0; r < rows; ++r)
2888
+ if (p[r] != NULL)
2889
+ free((char*) p[r]);
2890
+ break;
2891
+ }
2892
+
2893
+ case IT_bytes: {
2894
+ const Item *p = (const Item*) seq->data[0].p;
2895
+ for (r = 0; r < rows; ++r)
2896
+ if (p[r].u.ptr != NULL)
2897
+ free((char*) p[r].u.ptr);
2898
+ break;
2899
+ }
2900
+
2901
+ case IT_view: {
2902
+ const View_p *p = (const View_p*) seq->data[0].p;
2903
+ for (r = 0; r < rows; ++r)
2904
+ if (p[r] != NULL)
2905
+ DecRefCount(p[r]);
2906
+ break;
2907
+ }
2908
+
2909
+ default: break;
2910
+ }
2911
+
2912
+ DecRefCount(seq->data[2].p);
2913
+ }
2914
+
2915
+ static ItemTypes SettableGetter (int row, Item_p item) {
2916
+ ItemTypes type;
2917
+ Sequence_p seq = item->c.seq;
2918
+ const uint8_t *bitmap = seq->data[1].p;
2919
+
2920
+ if (!BitTest(bitmap, row)) {
2921
+ View_p view = seq->data[2].p;
2922
+ item->c = ViewCol(view, item->c.pos);
2923
+ return GetItem(row, item);
2924
+ }
2925
+
2926
+ type = seq->data[3].i;
2927
+
2928
+ switch (type) {
2929
+
2930
+ case IT_int:
2931
+ item->i = ((const int*) seq->data[0].p)[row];
2932
+ break;
2933
+
2934
+ case IT_wide:
2935
+ item->w = ((const int64_t*) seq->data[0].p)[row];
2936
+ break;
2937
+
2938
+ case IT_float:
2939
+ item->f = ((const float*) seq->data[0].p)[row];
2940
+ break;
2941
+
2942
+ case IT_double:
2943
+ item->d = ((const double*) seq->data[0].p)[row];
2944
+ break;
2945
+
2946
+ case IT_string:
2947
+ item->s = ((const char**) seq->data[0].p)[row];
2948
+ break;
2949
+
2950
+ case IT_bytes:
2951
+ item->u = ((const Item*) seq->data[0].p)[row].u;
2952
+ break;
2953
+
2954
+ case IT_view:
2955
+ item->v = ((const View_p*) seq->data[0].p)[row];
2956
+ break;
2957
+
2958
+ default: type = IT_unknown;
2959
+ }
2960
+
2961
+ return type;
2962
+ }
2963
+
2964
+ static int SettableSetter (int row, Column column, Item_p item) {
2965
+ int replace;
2966
+ void *data = column.seq->data[0].p;
2967
+ uint8_t *bitmap = column.seq->data[1].p;
2968
+ ItemTypes type = column.seq->data[3].i;
2969
+
2970
+ replace = BitTest(bitmap, row);
2971
+ BitSet(bitmap, row);
2972
+
2973
+ switch (type) {
2974
+
2975
+ case IT_int:
2976
+ ((int*) data)[row] = item->i;
2977
+ break;
2978
+
2979
+ case IT_wide:
2980
+ ((int64_t*) data)[row] = item->w;
2981
+ break;
2982
+
2983
+ case IT_float:
2984
+ ((float*) data)[row] = item->f;
2985
+ break;
2986
+
2987
+ case IT_double:
2988
+ ((double*) data)[row] = item->d;
2989
+ break;
2990
+
2991
+ case IT_string: {
2992
+ char **p = (char**) data + row;
2993
+ if (replace)
2994
+ free(*p);
2995
+ *p = strdup(item->s);
2996
+ break;
2997
+ }
2998
+
2999
+ case IT_bytes: {
3000
+ Item *p = (Item*) data + row;
3001
+ int n = item->u.len;
3002
+ if (replace)
3003
+ free((char*) p->u.ptr);
3004
+ p->u.ptr = memcpy(malloc(n), item->u.ptr, n);
3005
+ p->u.len = n;
3006
+ break;
3007
+ }
3008
+
3009
+ case IT_view: {
3010
+ View_p *p = (View_p*) data + row;
3011
+ if (replace)
3012
+ DecRefCount(*p);
3013
+ *p = IncRefCount(item->v);
3014
+ break;
3015
+ }
3016
+
3017
+ default: type = IT_unknown;
3018
+ }
3019
+
3020
+ return replace;
3021
+ }
3022
+
3023
+ static Column NewSettableVec (View_p view, int col) {
3024
+ int rows, width = 0, real = 0;
3025
+ ItemTypes type;
3026
+ Column column, result;
3027
+
3028
+ rows = ViewSize(view);
3029
+ type = ViewColType(view, col);
3030
+ column = ViewCol(view, col);
3031
+
3032
+ switch (type) {
3033
+
3034
+ case IT_bytes: width = sizeof(Item);
3035
+ break;
3036
+
3037
+ case IT_string:
3038
+ case IT_view: width = sizeof(void*);
3039
+ break;
3040
+
3041
+ case IT_double: real = 1; /* fall through */
3042
+ case IT_wide: width = 8;
3043
+ break;
3044
+
3045
+ case IT_float: real = 1; /* fall through */
3046
+ case IT_int: width = 4;
3047
+ break;
3048
+
3049
+ default: Assert(0);
3050
+ }
3051
+
3052
+ result = InitColumn(rows, SettableGetter, rows * width + (rows + 7) / 8);
3053
+ result.seq->head.cleaner = (Cleaner) SettableCleaner;
3054
+
3055
+ /* data[0] points to the column data */
3056
+ /* data[1] points to the bitmap */
3057
+ /* data[2] is the original view */
3058
+ /* data[3] is the type of items in this column */
3059
+ result.seq->data[1].p = (char*) result.seq->data[0].p + rows * width;
3060
+ result.seq->data[2].p = IncRefCount(view);
3061
+ result.seq->data[3].i = type;
3062
+
3063
+ result.pos = col;
3064
+ return result;
3065
+ }
3066
+
3067
+ static View_p SettableView (View_p view) {
3068
+ int c, cols;
3069
+ View_p result;
3070
+
3071
+ cols = ViewWidth(view);
3072
+ result = NewView(V_Meta(view));
3073
+
3074
+ for (c = 0; c < cols; ++c)
3075
+ SetViewColumns(result, c, 1, NewSettableVec(view, c));
3076
+
3077
+ return result;
3078
+ }
3079
+
3080
+ static void MutableCleaner (Sequence_p seq) {
3081
+ DecRefCount(seq->data[1].p);
3082
+ DecRefCount(seq->data[2].p);
3083
+ DecRefCount(seq->data[3].p);
3084
+ }
3085
+
3086
+ static int ChooseMutView (Sequence_p mutseq, int *prow) {
3087
+ int index, limit, row = *prow;
3088
+ const int *perm;
3089
+ Sequence_p permseq;
3090
+
3091
+ permseq = mutseq->data[2].p;
3092
+ perm = permseq->data[0].p;
3093
+ limit = permseq->data[1].i;
3094
+
3095
+ index = perm[row];
3096
+
3097
+ if (0 <= index && index < limit)
3098
+ row = -1;
3099
+ else if (index < 0) {
3100
+ row = perm[row+index] - limit;
3101
+ index = -index;
3102
+ } else {
3103
+ row = index - limit;
3104
+ index = 0;
3105
+ }
3106
+
3107
+ *prow = row;
3108
+ return index;
3109
+ }
3110
+
3111
+ static ItemTypes MutableGetter (int row, Item_p item) {
3112
+ int index;
3113
+ View_p view;
3114
+
3115
+ index = ChooseMutView(item->c.seq, &row);
3116
+
3117
+ if (row >= 0) {
3118
+ Sequence_p mapseq = item->c.seq->data[3].p;
3119
+ view = ((const View_p*) mapseq->data[0].p)[row];
3120
+ } else
3121
+ view = (View_p) item->c.seq->data[1].p;
3122
+
3123
+ item->c = V_Cols(view)[item->c.pos];
3124
+ return GetItem(index, item);
3125
+ }
3126
+
3127
+ View_p MutableView (View_p view) {
3128
+ int r, rows, *perm;
3129
+ Sequence_p seq;
3130
+ Column permcol;
3131
+
3132
+ rows = ViewSize(view);
3133
+ seq = InitColumn(rows, MutableGetter, 0).seq;
3134
+ seq->head.cleaner = (Cleaner) MutableCleaner;
3135
+
3136
+ permcol = NewIntVec(rows, &perm);
3137
+ permcol.seq->data[1].i = rows;
3138
+
3139
+ /* data[0] tracks the number of insertions */
3140
+ /* data[1] is a settable version of the parent view */
3141
+ /* data[2] is the insert/delete permutation map, as a sequence */
3142
+ /* data[3] is a sequence column with all inserted views */
3143
+ seq->data[0].i = 0;
3144
+ seq->data[1].p = IncRefCount(SettableView(view));
3145
+ seq->data[2].p = IncRefCount(permcol.seq);
3146
+ seq->data[3].p = IncRefCount(NewSequenceColumn(IT_view, NULL, 0).seq);
3147
+
3148
+ for (r = 0; r < rows; ++r)
3149
+ perm[r] = r;
3150
+
3151
+ return IndirectView(V_Meta(view), seq);
3152
+ }
3153
+
3154
+ static int IsMutable(View_p view) {
3155
+ return view->head.cleaner == (Cleaner) MutableCleaner;
3156
+ }
3157
+
3158
+ View_p ViewSet (View_p view, int row, int col, Item_p item) {
3159
+ int index;
3160
+ Sequence_p mutseq;
3161
+ View_p setview;
3162
+
3163
+ if (!IsMutable(view))
3164
+ view = MutableView(view);
3165
+
3166
+ mutseq = ViewCol(view, 0).seq;
3167
+ index = ChooseMutView(mutseq, &row);
3168
+
3169
+ if (row >= 0) {
3170
+ Sequence_p insseq = mutseq->data[3].p;
3171
+ View_p *modvec = insseq->data[0].p;
3172
+ View_p oldview = modvec[row];
3173
+
3174
+ if (!IsMutable(oldview)) {
3175
+ modvec[row] = IncRefCount(MutableView(oldview));
3176
+ DecRefCount(oldview);
3177
+ }
3178
+
3179
+ mutseq = ViewCol(modvec[row], 0).seq;
3180
+ }
3181
+
3182
+ setview = mutseq->data[1].p;
3183
+ SettableSetter(index, ViewCol(setview, col), item);
3184
+
3185
+ return view;
3186
+ }
3187
+
3188
+ View_p ViewReplace (View_p view, int off, int count, View_p data) {
3189
+ int row, index, grow, rows, nrows, inscount, limit, *perm;
3190
+ Sequence_p mutseq, permseq;
3191
+
3192
+ inscount = ViewSize(data);
3193
+ if (inscount > 0 && !ViewCompat(view, data))
3194
+ return NULL;
3195
+
3196
+ if (!IsMutable(view))
3197
+ view = MutableView(view);
3198
+
3199
+ row = off;
3200
+ mutseq = ViewCol(view, 0).seq;
3201
+ if (row < S_Count(mutseq))
3202
+ index = ChooseMutView(mutseq, &row);
3203
+ else {
3204
+ index = row;
3205
+ row = -1;
3206
+ }
3207
+
3208
+ permseq = (Sequence_p) mutseq->data[2].p;
3209
+ perm = permseq->data[0].p;
3210
+ limit = permseq->data[1].i;
3211
+ rows = S_Count(permseq);
3212
+
3213
+ grow = inscount - count;
3214
+ nrows = rows + grow;
3215
+
3216
+ #if 0
3217
+ /* turn insertion before row 0 of a subview into insertion in main view */
3218
+ if (grow > 0 && row >= 0 && index == 0) {
3219
+ index = row;
3220
+ row = -1;
3221
+ }
3222
+
3223
+ if (row >= 0) {
3224
+ Sequence_p insseq = mutseq->data[3].p;
3225
+ View_p *modvec = insseq->data[0].p;
3226
+ View_p newview, oldview = modvec[row];
3227
+
3228
+ newview = ViewReplace(oldview, index, count, data);
3229
+
3230
+ modvec[row] = IncRefCount(newview);
3231
+ DecRefCount(oldview);
3232
+
3233
+ mutseq = ViewCol(newview, 0).seq;
3234
+ }
3235
+ #else
3236
+ /* with multiple replaces, bail out with an extra mutable layer for now */
3237
+ if (mutseq->data[0].i > 0)
3238
+ return ViewReplace(MutableView(view), off, count, data);
3239
+ #endif
3240
+
3241
+ if (grow != 0) {
3242
+ int *nperm;
3243
+ Column npermcol;
3244
+
3245
+ npermcol = NewIntVec(nrows, &nperm);
3246
+ npermcol.seq->data[1].i = limit;
3247
+
3248
+ memcpy(nperm, perm, off * sizeof(int));
3249
+
3250
+ if (grow > 0)
3251
+ memcpy(nperm + off + grow, perm + off, (rows - off) * sizeof(int));
3252
+ else
3253
+ memcpy(nperm + off, perm + off - grow, (nrows - off) * sizeof(int));
3254
+
3255
+ DecRefCount(permseq);
3256
+ mutseq->data[2].p = IncRefCount(npermcol.seq);
3257
+
3258
+ perm = nperm;
3259
+ }
3260
+
3261
+ if (inscount > 0) {
3262
+ int i, mods;
3263
+ Sequence_p modseq, *modptr, *nmodptr;
3264
+ Column nmodcol;
3265
+
3266
+ mods = mutseq->data[0].i;
3267
+ modseq = mutseq->data[3].p;
3268
+ modptr = modseq->data[0].p;
3269
+
3270
+ nmodcol = NewSequenceColumn(IT_view, NULL, ++mutseq->data[0].i);
3271
+ nmodptr = nmodcol.seq->data[0].p;
3272
+
3273
+ memcpy(nmodptr, modptr, mods * sizeof(View_p));
3274
+ memset(modptr, 0, mods * sizeof(View_p)); /* prevent decref's later */
3275
+ nmodptr[mods] = IncRefCount(data);
3276
+
3277
+ DecRefCount(modseq);
3278
+ mutseq->data[3].p = IncRefCount(nmodcol.seq);
3279
+
3280
+ perm[off] = limit + mods;
3281
+ for (i = 1; i < inscount; ++i)
3282
+ perm[off+i] = -i;
3283
+ }
3284
+
3285
+ S_Count(mutseq) = nrows;
3286
+ return view;
3287
+ }
3288
+
3289
+ ItemTypes SetCmd_VIX (Item args[]) {
3290
+ int i, col, row, objc;
3291
+ const Object_p *objv;
3292
+ View_p view;
3293
+ Item item;
3294
+
3295
+ view = args[0].v;
3296
+ row = args[1].i;
3297
+
3298
+ objv = (const void*) args[2].u.ptr;
3299
+ objc = args[2].u.len;
3300
+
3301
+ if (objc % 2 != 0) {
3302
+ args[0].e = EC_wnoa;
3303
+ return IT_error;
3304
+ }
3305
+
3306
+ for (i = 0; i < objc; i += 2) {
3307
+ col = ColumnByName(V_Meta(view), objv[i]);
3308
+ if (col < 0)
3309
+ return IT_unknown;
3310
+
3311
+ item.o = objv[i+1];
3312
+ if (!CastObjToItem(GetColType(V_Meta(view), col), &item))
3313
+ return IT_unknown;
3314
+
3315
+ view = ViewSet(view, row, col, &item);
3316
+ }
3317
+
3318
+ args[0].v = view;
3319
+ return IT_view;
3320
+ }
3321
+ /* %include<sorted.c>% */
3322
+ /*
3323
+ * sorted.c - Implementation of sorting functions.
3324
+ */
3325
+
3326
+ #include <stdlib.h>
3327
+ #include <string.h>
3328
+
3329
+
3330
+ static int ItemsEqual (ItemTypes type, Item a, Item b) {
3331
+ switch (type) {
3332
+
3333
+ case IT_int:
3334
+ return a.i == b.i;
3335
+
3336
+ case IT_wide:
3337
+ return a.w == b.w;
3338
+
3339
+ case IT_float:
3340
+ return a.f == b.f;
3341
+
3342
+ case IT_double:
3343
+ return a.d == b.d;
3344
+
3345
+ case IT_string:
3346
+ return strcmp(a.s, b.s) == 0;
3347
+
3348
+ case IT_bytes:
3349
+ return a.u.len == b.u.len && memcmp(a.u.ptr, b.u.ptr, a.u.len) == 0;
3350
+
3351
+ case IT_view:
3352
+ return ViewCompare(a.v, b.v) == 0;
3353
+
3354
+ default: Assert(0); return -1;
3355
+ }
3356
+ }
3357
+
3358
+ int RowEqual (int r1, View_p v1, int r2, View_p v2) {
3359
+ int c, cols = ViewWidth(v1);
3360
+ ItemTypes type;
3361
+ Item item1, item2;
3362
+
3363
+ for (c = 0; c < cols; ++c) {
3364
+ type = ViewColType(v1, c);
3365
+ item1 = GetTypedItem(r1, V_Cols(v1)[c], type);
3366
+ item2 = GetTypedItem(r2, V_Cols(v2)[c], type);
3367
+
3368
+ if (!ItemsEqual(type, item1, item2))
3369
+ return 0;
3370
+ }
3371
+
3372
+ return 1;
3373
+ }
3374
+
3375
+ /* TODO: UTF-8 comparisons, also case-sensitive & insensitive */
3376
+
3377
+ static int ItemsCompare (ItemTypes type, Item a, Item b, int lower) {
3378
+ switch (type) {
3379
+
3380
+ case IT_int:
3381
+ return (a.i > b.i) - (a.i < b.i);
3382
+
3383
+ case IT_wide:
3384
+ return (a.w > b.w) - (a.w < b.w);
3385
+
3386
+ case IT_float:
3387
+ return (a.f > b.f) - (a.f < b.f);
3388
+
3389
+ case IT_double:
3390
+ return (a.d > b.d) - (a.d < b.d);
3391
+
3392
+ case IT_string:
3393
+ return (lower ? strcasecmp : strcmp)(a.s, b.s);
3394
+
3395
+ case IT_bytes: {
3396
+ int f;
3397
+
3398
+ if (a.u.len == b.u.len)
3399
+ return memcmp(a.u.ptr, b.u.ptr, a.u.len);
3400
+
3401
+ f = memcmp(a.u.ptr, b.u.ptr, a.u.len < b.u.len ? a.u.len : b.u.len);
3402
+ return f != 0 ? f : a.u.len - b.u.len;
3403
+ }
3404
+
3405
+ case IT_view:
3406
+ return ViewCompare(a.v, b.v);
3407
+
3408
+ default: Assert(0); return -1;
3409
+ }
3410
+ }
3411
+
3412
+ int RowCompare (int r1, View_p v1, int r2, View_p v2) {
3413
+ int c, f, cols = ViewWidth(v1);
3414
+ ItemTypes type;
3415
+ Item item1, item2;
3416
+
3417
+ for (c = 0; c < cols; ++c) {
3418
+ type = ViewColType(v1, c);
3419
+ item1 = GetTypedItem(r1, V_Cols(v1)[c], type);
3420
+ item2 = GetTypedItem(r2, V_Cols(v2)[c], type);
3421
+
3422
+ f = ItemsCompare(type, item1, item2, 0);
3423
+ if (f != 0)
3424
+ return f;
3425
+ }
3426
+
3427
+ return 0;
3428
+ }
3429
+
3430
+ static int RowIsLess (View_p v, int a, int b) {
3431
+ int c, cols, f;
3432
+ ItemTypes type;
3433
+ Item va, vb;
3434
+
3435
+ if (a != b) {
3436
+ cols = ViewWidth(v);
3437
+ for (c = 0; c < cols; ++c) {
3438
+ type = ViewColType(v, c);
3439
+ va = GetTypedItem(a, V_Cols(v)[c], type);
3440
+ vb = GetTypedItem(b, V_Cols(v)[c], type);
3441
+
3442
+ f = ItemsCompare(type, va, vb, 0);
3443
+ if (f != 0)
3444
+ return f < 0;
3445
+ }
3446
+ }
3447
+
3448
+ return a < b;
3449
+ }
3450
+
3451
+ static int TestAndSwap (View_p v, int *a, int *b) {
3452
+ if (RowIsLess(v, *b, *a)) {
3453
+ int t = *a;
3454
+ *a = *b;
3455
+ *b = t;
3456
+ return 1;
3457
+ }
3458
+ return 0;
3459
+ }
3460
+
3461
+ static void MergeSort (View_p v, int *ar, int nr, int *scr) {
3462
+ switch (nr) {
3463
+ case 2:
3464
+ TestAndSwap(v, ar, ar+1);
3465
+ break;
3466
+ case 3:
3467
+ TestAndSwap(v, ar, ar+1);
3468
+ if (TestAndSwap(v, ar+1, ar+2))
3469
+ TestAndSwap(v, ar, ar+1);
3470
+ break;
3471
+ case 4: /* TODO: optimize with if's */
3472
+ TestAndSwap(v, ar, ar+1);
3473
+ TestAndSwap(v, ar+2, ar+3);
3474
+ TestAndSwap(v, ar, ar+2);
3475
+ TestAndSwap(v, ar+1, ar+3);
3476
+ TestAndSwap(v, ar+1, ar+2);
3477
+ break;
3478
+ /* TODO: also special-case 5-item sort? */
3479
+ default: {
3480
+ int s1 = nr / 2, s2 = nr - s1;
3481
+ int *f1 = scr, *f2 = scr + s1, *t1 = f1 + s1, *t2 = f2 + s2;
3482
+ MergeSort(v, f1, s1, ar);
3483
+ MergeSort(v, f2, s2, ar+s1);
3484
+ for (;;)
3485
+ if (RowIsLess(v, *f1, *f2)) {
3486
+ *ar++ = *f1++;
3487
+ if (f1 >= t1) {
3488
+ while (f2 < t2)
3489
+ *ar++ = *f2++;
3490
+ break;
3491
+ }
3492
+ } else {
3493
+ *ar++ = *f2++;
3494
+ if (f2 >= t2) {
3495
+ while (f1 < t1)
3496
+ *ar++ = *f1++;
3497
+ break;
3498
+ }
3499
+ }
3500
+ }
3501
+ }
3502
+ }
3503
+
3504
+ Column SortMap (View_p view) {
3505
+ int r, rows, *imap, *itmp;
3506
+ Column result;
3507
+
3508
+ rows = ViewSize(view);
3509
+
3510
+ if (rows <= 1 || ViewWidth(view) == 0)
3511
+ return NewIotaColumn(rows);
3512
+
3513
+ result = NewIntVec(rows, &imap);
3514
+ NewIntVec(rows, &itmp);
3515
+
3516
+ for (r = 0; r < rows; ++r)
3517
+ imap[r] = itmp[r] = r;
3518
+
3519
+ MergeSort(view, imap, rows, itmp);
3520
+
3521
+ return result;
3522
+ }
3523
+
3524
+ static ItemTypes AggregateMax (ItemTypes type, Column column, Item_p item) {
3525
+ int r, rows;
3526
+ Item temp;
3527
+
3528
+ rows = S_Count(column.seq);
3529
+ if (rows == 0) {
3530
+ item->e = EC_nalor;
3531
+ return IT_error;
3532
+ }
3533
+
3534
+ *item = GetTypedItem(0, column, type);
3535
+ for (r = 1; r < rows; ++r) {
3536
+ temp = GetTypedItem(r, column, type);
3537
+ if (ItemsCompare (type, temp, *item, 0) > 0)
3538
+ *item = temp;
3539
+ }
3540
+
3541
+ return type;
3542
+ }
3543
+
3544
+ ItemTypes MaxCmd_VN (Item args[]) {
3545
+ Column column = ViewCol(args[0].v, args[1].i);
3546
+ return AggregateMax(ViewColType(args[0].v, args[1].i), column, args);
3547
+ }
3548
+
3549
+ static ItemTypes AggregateMin (ItemTypes type, Column column, Item_p item) {
3550
+ int r, rows;
3551
+ Item temp;
3552
+
3553
+ rows = S_Count(column.seq);
3554
+ if (rows == 0) {
3555
+ item->e = EC_nalor;
3556
+ return IT_error;
3557
+ }
3558
+
3559
+ *item = GetTypedItem(0, column, type);
3560
+ for (r = 1; r < rows; ++r) {
3561
+ temp = GetTypedItem(r, column, type);
3562
+ if (ItemsCompare (type, temp, *item, 0) < 0)
3563
+ *item = temp;
3564
+ }
3565
+
3566
+ return type;
3567
+ }
3568
+
3569
+ ItemTypes MinCmd_VN (Item args[]) {
3570
+ Column column = ViewCol(args[0].v, args[1].i);
3571
+ return AggregateMin(ViewColType(args[0].v, args[1].i), column, args);
3572
+ }
3573
+
3574
+ static ItemTypes AggregateSum (ItemTypes type, Column column, Item_p item) {
3575
+ int r, rows = S_Count(column.seq);
3576
+
3577
+ switch (type) {
3578
+
3579
+ case IT_int:
3580
+ item->w = 0;
3581
+ for (r = 0; r < rows; ++r)
3582
+ item->w += GetTypedItem(r, column, IT_int).i;
3583
+ return IT_wide;
3584
+
3585
+ case IT_wide:
3586
+ item->w = 0;
3587
+ for (r = 0; r < rows; ++r)
3588
+ item->w += GetTypedItem(r, column, IT_wide).w;
3589
+ return IT_wide;
3590
+
3591
+ case IT_float:
3592
+ item->d = 0;
3593
+ for (r = 0; r < rows; ++r)
3594
+ item->d += GetTypedItem(r, column, IT_float).f;
3595
+ return IT_double;
3596
+
3597
+ case IT_double:
3598
+ item->d = 0;
3599
+ for (r = 0; r < rows; ++r)
3600
+ item->d += GetTypedItem(r, column, IT_double).d;
3601
+ return IT_double;
3602
+
3603
+ default:
3604
+ return IT_unknown;
3605
+ }
3606
+ }
3607
+
3608
+ ItemTypes SumCmd_VN (Item args[]) {
3609
+ Column column = ViewCol(args[0].v, args[1].i);
3610
+ return AggregateSum(ViewColType(args[0].v, args[1].i), column, &args[0]);
3611
+ }
3612
+ /* %include<view.c>% */
3613
+ /*
3614
+ * view.c - Implementation of views.
3615
+ */
3616
+
3617
+ #include <stdlib.h>
3618
+ #include <string.h>
3619
+
3620
+
3621
+ int ViewSize (View_p view) {
3622
+ Sequence_p seq = V_Cols(view)[0].seq;
3623
+ return seq != NULL ? S_Count(seq) : 0;
3624
+ }
3625
+
3626
+ char GetColType (View_p meta, int col) {
3627
+ /* TODO: could be a #define */
3628
+ return *GetTypedItem(col, V_Cols(meta)[MC_type], IT_string).s;
3629
+ }
3630
+
3631
+ static View_p ForceMetaView(View_p meta) {
3632
+ View_p newmeta;
3633
+ Column orignames, names;
3634
+
3635
+ /* this code is needed so we can always do a hash lookup on the name column */
3636
+
3637
+ orignames = ViewCol(meta, MC_name);
3638
+ names = ForceStringColumn(orignames);
3639
+
3640
+ if (names.seq == orignames.seq)
3641
+ return meta;
3642
+
3643
+ /* need to construct a new meta view with the adjusted names column */
3644
+ newmeta = NewView(V_Meta(meta));
3645
+
3646
+ SetViewColumns(newmeta, MC_name, 1, names);
3647
+ SetViewColumns(newmeta, MC_type, 1, ViewCol(meta, MC_type));
3648
+ SetViewColumns(newmeta, MC_subv, 1, ViewCol(meta, MC_subv));
3649
+
3650
+ return newmeta;
3651
+ }
3652
+
3653
+ static void ViewCleaner (View_p view) {
3654
+ int c, cols = ViewWidth(view) + 1;
3655
+ for (c = 0; c < cols; ++c)
3656
+ DecRefCount(V_Cols(view)[c].seq);
3657
+ DecRefCount(V_Meta(view));
3658
+ }
3659
+
3660
+ static ItemTypes ViewGetter (int row, Item_p item) {
3661
+ item->c = V_Cols(item->c.seq)[row];
3662
+ return IT_column;
3663
+ }
3664
+
3665
+ View_p NewView (View_p meta) {
3666
+ int c, cols, bytes;
3667
+ View_p view;
3668
+
3669
+ /* a view must always be able to store at least one column */
3670
+ cols = ViewSize(meta);
3671
+ bytes = (cols + 1) * (sizeof(Column) + 1);
3672
+
3673
+ view = InitColumn(cols, ViewGetter, bytes).seq;
3674
+ view->head.cleaner = (Cleaner) ViewCleaner;
3675
+
3676
+ /* data[0] points to the types string (allocated inline after the columns) */
3677
+ /* data[1] is the meta view */
3678
+ V_Types(view) = (char*) (V_Cols(view) + cols + 1);
3679
+ V_Meta(view) = IncRefCount(ForceMetaView(meta));
3680
+
3681
+ /* TODO: could optimize by storing the types with the meta view instead */
3682
+ for (c = 0; c < cols; ++c)
3683
+ V_Types(view)[c] = CharAsItemType(GetColType(meta, c));
3684
+
3685
+ return view;
3686
+ }
3687
+
3688
+ void SetViewColumns (View_p view, int first, int count, Column src) {
3689
+ int c;
3690
+
3691
+ AdjustSeqRefs(src.seq, count);
3692
+ for (c = first; c < first + count; ++c) {
3693
+ DecRefCount(V_Cols(view)[c].seq);
3694
+ V_Cols(view)[c] = src;
3695
+ }
3696
+ }
3697
+
3698
+ View_p IndirectView (View_p meta, Sequence_p seq) {
3699
+ int c, cols;
3700
+ View_p result;
3701
+ Column column;
3702
+
3703
+ cols = ViewSize(meta);
3704
+ column.seq = seq;
3705
+ column.pos = INVALID_COUNT; /* adjusted below */
3706
+
3707
+ result = NewView(meta);
3708
+ SetViewColumns(result, 0, cols, column);
3709
+
3710
+ for (c = 0; c < cols; ++c)
3711
+ V_Cols(result)[c].pos = c;
3712
+
3713
+ return result;
3714
+ }
3715
+
3716
+ View_p EmptyMetaView () {
3717
+ int bytes;
3718
+ View_p meta, subs [MC_limit];
3719
+ Column tempcol;
3720
+ Shared_p sh = GetShared();
3721
+
3722
+ if (sh->empty != NULL)
3723
+ return sh->empty;
3724
+
3725
+ /* meta is recursively defined, so we can't use NewView here */
3726
+ bytes = (MC_limit + 1) * (sizeof(Column) + 1);
3727
+ meta = InitColumn(MC_limit, ViewGetter, bytes).seq;
3728
+ meta->head.cleaner = (Cleaner) ViewCleaner;
3729
+ V_Meta(meta) = IncRefCount(meta); /* circular */
3730
+
3731
+ V_Types(meta) = (char*) (V_Cols(meta) + MC_limit + 1);
3732
+ V_Types(meta)[0] = V_Types(meta)[1] = IT_string;
3733
+ V_Types(meta)[2] = IT_view;
3734
+
3735
+ /* initialize all but last columns of meta with static pointer contents */
3736
+ tempcol = NewStringColumn(MC_limit, MC_limit * 5, 1);
3737
+ AppendToStringColumn("name", -1, &tempcol);
3738
+ AppendToStringColumn("type", -1, &tempcol);
3739
+ AppendToStringColumn("subv", -1, &tempcol);
3740
+ SetViewColumns(meta, MC_name, 1, tempcol);
3741
+
3742
+ tempcol = NewStringColumn(MC_limit, MC_limit * 2, 1);
3743
+ AppendToStringColumn("S", -1, &tempcol);
3744
+ AppendToStringColumn("S", -1, &tempcol);
3745
+ AppendToStringColumn("V", -1, &tempcol);
3746
+ SetViewColumns(meta, MC_type, 1, tempcol);
3747
+
3748
+ /* same structure as meta but no rows */
3749
+ sh->empty = NewView(meta);
3750
+
3751
+ /* initialize last column of meta, now that empty exists */
3752
+ subs[MC_name] = subs[MC_type] = subs[MC_subv] = sh->empty;
3753
+ SetViewColumns(meta, MC_subv, 1, NewSequenceColumn(IT_view, subs, MC_limit));
3754
+
3755
+ return sh->empty;
3756
+ }
3757
+
3758
+ View_p NoColumnView (rows) {
3759
+ View_p result = NewView(EmptyMetaView());
3760
+ SetViewColumns(result, 0, 1, InitColumn(rows, NULL, 0));
3761
+ return result;
3762
+ }
3763
+
3764
+ View_p ColMapView (View_p view, Column mapcol) {
3765
+ int c, cols;
3766
+ const int *map;
3767
+ View_p result;
3768
+
3769
+ map = (const int*) mapcol.seq->data[0].p;
3770
+ cols = S_Count(mapcol.seq);
3771
+
3772
+ if (cols == 0)
3773
+ return NoColumnView(ViewSize(view));
3774
+
3775
+ result = NewView(RemapSubview(V_Meta(view), mapcol, 0, cols));
3776
+
3777
+ for (c = 0; c < cols; ++c)
3778
+ SetViewColumns(result, c, 1, V_Cols(view)[map[c]]);
3779
+
3780
+ return result;
3781
+ }
3782
+
3783
+ View_p ColOmitView (View_p view, Column omitcol) {
3784
+ int c, d, *map;
3785
+ Column mapcol;
3786
+
3787
+ mapcol = NewIntVec(ViewWidth(view), &map);
3788
+
3789
+ /* TODO: make this robust, may have to add bounds check */
3790
+ for (c = 0; c < S_Count(omitcol.seq); ++c)
3791
+ map[GetTypedItem(c, omitcol, IT_int).i] = 1;
3792
+
3793
+ for (c = d = 0; c < S_Count(mapcol.seq); ++c)
3794
+ if (!map[c])
3795
+ map[d++] = c;
3796
+
3797
+ S_Count(mapcol.seq) = d; /* TODO: truncate unused area */
3798
+ return ColMapView(view, mapcol);
3799
+ }
3800
+
3801
+ View_p NameColView (View_p view) {
3802
+ View_p meta, result;
3803
+
3804
+ meta = V_Meta(view);
3805
+ result = NewView(FirstView(V_Meta(meta), 1));
3806
+ SetViewColumns(result, 0, 1, V_Cols(meta)[0]);
3807
+
3808
+ return result;
3809
+ }
3810
+
3811
+ View_p FirstView (View_p view, int count) {
3812
+ if (count >= ViewSize(view))
3813
+ return view;
3814
+ return StepView(view, count, 0, 1, 1);
3815
+ }
3816
+
3817
+ View_p LastView (View_p view, int count) {
3818
+ int rows = ViewSize(view);
3819
+ if (count >= rows)
3820
+ return view;
3821
+ return StepView(view, count, rows - count, 1, 1);
3822
+ }
3823
+
3824
+ View_p TakeView (View_p view, int count) {
3825
+ if (count >= 0)
3826
+ return StepView(view, count, 0, 1, 1);
3827
+ else
3828
+ return StepView(view, -count, -1, 1, -1);
3829
+ }
3830
+
3831
+ View_p CloneView (View_p view) {
3832
+ return NewView(V_Meta(view));
3833
+ }
3834
+
3835
+ View_p PairView (View_p view1, View_p view2) {
3836
+ int c, cols1, cols2;
3837
+ View_p meta, result;
3838
+
3839
+ cols1 = ViewWidth(view1);
3840
+ if (cols1 == 0)
3841
+ return view2;
3842
+
3843
+ cols2 = ViewWidth(view2);
3844
+ if (cols2 == 0)
3845
+ return view1;
3846
+
3847
+ meta = ConcatView(V_Meta(view1), V_Meta(view2));
3848
+ result = NewView(meta);
3849
+
3850
+ for (c = 0; c < cols1; ++c)
3851
+ SetViewColumns(result, c, 1, V_Cols(view1)[c]);
3852
+ for (c = 0; c < cols2; ++c)
3853
+ SetViewColumns(result, cols1 + c, 1, V_Cols(view2)[c]);
3854
+
3855
+ return result;
3856
+ }
3857
+
3858
+ void ViewStructure (View_p meta, Buffer_p buffer) {
3859
+ int c, cols = ViewSize(meta);
3860
+
3861
+ for (c = 0; c < cols; ++c) {
3862
+ char type = GetColType(meta, c);
3863
+
3864
+ if (type == 'V') {
3865
+ View_p submeta = GetTypedItem(c, V_Cols(meta)[MC_subv], IT_view).v;
3866
+
3867
+ if (ViewSize(submeta) > 0) {
3868
+ ADD_CHAR_TO_BUF(*buffer, '(');
3869
+ ViewStructure(submeta, buffer);
3870
+ ADD_CHAR_TO_BUF(*buffer, ')');
3871
+ continue;
3872
+ }
3873
+ }
3874
+ ADD_CHAR_TO_BUF(*buffer, type);
3875
+ }
3876
+ }
3877
+
3878
+ int MetaIsCompatible (View_p meta1, View_p meta2) {
3879
+ if (meta1 != meta2) {
3880
+ int c, cols = ViewSize(meta1);
3881
+
3882
+ if (cols != ViewSize(meta2))
3883
+ return 0;
3884
+
3885
+ for (c = 0; c < cols; ++c) {
3886
+ char type = GetColType(meta1, c);
3887
+
3888
+ if (type != GetColType(meta2, c))
3889
+ return 0;
3890
+
3891
+ if (type == 'V') {
3892
+ View_p v1 = GetTypedItem(c, V_Cols(meta1)[MC_subv], IT_view).v;
3893
+ View_p v2 = GetTypedItem(c, V_Cols(meta2)[MC_subv], IT_view).v;
3894
+
3895
+ if (!MetaIsCompatible(v1, v2))
3896
+ return 0;
3897
+ }
3898
+ }
3899
+ }
3900
+
3901
+ return 1;
3902
+ }
3903
+
3904
+ int ViewCompare (View_p view1, View_p view2) {
3905
+ int f, r, rows1, rows2;
3906
+
3907
+ if (view1 == view2)
3908
+ return 0;
3909
+
3910
+ f = ViewCompare(V_Meta(view1), V_Meta(view2));
3911
+ if (f != 0)
3912
+ return f;
3913
+
3914
+ rows1 = ViewSize(view1);
3915
+ rows2 = ViewSize(view2);
3916
+
3917
+ for (r = 0; r < rows1; ++r) {
3918
+ if (r >= rows2)
3919
+ return 1;
3920
+
3921
+ f = RowCompare(r, view1, r, view2);
3922
+ if (f != 0)
3923
+ return f < 0 ? -1 : 1;
3924
+ }
3925
+
3926
+ return rows1 < rows2 ? -1 : 0;
3927
+ }
3928
+
3929
+ static View_p MakeIotaMeta (const char *name) {
3930
+ View_p result, subv;
3931
+ Column namecol, typecol, subvcol;
3932
+
3933
+ namecol = NewStringColumn(1, strlen(name) + 1, 1);
3934
+ AppendToStringColumn(name, -1, &namecol);
3935
+
3936
+ typecol = NewStringColumn(1, 2, 1);
3937
+ AppendToStringColumn("I", -1, &typecol);
3938
+
3939
+ subv = EmptyMetaView();
3940
+ subvcol = NewSequenceColumn(IT_view, &subv, 1);
3941
+
3942
+ result = NewView(V_Meta(EmptyMetaView()));
3943
+ SetViewColumns(result, MC_name, 1, namecol);
3944
+ SetViewColumns(result, MC_type, 1, typecol);
3945
+ SetViewColumns(result, MC_subv, 1, subvcol);
3946
+ return result;
3947
+ }
3948
+
3949
+ View_p TagView (View_p view, const char* name) {
3950
+ View_p tagview;
3951
+
3952
+ tagview = NewView(MakeIotaMeta(name));
3953
+ SetViewColumns(tagview, 0, 1, NewIotaColumn(ViewSize(view)));
3954
+
3955
+ return PairView(view, tagview);
3956
+ }
3957
+
3958
+ Column ViewAsCol (View_p view) {
3959
+ Column result;
3960
+ result.seq = view;
3961
+ result.pos = -1;
3962
+ return result;
3963
+ }
3964
+
3965
+ View_p DescAsMeta (const char** desc, const char* end) {
3966
+ int c, len, cols = 0, namebytes = 0;
3967
+ char sep, *buf, *ptr, **strings;
3968
+ Sequence_p *views;
3969
+ Buffer names, types, subvs;
3970
+ Column tempcol;
3971
+ View_p result, empty;
3972
+
3973
+ InitBuffer(&names);
3974
+ InitBuffer(&types);
3975
+ InitBuffer(&subvs);
3976
+
3977
+ len = end - *desc;
3978
+ buf = memcpy(malloc(len+1), *desc, len);
3979
+ buf[len] = ',';
3980
+
3981
+ empty = EmptyMetaView();
3982
+ result = NewView(V_Meta(empty));
3983
+
3984
+ for (ptr = buf; ptr < buf + len; ++ptr) {
3985
+ const char *s = ptr;
3986
+ while (strchr(":,[]", *ptr) == 0)
3987
+ ++ptr;
3988
+ sep = *ptr;
3989
+ *ptr = 0;
3990
+
3991
+ ADD_PTR_TO_BUF(names, s);
3992
+ namebytes += ptr - s + 1;
3993
+
3994
+ switch (sep) {
3995
+
3996
+ case '[':
3997
+ ADD_PTR_TO_BUF(types, "V");
3998
+ ++ptr;
3999
+ ADD_PTR_TO_BUF(subvs, DescAsMeta((const char**) &ptr, buf + len));
4000
+ sep = *++ptr;
4001
+ break;
4002
+
4003
+ case ':':
4004
+ ptr += 2;
4005
+ sep = *ptr;
4006
+ *ptr = 0;
4007
+ ADD_PTR_TO_BUF(types, ptr - 1);
4008
+ ADD_PTR_TO_BUF(subvs, empty);
4009
+ break;
4010
+
4011
+ default:
4012
+ ADD_PTR_TO_BUF(types, "S");
4013
+ ADD_PTR_TO_BUF(subvs, empty);
4014
+ break;
4015
+ }
4016
+
4017
+ ++cols;
4018
+ if (sep != ',')
4019
+ break;
4020
+ }
4021
+
4022
+ strings = (char**) BufferAsPtr(&names, 1);
4023
+ tempcol = NewStringColumn(cols, namebytes, 1);
4024
+ for (c = 0; c < cols; ++c)
4025
+ AppendToStringColumn(strings[c], -1, &tempcol);
4026
+ SetViewColumns(result, MC_name, 1, tempcol);
4027
+ ReleaseBuffer(&names, 0);
4028
+
4029
+ strings = (char**) BufferAsPtr(&types, 1);
4030
+ tempcol = NewStringColumn(cols, 2 * cols, 1);
4031
+ for (c = 0; c < cols; ++c)
4032
+ AppendToStringColumn(strings[c], -1, &tempcol);
4033
+ SetViewColumns(result, MC_type, 1, tempcol);
4034
+ ReleaseBuffer(&types, 0);
4035
+
4036
+ views = (Sequence_p*) BufferAsPtr(&subvs, 1);
4037
+ tempcol = NewSequenceColumn(IT_view, views, cols);
4038
+ SetViewColumns(result, MC_subv, 1, tempcol);
4039
+ ReleaseBuffer(&subvs, 0);
4040
+
4041
+ free(buf);
4042
+ *desc += ptr - buf;
4043
+ return result;
4044
+ }
4045
+
4046
+ View_p DescToMeta (const char *desc) {
4047
+ int len;
4048
+ const char *end;
4049
+ View_p meta;
4050
+
4051
+ len = strlen(desc);
4052
+ end = desc + len;
4053
+
4054
+ meta = DescAsMeta(&desc, end);
4055
+ if (desc < end)
4056
+ return NULL;
4057
+
4058
+ return meta;
4059
+ }
4060
+
4061
+ ItemTypes DataCmd_VX (Item args[]) {
4062
+ View_p meta, view;
4063
+ int c, cols, objc;
4064
+ const Object_p *objv;
4065
+ Column column;
4066
+
4067
+ meta = args[0].v;
4068
+ cols = ViewSize(meta);
4069
+
4070
+ objv = (const void*) args[1].u.ptr;
4071
+ objc = args[1].u.len;
4072
+
4073
+ if (objc != cols) {
4074
+ args[0].e = EC_wnoa;
4075
+ return IT_error;
4076
+ }
4077
+
4078
+ view = NewView(meta);
4079
+ for (c = 0; c < cols; ++c) {
4080
+ column = CoerceColumn(ViewColType(view, c), objv[c]);
4081
+ if (column.seq == NULL)
4082
+ return IT_unknown;
4083
+
4084
+ SetViewColumns(view, c, 1, column);
4085
+ }
4086
+
4087
+ args[0].v = view;
4088
+ return IT_view;
4089
+ }
4090
+ /* %include<wrap_gen.c>% */
4091
+ /* wrap_gen.c - generated code, do not edit */
4092
+
4093
+ #include <stdlib.h>
4094
+
4095
+
4096
+ ItemTypes BlockedCmd_V (Item_p a) {
4097
+ a[0].v = BlockedView(a[0].v);
4098
+ return IT_view;
4099
+ }
4100
+
4101
+ ItemTypes CloneCmd_V (Item_p a) {
4102
+ a[0].v = CloneView(a[0].v);
4103
+ return IT_view;
4104
+ }
4105
+
4106
+ ItemTypes CoerceCmd_OS (Item_p a) {
4107
+ a[0].c = CoerceCmd(a[0].o, a[1].s);
4108
+ return IT_column;
4109
+ }
4110
+
4111
+ ItemTypes ColMapCmd_Vn (Item_p a) {
4112
+ a[0].v = ColMapView(a[0].v, a[1].c);
4113
+ return IT_view;
4114
+ }
4115
+
4116
+ ItemTypes ColOmitCmd_Vn (Item_p a) {
4117
+ a[0].v = ColOmitView(a[0].v, a[1].c);
4118
+ return IT_view;
4119
+ }
4120
+
4121
+ ItemTypes CompareCmd_VV (Item_p a) {
4122
+ a[0].i = ViewCompare(a[0].v, a[1].v);
4123
+ return IT_int;
4124
+ }
4125
+
4126
+ ItemTypes CompatCmd_VV (Item_p a) {
4127
+ a[0].i = ViewCompat(a[0].v, a[1].v);
4128
+ return IT_int;
4129
+ }
4130
+
4131
+ ItemTypes ConcatCmd_VV (Item_p a) {
4132
+ a[0].v = ConcatView(a[0].v, a[1].v);
4133
+ return IT_view;
4134
+ }
4135
+
4136
+ ItemTypes CountsColCmd_C (Item_p a) {
4137
+ a[0].c = NewCountsColumn(a[0].c);
4138
+ return IT_column;
4139
+ }
4140
+
4141
+ ItemTypes CountViewCmd_I (Item_p a) {
4142
+ a[0].v = NoColumnView(a[0].i);
4143
+ return IT_view;
4144
+ }
4145
+
4146
+ ItemTypes FirstCmd_VI (Item_p a) {
4147
+ a[0].v = FirstView(a[0].v, a[1].i);
4148
+ return IT_view;
4149
+ }
4150
+
4151
+ ItemTypes GetColCmd_VN (Item_p a) {
4152
+ a[0].c = ViewCol(a[0].v, a[1].i);
4153
+ return IT_column;
4154
+ }
4155
+
4156
+ ItemTypes GetInfoCmd_VVI (Item_p a) {
4157
+ a[0].c = GetHashInfo(a[0].v, a[1].v, a[2].i);
4158
+ return IT_column;
4159
+ }
4160
+
4161
+ ItemTypes GroupCmd_VnS (Item_p a) {
4162
+ a[0].v = GroupCol(a[0].v, a[1].c, a[2].s);
4163
+ return IT_view;
4164
+ }
4165
+
4166
+ ItemTypes GroupedCmd_ViiS (Item_p a) {
4167
+ a[0].v = GroupedView(a[0].v, a[1].c, a[2].c, a[3].s);
4168
+ return IT_view;
4169
+ }
4170
+
4171
+ ItemTypes HashFindCmd_VIViii (Item_p a) {
4172
+ a[0].i = HashDoFind(a[0].v, a[1].i, a[2].v, a[3].c, a[4].c, a[5].c);
4173
+ return IT_int;
4174
+ }
4175
+
4176
+ ItemTypes HashViewCmd_V (Item_p a) {
4177
+ a[0].c = HashValues(a[0].v);
4178
+ return IT_column;
4179
+ }
4180
+
4181
+ ItemTypes IjoinCmd_VV (Item_p a) {
4182
+ a[0].v = IjoinView(a[0].v, a[1].v);
4183
+ return IT_view;
4184
+ }
4185
+
4186
+ ItemTypes IotaCmd_I (Item_p a) {
4187
+ a[0].c = NewIotaColumn(a[0].i);
4188
+ return IT_column;
4189
+ }
4190
+
4191
+ ItemTypes IsectMapCmd_VV (Item_p a) {
4192
+ a[0].c = IntersectMap(a[0].v, a[1].v);
4193
+ return IT_column;
4194
+ }
4195
+
4196
+ ItemTypes JoinCmd_VVS (Item_p a) {
4197
+ a[0].v = JoinView(a[0].v, a[1].v, a[2].s);
4198
+ return IT_view;
4199
+ }
4200
+
4201
+ ItemTypes LastCmd_VI (Item_p a) {
4202
+ a[0].v = LastView(a[0].v, a[1].i);
4203
+ return IT_view;
4204
+ }
4205
+
4206
+ ItemTypes MdescCmd_S (Item_p a) {
4207
+ a[0].v = DescToMeta(a[0].s);
4208
+ return IT_view;
4209
+ }
4210
+
4211
+ ItemTypes MetaCmd_V (Item_p a) {
4212
+ a[0].v = V_Meta(a[0].v);
4213
+ return IT_view;
4214
+ }
4215
+
4216
+ ItemTypes NameColCmd_V (Item_p a) {
4217
+ a[0].v = NameColView(a[0].v);
4218
+ return IT_view;
4219
+ }
4220
+
4221
+ ItemTypes OmitMapCmd_iI (Item_p a) {
4222
+ a[0].c = OmitColumn(a[0].c, a[1].i);
4223
+ return IT_column;
4224
+ }
4225
+
4226
+ ItemTypes PairCmd_VV (Item_p a) {
4227
+ a[0].v = PairView(a[0].v, a[1].v);
4228
+ return IT_view;
4229
+ }
4230
+
4231
+ ItemTypes RemapSubCmd_ViII (Item_p a) {
4232
+ a[0].v = RemapSubview(a[0].v, a[1].c, a[2].i, a[3].i);
4233
+ return IT_view;
4234
+ }
4235
+
4236
+ ItemTypes ReplaceCmd_VIIV (Item_p a) {
4237
+ a[0].v = ViewReplace(a[0].v, a[1].i, a[2].i, a[3].v);
4238
+ return IT_view;
4239
+ }
4240
+
4241
+ ItemTypes RowEqCmd_IVIV (Item_p a) {
4242
+ a[0].i = RowEqual(a[0].i, a[1].v, a[2].i, a[3].v);
4243
+ return IT_int;
4244
+ }
4245
+
4246
+ ItemTypes RowHashCmd_VI (Item_p a) {
4247
+ a[0].i = RowHash(a[0].v, a[1].i);
4248
+ return IT_int;
4249
+ }
4250
+
4251
+ ItemTypes SizeCmd_V (Item_p a) {
4252
+ a[0].i = ViewSize(a[0].v);
4253
+ return IT_int;
4254
+ }
4255
+
4256
+ ItemTypes SortMapCmd_V (Item_p a) {
4257
+ a[0].c = SortMap(a[0].v);
4258
+ return IT_column;
4259
+ }
4260
+
4261
+ ItemTypes StepCmd_VIIII (Item_p a) {
4262
+ a[0].v = StepView(a[0].v, a[1].i, a[2].i, a[3].i, a[4].i);
4263
+ return IT_view;
4264
+ }
4265
+
4266
+ ItemTypes StrLookupCmd_Ss (Item_p a) {
4267
+ a[0].i = StringLookup(a[0].s, a[1].c);
4268
+ return IT_int;
4269
+ }
4270
+
4271
+ ItemTypes TagCmd_VS (Item_p a) {
4272
+ a[0].v = TagView(a[0].v, a[1].s);
4273
+ return IT_view;
4274
+ }
4275
+
4276
+ ItemTypes TakeCmd_VI (Item_p a) {
4277
+ a[0].v = TakeView(a[0].v, a[1].i);
4278
+ return IT_view;
4279
+ }
4280
+
4281
+ ItemTypes UngroupCmd_VN (Item_p a) {
4282
+ a[0].v = UngroupView(a[0].v, a[1].i);
4283
+ return IT_view;
4284
+ }
4285
+
4286
+ ItemTypes UniqueMapCmd_V (Item_p a) {
4287
+ a[0].c = UniqMap(a[0].v);
4288
+ return IT_column;
4289
+ }
4290
+
4291
+ ItemTypes ViewAsColCmd_V (Item_p a) {
4292
+ a[0].c = ViewAsCol(a[0].v);
4293
+ return IT_column;
4294
+ }
4295
+
4296
+ ItemTypes WidthCmd_V (Item_p a) {
4297
+ a[0].i = ViewWidth(a[0].v);
4298
+ return IT_int;
4299
+ }
4300
+
4301
+ /* : append ( VV-V ) over size swap insert ; */
4302
+ ItemTypes AppendCmd_VV (Item_p a) {
4303
+ ItemTypes t;
4304
+ /* over 0 */ a[2] = a[0];
4305
+ t = SizeCmd_V(a+2);
4306
+ /* swap 1 */ a[3] = a[1]; a[1] = a[2]; a[2] = a[3];
4307
+ t = InsertCmd_VIV(a);
4308
+ return IT_view;
4309
+ }
4310
+
4311
+ /* : colconv ( C-C ) ; */
4312
+ ItemTypes ColConvCmd_C (Item_p a) {
4313
+ return IT_column;
4314
+ }
4315
+
4316
+ /* : counts ( VN-C ) getcol countscol ; */
4317
+ ItemTypes CountsCmd_VN (Item_p a) {
4318
+ ItemTypes t;
4319
+ t = GetColCmd_VN(a);
4320
+ t = CountsColCmd_C(a);
4321
+ return IT_column;
4322
+ }
4323
+
4324
+ /* : delete ( VII-V ) 0 countview replace ; */
4325
+ ItemTypes DeleteCmd_VII (Item_p a) {
4326
+ ItemTypes t;
4327
+ a[3].i = 0;
4328
+ t = CountViewCmd_I(a+3);
4329
+ t = ReplaceCmd_VIIV(a);
4330
+ return IT_view;
4331
+ }
4332
+
4333
+ /* : except ( VV-V ) over swap exceptmap remap ; */
4334
+ ItemTypes ExceptCmd_VV (Item_p a) {
4335
+ ItemTypes t;
4336
+ /* over 0 */ a[2] = a[0];
4337
+ /* swap 1 */ a[3] = a[1]; a[1] = a[2]; a[2] = a[3];
4338
+ t = ExceptMapCmd_VV(a+1);
4339
+ t = RemapCmd_Vi(a);
4340
+ return IT_view;
4341
+ }
4342
+
4343
+ /* : exceptmap ( VV-C ) over swap isectmap swap size omitmap ; */
4344
+ ItemTypes ExceptMapCmd_VV (Item_p a) {
4345
+ ItemTypes t;
4346
+ /* over 0 */ a[2] = a[0];
4347
+ /* swap 1 */ a[3] = a[1]; a[1] = a[2]; a[2] = a[3];
4348
+ t = IsectMapCmd_VV(a+1);
4349
+ /* swap 0 */ a[2] = a[0]; a[0] = a[1]; a[1] = a[2];
4350
+ t = SizeCmd_V(a+1);
4351
+ t = OmitMapCmd_iI(a);
4352
+ return IT_column;
4353
+ }
4354
+
4355
+ /* : groupinfo ( V-C ) dup 1 getinfo ; */
4356
+ ItemTypes GroupInfoCmd_V (Item_p a) {
4357
+ ItemTypes t;
4358
+ /* dup 0 */ a[1] = a[0];
4359
+ a[2].i = 1;
4360
+ t = GetInfoCmd_VVI(a);
4361
+ return IT_column;
4362
+ }
4363
+
4364
+ /* : hashinfo ( V-C ) dup 0 getinfo ; */
4365
+ ItemTypes HashInfoCmd_V (Item_p a) {
4366
+ ItemTypes t;
4367
+ /* dup 0 */ a[1] = a[0];
4368
+ a[2].i = 0;
4369
+ t = GetInfoCmd_VVI(a);
4370
+ return IT_column;
4371
+ }
4372
+
4373
+ /* : insert ( VIV-V ) 0 swap replace ; */
4374
+ ItemTypes InsertCmd_VIV (Item_p a) {
4375
+ ItemTypes t;
4376
+ a[3].i = 0;
4377
+ /* swap 2 */ a[4] = a[2]; a[2] = a[3]; a[3] = a[4];
4378
+ t = ReplaceCmd_VIIV(a);
4379
+ return IT_view;
4380
+ }
4381
+
4382
+ /* : intersect ( VV-V ) over swap isectmap remap ; */
4383
+ ItemTypes IntersectCmd_VV (Item_p a) {
4384
+ ItemTypes t;
4385
+ /* over 0 */ a[2] = a[0];
4386
+ /* swap 1 */ a[3] = a[1]; a[1] = a[2]; a[2] = a[3];
4387
+ t = IsectMapCmd_VV(a+1);
4388
+ t = RemapCmd_Vi(a);
4389
+ return IT_view;
4390
+ }
4391
+
4392
+ /* : joininfo ( VV-C ) 2 getinfo ; */
4393
+ ItemTypes JoinInfoCmd_VV (Item_p a) {
4394
+ ItemTypes t;
4395
+ a[2].i = 2;
4396
+ t = GetInfoCmd_VVI(a);
4397
+ return IT_column;
4398
+ }
4399
+
4400
+ /* : names ( V-C ) meta 0 getcol ; */
4401
+ ItemTypes NamesCmd_V (Item_p a) {
4402
+ ItemTypes t;
4403
+ t = MetaCmd_V(a);
4404
+ a[1].i = 0;
4405
+ t = GetColCmd_VN(a);
4406
+ return IT_column;
4407
+ }
4408
+
4409
+ /* : product ( VV-V ) over over size spread rrot swap size repeat pair ; */
4410
+ ItemTypes ProductCmd_VV (Item_p a) {
4411
+ ItemTypes t;
4412
+ /* over 0 */ a[2] = a[0];
4413
+ /* over 1 */ a[3] = a[1];
4414
+ t = SizeCmd_V(a+3);
4415
+ t = SpreadCmd_VI(a+2);
4416
+ /* rrot 0 */ a[3] = a[2]; a[2] = a[1]; a[1] = a[0]; a[0] = a[3];
4417
+ /* swap 1 */ a[3] = a[1]; a[1] = a[2]; a[2] = a[3];
4418
+ t = SizeCmd_V(a+2);
4419
+ t = RepeatCmd_VI(a+1);
4420
+ t = PairCmd_VV(a);
4421
+ return IT_view;
4422
+ }
4423
+
4424
+ /* : remap ( Vi-V ) 0 -1 remapsub ; */
4425
+ ItemTypes RemapCmd_Vi (Item_p a) {
4426
+ ItemTypes t;
4427
+ a[2].i = 0;
4428
+ a[3].i = -1;
4429
+ t = RemapSubCmd_ViII(a);
4430
+ return IT_view;
4431
+ }
4432
+
4433
+ /* : repeat ( VI-V ) over size imul 0 1 1 step ; */
4434
+ ItemTypes RepeatCmd_VI (Item_p a) {
4435
+ ItemTypes t;
4436
+ /* over 0 */ a[2] = a[0];
4437
+ t = SizeCmd_V(a+2);
4438
+ /* imul 1 */ a[1].i *= a[2].i;
4439
+ a[2].i = 0;
4440
+ a[3].i = 1;
4441
+ a[4].i = 1;
4442
+ t = StepCmd_VIIII(a);
4443
+ return IT_view;
4444
+ }
4445
+
4446
+ /* : reverse ( V-V ) dup size -1 1 -1 step ; */
4447
+ ItemTypes ReverseCmd_V (Item_p a) {
4448
+ ItemTypes t;
4449
+ /* dup 0 */ a[1] = a[0];
4450
+ t = SizeCmd_V(a+1);
4451
+ a[2].i = -1;
4452
+ a[3].i = 1;
4453
+ a[4].i = -1;
4454
+ t = StepCmd_VIIII(a);
4455
+ return IT_view;
4456
+ }
4457
+
4458
+ /* : slice ( VIII-V ) rrot 1 swap step ; */
4459
+ ItemTypes SliceCmd_VIII (Item_p a) {
4460
+ ItemTypes t;
4461
+ /* rrot 1 */ a[4] = a[3]; a[3] = a[2]; a[2] = a[1]; a[1] = a[4];
4462
+ a[4].i = 1;
4463
+ /* swap 3 */ a[5] = a[3]; a[3] = a[4]; a[4] = a[5];
4464
+ t = StepCmd_VIIII(a);
4465
+ return IT_view;
4466
+ }
4467
+
4468
+ /* : sort ( V-V ) dup sortmap remap ; */
4469
+ ItemTypes SortCmd_V (Item_p a) {
4470
+ ItemTypes t;
4471
+ /* dup 0 */ a[1] = a[0];
4472
+ t = SortMapCmd_V(a+1);
4473
+ t = RemapCmd_Vi(a);
4474
+ return IT_view;
4475
+ }
4476
+
4477
+ /* : spread ( VI-V ) over size 0 rot 1 step ; */
4478
+ ItemTypes SpreadCmd_VI (Item_p a) {
4479
+ ItemTypes t;
4480
+ /* over 0 */ a[2] = a[0];
4481
+ t = SizeCmd_V(a+2);
4482
+ a[3].i = 0;
4483
+ /* rot 1 */ a[4] = a[1]; a[1] = a[2]; a[2] = a[3]; a[3] = a[4];
4484
+ a[4].i = 1;
4485
+ t = StepCmd_VIIII(a);
4486
+ return IT_view;
4487
+ }
4488
+
4489
+ /* : types ( V-C ) meta 1 getcol ; */
4490
+ ItemTypes TypesCmd_V (Item_p a) {
4491
+ ItemTypes t;
4492
+ t = MetaCmd_V(a);
4493
+ a[1].i = 1;
4494
+ t = GetColCmd_VN(a);
4495
+ return IT_column;
4496
+ }
4497
+
4498
+ /* : union ( VV-V ) over except concat ; */
4499
+ ItemTypes UnionCmd_VV (Item_p a) {
4500
+ ItemTypes t;
4501
+ /* over 0 */ a[2] = a[0];
4502
+ t = ExceptCmd_VV(a+1);
4503
+ t = ConcatCmd_VV(a);
4504
+ return IT_view;
4505
+ }
4506
+
4507
+ /* : unionmap ( VV-C ) swap exceptmap ; */
4508
+ ItemTypes UnionMapCmd_VV (Item_p a) {
4509
+ ItemTypes t;
4510
+ /* swap 0 */ a[2] = a[0]; a[0] = a[1]; a[1] = a[2];
4511
+ t = ExceptMapCmd_VV(a);
4512
+ return IT_column;
4513
+ }
4514
+
4515
+ /* : unique ( V-V ) dup uniquemap remap ; */
4516
+ ItemTypes UniqueCmd_V (Item_p a) {
4517
+ ItemTypes t;
4518
+ /* dup 0 */ a[1] = a[0];
4519
+ t = UniqueMapCmd_V(a+1);
4520
+ t = RemapCmd_Vi(a);
4521
+ return IT_view;
4522
+ }
4523
+
4524
+ /* : viewconv ( V-V ) ; */
4525
+ ItemTypes ViewConvCmd_V (Item_p a) {
4526
+ return IT_view;
4527
+ }
4528
+
4529
+ /* end of generated code */
4530
+
4531
+ /* end of generated code */