From f98e3fa8712a6fb5f4d49233123318104eab7bc3 Mon Sep 17 00:00:00 2001 From: Andrey Listopadov Date: Thu, 25 Aug 2022 23:20:45 +0300 Subject: make vector support nils, implement pop on vectors and sequences --- CHANGELOG.md | 12 +++++++++++- init.fnl | 45 +++++++++++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 382dd41..39c8a08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,16 @@ +## Cljlib dev (???) + +- Vectors can store `nil` values +- Add `pop` operation for vectors and sequences + ## Cljlib v1.0.0 (2022-08-21) + Full rewrite of the library. This library now requires the minimum Fennel version 1.2.0. (Fennel v1.2.0 isn't yet released at the moment of cljlib v1.0.0 release, use the build from the `main` branch). ### New features + - added [lazy-seq](https://gitlab.com/andreyorst/lazy-seq) as a dependency, and made all sequence functions use it - added [itable](https://gitlab.com/andreyorst/itable) as a dependency, and made all tables immutable by default - implemented transducers @@ -11,19 +18,22 @@ This library now requires the minimum Fennel version 1.2.0. - added `ns` macro ### Changes + - `fn*` no longer splits multisyms and doesn't bind both local and namespaced versions - `fn*` is for anonymous functions, it doesn't create a local binding - `def` now binds in terms of the namespace, specified by `ns` - `def` no longer support documentation metadata ### Removed features + - removed `ordered-set` and `ordered-map` - `into` is no longer a macro - `empty` is no longer a macro - removed metadata-related macros ### Fixes -- #1 has been fixed, and `fn*` now generates multi-value destructuring when possible. + +- [#1](https://gitlab.com/andreyorst/fennel-cljlib/-/issues/1) has been fixed, and `fn*` now generates multi-value destructuring when possible. ## Cljlib v0.5.4 (2021-07-22) diff --git a/init.fnl b/init.fnl index 361208b..321bd12 100644 --- a/init.fnl +++ b/init.fnl @@ -546,21 +546,31 @@ Empty tables created with `vector` will pass the test: (immutable (itable v))))} (setmetatable {})))) -(fn vec* [v] +(fn vec* [v len] (match (getmetatable v) mt (doto mt + (tset :__len (constantly (or len (length* v)))) (tset :cljlib/type :vector) (tset :cljlib/editable true) (tset :cljlib/conj - (fn [t v] (vec* (itable.insert t v)))) + (fn [t v] + (let [len (length* t)] + (vec* (itable.assoc t (+ len 1) v) (+ len 1))))) + (tset :cljlib/pop + (fn [t] + (let [len (- (length* t) 1) + coll []] + (for [i 1 len] + (tset coll i (. t i))) + (vec* (itable coll) len)))) (tset :cljlib/empty (fn [] (vec* (itable [])))) (tset :cljlib/transient (vec->transient vec*)) (tset :__fennelview (fn [coll view inspector indent] (if (empty? coll) "[]" - (let [lines (icollect [_ v (ipairs coll)] - (.. " " (view v inspector indent)))] + (let [lines (fcollect [i 1 (length* coll)] + (.. " " (view (. coll i) inspector indent)))] (tset lines 1 (.. "[" (string.gsub (or (. lines 1) "") "^%s+" ""))) (tset lines (length lines) (.. (. lines (length lines)) "]")) lines))))) @@ -570,14 +580,14 @@ Empty tables created with `vector` will pass the test: (defn vec "Coerce collection `coll` to a vector." [coll] - (cond (empty? coll) (vec* (itable [])) - (vector? coll) (vec* (itable coll)) - :else (-> coll - core.seq - lazy.pack - (doto (tset :n nil)) - itable - vec*))) + (cond (empty? coll) (vec* (itable []) 0) + (vector? coll) (vec* (itable coll) (length* coll)) + :else (let [packed (-> coll core.seq lazy.pack) + len packed.n] + (-> packed + (doto (tset :n nil)) + (itable {:fast-index? true}) + (vec* len))))) (defn vector "Constructs sequential table out of it's arguments. @@ -1950,6 +1960,17 @@ specified `key` or `keys`." {:cljlib/type :hash-set :cljlib/disj f} (apply f Set key keys) _ (error (.. "disj is not supported on " (class Set)) 2)))) +(defn pop + "For a list or queue, returns a new list/queue without the first +item, for a vector, returns a new vector without the last item. If +the collection is empty, throws an exception. Note - not the same +as next/butlast." + [coll] + (match (getmetatable coll) + {:cljlib/type :seq} (drop 1 coll) + {:cljlib/pop f} (f coll) + _ (error (.. "pop is not supported on " (class coll)) 2))) + ;;; Transients (defn transient -- cgit v1.2.3