Skip to content

Automatic Pointer Resolution

Jeremy Phelps edited this page Oct 20, 2016 · 3 revisions

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:

  1. Write out the value (and all other values pending under this tag).
  2. 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, POINTERs 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 POINTERs, REGION-TAGs, or BASE-POINTERs 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

  • 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

  • (REGION-TAG &key base-pointer-name)

Instead of writing the value of this slot, all POINTERs 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 POINTERs themselves will be written as offsets from whatever object has the BASE-POINTER named BASE-POINTER-NAME.