You can traverse BTrees with cursors. Open one with
* (defvar curs (make-cursor *friends-birthdays*)) => CURS
and close it with
* (cursor-close curs) => NIL
Typically one opens a cursor within an transaction. Cursors should be closed after they are done with, before the enclosing transaction is closed. This is encapsulated in the idiom
* (with-transaction () (with-btree-cursor (curs *friends-birthdays*) ...))
The cursor movement functions in general return three values: a boolean indicating whether a pair was found / available, the key, and the value. For example:
* (cursor-current curs) ; Not initialized! => NIL * (cursor-first curs) => T "Andrew" 2429071200 * (cursor-next curs) => T "Ben" 2407298400 * (cursor-next curs) ; No more entries! => NIL
cursor-* functions include:
prev, last, current,
set (set to a key),
set-range (get the first key greater or
equal to the key),
get-both (set to a key / value pair),
get-both-range (set to a key / value pair with value greater or
equal to a particular value), et cetera. Details can be found at
Cursors. In general if a movement command fails, the cursor is
invalidated, and has to be repositioned.
Internally, BTree keys and values are sorted by an ad-hoc C function. It is capable of sorting most numbers (floats are fine, integers up to 64 bits) and strings (case-insensitively, though Unicode users will find their strings sorted code-point-order which is case sensitive.) Other values it sorts byte-lexically, which is usually meaningless in Lisp.
Finally, one can also insert and delete by cursor, and there is a
map-btree function, which functions analogously to the
maphash CL function.