Advertisement
Guest User

Untitled

a guest
Aug 7th, 2015
302
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 5.66 KB | None | 0 0
  1. ;;;
  2. ;;; COLLECTING THINGS
  3. ;;;
  4.  
  5. (defparameter *pouch* nil)
  6.  
  7. (defun funcall-collector (callback)
  8.   (declare (type (function (&optional T)) callback))
  9.   (cons
  10.    (lambda (x) (funcall callback x))
  11.    (lambda () (funcall callback))))
  12.  
  13. (defun queue-collector ()
  14.   (let ((q (serapeum:queue)))
  15.     (cons
  16.      (lambda (x) (serapeum:enq x q))
  17.      (lambda () (serapeum:qlist q)))))
  18.  
  19. (defun vector-collector (size)
  20.   (let ((v (make-array size :fill-pointer 0 :adjustable nil)))
  21.     (cons
  22.      (lambda (x) (vector-push x v))
  23.      (lambda () v))))
  24.  
  25. (defun take (value &optional (cons *pouch*))
  26.   (prog1 value
  27.     (funcall (car cons) value)))
  28.  
  29. (defun loot (&optional (cons *pouch*))
  30.   (funcall (cdr cons)))
  31.  
  32. (defun call-while-hoarding (function &key (result-type 'list) size)
  33.   (let ((*pouch* (case result-type
  34.                    (list (queue-collector))
  35.                    (vector (if size
  36.                                (vector-collector size)
  37.                                (unbounded-vector-collector)))
  38.                    (t (etypecase result-type
  39.                         (function (funcall-collector result-type)))))))
  40.     (funcall function)))
  41.  
  42. (defmacro hoarding ((&rest args) &body body)
  43.   ;; parse: name is optional
  44.   (let* ((name-p (not (keywordp (first args))))
  45.          (args (if name-p (cdr args) args))
  46.          (name (when name-p (car args))))
  47.     `(funcall #'call-while-hoarding
  48.               (lambda ()
  49.                 ,@(if name
  50.                       `((let ((,name *pouch*)) ,@body))
  51.                       body))
  52.               ,@args)))
  53. ;;;
  54. ;;; SPLIT BY N
  55. ;;;
  56.  
  57. (defun split-n (sequence n
  58.                 &key last sharedp (result-type 'list)
  59.                 &aux (size (length sequence)))
  60.   (check-type sequence sequence)
  61.   (check-type n (integer 1 *))
  62.   (ecase last
  63.     ((nil t) (setf last :undersized))
  64.     ((:truncated :oversized :undersized) last))
  65.   (let ((slice
  66.           (etypecase sequence
  67.             (vector
  68.              (let* ((type (array-element-type sequence))
  69.                     (beg 0)
  70.                     (end n)
  71.                     (copy (if sharedp
  72.                               (lambda (b e)
  73.                                 (make-array (- e b)
  74.                                             :displaced-to sequence
  75.                                             :displaced-index-offset b
  76.                                             :element-type type))
  77.                               (lambda (b e)
  78.                                 (subseq sequence b e)))))
  79.                (lambda (&optional tail)
  80.                  (if tail
  81.                      (when (< beg size)
  82.                        (funcall copy beg size))
  83.                      (prog1 (funcall copy beg end)
  84.                        (setf beg end
  85.                              end (+ n end)))))))
  86.             (list
  87.              (let ((copy
  88.                      (if sharedp #'identity #'copy-list))
  89.                    (current sequence))
  90.                (lambda (&optional tail)
  91.                  (when current
  92.                    (if tail
  93.                        (funcall copy current)
  94.                        (prog1 (subseq current 0 n)
  95.                          (setf current (nthcdr n current)))))))))))
  96.     (multiple-value-bind (count remainder) (truncate size n)
  97.       (hoarding (:result-type result-type
  98.                  :size (ecase last
  99.                          (:undersized (+ count (signum remainder)))
  100.                          (:oversized count)
  101.                          (:truncated count)))
  102.         (dotimes (_ (ecase last
  103.                       (:undersized count)
  104.                       (:oversized (1- count))
  105.                       (:truncated count)))
  106.           (take (funcall slice)))
  107.         (let ((residual (funcall slice t)))
  108.           (case last
  109.             ((:undersized :oversized)
  110.              (when residual (take residual))
  111.              (values (loot)
  112.                      (cond
  113.                        ((zerop remainder) nil)
  114.                        ((eq last :undersized) remainder)
  115.                        (t (min size (+ remainder n))))))
  116.             (:truncated (values (loot)
  117.                                 residual))))))))
  118.  
  119. ;;;
  120. ;;; DO-BATCHES
  121. ;;;
  122.  
  123. (defmacro do-batches ((name args &optional result-form) &body body)
  124.   (check-type name symbol)
  125.   (destructuring-bind (sequence n &key last sharedp) args
  126.     (let ((call
  127.             `(funcall #'split-n ,sequence ,n
  128.                       :last ,last
  129.                       :sharedp ,sharedp
  130.                       :result-type (lambda (&optional ,name)
  131.                                      (if ,name
  132.                                          (progn ,@body)
  133.                                          ,result-form)))))
  134.       (if result-form
  135.           call
  136.           `(nth-value 1 ,call)))))
  137.  
  138. ;; example
  139.  
  140. (let* ((list '(1 2 3 4 5 6 7 8 9 10))
  141.        (sub (nthcdr 8 list)))
  142.   (eq sub
  143.       (do-batches (x (list 4 :last :truncated :sharedp t))
  144.         (print x))))
  145.  
  146. ;; tests
  147.  
  148. (trace split-n)
  149.  
  150. (with-open-file (*trace-output*
  151.                  #P"/tmp/pastebin" :direction :output :if-exists :supersede)
  152.   (dolist (last '(:undersized :oversized :truncated))
  153.     (dolist (shared '(nil t))
  154.       (dolist (type '(vector list))
  155.         (dolist (input (list #() '()
  156.                              #(1) '(1)
  157.                              '(a b c) #(a b c)
  158.                              '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
  159.                              #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
  160.                              "something in a string"))
  161.           (dolist (n '(1 2 3 4 5 6 7 8))
  162.             (split-n input n :last last :sharedp shared :result-type type)
  163.             (terpri *trace-output*)))))))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement