Книга: Practical Common Lisp

The Current Object Stack

The Current Object Stack

One last bit of functionality you'll need in the next chapter is a way to get at the binary object being read or written while reading and writing. More generally, when reading or writing nested composite objects, it's useful to be able to get at any of the objects currently being read or written. Thanks to dynamic variables and :around methods, you can add this enhancement with about a dozen lines of code. To start, you should define a dynamic variable that will hold a stack of objects currently being read or written.

(defvar *in-progress-objects* nil)

Then you can define :around methods on read-object and write-object that push the object being read or written onto this variable before invoking CALL-NEXT-METHOD.

(defmethod read-object :around (object stream)
(declare (ignore stream))
(let ((*in-progress-objects* (cons object *in-progress-objects*)))
(call-next-method)))
(defmethod write-object :around (object stream)
(declare (ignore stream))
(let ((*in-progress-objects* (cons object *in-progress-objects*)))
(call-next-method)))

Note how you rebind *in-progress-objects* to a list with a new item on the front rather than assigning it a new value. This way, at the end of the LET, after CALL-NEXT-METHOD returns, the old value of *in-progress-objects* will be restored, effectively popping the object of the stack.

With those two methods defined, you can provide two convenience functions for getting at specific objects in the in-progress stack. The function current-binary-object will return the head of the stack, the object whose read-object or write-object method was invoked most recently. The other, parent-of-type, takes an argument that should be the name of a binary object class and returns the most recently pushed object of that type, using the TYPEP function that tests whether a given object is an instance of a particular type.

(defun current-binary-object () (first *in-progress-objects*))
(defun parent-of-type (type)
(find-if #'(lambda (x) (typep x type)) *in-progress-objects*))

These two functions can be used in any code that will be called within the dynamic extent of a read-object or write-object call. You'll see one example of how current-binary-object can be used in the next chapter.[270]

Now you have all the tools you need to tackle an ID3 parsing library, so you're ready to move onto the next chapter where you'll do just that.

Оглавление книги


Генерация: 7.320. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз