可変配列
今試していることで可変の配列が使いたくなったので、用意。
;; indexが(length vector)の範囲を越えている場合は、自動で配列を拡張 ;; vectorはsymbolである必要がある (defmacro assure-access (vector index) `(locally (declare ,@(if (symbolp index) `((fixnum ,index))) (vector ,vector) (optimize (safety 0))) (when (>= ,index (length ,vector)) (setf ,vector (adjust-array ,vector (* ,index 2)))) ,vector)) > (defvar as #(1)) > (assure-access as 2) --> #(1 0 0 0) > (setf (aref (assure-access as 5) 5) #\a) --> #\a > as --> #(1 0 0 0 0 #\a 0 0 0 0)
このままだと長いのでリードマクロを定義。
ついでに、範囲チェックをしない版も選択できるようにしておく。
(flet ((split (str) (dotimes (i (length str)) (case (char str i) ((#\? #\#) (return-from split (values (read-from-string (subseq str 0 i)) (char str i) (read-from-string (subseq str (1+ i)))))))) (error "string ~S don't include delimiter(#\\? or #\\#)" str))) (set-macro-character #\@ (lambda (stream c) (declare (ignore c)) (multiple-value-bind (array delim index) (split (s (read stream))) (if (char= delim #\?) `(aref (assure-access ,array ,index) ,index) `(aref ,array ,index)))))) ;;;; ;; @as?index --> (aref (assure-access as index) index) ;; @as#index --> (aref as index) > (setf @as#100 "100") --> Error > (setf @as?100 "100") --> "100"
とりあえず、開発で試したいだけなので、これで充分だろう。
追記
「可変」というよりは、範囲外のアクセスをしてもエラーを出さない配列。末尾に順々に追加したいだけなら、vector-push-extendを使えばいい。
追記2
sという未定義の関数*1を使っていたので、修正。
ついでに、symbol以外も扱えるように変更(ex. @(car '(#(1) 2 (3)))?10))。
正しく使うことが前提なので、エラーチェックは無し。
(defmacro assure-access (vector index) `(locally (declare ,@(if (symbolp index) `((fixnum ,index))) ,@(if (symbolp vector) `((vector ,vector))) (optimize (safety 0))) (when (>= ,index (length ,vector)) (setf ,vector (adjust-array ,vector (* ,index 2)))) ,vector)) (flet ((split (str) (dotimes (i (length str)) (case (char str i) ((#\? #\#) (return-from split (values (read-from-string (subseq str 0 i)) (char str i) (read-from-string (subseq str (1+ i)))))))) (error "string ~S didn't include delimiter(#\\? or #\\#)" str))) (set-macro-character #\@ (lambda (stream c) (declare (ignore c)) (let ((exp (read stream))) (multiple-value-bind (array delim index) (if (symbolp exp) (split (symbol-name exp)) (values exp (read-char stream) (read stream))) (if (char= delim #\?) `(aref (assure-access ,array ,index) ,index) `(aref ,array ,index)))))))