From e293ff4c45b9ccd5ccd89f9284d6647a7f0e022f Mon Sep 17 00:00:00 2001 From: "carpentry-heartbeat[bot]" Date: Tue, 9 Jun 2026 13:13:49 +0200 Subject: [PATCH] Add map and filter to persistent vector --- persistent.carp | 17 ++++++++++++ test/persistent_vector.carp | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/persistent.carp b/persistent.carp index 19ee269..b421ca8 100644 --- a/persistent.carp +++ b/persistent.carp @@ -3052,6 +3052,23 @@ Example: (defn all? [pred coll-ref] (reduce &(fn [acc x] (and acc (~pred &x))) true coll-ref)) + (doc map + "Apply a function to each element, returning a new vector in index order.") + (sig map + (Fn [(Ref (Fn [%value-type] %value-type) q) (Ref %name r)] %name)) + (defn map [f vec-ref] + (reduce &(fn [acc x] (push-back (~f x) &acc)) (empty) vec-ref)) + + (doc filter + "Keep only elements satisfying a predicate, preserving index order.") + (sig filter + (Fn [(Ref (Fn [(Ref %value-type q)] Bool) r) (Ref %name s)] %name)) + (defn filter [pred vec-ref] + (reduce + &(fn [acc x] (if (~pred &x) (push-back x &acc) acc)) + (empty) + vec-ref)) + (doc str "Diagnostic formatting for a vector.") (sig str (Fn [(Ref %name q)] String)) (defn str [vec-ref] diff --git a/test/persistent_vector.carp b/test/persistent_vector.carp index 10b8453..079278a 100644 --- a/test/persistent_vector.carp +++ b/test/persistent_vector.carp @@ -152,6 +152,58 @@ (IntVec.all? &(fn [x] (= x &1)) &(IntVec.empty)) "all? on empty returns true") + (assert-equal test + true + (let [v0 (IntVec.empty) + v1 (IntVec.push-back 1 &v0) + v2 (IntVec.push-back 2 &v1) + v3 (IntVec.push-back 3 &v2) + mapped (IntVec.map &(fn [x] (+ x 10)) &v3) + arr (IntVec.to-array &mapped)] + (and (= (Array.length &arr) 3) + (= @(Array.unsafe-nth &arr 0) 11) + (= @(Array.unsafe-nth &arr 1) 12) + (= @(Array.unsafe-nth &arr 2) 13))) + "map applies function preserving index order") + + (assert-equal test + true + (let [v (IntVec.empty) + m (IntVec.map &(fn [x] (+ x 1)) &v)] + (IntVec.empty? &m)) + "map over empty vector yields empty") + + (assert-equal test + true + (let [v0 (IntVec.empty) + v1 (IntVec.push-back 1 &v0) + v2 (IntVec.push-back 2 &v1) + v3 (IntVec.push-back 3 &v2) + filtered (IntVec.filter &(fn [x] (> @x 1)) &v3) + arr (IntVec.to-array &filtered)] + (and (= (Array.length &arr) 2) + (= @(Array.unsafe-nth &arr 0) 2) + (= @(Array.unsafe-nth &arr 1) 3))) + "filter keeps elements matching predicate in order") + + (assert-equal test + true + (let [v0 (IntVec.empty) + v1 (IntVec.push-back 1 &v0) + v2 (IntVec.push-back 2 &v1) + filtered (IntVec.filter &(fn [x] false) &v2)] + (IntVec.empty? &filtered)) + "filter with always-false yields empty vector") + + (assert-equal test + true + (let [v0 (IntVec.empty) + v1 (IntVec.push-back 1 &v0) + v2 (IntVec.push-back 2 &v1) + filtered (IntVec.filter &(fn [x] true) &v2)] + (= &filtered &v2)) + "filter with always-true preserves all elements") + (assert-memory-balance test vec-branch-lifecycle 0l