# HG changeset patch # User Steve Losh # Date 1636596780 18000 # Node ID 55c796d79111805e483c3dc05098d3ebd69ccf7c # Parent eb9bf5de0279db3724637b1fe1afdbba12ab8e52 Add `window` and a few other things that have been sitting around diff -r eb9bf5de0279 -r 55c796d79111 DOCUMENTATION.markdown --- a/DOCUMENTATION.markdown Mon Jul 12 22:03:01 2021 -0400 +++ b/DOCUMENTATION.markdown Wed Nov 10 21:13:00 2021 -0500 @@ -179,6 +179,33 @@ +## Package `LOSH.BASE` + +A few utilities re-exported from Alexandria, plus some other basic stuff. + +### `MKSTR` (function) + + (MKSTR &REST ARGS) + +### `SYMB` (function) + + (SYMB &REST ARGS) + +### `TIMING` (macro) + + (TIMING (&KEY (TIME :RUN) (RESULT-TYPE 'INTEGER)) + &BODY + BODY) + +Execute `body`, discard its result, and return the time taken. + + `time` must be one of `:run` or `:real`. + + `result-type` must be `integer` (which will return internal time units) or + `rational`/`single-float`/`double-float` (which will return seconds). + + + ## Package `LOSH.BITS` Utilities for low-level bit stuff. @@ -1181,7 +1208,7 @@ ### `PLOT` (function) - (PLOT DATA &KEY (STYLE :LINESPOINTS) (FILE plot.pdf)) + (PLOT DATA &KEY (STYLE :LINESPOINTS) (FILE plot.pdf) (LOGSCALE NIL)) Plot `data` with gnuplot. @@ -2596,8 +2623,9 @@ completes. If false, it will return immediately and allow the program to run asynchronously. - `input` must be a character input stream, a string, or `nil`. If non-`nil` - its contents will be sent to the program as its standard input. + `input` must be a character input stream, a string, a list of strings, or + `nil`. If non-`nil` its contents will be sent to the program as its standard + input. A list of strings will be sent separated by newlines. `result-type` must be one of: diff -r eb9bf5de0279 -r 55c796d79111 make-docs.lisp --- a/make-docs.lisp Mon Jul 12 22:03:01 2021 -0400 +++ b/make-docs.lisp Wed Nov 10 21:13:00 2021 -0500 @@ -4,6 +4,7 @@ (list "LOSH" "LOSH.ARRAYS" + "LOSH.BASE" "LOSH.BITS" "LOSH.CHILI-DOGS" "LOSH.CLOS" diff -r eb9bf5de0279 -r 55c796d79111 src/debugging.lisp --- a/src/debugging.lisp Mon Jul 12 22:03:01 2021 -0400 +++ b/src/debugging.lisp Wed Nov 10 21:13:00 2021 -0500 @@ -210,6 +210,31 @@ (stop-profiling)))) +(defmacro timing ((&key (time :run) (result-type 'integer)) &body body) + "Execute `body`, discard its result, and return the time taken. + + `time` must be one of `:run` or `:real`. + + `result-type` must be `integer` (which will return internal time units) or + `rational`/`single-float`/`double-float` (which will return seconds). + + " + (with-gensyms (start end result) + `(let ((,start ,(ecase time + (:run '(get-internal-run-time)) + (:real '(get-internal-real-time))))) + (progn ,@body) + (let* ((,end ,(ecase time + (:run '(get-internal-run-time)) + (:real '(get-internal-real-time)))) + (,result (- ,end ,start))) + ,(ecase result-type + (integer `,result) + (rational `(/ ,result internal-time-units-per-second)) + (single-float `(coerce (/ ,result internal-time-units-per-second) 'single-float)) + (double-float `(coerce (/ ,result internal-time-units-per-second) 'double-float))))))) + + (defmacro gimme (n &body body) `(iterate (repeat ,n) (collect (progn ,@body)))) diff -r eb9bf5de0279 -r 55c796d79111 src/gnuplot.lisp --- a/src/gnuplot.lisp Mon Jul 12 22:03:01 2021 -0400 +++ b/src/gnuplot.lisp Wed Nov 10 21:13:00 2021 -0500 @@ -105,7 +105,7 @@ ;;;; Convenience Wrappers ----------------------------------------------------- -(defun plot (data &key (style :linespoints) (file "plot.pdf")) +(defun plot (data &key (style :linespoints) (file "plot.pdf") (logscale nil)) "Plot `data` with gnuplot. Convenience wrapper around the gnuplot functions. This is only intended for @@ -116,8 +116,8 @@ (with-gnuplot () (gnuplot-data "$data" data) (gnuplot-format "set terminal pdfcairo size 10in, 8in - set output '~A' - plot $data using 1:2 with ~A" - file - (string-downcase (symbol-name style))))) - + set output '~A'" + file) + (when logscale + (gnuplot-format "set logscale y")) + (gnuplot-format "plot $data using 1:2 with ~A" (string-downcase (symbol-name style))))) diff -r eb9bf5de0279 -r 55c796d79111 src/iterate.lisp --- a/src/iterate.lisp Mon Jul 12 22:03:01 2021 -0400 +++ b/src/iterate.lisp Wed Nov 10 21:13:00 2021 -0500 @@ -1112,3 +1112,77 @@ "Sugar for `(if-first-iteration nil expr)`." `(if-first-iteration nil ,expr)) + +(defmacro-clause (FOR vars WINDOW size ON sequence-or-length + &optional START start END end) + "Iterate a window over a sequence. + + The exact nature of the iteration depends on the form of `vars`: + + If `vars` is a symbol, or a list of a single symbol, it will be bound to + a `size`-element `subseq` of `sequence-or-length` on each iteration. In this + case, `sequence-or-length` must be a sequence. + + If `vars` is a list of two symbols `(start end)`, they will be bound to the + start and end bounding indices of a a `size`-element window of + `sequence-or-length` on each iteration. In this case, `sequence-or-length` + can be a sequence (in which case its `length` is used) or an integer. + + If `vars` is a list of three symbols `(subseq start end)`, both of the above + bindings will happen. In this case, `sequence-or-length` must be a sequence. + + If `start` or `end` are given, they are used to restrict the range of the + sequence being iterated over. + + `generate` is not supported at this time. + + Examples: + + (iterate (with string = \"abcdefg\") + (for x :window 2 :on string) + (collect x)) + ; => (\"ab\" \"bc\" \"cd\" \"de\" \"ef\" \"fg\") + + (iterate (with string = \"abcdefg\") + (for (start end) :window 2 :on 5) + (collect (subseq string start end))) + ; => (\"ab\" \"bc\" \"cd\" \"de\") + + (iterate (with string = \"abcdefg\") + (for (x start end) :window 2 :on string) + (collect (list x start end))) + ; => ((\"ab\" 0 2) (\"bc\" 1 3) (\"cd\" 2 4) (\"de\" 3 5) (\"ef\" 4 6) (\"fg\" 5 7)) + + (iterate (with string = \"abcdefg\") + (for (x start end) :window 2 :on string :start 1 :end 5) + (collect (list x start end))) + ; => ((\"bc\" 1 3) (\"cd\" 2 4) (\"de\" 3 5)) + + " + (setf vars (ensure-list vars)) + (alexandria:with-gensyms (n seq s) + (let (subseq% start% end%) + (ecase (length vars) + (1 (setf subseq% (first vars) + start% (gensym "START") + end% (gensym "END"))) + (2 (setf subseq% nil + start% (first vars) + end% (second vars))) + (3 (setf subseq% (first vars) + start% (second vars) + end% (third vars)))) + `(progn + (with ,s = ,(or start 0)) + (with ,n = ,size) + (with ,seq = ,sequence-or-length) + (for ,start% :from ,s) + (for ,end% :from (+ ,n ,s) :to + ,(cond + (end end) + (subseq% `(length ,seq)) + (t `(etypecase ,seq + (integer ,seq) + (sequence (length ,seq)))))) + ,@(when subseq% + `((for ,subseq% = (subseq ,seq ,start% ,end%)))))))) diff -r eb9bf5de0279 -r 55c796d79111 src/package.lisp --- a/src/package.lisp Mon Jul 12 22:03:01 2021 -0400 +++ b/src/package.lisp Wed Nov 10 21:13:00 2021 -0500 @@ -19,6 +19,7 @@ (defpackage :losh.base (:use :cl) + (:documentation "A few utilities re-exported from Alexandria, plus some other basic stuff.") (:import-from :alexandria :compose :curry :rcurry :with-gensyms :once-only @@ -29,6 +30,8 @@ :with-gensyms :once-only :ensure-list + :timing ; both profiling and iterate use this symbol + :symb :mkstr)) @@ -346,6 +349,7 @@ :unless-first-time :when-first-iteration :when-first-time + :window :within-radius )) @@ -418,6 +422,7 @@ :prl :shut-up :structural-string + :timing )) @@ -453,6 +458,7 @@ (defpackage-inheriting :losh ( + :losh.base :losh.arrays :losh.bits :losh.chili-dogs diff -r eb9bf5de0279 -r 55c796d79111 src/shell.lisp --- a/src/shell.lisp Mon Jul 12 22:03:01 2021 -0400 +++ b/src/shell.lisp Wed Nov 10 21:13:00 2021 -0500 @@ -10,8 +10,9 @@ completes. If false, it will return immediately and allow the program to run asynchronously. - `input` must be a character input stream, a string, or `nil`. If non-`nil` - its contents will be sent to the program as its standard input. + `input` must be a character input stream, a string, a list of strings, or + `nil`. If non-`nil` its contents will be sent to the program as its standard + input. A list of strings will be sent separated by newlines. `result-type` must be one of: @@ -31,6 +32,7 @@ (ctypecase input (string (setf input (make-string-input-stream input))) (vector (setf input (flexi-streams:make-in-memory-input-stream input))) + (cons (setf input (make-string-input-stream (format nil "~{~A~^~%~}" input)))) ; todo make this not cons as much (stream) (null)) (when (not wait)