Hello to all Elephant developers, and many words of thanks for what appears to be a useful and well thought out library!
I've recently started a project which will (I hope) make some good use of Elephant. I'm still wrapping my head around things, so go easy on me. As a show of good will, here's my first attempt at adding something to elephant. Suppose you have a class like this: (defclass test-user () ((name :reader name :initarg :name :type string :index t) (timestamp :reader timestamp :initform (get-universal-time) :type integer :index t)) (:metaclass persistent-metaclass)) (defun make-some-users () (let ((n 0) (*auto-commit* t)) (dotimes (i 1000) (make-instance 'test-user :name (format nil "User name ~D" (incf n)))) (get-instances-by-range 'test-user 'name "User name 10" "User name 20"))) (make-some-users) If you try to do something like (length (get-instances-by-range 'test-user 'timestamp 0 999999999999)) ==> 1000 It succeeds. But if you try on the name, (get-instances-by-range 'test-user 'name "User name 10" "User name 11") ==> Argument X is not a REAL: "User name 10" [Condition of type SIMPLE-TYPE-ERROR] Because the get-instances-by-range function (needlessly) assumes that the objects being returned can be compared with numeric equality. This little snippet fixes this problem: (change from the 0.6 distribution) =============cut================================================ (defun find-slot-type (class idx-name) (flet ((candidate-slot-p (slot) (and (eq (type-of slot) 'persistent-effective-slot-definition) (slot-value slot 'indexed) (eq (slot-definition-name slot) idx-name)))) (find-if #'candidate-slot-p (class-slots class)))) (defun find-index-comparison-function (class index) (let ((type (sb-pcl:slot-definition-type (find-indexed-slot class index)))) (cond ((subtypep type 'number) #'<=) ((subtypep type 'string) #'string<=) (t ;; We'll fall back to numerical, though it's not clear to ;; me that this is sensible. Maybe should just signal an error, ;; and force users to declare :type on all indexed slots? #'<=)))) (defmethod get-instances-by-range ((class persistent-metaclass) idx-name start end) (let ((comparison (find-index-comparison-function class idx-name))) (with-inverted-cursor (cur class idx-name) (labels ((next-range (instances) (multiple-value-bind (exists? skey val pkey) (cursor-pnext-nodup cur) (declare (ignore pkey)) (if (and exists? (funcall comparison skey end)) (next-in-range skey (cons val instances)) (nreverse instances)))) (next-in-range (key instances) (multiple-value-bind (exists? skey val pkey) (cursor-pnext-dup cur) (declare (ignore pkey skey)) (if exists? (next-in-range key (cons val instances)) (progn (cursor-pset-range cur key) (next-range instances)))))) (multiple-value-bind (exists? skey val pkey) (cursor-pset-range cur start) (declare (ignore pkey)) (if (and exists? (funcall comparison skey end)) (next-in-range skey (cons val nil)) nil)))))) =============cut================================================ Note that unfortunately FIND-INDEX-COMPARISON-FUNCTION makes use of SB-PCL:SLOT-DEFINITION-TYPE; I have not conditionalized this for other lisps, nor do I really know what forms are appropriate in any other lisps. Obviously, it is possible to extend this scheme to let users register their own comparison functions for more complex types; I'll let you judge if this is worth the effort. Hoping this helps someone, somewhere. If this was already covered in some other way, then consider this message a bug report on the documentation instead. :-) Alain Picard -- Please read about why Top Posting is evil at: http://en.wikipedia.org/wiki/Top-posting and http://www.dickalba.demon.co.uk/usenet/guide/faq_topp.html Please read about why HTML in email is evil at: http://www.birdhouse.org/etc/evilmail.html _______________________________________________ elephant-devel site list elephant-devel@common-lisp.net http://common-lisp.net/mailman/listinfo/elephant-devel