Comments on SRFI-13 reference implementation
Brad Lucier
(16 Nov 2000 20:05 UTC)
|
Re: Comments on SRFI-13 reference implementation
shivers@xxxxxx
(16 Dec 2000 02:42 UTC)
|
Re: Comments on SRFI-13 reference implementation Brad Lucier (16 Dec 2000 03:16 UTC)
|
Re: Comments on SRFI-13 reference implementation
Brad Lucier
(16 Dec 2000 04:55 UTC)
|
list of alphas
shivers@xxxxxx
(16 Dec 2000 16:05 UTC)
|
> string-index, string-index-right, string-skip, string-skip-right, string-count: > Add internal routines that do the work but no error checking. Call the > string arg s for consistency. > > There are no module-internal calls to STRING-COUNT. > > Adding internal routines for string-index & string-index-right would only > speed up string-titlecase & string-tokenize... but would slow down other > code's use of string-index by the cost of the procedure call from string-index > to the internal %string-index Well, it's a tail call from string-index to %string-index with the same arguments, so in Gambit it's a jump. Doing all the the optional argument parsing and checking that the arguments are reasonable takes a lot longer than this. (Although in Gambit, optional arguments are quite fast.) For example, my checking code is (##define-macro (macro-check-string-start-end s start end form expr) (define (flat x) (if (pair? x) (cons (car x) (flat (cdr x))) (list x))) `(if (##string? ,s) (let ((,end (if (absent-object? ,end) (string-length ,s) ,end))) (if (##fixnum? ,start) (if (##fixnum.>= ,start 0) (if (##fixnum? ,end) (if (and (##fixnum.<= ,start ,end) (##fixnum.<= ,end (string-length ,s))) ,expr ,(if (list? form) `(##trap-check-range ',(car form) ,@(cdr form)) `(##trap-check-range* ',(car form) ,@(flat (cdr form))))) (if (##bignum? ,end) ,(if (list? form) `(##trap-check-range ',(car form) ,@(cdr form)) `(##trap-check-range* ',(car form) ,@(flat (cdr form)))) ,(if (list? form) `(##trap-check-exact-int ',(car form) ,@(cdr form)) `(##trap-check-exact-int* ',(car form) ,@(flat (cdr form)))))) ,(if (list? form) `(##trap-check-range ',(car form) ,@(cdr form)) `(##trap-check-range* ',(car form) ,@(flat (cdr form))))) (if (##bignum? ,start) ,(if (list? form) `(##trap-check-range ',(car form) ,@(cdr form)) `(##trap-check-range* ',(car form) ,@(flat (cdr form)))) ,(if (list? form) `(##trap-check-exact-int ',(car form) ,@(cdr form)) `(##trap-check-exact-int* ',(car form) ,@(flat (cdr form))))))) ,(if (list? form) `(##trap-check-string ',(car form) ,@(cdr form)) `(##trap-check-string* ',(car form) ,@(flat (cdr form)))))) in (define (string-index s criterion #!optional (start 0) (end (macro-absent-object))) (macro-check-string-start-end s start end (string-index criterion s start end) (##string-index s criterion start end))) Each individual check is fast (a few hardware instructions at most), but there are 7 of them, 8 if you have to get end from (string-length s). So I'd rather do the extra jump for string-index than the extra checks for the routines that use it. > string-concatenate/shared, string-concatenate, string-join: > Need to check strings. > > There's no cheap way to check an alpha list to ensure that all elements > are alphas. So I don't check these. Well, my version reads (##define-macro (##every? proc lst) `(let ((proc ,proc)) (let loop ((lst ,lst)) (or (null? lst) (and (proc (car lst)) (loop (cdr lst))))))) (define (string-concatenate/shared strings) (if (list? strings) (if (##every? string? strings) (let lp ((strings strings) (nchars 0) (first #f)) (cond ((pair? strings) ; Scan the args, add up total (let* ((string (car strings)) ; length, remember 1st (tail (cdr strings)) ; non-empty string. (slen (string-length string))) (if (zero? slen) (lp tail nchars first) (lp tail (+ nchars slen) (or first strings))))) ((zero? nchars) "") ;; Just one non-empty string! Return it. ((= nchars (string-length (car first))) (car first)) (else (let ((ans (make-string nchars))) (let lp ((strings first) (i 0)) (if (pair? strings) (let* ((s (car strings)) (slen (string-length s))) (##string-copy! ans i s 0 slen) (lp (cdr strings) (+ i slen))))) ans)))) (error "Not every element of strings is a string: (string-concatenate/shared " strings ")")) (error "strings is not a list: (string-concatenate/shared " strings ")"))) Considering the amount of stuff you actually do with the contents of these strings, and how the routine is going to blow up if it isn't a list or if all the entries are not strings, I'd check it. I suppose since you're walking the list anyway in lp, you could check it inside the cond and get rid of the extra two traversals of the list (for list? and ##every?). Brad