• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/tests/custom/17_lib_ffi/33_closure_values

  1 A closure describes the types of its own signature, and does so for as long as
  2 it can still be invoked. Storage shared with the surrounding call cannot be used
  3 for that: it holds one entry per top level type, so a structure gets described
  4 through the entry of whichever type was converted into it before and is left
  5 with that type's size and alignment, which makes ffi_prep_cif() place the
  6 argument wrongly and die while reading the descriptor.
  7 
  8 The descriptors a closure synthesized belong to it rather than to the call which
  9 happened to create it, since it is invoked long after that call returned.
 10 
 11 A system library offers no entry point taking a caller defined structure, so
 12 each testcase ships the source of one, compiles it with cc, and abstains when
 13 no C compiler is available.
 14 
 15 Add up the members of two structures supplied to a callback.
 16 
 17 -- Testcase --
 18 {%
 19     import * as ffi from 'ffi';
 20 
 21     let src = TESTFILES_PATH + '/uctestlib.c';
 22     let so = TESTFILES_PATH + '/uctestlib.so';
 23 
 24     if (system([ 'cc', '-shared', '-fPIC', '-o', so, src ]) != 0)
 25         exit(77);
 26 
 27     let lib = ffi.dlopen(so, false, `
 28         struct point { int x; int y; };
 29         struct wide { long a; long b; };
 30 
 31         int uctest_pick(int (*cmp)(struct point a, struct point b),
 32                         struct point a, struct point b);
 33         long uctest_pick_wide(long (*cmp)(struct wide w), long a, long b);
 34     `);
 35 
 36     // A structure as an argument of a closure is what cannot be described
 37     // through the storage of the enclosing call: that storage holds one entry
 38     // per top level type, so the structure would be described through the
 39     // entry of whichever type was converted into it before.
 40     print("picked: ", lib.uctest_pick(
 41         (a, b) => (a.x + a.y) - (b.x + b.y),
 42         { x: 1, y: 2 },
 43         { x: 3, y: 4 }), "\n");
 44 
 45     print("wide: ", lib.uctest_pick_wide(
 46         (w) => w.a * 1000 + w.b, 7, 3), "\n");
 47 %}
 48 -- End --
 49 
 50 -- File uctestlib.c --
 51 struct point {
 52         int x;
 53         int y;
 54 };
 55 
 56 struct wide {
 57         long a;
 58         long b;
 59 };
 60 
 61 int
 62 uctest_pick(int (*cmp)(struct point a, struct point b),
 63             struct point a, struct point b)
 64 {
 65         return cmp(a, b);
 66 }
 67 
 68 long
 69 uctest_pick_wide(long (*cmp)(struct wide w), long a, long b)
 70 {
 71         struct wide w = { a, b };
 72 
 73         return cmp(w);
 74 }
 75 -- End --
 76 
 77 -- Expect stdout --
 78 picked: -4
 79 wide: 7003
 80 -- End --
 81 
 82 
 83 Compare two structures supplied to a sorting callback.
 84 
 85 -- Testcase --
 86 {%
 87     import * as ffi from 'ffi';
 88 
 89     let src = TESTFILES_PATH + '/uctestlib.c';
 90     let so = TESTFILES_PATH + '/uctestlib.so';
 91 
 92     if (system([ 'cc', '-shared', '-fPIC', '-o', so, src ]) != 0)
 93         exit(77);
 94 
 95     let lib = ffi.dlopen(so, false, `
 96         struct point { int x; int y; };
 97         void uctest_sort(struct point *base, size_t n,
 98                          int (*compar)(const void *, const void *));
 99     `);
100 
101     let arr = ffi.ctype('struct point[4]',
102         [{ x: 3, y: 1 }, { x: 1, y: 9 }, { x: 2, y: 0 }, { x: 0, y: 5 }]);
103 
104     lib.uctest_sort(arr.ptr(), 4,
105         (a, b) => a.deref('struct point').x - b.deref('struct point').x);
106 
107     let order = [];
108 
109     for (let i = 0; i < 4; i++)
110         push(order, `${arr[i].x},${arr[i].y}`);
111 
112     print("sorted: ", join(" ", order), "\n");
113 %}
114 -- End --
115 
116 -- File uctestlib.c --
117 #include <stddef.h>
118 
119 struct point {
120         int x;
121         int y;
122 };
123 
124 void
125 uctest_sort(struct point *base, size_t n,
126             int (*compar)(const void *, const void *))
127 {
128         for (size_t i = 1; i < n; i++)
129                 for (size_t j = i; j > 0 && compar(&base[j - 1], &base[j]) > 0; j--) {
130                         struct point t = base[j - 1];
131 
132                         base[j - 1] = base[j];
133                         base[j] = t;
134                 }
135 }
136 -- End --
137 
138 -- Expect stdout --
139 sorted: 0,5 1,9 2,0 3,1
140 -- End --
141 
142 
143 Invoke one closure again after the call which created it returned.
144 
145 -- Testcase --
146 {%
147     import * as ffi from 'ffi';
148 
149     let src = TESTFILES_PATH + '/uctestlib.c';
150     let so = TESTFILES_PATH + '/uctestlib.so';
151 
152     if (system([ 'cc', '-shared', '-fPIC', '-o', so, src ]) != 0)
153         exit(77);
154 
155     let lib = ffi.dlopen(so, false, `
156         struct point { int x; int y; };
157         void uctest_sort(struct point *base, size_t n,
158                          int (*compar)(const void *, const void *));
159     `);
160 
161     let arr = ffi.ctype('struct point[3]',
162         [{ x: 2, y: 0 }, { x: 0, y: 1 }, { x: 1, y: 2 }]);
163 
164     // The closure outlives every single call below, so the descriptors it
165     // synthesized for its own argument types belong to it and cannot be
166     // released along the first of them.
167     let cmp = ffi.closure('int (*)(const void *, const void *)',
168         (a, b) => a.deref('struct point').x - b.deref('struct point').x);
169 
170     let rounds = [];
171 
172     for (let round = 0; round < 3; round++) {
173         lib.uctest_sort(arr.ptr(), 3, cmp);
174 
175         let sorted = [];
176 
177         for (let i = 0; i < 3; i++)
178             push(sorted, `${arr[i].x},${arr[i].y}`);
179 
180         push(rounds, join(",", sorted));
181     }
182 
183     print("rounds: ", join(" | ", rounds), "\n");
184 %}
185 -- End --
186 
187 -- File uctestlib.c --
188 #include <stddef.h>
189 
190 struct point {
191         int x;
192         int y;
193 };
194 
195 void
196 uctest_sort(struct point *base, size_t n,
197             int (*compar)(const void *, const void *))
198 {
199         for (size_t i = 1; i < n; i++)
200                 for (size_t j = i; j > 0 && compar(&base[j - 1], &base[j]) > 0; j--) {
201                         struct point t = base[j - 1];
202 
203                         base[j - 1] = base[j];
204                         base[j] = t;
205                 }
206 }
207 -- End --
208 
209 -- Expect stdout --
210 rounds: 0,1,1,2,2,0 | 0,1,1,2,2,0 | 0,1,1,2,2,0
211 -- End --

This page was automatically generated by LXR 0.3.1.  •  OpenWrt