85 lines
4.0 KiB
Racket
85 lines
4.0 KiB
Racket
#lang scribble/doc
|
|
@(require "utils.ss")
|
|
|
|
@title[#:tag "foreign:tagged-pointers"]{Tagged C Pointer Types}
|
|
|
|
The unsafe @scheme[cpointer-has-tag?] and @scheme[cpointer-push-tag!]
|
|
operations manage tags to distinguish pointer types.
|
|
|
|
@defproc*[([(_cpointer [tag any/c]
|
|
[ptr-type ctype? _xpointer]
|
|
[scheme-to-c (any/c . -> . any/c) values]
|
|
[c-to-scheme (any/c . -> . any/c) values])
|
|
ctype]
|
|
[(_cpointer/null [tag any/c]
|
|
[ptr-type ctype? _xpointer]
|
|
[scheme-to-c (any/c . -> . any/c) values]
|
|
[c-to-scheme (any/c . -> . any/c) values])
|
|
ctype])]{
|
|
|
|
Construct a kind of a pointer that gets a specific tag when converted
|
|
to Racket, and accept only such tagged pointers when going to C. An
|
|
optional @scheme[ptr-type] can be given to be used as the base pointer
|
|
type, instead of @scheme[_pointer].
|
|
|
|
Pointer tags are checked with @scheme[cpointer-has-tag?] and changed
|
|
with @scheme[cpointer-push-tag!] which means that other tags are
|
|
preserved. Specifically, if a base @scheme[ptr-type] is given and is
|
|
itself a @scheme[_cpointer], then the new type will handle pointers
|
|
that have the new tag in addition to @scheme[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 will be
|
|
displayed.
|
|
|
|
Note that tags are compared with @scheme[eq?] (or @scheme[memq]), which means
|
|
an interface can hide its value from users (e.g., not provide the
|
|
@scheme[cpointer-tag] accessor), which makes such pointers un-fake-able.
|
|
|
|
@scheme[_cpointer/null] is similar to @scheme[_cpointer] except that
|
|
it tolerates @cpp{NULL} pointers both going to C and back. Note that
|
|
@cpp{NULL} pointers are represented as @scheme[#f] in Racket, so they
|
|
are not tagged.}
|
|
|
|
|
|
@defform*[[(define-cpointer-type _id)
|
|
(define-cpointer-type _id scheme-to-c-expr)
|
|
(define-cpointer-type _id scheme-to-c-expr c-to-scheme-expr)]]{
|
|
|
|
A macro version of @scheme[_cpointer] and @scheme[_cpointer/null],
|
|
using the defined name for a tag string, and defining a predicate
|
|
too. The @scheme[_id] must start with @litchar{_}.
|
|
|
|
The optional expression produces optional arguments to @scheme[_cpointer].
|
|
|
|
In addition to defining @scheme[_id] to a type generated by
|
|
@scheme[_cpointer], @scheme[_id]@schemeidfont{/null} is bound to a
|
|
type produced by @scheme[_cpointer/null] type. Finally,
|
|
@schemevarfont{id}@schemeidfont{?} is defined as a predicate, and
|
|
@schemevarfont{id}@schemeidfont{-tag} is defined as an accessor to
|
|
obtain a tag. The tag is the string form of @schemevarfont{id}.}
|
|
|
|
@defproc*[([(cpointer-has-tag? [cptr any/c] [tag any/c]) boolean?]
|
|
[(cpointer-push-tag! [cptr any/c] [tag any/c]) void])]{
|
|
|
|
These two functions treat pointer tags as lists of tags. As described
|
|
in @secref["foreign:pointer-funcs"], a pointer tag does not have any
|
|
role, except for Racket code that uses it to distinguish pointers;
|
|
these functions treat the tag value as a list of tags, which makes it
|
|
possible to construct pointer types that can be treated as other
|
|
pointer types, mainly for implementing inheritance via upcasts (when a
|
|
struct contains a super struct as its first element).
|
|
|
|
The @scheme[cpointer-has-tag?] function checks whether if the given
|
|
@scheme[cptr] has the @scheme[tag]. A pointer has a tag @scheme[tag]
|
|
when its tag is either @scheme[eq?] to @scheme[tag] or a list that
|
|
contains (in the sense of @scheme[memq]) @scheme[tag].
|
|
|
|
The @scheme[cpointer-push-tag!] function pushes the given @scheme[tag]
|
|
value on @scheme[cptr]'s tags. The main properties of this operation
|
|
are: (a) pushing any tag will make later calls to
|
|
@scheme[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).}
|