-
Notifications
You must be signed in to change notification settings - Fork 15
Automatic Pointer Resolution
Type signature:
(POINTER &key pointer-type data-type base-pointer-name region-tag)
Specifies that the value is really a pointer to another value somewhere else
in the file. When reading, if a BASE-POINTER-NAME
is supplied and a base-pointer
tag has been created, then the pointer will be treated as an offset from that
base-pointer. If no BASE-POINTER-NAME
is provided, then the pointer is treated
as being an absolute file-position.
The :POINTER-TYPE
key specifies the type of the pointer itself, and must be some kind
of integer.
The :DATA-TYPE
specifies the data that is being pointed to.
The :REGION-TAG
is used when writing. This specifies that the value to be written
will reside in an area tagged with the region tag.
What this means is that when Lisp-Binary encounters this pointer, it will write a zero, and then it'll store the value to be written in a memory structure indexed by the tag.
When Lisp-Binary later encounters a slot of type REGION-TAG
with a name matching the tag
given here, then it'll do two things:
- Write out the value (and all other values pending under this tag).
- Go back and update the pointer (and all other pointers that correspond to pending values).
Because of the need to go back and update what was written previously, POINTER
s only work with
streams that are opened with :DIRECTION :IO
.
POINTERs
cannot be automatically written if they point to an earlier part of the file
than they themselves occur, because the tag will have already been encountered before writing
the pointers.
All I/O involving POINTER
s, REGION-TAG
s, or BASE-POINTER
s should be performed
within a WITH-LOCAL-POINTER-RESOLVING-CONTEXT
block. This arranges to clear any tags
that weren't encountered during writing, and also rebinds the special variables involved
so that they don't interfere with other threads.
Example:
(defbinary bar ()
(pointer-1 nil :type (pointer :pointer-type (unsigned-byte 16)
:data-type (terminated-string 1)
:base-pointer-name foo-base
:region-tag foo-region))
(pointer-2 0 :type (pointer :pointer-type (unsigned-byte 16)
:data-type quadruple-float
:base-pointer-name foo-base
:region-tag foo-region)))
(defbinary foo ()
(foo-base 0 :type base-pointer)
(bar nil :type bar)
;; POINTER-1 and POINTER-2 will point to this:
(foo-region nil :type (region-tag :base-pointer-name foo-base)))
(with-local-pointer-resolving-context
(let ((input (with-open-binary-file (in "foo.bin")
(read-binary 'foo in))))
(with-open-binary-file (out "bar.bin"
:direction :io)
(write-binary input stream))))
Other related types:
BASE-POINTER
Instead of reading or writing this field, CL:FILE-POSITION
will be called
on the current stream, and the address returned will be stored under a tag
with the same name as this slot. The tag can then be used to calculate
file positions and offsets. See the POINTER
type for an example.
FILE-POSITION
Like BASE-POINTER
, but no global tag is stored. The slot will contain the
address in the file of the next thing to be read. No actual reading or
writing is triggered by a slot of this type.
(REGION-TAG &key base-pointer-name)
Instead of writing the value of this slot, all POINTER
s that have the same
REGION-TAG
name as this slot will be written out here, and the corresponding
offsets will be updated. The file being written must be opened with
:DIRECTION :IO
. The POINTER
s themselves will be written as offsets from
whatever object has the BASE-POINTER
named BASE-POINTER-NAME
.