Hello all,
I have a question that will require quite a bit of an explanation. I hope
this won't be too long =P
I have this table object that holds column objects, and a collection of
records.
Each record is an array of values.
I need to access specific fields of these records.
So here goes the standard code :
(defun field-value (record column-name)
(aref (data record) (get-column-index (table record) column-name)))
(field-value record 'day) ;retreives the value of the day field on this
record
This is fine, but i have lots of records and need to make it as fast as
possible.
It seems that i can achieve double performances by doing a direct array
access, bypassing the column lookup.
So i made these two macros :
(defmacro with-bindable-columns ((&rest var-and-column-names) table-or-index
&body body)
(let ((table (gensym "TABLE-OR-INDEX")))
`(let* ((,table ,table-or-index)
,@(loop for var-and-column-name in var-and-column-names
when (listp var-and-column-name)
collect (list (conc-symbol (first var-and-column-name)
"-idx")
`(get-column-index ,table ',(second
var-and-column-name)))
when (symbolp var-and-column-name)
collect (list (conc-symbol var-and-column-name "-idx")
`(get-column-index ,table
',var-and-column-name))))
,@body)))
(defmacro bind-vars ((&rest vars) data &body body)
`(let ,(loop for var in vars
collecting `(,var (aref ,data ,(conc-symbol var "-idx"))))
,@body))
Here is a sample usage :
(defun get-first-date ()
(let ((lowest nil))
(with-bindable-columns (day)
*stats-table*
(do-table-records (*stats-table* record)
(bind-vars (day)
(data record)
(when (or (null lowest)
(< day lowest))
(setf lowest day)))))
lowest))
My problem here is the name to give to those -idx variables.
In order to avoid variable capture, i would like to give these a GENSYM
name.
The name would be created in the with-bindable-columns macro and used in the
bin-vars macro.
And of course, i'm clueless as how to do this.
Would it be possible to tell the compiler sometyhing like : "hey ! this
_compiler_ variable holds some data that will only be available within the
lexical scope of that macro expansion" ?
Thanks in advance,
Sacha
"Sacha" <··@address.spam> writes:
> (defmacro with-bindable-columns ((&rest var-and-column-names) table-or-index
> &body body)
> (let ((table (gensym "TABLE-OR-INDEX")))
> `(let* ((,table ,table-or-index)
> ,@(loop for var-and-column-name in var-and-column-names
> when (listp var-and-column-name)
> collect (list (conc-symbol (first var-and-column-name)
> "-idx")
> `(get-column-index ,table ',(second
> var-and-column-name)))
> when (symbolp var-and-column-name)
> collect (list (conc-symbol var-and-column-name "-idx")
> `(get-column-index ,table
> ',var-and-column-name))))
> ,@body)))
>
> (defmacro bind-vars ((&rest vars) data &body body)
> `(let ,(loop for var in vars
> collecting `(,var (aref ,data ,(conc-symbol var "-idx"))))
> ,@body))
>
> Here is a sample usage :
>
> (defun get-first-date ()
> (let ((lowest nil))
> (with-bindable-columns (day)
> *stats-table*
> (do-table-records (*stats-table* record)
> (bind-vars (day)
> (data record)
> (when (or (null lowest)
> (< day lowest))
> (setf lowest day)))))
> lowest))
>
> My problem here is the name to give to those -idx variables.
> In order to avoid variable capture, i would like to give these a GENSYM
> name.
> The name would be created in the with-bindable-columns macro and used in the
> bin-vars macro.
> And of course, i'm clueless as how to do this.
> Would it be possible to tell the compiler sometyhing like : "hey ! this
> _compiler_ variable holds some data that will only be available within the
> lexical scope of that macro expansion" ?
MACROLET
--
__Pascal Bourguignon__ http://www.informatimago.com/
Pour moi, la grande question n'a jamais �t�: �Qui suis-je? O� vais-je?�
comme l'a formul� si adroitement notre ami Pascal, mais plut�t:
�Comment vais-je m'en tirer?� -- Jean Yanne
>> Here is a sample usage :
>>
>> (defun get-first-date ()
>> (let ((lowest nil))
>> (with-bindable-columns (day)
>> *stats-table*
>> (do-table-records (*stats-table* record)
>> (bind-vars (day)
>> (data record)
>> (when (or (null lowest)
>> (< day lowest))
>> (setf lowest day)))))
>> lowest))
>>
>> My problem here is the name to give to those -idx variables.
>> In order to avoid variable capture, i would like to give these a GENSYM
>> name.
>> The name would be created in the with-bindable-columns macro and used in
>> the
>> bin-vars macro.
>> And of course, i'm clueless as how to do this.
>> Would it be possible to tell the compiler sometyhing like : "hey ! this
>> _compiler_ variable holds some data that will only be available within
>> the
>> lexical scope of that macro expansion" ?
>
> MACROLET
> --
> __Pascal Bourguignon__ http://www.informatimago.com/
Here is the modified version of this macro :
(defmacro with-bindable-columns ((&rest var-and-column-names) table-or-index
&body body)
(let ((table (gensym "TABLE-OR-INDEX"))
(var-indexes nil))
(flet ((gen-idx-var (var-name)
(let ((result (gensym (concatenate 'string (symbol-name
var-name) "-IDX"))))
(push result var-indexes)
(push var-name var-indexes)
result)))
`(let* ((,table ,table-or-index)
,@(loop for var-and-column-name in var-and-column-names
if (listp var-and-column-name)
collect (list (gen-idx-var (first var-and-column-name))
`(get-column-index ,table ',(second
var-and-column-name)))
else if (symbolp var-and-column-name)
collect (list (gen-idx-var var-and-column-name)
`(get-column-index ,table
',var-and-column-name))))
(macrolet ((bind-vars ((&rest vars) data &body body)
`(let ,(loop for var in vars
collecting `(,var (aref ,data ,(getf
',var-indexes var))))
,@body)))
,@body)))))
Pretty hairy considering the double backquote syntax.
Thanks a lot Pascal.
Sacha