1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
* Copyright (c) 2025-2026 Anton Kundenko <singaraiona@gmail.com>
* All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* linkop.h -- Linked columns.
*
* A linked column is an integer vector (RAY_I32 / RAY_I64) where every
* value is a row index into a target table. Querying linkcol.field
* dereferences as target_table[linkcol[i]][field] for each row i — a
* single array access, no hash probe.
*
* Storage: RAY_ATTR_HAS_LINK = 0x04 set on the column; the int64 sym ID
* naming the target lives at bytes 8-15 of the nullmap union (the
* `link_target` field). See include/rayforce.h for the union layout
* and src/mem/heap.h for the attr-bit semantics.
*
* Resolution is lazy: link_target is just a sym, looked up against the
* global env at deref time. If the target table has been rebound, the
* link follows automatically.
*
* HAS_LINK is a property of the column, not a transient accelerator —
* unlike HAS_INDEX it is preserved across in-place mutation and
* persisted to disk via a `.link` sidecar file.
*/
/* == */
/* Attach a link to *vp pointing at the target named by target_sym_id.
* Returns the (possibly COW'd) parent vector with HAS_LINK set, or a
* RAY_ERROR. Validates: target sym must resolve to a RAY_TABLE in the
* current env; *vp must be a RAY_I32 or RAY_I64 vector and not a slice. */
ray_t* ;
/* Clear HAS_LINK from *vp. No-op if not linked. link_target byte slot
* is zeroed. Returns *vp. */
ray_t* ;
/* == */
/* True iff `v` is a linked column or a slice of one. Slices over a
* linked parent inherit the link transparently — the slice's own attrs
* carry RAY_ATTR_SLICE without HAS_LINK, but `link_target` lives on the
* parent and reading it through the slice is safe via slice_parent. */
static inline bool
/* Returns the target sym ID (int64) or -1 if no link is attached.
* Slice-aware: looks through to slice_parent->link_target. */
static inline int64_t
/* == */
/* Dereference linked column v at field sym_id of the target table.
* Returns a fresh owning ref to a column the same length as v, with
* the same type as the target's field column. Null rows in v
* propagate as nulls in the result; null rows in the target also
* propagate. Returns NULL if the target table is missing or doesn't
* have a column named `sym_id` (caller may treat as a probe miss). */
ray_t* ;
/* == */
ray_t* ; /* (.col.link 'target v) */
ray_t* ; /* (.col.unlink v) */
ray_t* ; /* (.col.link? v) */
ray_t* ; /* (.col.target v) */
/* RAY_LINKOP_H */