[elephant-devel] get-instances-by-range should work with string types

Alain Picard Alain.Picard at memetrics.com
Fri Nov 17 10:18:38 UTC 2006


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



More information about the elephant-devel mailing list