5.3 Tagged C Pointer Types
The unsafe cpointer-has-tag? and cpointer-push-tag!
operations manage tags to distinguish pointer types.
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
can be given to be used as the base pointer
type, instead of _pointer
Although any value can be used as a tag, by convention the symbol form
of a type name—without a leading underscore—is used as the
tag. For example, a pointer type _animal
would normally use 'animal as the key.
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 a _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.
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.
A macro version of _cpointer
using the defined name for a tag symbol, and defining a predicate
too. The _id
must start with _
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.
These two functions treat pointer tags as lists of tags. As described
in Pointer Functions
, 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 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).