5.3 Tagged C Pointer Types
The unsafe cpointer-has-tag? and cpointer-push-tag! operations manage tags to distinguish pointer types.
procedure
(_cpointer tag [ ptr-type racket-to-c c-to-racket]) → ctype tag : any/c ptr-type : (or/c ctype? #f) = _pointer racket-to-c : (or/c (any/c . -> . any/c) #f) = values c-to-racket : (or/c (any/c . -> . any/c) #f) = values
(_cpointer/null tag [ ptr-type racket-to-c c-to-racket]) → ctype tag : any/c ptr-type : (or/c ctype? #f) = _pointer racket-to-c : (or/c (any/c . -> . any/c) #f) = values c-to-racket : (or/c (any/c . -> . any/c) #f) = values
The ptr-type is used as the base pointer type for _tag. Values of ptr-type must be represented as pointers.
Although any value can be used as tag, by convention it is
the symbol form of a type name—
Pointer tags are checked with cpointer-has-tag? and changed with cpointer-push-tag!, which means that other tags are preserved on an existing pointer value. Specifically, if a base ptr-type is given and is itself produced by _cpointer, then the new type will handle pointers that have the new tag in addition to ptr-type’s tag(s). When the tag is a pair, its first value is used for printing, so the most recently pushed tag (which corresponds to the inheriting type) is displayed.
A Racket value to be used as a _tag value is first passed to racket-to-c, and the result must be a pointer that is tagged with tag. Similarly, a C value to be returned as a _tag value is initially represented as pointer tagged with tag, but then it is passed to c-to-racket to obtain the Racket representation. Thus, a _tag value is represented by a pointer at the C level, but (unlike the given ptr-type) it can have any representation at the Racket level as implemented by racket-to-c and c-to-racket.
The _cpointer/null function is similar to _cpointer, except that it tolerates NULL pointers both going to C and back. Note that NULL pointers are represented as #f in Racket, so they are not tagged.
syntax
(define-cpointer-type _id)
(define-cpointer-type _id ptr-type-expr)
(define-cpointer-type _id ptr-type-expr racket-to-c-expr c-to-racket-expr)
The optional expressions produce optional arguments to _cpointer.
In addition to defining _id to a type generated by _cpointer, _id/null is bound to a type produced by _cpointer/null type. Finally, id? is defined as a predicate, and id-tag is defined as an accessor to obtain a tag. The tag is the symbol form of id.
procedure
(cpointer-has-tag? cptr tag) → boolean?
cptr : cpointer? tag : any/c (cpointer-push-tag! cptr tag) → void cptr : cpointer? tag : any/c
The cpointer-has-tag? function checks whether if the given cptr has the tag. A pointer has a tag tag when its tag is either eq? to tag or a list that contains (in the sense of memq) tag.
The cpointer-push-tag! function pushes the given tag value on cptr’s tags. The main properties of this operation are: (a) pushing any tag will make later calls to cpointer-has-tag? succeed with this tag, and (b) the pushed tag will be used when printing the pointer (until a new value is pushed). Technically, pushing a tag will simply set it if there is no tag set, otherwise push it on an existing list or an existing value (treated as a single-element list).