4 files changed, 98 insertions(+), 20 deletions(-)
R com.djhaskin.nrdl.asd => com.djhaskin.pcoll.asd
R com.djhaskin.nrdl.ros => com.djhaskin.pcoll.ros
M src/main.lisp
A src/utils.lisp
R com.djhaskin.nrdl.asd => com.djhaskin.pcoll.asd +14 -9
@@ 1,4 1,4 @@
-(defsystem "com.djhaskin.nrdl"
+(defsystem "com.djhaskin.pcoll"
:version "0.5.0"
:author "Daniel Jay Haskin"
:license "MIT"
@@ 6,26 6,31 @@
"alexandria"
"trivial-features"
)
- :components ((:module "cl"
- :components
- ((:file "main"))))
+ :components
+ (
+ (:module "src"
+ :serial t
+ :components
+ ((:file "utils")
+ (:file "node")
+ (:file "main"))))
:description "Nestable Readable Document Language"
:in-order-to (
- (test-op (test-op "com.djhaskin.nrdl/tests"))))
+ (test-op (test-op "com.djhaskin.pcoll/tests"))))
-(defsystem "com.djhaskin.nrdl/tests"
+(defsystem "com.djhaskin.pcoll/tests"
:version "0.5.0"
:author "Daniel Jay Haskin"
:license "MIT"
:depends-on (
- "com.djhaskin.nrdl"
+ "com.djhaskin.pcoll"
"parachute")
:components ((:module "cl-tests"
:components
((:file "main"))))
- :description "Test system for NRDL"
+ :description "Test system for pcoll"
:perform (asdf:test-op (op c)
(uiop:symbol-call
:parachute
- :test :com.djhaskin.nrdl/tests)))
+ :test :com.djhaskin.pcoll/tests)))
R com.djhaskin.nrdl.ros => com.djhaskin.pcoll.ros +0 -0
M src/main.lisp => src/main.lisp +62 -11
@@ 14,7 14,7 @@
(in-package #:cl-user)
(defpackage
- #:com.djhaskin.pcoll (:use #:cl)
+ #:com.djhaskin.pcoll (:use #:cl #:com.djhaskin.pcoll/utils)
(:documentation
"
Fast Persistent Collections in Common Lisp
@@ 63,6 63,23 @@
(:include node))
(middle nil))
+
+(defun reduce-node
+ (function tree key from-end start end initial-value)
+ (declare (type node tree))
+ ;; 1. Bound the tree
+ (when (>= start (node-size tree))
+ (return (single-reduce function 'unspecified initial-value)))
+ (when (>=
+
+ (if (= 1 (node-height tree))
+ ;; Then start is less than the node's number of children
+ (cond ((= (node-size tree)
+ (if (large-node-p tree)
+
+
+
+ (when (>=
;;; Here are the polymorphic structs used for finger trees:
;;; Why use an empty struct instead of simply nil? So that finger trees are
@@ 90,15 107,11 @@
;;;
;;; The sequences dictionary has something like that, so let's define it now:
-(declaim (inline single-reduce))
-(defun single-reduce (function thing initial-value)
- (if (eq initial-value 'unspecified)
- (if (eq thing 'unspecified)
- (funcall function)
- thing)
- (if (eq thing 'unspecified)
- initial-value
- (funcall function initial-value thing))))
+ ((> start (node-size (
+
+ (typecase tree
+ (large-node
+ (if (
(defun
reduce
@@ 109,8 122,46 @@
(start 0)
(end nil)
(initial-value 'unspecified))
+ "
+ reduce uses a binary operation, `function`, to combine the elements of sequence
+ bounded by `start` and `end`.
+
+ The function must accept as arguments two elements of sequence or the results
+ from combining those elements. The function must also be able to accept no
+ arguments.
+
+ If `key` is supplied, it is used is used to extract the values to reduce. The
+ key function is applied exactly once to each element of sequence in the order
+ implied by the reduction order but not to the value of initial-value, if
+ supplied. The key function typically returns part of the element of sequence.
+ If key is not supplied or is nil, the sequence element itself is used.
+
+ The reduction is left-associative, unless from-end is true in which case it is
+ right-associative.
+
+ If initial-value is supplied, it is logically placed before the subsequence
+ (or after it if from-end is true) and included in the reduction operation.
+
+ In the normal case, the result of reduce is the combined result of function's
+ being applied to successive pairs of elements of sequence. If the subsequence
+ contains exactly one element and no initial-value is given, then that element
+ is returned and function is not called. If the subsequence is empty and an
+ initial-value is given, then the initial-value is returned and function is not
+ called. If the subsequence is empty and no initial-value is given, then the
+ function is called with zero arguments, and reduce returns whatever function
+ does. This is the only case where the function is called with other than two
+ arguments.
+ "
+ ;; Make sure the arguments make sense
+ (when (and end
+ (>= start end))
+ (return (single-reduce 'unspecified initial-value)))
+
+
+
(typecase sequence
- (large-node
+ (node
+ (reduce-node
(if (zerop (node-height sequence))
(cond ((> start 2)
(single-reduce 'unspecified initial-value))
A src/utils.lisp => src/utils.lisp +22 -0
@@ 0,0 1,22 @@
+(in-package #:cl-user)
+
+(defpackage
+ #:com.djhaskin.pcoll/utils (:use #:cl)
+ (:documentation
+ "
+ Fast Persistent Collections in Common Lisp
+ ")
+ (:import-from #:alexandria)
+ )
+
+(in-package #:com.djhaskin.pcoll/utils)
+
+(declaim (inline single-reduce))
+(defun single-reduce (function thing initial-value)
+ (if (eq initial-value 'unspecified)
+ (if (eq thing 'unspecified)
+ (funcall function)
+ thing)
+ (if (eq thing 'unspecified)
+ initial-value
+ (funcall function initial-value thing))))