Garten is a library that provides a generic interface for building collections. It was inspired by things like the Growable trait in scala or the StringBuilder class from Java.
Growers
A grower is an object which can be fed items to grow a data structure, and once all the desired items have been added a final result (or fruit) can be obtained.
make-grower
(type &key)
Make a grower object that can be used to "grow" a collection. The returned object must define the FEED method and in most cases should define the FRUIT method and RESET-GROWER methods.
The TYPE argument is an object for which a MAKE-GROWER method is specialized, usually a symbol.
feed
(grower item)
feed-iterable
(grower iterable)
Add all items from ITERABLE into GROWER. The default method just iterates over iterable and calls FEED with each item.
The function is generic so that GROWERs can use more efficient methods if desired.
fruit
(grower)
Return the final result of a grower. A grower doesn't necessarily need this to be defined if there is another way to access the result, but in most cases it should be supplied.
It is undefined what happens if this is called more than once for the same grower. Or more specifically, the behavior depends on the grower implementation.
reset-grower
(grower)
Reset a grower to an empty collection.
This can be used to recycle data structures if the result is no longer used. But it is undefined whether it is safe to use the result of FRUIT after RESET-GROWER has been called on the grower that generated it.
It also may not be defined for all growers.
feed*
(grower &rest items)
grower
Base class for specialized growers.
Note that not all grower's will be subclasses of GROWER.
grower-state
The state of the grower. By default this is what is returned by FRUIT.
fruit
((grower grower))
Implementations
Garten provides the following basic built in implementations of the grower interface:
type argument | result type | key args | feed argument | backing-type |
'vector | vector | :element-type :size :adjustable | element | vector |
'string | string | :element-type | character | string-stream |
'hash-table | hash-table | same as for make-hashtable | cons cell | hash-table |
'list | list | :prepend | element | list-grower or prepend-list-grower |
:plist | list (plist) | :default | cons cell | plist-grower |
:alist | list (alist) | cons cell | prepend-list-grower |
reset-grower
is defined for all of the above.
The keyword arguments for make-grower have the following meanings.
- :element-type
- The type of the element stored in the collection. For key-value collections it is the type of the value.
- :size
- The initial size to allocate for the container. Useful for things like vectors and hash-tables. For some data structures it may not be possible to add more items than the amount specified by size.
- :adjustable
- Whether or not the underlying container's size can be adjustable. Defaults to true.
- :prepend
- Whether or not elements should be prepended to the front of a sequence rather than the end. Defaults to false
- :default
- For plists, if a non-cons value is supplied, the value is assumed to be a key, and default is used as the value. Defaults to nil.
Note that for key-value mapping structures, the key and value must be supplied as a cons cell with the key as the CAR and the value as the CDR.
The feed
and feed-iterable
functions can also be used for any stream with either
elements of the streams element-type, or sequences of elements of the streams element-type.
They can also be used on lists, although they are linear operations, since they use nconc.
List Classes
list-grower
grower-state
A queue of items added. This makes insertion at the end a constant time operation.
plist-grower
default-value
The default value to store in the plist if the fed item isn't a cons cell.
prepend-list-grower