Книга: 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.
- Binary Files
- Binary Format Basics
- Strings in Binary Files
- Composite Structures
- Designing the Macros
- Making the Dream a Reality
- Reading Binary Objects
- Writing Binary Objects
- Adding Inheritance and Tagged Structures
- Keeping Track of Inherited Slots
- Tagged Structures
- Primitive Binary Types
- The Current Object Stack
- 4.4.4 The Dispatcher
- About the author
- Chapter 7. The state machine
- Appendix E. Other resources and links
- Example NAT machine in theory
- The final stage of our NAT machine
- Compiling the user-land applications
- The conntrack entries
- Untracked connections and the raw table
- Basics of the iptables command
- Other debugging tools
- Setting up user specified chains in the filter table