source: project/wiki/man/4/Unit lolevel @ 33342

Last change on this file since 33342 was 33342, checked in by Vasilij Schneidermann, 5 years ago

Document pointer-vector-length

File size: 20.6 KB
Line 
1[[tags: manual internals]]
2[[toc:]]
3
4
5== Unit lolevel
6
7This unit provides a number of handy low-level operations. '''Use
8at your own risk.'''
9
10This unit uses the {{srfi-4}} and {{extras}} units.
11
12
13
14=== Foreign pointers
15
16The abstract class of ''pointer'' is divided into 2 categories:
17
18; ''pointer object'' : is a foreign pointer object, a [[#Tagged pointers|tagged foreign pointer object]], or a SWIG-pointer.
19
20; ''pointer-like object'' : is a closure, port, [[#Locatives|locative]], or a pointer object.
21
22SWIG-pointers are currently an issue due to "bitrot" in the SWIG CHICKEN
23translator. While they are considered a pointer object unexpected results are
24possible.
25
26Note that Locatives, while technically pointers, are not considered a ''pointer
27object'', but a ''pointer-like object''. The distinction is artificial.
28
29
30==== address->pointer
31
32<procedure>(address->pointer ADDRESS)</procedure>
33
34Creates a new foreign pointer object initialized to point to the address
35given in the integer {{ADDRESS}}.
36
37
38==== allocate
39
40<procedure>(allocate BYTES)</procedure>
41
42Returns a foreign pointer object to a freshly allocated region of static
43memory.
44
45This procedure could be defined as follows:
46
47<enscript highlight=scheme>
48(define allocate (foreign-lambda c-pointer "malloc" integer))
49</enscript>
50
51
52==== free
53
54<procedure>(free POINTER)</procedure>
55
56Frees the memory pointed to by {{POINTER}}.
57
58This procedure could be defined as follows:
59
60<enscript highlight=scheme>
61(define free (foreign-lambda void "free" c-pointer))
62</enscript>
63
64
65==== object->pointer
66
67<procedure>(object->pointer X)</procedure>
68
69Returns a foreign pointer object pointing to the Scheme object X, which should
70be a non-immediate object. ("foreign" here is a bit of a misnomer.)
71
72Note that data in the garbage collected heap moves during garbage collection.
73
74
75==== pointer->object
76
77<procedure>(pointer->object POINTER)</procedure>
78
79Returns the Scheme object pointed to by the pointer object {{POINTER}}.
80
81Whether the {{POINTER}} actually points to a Scheme object is not guaranteed. Use
82at your own risk.
83
84==== pointer?
85
86<procedure>(pointer? X)</procedure>
87
88Returns {{#t}} if {{X}} is a pointer object, or {{#f}} otherwise.
89
90
91==== pointer-like?
92
93<procedure>(pointer-like? X)</procedure>
94
95Returns {{#t}} if {{X}} is a pointer-like object, or {{#f}} otherwise.
96
97
98==== pointer=?
99
100<procedure>(pointer=? POINTER*1 POINTER*2)</procedure>
101
102Returns {{#t}} if the pointer-like objects {{POINTER*1}} and {{POINTER*2}} point
103to the same address, or {{#f}} otherwise.
104
105
106==== pointer->address
107
108<procedure>(pointer->address POINTER*)</procedure>
109
110Returns the address, to which the pointer-like object {{POINTER*}} points.
111
112
113==== pointer+
114
115<procedure>(pointer+ POINTER* N)</procedure>
116
117Returns a new foreign pointer object representing the pointer-like object
118{{POINTER*}} address value increased by the byte-offset {{N}}.
119
120Use of anything other than a pointer object as an argument is questionable.
121
122
123==== align-to-word
124
125<procedure>(align-to-word POINTER*-OR-INT)</procedure>
126
127Accepts either a pointer-like object or an integer as the argument and returns
128a new foreign pointer or integer aligned to the native word size of the host
129platform.
130
131Use of anything other than an integer or pointer object as an argument is
132questionable.
133
134
135
136=== SRFI-4 Foreign pointers
137
138These procedures actually accept a pointer-like object as the {{POINTER}} argument.
139However, as usual, use of anything other than a pointer object is questionable.
140
141==== pointer-u8-ref
142
143<procedure>(pointer-u8-ref POINTER)</procedure>
144
145Returns the unsigned byte at the address designated by {{POINTER}}.
146
147
148==== pointer-s8-ref
149
150<procedure>(pointer-s8-ref POINTER)</procedure>
151
152Returns the signed byte at the address designated by {{POINTER}}.
153
154
155==== pointer-u16-ref
156
157<procedure>(pointer-u16-ref POINTER)</procedure>
158
159Returns the unsigned 16-bit integer at the address designated by {{POINTER}}.
160
161
162==== pointer-s16-ref
163
164<procedure>(pointer-s16-ref POINTER)</procedure>
165
166Returns the signed 16-bit integer at the address designated by {{POINTER}}.
167
168
169==== pointer-u32-ref
170
171<procedure>(pointer-u32-ref POINTER)</procedure>
172
173Returns the unsigned 32-bit integer at the address designated by {{POINTER}}.
174
175
176==== pointer-s32-ref
177
178<procedure>(pointer-s32-ref POINTER)</procedure>
179
180Returns the signed 32-bit integer at the address designated by {{POINTER}}.
181
182
183==== pointer-f32-ref
184
185<procedure>(pointer-f32-ref POINTER)</procedure>
186
187Returns the 32-bit float at the address designated by {{POINTER}}.
188
189
190==== pointer-f64-ref
191
192<procedure>(pointer-f64-ref POINTER)</procedure>
193
194Returns the 64-bit double at the address designated by {{POINTER}}.
195
196
197==== pointer-u8-set!
198
199<procedure>(pointer-u8-set! POINTER N)</procedure><br>
200<procedure>(set! (pointer-u8-ref POINTER) N)</procedure>
201
202Stores the unsigned byte {{N}} at the address designated by {{POINTER}}.
203
204
205==== pointer-s8-set!
206
207<procedure>(pointer-s8-set! POINTER N)</procedure><br>
208<procedure>(set! (pointer-s8-ref POINTER) N)</procedure>
209
210Stores the signed byte {{N}} at the address designated by {{POINTER}}.
211
212
213==== pointer-u16-set!
214
215<procedure>(pointer-u16-set! POINTER N)</procedure><br>
216<procedure>(set! (pointer-u16-ref POINTER) N)</procedure>
217
218Stores the unsigned 16-bit integer {{N}} at the address designated by {{POINTER}}.
219
220
221==== pointer-s16-set!
222
223<procedure>(pointer-s16-set! POINTER N)</procedure><br>
224<procedure>(set! (pointer-s16-ref POINTER) N)</procedure>
225
226Stores the signed 16-bit integer {{N}} at the address designated by {{POINTER}}.
227
228
229==== pointer-u32-set!
230
231<procedure>(pointer-u32-set! POINTER N)</procedure><br>
232<procedure>(set! (pointer-u32-ref POINTER) N)</procedure>
233
234Stores the unsigned 32-bit integer {{N}} at the address designated by {{POINTER}}.
235
236
237==== pointer-s32-set!
238
239<procedure>(pointer-s32-set! POINTER N)</procedure><br>
240<procedure>(set! (pointer-s32-ref POINTER) N)</procedure>
241
242Stores the 32-bit integer {{N}} at the address designated by {{POINTER}}.
243
244
245==== pointer-f32-set!
246
247<procedure>(pointer-f32-set! POINTER N)</procedure><br>
248<procedure>(set! (pointer-f32-ref POINTER) N)</procedure>
249
250Stores the 32-bit floating-point number {{N}} at the address designated by {{POINTER}}.
251
252
253==== pointer-f64-set!
254
255<procedure>(pointer-f64-set! POINTER N)</procedure><br>
256<procedure>(set! (pointer-f64-ref POINTER) N)</procedure>
257
258Stores the 64-bit floating-point number {{N}} at the address designated by {{POINTER}}.
259
260
261
262=== Tagged pointers
263
264''Tagged'' pointers are foreign pointer objects with an extra tag object.
265
266
267==== tag-pointer
268
269<procedure>(tag-pointer POINTER* TAG)</procedure>
270
271Creates a new tagged foreign pointer object from the pointer-like object
272{{POINTER*}} with the tag {{TAG}}, which may an arbitrary Scheme object.
273
274Use of anything other than a pointer object is questionable.
275
276==== tagged-pointer?
277
278<procedure>(tagged-pointer? X [TAG])</procedure>
279
280Returns {{#t}} if {{X}} is a tagged foreign pointer object, or {{#f}} otherwise.
281
282Further, returns {{#t}} when {{X}} has the optional tag {{TAG}} (using an
283{{equal?}} comparison), or {{#f}} otherwise.
284
285
286==== pointer-tag
287
288<procedure>(pointer-tag POINTER*)</procedure>
289
290If {{POINTER}} is a tagged foreign pointer object, its tag is returned. If {{POINTER*}}
291is any other kind of pointer-like object {{#f}} is returned. Otherwise an
292error is signalled.
293
294
295=== Pointer vectors
296
297''Pointer vectors'' are specialized and space-efficient vectors for
298foreign pointer objects. All procedures defined below that accept
299a pointer object allow {{#f}} as an alternative representation of
300the {{NULL}}-pointer.
301
302==== make-pointer-vector
303
304<procedure>(make-pointer-vector LENGTH [INIT])</procedure>
305
306Creates a pointer-vector of the given length and optionally initializes each
307element to {{INIT}}, which should be a pointer or {{#f}}, which represents the
308{{NULL}} pointer.
309
310==== pointer-vector?
311
312<procedure>(pointer-vector? X)</procedure>
313
314Returns {{#t}} if {{X}} is a pointer-vector or {{#f}} otherwise.
315
316==== pointer-vector
317
318<procedure>(pointer-vector POINTER ...)</procedure>
319
320Returns a pointer-vector from the given pointer arguments.
321
322==== pointer-vector-length
323
324<procedure>(pointer-vector-length POINTERVECTOR)</procedure>
325
326Returns the length of the given pointer-vector.
327
328==== pointer-vector-ref
329
330<procedure>(pointer-vector-ref POINTERVECTOR INDEX)</procedure>
331
332Returns the pointer at {{INDEX}} in the given pointer-vector or
333{{#f}} if the element is a {{NULL}}- pointer.
334
335==== pointer-vector-set!
336
337<procedure>(pointer-vector-set! POINTERVECTOR INDEX POINTER)</procedure>
338
339Sets the element at the position {{INDEX}} in the given pointer-vector to
340{{POINTER}}. The alternative syntax
341
342  (set! (pointer-vector-ref POINTERVECTOR INDEX) POINTER)
343
344is also allowed.
345
346
347=== Locatives
348
349
350A ''locative'' is an object that points to an element of a containing object,
351much like a ''pointer'' in low-level, imperative programming languages like ''C''. The element can
352be accessed and changed indirectly, by performing access or change operations
353on the locative. The container object can be computed by calling the
354{{locative->object}} procedure.
355
356Locatives may be passed to foreign procedures that expect pointer arguments.
357The effect of creating locatives for evicted data (see {{object-evict}}) is undefined.
358
359
360==== make-locative
361
362<procedure>(make-locative OBJ [INDEX])</procedure>
363
364Creates a locative that refers to the element of the non-immediate object
365{{OBJ}} at position {{INDEX}}. {{OBJ}} may be a vector, pair, string, blob,
366SRFI-4 number-vector, or record structure. {{INDEX}} should be a fixnum.
367{{INDEX}} defaults to 0.
368
369
370==== make-weak-locative
371
372<procedure>(make-weak-locative OBJ [INDEX])</procedure>
373
374Creates a ''weak'' locative. Even though the locative refers to an element of a container object,
375the container object will still be reclaimed by garbage collection if no other references
376to it exist.
377
378
379==== locative?
380
381<procedure>(locative? X)</procedure>
382
383Returns {{#t}} if {{X}} is a locative, or {{#f}} otherwise.
384
385
386==== locative-ref
387
388<procedure>(locative-ref LOC)</procedure>
389
390Returns the element to which the locative {{LOC}} refers. If the containing
391object has been reclaimed by garbage collection, an error is signalled.
392
393 (locative-ref (make-locative "abc" 1)) ==> #\b
394
395==== locative-set!
396
397<procedure>(locative-set! LOC X)</procedure><br>
398<procedure>(set! (locative-ref LOC) X)</procedure>
399
400Changes the element to which the locative {{LOC}} refers to {{X}}.
401If the containing
402object has been reclaimed by garbage collection, an error is signalled.
403
404
405==== locative->object
406
407<procedure>(locative->object LOC)</procedure>
408
409Returns the object that contains the element referred to by {{LOC}} or
410{{#f}} if the container has been reclaimed by garbage collection.
411
412 (locative->object (make-locative "abc" 1)) ==> "abc"
413
414
415
416=== Extending procedures with data
417
418
419==== extend-procedure
420
421<procedure>(extend-procedure PROCEDURE X)</procedure>
422
423Returns a copy of the procedure {{PROCEDURE}} which contains an additional data
424slot initialized to {{X}}. If {{PROCEDURE}} is already an extended procedure,
425then its data slot is changed to contain {{X}} and the same procedure is
426returned. Signals an error when {{PROCEDURE}} is not a procedure.
427
428
429==== extended-procedure?
430
431<procedure>(extended-procedure? PROCEDURE)</procedure>
432
433Returns {{#t}} if {{PROCEDURE}} is an extended procedure,
434or {{#f}} otherwise.
435
436
437==== procedure-data
438
439<procedure>(procedure-data PROCEDURE)</procedure>
440
441Returns the data object contained in the extended procedure {{PROCEDURE}}, or
442{{#f}} if it is not an extended procedure.
443
444
445==== set-procedure-data!
446
447<procedure>(set-procedure-data! PROCEDURE X)</procedure>
448
449Changes the data object contained in the extended procedure {{PROCEDURE}} to
450{{X}}. Signals an error when {{PROCEDURE}} is not an extended procedure.
451
452<enscript highlight=scheme>
453(define foo
454  (letrec ((f (lambda () (procedure-data x)))
455           (x #f) )
456    (set! x (extend-procedure f 123))
457    x) )
458(foo)                                         ==> 123
459(set-procedure-data! foo 'hello)
460(foo)                                         ==> hello
461</enscript>
462
463
464
465=== Low-level data access
466
467These procedures operate with what are known as {{vector-like objects}}. A
468{{vector-like object}} is a vector, record structure, pair, symbol or keyword.
469
470Note that strings and blobs are not considered vector-like.
471
472
473==== vector-like?
474
475<procedure>(vector-like? X)</procedure>
476
477Returns {{#t}} when {{X}} is a vector-like object, returns {{#f}}
478otherwise.
479
480
481==== block-ref
482
483<procedure>(block-ref VECTOR* INDEX)</procedure>
484
485Returns the contents of the {{INDEX}}th slot of the vector-like object
486{{VECTOR*}}.
487
488
489==== block-set!
490
491<procedure>(block-set! VECTOR* INDEX X)</procedure><br>
492<procedure>(set! (block-ref VECTOR* INDEX) X)</procedure>
493
494Sets the contents of the {{INDEX}}th slot of the vector-like object {{VECTOR*}}
495to the value of {{X}}.
496
497==== number-of-slots
498
499<procedure>(number-of-slots VECTOR*)</procedure>
500
501Returns the number of slots that the vector-like object {{VECTOR*}} contains.
502
503
504==== number-of-bytes
505
506<procedure>(number-of-bytes BLOCK)</procedure>
507
508Returns the number of bytes that the object {{BLOCK}} contains. {{BLOCK}} may
509be any non-immediate value.
510
511
512==== object-copy
513
514<procedure>(object-copy X)</procedure>
515
516Copies {{X}} recursively and returns the fresh copy. Objects allocated in
517static memory are copied back into garbage collected storage.
518
519
520==== move-memory!
521
522<procedure>(move-memory! FROM TO [BYTES [FROM-OFFSET [TO-OFFSET]]])</procedure>
523
524Copies {{BYTES}} bytes of memory from {{FROM}} to {{TO}}. {{FROM}} and {{TO}}
525may be strings, blobs, [[Unit srfi-4|SRFI-4 number-vectors]], memory
526mapped files, foreign pointers (as obtained from a call to {{foreign-lambda}},
527for example), tagged-pointers or locatives. if {{BYTES}} is not given and the
528size of the source or destination operand is known then the maximal number of
529bytes will be copied. Moving memory to the storage returned by locatives will
530cause havoc, if the locative refers to containers of non-immediate data, like
531vectors or pairs.
532
533The additional fourth and fifth argument specify starting offsets (in bytes)
534for the source and destination arguments.
535
536Signals an error if any of the above constraints is violated.
537
538
539
540=== Data in unmanaged memory
541
542
543==== object-evict
544
545<procedure>(object-evict X [ALLOCATOR])</procedure>
546
547Copies the object {{X}} recursively into the memory pointed to by the foreign
548pointer object returned by {{ALLOCATOR}}.  The freshly copied object is
549returned.  {{ALLOCATOR}} should be a procedure of a single argument
550(the number of bytes to allocate), and defaults to {{allocate}}.
551
552This facility allows moving arbitrary objects into static memory, but care
553should be taken when mutating evicted data: setting slots in evicted
554vector-like objects to non-evicted data is not allowed. It '''is''' possible to
555set characters/bytes in evicted strings or byte-vectors, though.  It is
556advisable '''not''' to evict ports, because they might be mutated by certain
557file-operations.  {{object-evict}} is able to handle circular and shared
558structures.
559
560Evicted symbols are no longer unique: a fresh copy of the
561symbol is created, so
562
563<enscript highlight=scheme>
564(define x 'foo)
565(define y (object-evict 'foo))
566y                              ==> foo
567(eq? x y)                      ==> #f
568(define z (object-evict '(bar bar)))
569(eq? (car z) (cadr z))         ==> #t
570</enscript>
571
572This loss of uniqueness also implies that an evicted structure --
573such as one created with {{define-record}} -- cannot be operated on with
574the existing predicate or accessors, as internally a symbol is used to
575denote the type:
576
577<enscript highlight=scheme>
578(define-record point x y)
579(point? (make-point x y))                  ; => #t
580(point? (object-evict (make-point x y)))   ; => #f
581</enscript>
582
583==== object-evict-to-location
584
585<procedure>(object-evict-to-location X POINTER* [LIMIT])</procedure>
586
587As {{object-evict}} but moves the object at the address pointed to by
588the pointer-like object {{POINTER*}}. If the number of copied bytes exceeds
589the optional {{LIMIT}} then an error is signalled (specifically a composite
590condition of types {{exn}} and {{evict}}. The latter provides
591a {{limit}} property which holds the exceeded limit. Two values are
592returned: the evicted object and a new pointer pointing to the first
593free address after the evicted object.
594
595Use of anything other than a pointer object as the {{POINTER*}} argument is
596questionable.
597
598==== object-evicted?
599
600<procedure>(object-evicted? X)</procedure>
601
602Returns {{#t}} if {{X}} is a non-immediate evicted data object, or {{#f}}
603otherwise.
604
605
606==== object-release
607
608<procedure>(object-release X [RELEASER])</procedure>
609
610Frees memory occupied by the evicted object {{X}} recursively.
611{{RELEASER}} should be a procedure of a single argument (a foreign
612pointer object to the static memory to be freed) and defaults to
613{{free}}.
614
615
616==== object-unevict
617
618<procedure>(object-unevict X [FULL])</procedure>
619
620Copies the object {{X}} and nested objects back into the normal Scheme heap.
621Symbols are re-interned into the symbol table. Strings and byte-vectors are
622'''not''' copied, unless {{FULL}} is given and not {{#f}}.
623
624
625==== object-size
626
627<procedure>(object-size X)</procedure>
628
629Returns the number of bytes that would be needed to evict the data object
630{{X}}. If {{X}} is an immediate object, zero is returned.
631
632
633
634=== Record instance
635
636
637==== make-record-instance
638
639<procedure>(make-record-instance SYMBOL ARG1 ...)</procedure>
640
641Returns a new instance of the record type {{SYMBOL}}, with its
642slots initialized to {{ARG1 ...}}.  To illustrate:
643
644<enscript highlight=scheme>
645(define-record-type point (make-point x y) point?
646  (x point-x point-x-set!)
647  (y point-y point-y-set!))
648</enscript>
649
650expands into something quite similar to:
651
652<enscript highlight=scheme>
653(begin
654  (define (make-point x y)
655    (make-record-instance 'point x y) )
656  (define (point? x)
657    (and (record-instance? x)
658         (eq? 'point (block-ref x 0)) ) )
659  (define (point-x p) (block-ref p 1))
660  (define (point-x-set! p x) (block-set! p 1 x))
661  (define (point-y p) (block-ref p 2))
662  (define (point-y-set! p y) (block-set! p 1 y)) )
663</enscript>
664
665
666==== record-instance?
667
668<procedure>(record-instance? X [SYMBOL])</procedure>
669
670Returns {{#t}} if {{X}} is a record structure, or {{#f}} otherwise.
671
672Further, returns {{#t}} if {{X}} is of type {{SYMBOL}}, or {{#f}} otherwise.
673
674
675==== record-instance-type
676
677<procedure>(record-instance-type RECORD)</procedure>
678
679Returns type symbol of the record structure {{RECORD}}. Signals an error if
680{{RECORD}} is not a record structure.
681
682
683==== record-instance-length
684
685<procedure>(record-instance-length RECORD)</procedure>
686
687Returns number of slots for the record structure {{RECORD}}. The
688record-instance type is not counted. Signals an error if
689{{RECORD}} is not a record structure.
690
691
692==== record-instance-slot
693
694<procedure>(record-instance-slot RECORD INDEX)</procedure>
695
696Returns the contents of the {{INDEX}}th slot of the record structure
697{{RECORD}}. The slot index range is the open interval {{[0
698record-instance-length)}}. Signals an error if {{RECORD}} is not a record
699structure.
700
701
702==== record-instance-slot-set!
703
704<procedure>(record-instance-slot-set! RECORD INDEX X)</procedure><br>
705<procedure>(set! (record-instance-slot RECORD INDEX) X)</procedure>
706
707Sets the {{INDEX}}th slot of the record structure {{RECORD}} to {{X}}. The slot
708index range is the open interval {{[0 record-instance-length)}}. Signals an
709error if {{RECORD}} is not a record structure.
710
711
712==== record->vector
713
714<procedure>(record->vector RECORD)</procedure>
715
716Returns a new vector with the type and the elements of the record structure
717{{RECORD}}. Signals an error if {{RECORD}} is not a record structure.
718
719
720=== Magic
721
722
723==== object-become!
724
725<procedure>(object-become! ALIST)</procedure>
726
727Changes the identity of the value of the car of each pair in {{ALIST}} to the
728value of the cdr. Both values may not be immediate (i.e. exact integers,
729characters, booleans or the empty list).
730
731<enscript highlight=scheme>
732(define x "i used to be a string")
733(define y '#(and now i am a vector))
734(object-become! (list (cons x y)))
735x                                    ==> #(and now i am a vector)
736y                                    ==> #(and now i am a vector)
737(eq? x y)                            ==> #t
738</enscript>
739
740Note: this operation invokes a major garbage collection.
741
742The effect of using {{object-become!}} on evicted data (see {{object-evict}})
743is undefined.
744
745
746==== mutate-procedure!
747
748<procedure>(mutate-procedure! OLD PROC)</procedure>
749
750Replaces the procedure {{OLD}} with the result of calling the one-argument
751procedure {{PROC}}. {{PROC}} will receive a copy of {{OLD}} that will be
752identical in behaviour to the result of {{OLD}}:
753
754<enscript highlight=scheme>
755 ;;; Replace arbitrary procedure with tracing one:
756
757 (mutate-procedure! my-proc
758   (lambda (new)
759     (lambda args
760       (printf "~s called with arguments: ~s~%" new args)
761       (apply new args) ) ) )
762</enscript>
763
764---
765Previous: [[Unit tcp]]
766
767Next: [[Interface to external functions and variables]]
Note: See TracBrowser for help on using the repository browser.