rural 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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 */