Last active
January 19, 2022 02:04
-
-
Save jaawerth/fb1f66090c640d2eeb6c95f598a9f5db to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(local identity #$) | |
(local second #$2) | |
(local always-nil #nil) | |
(fn int? [v] (and (= :number (type v)) (= v (math.floor v)))) | |
(fn assert-int [v ?msg ?lvl] | |
(if (int? v) v | |
(error (or ?msg (.. "expected value '" (tostring v) "' to be a number")) | |
(or ?lvl 2)))) | |
(fn rawget-or-0 [self k] (or (rawget self k) 0)) ; (. t k) but bypass __index | |
(fn count-into [into-tgt ?op src ...] | |
(local op (or ?op second)) | |
(local (gen param state) | |
(match (type src) | |
:function (values src ...) | |
:string (string.gmatch src ".") | |
:nil always-nil | |
_ (pairs src) ; assume table/userdata-with-__pairs as fallback; | |
; will result in error for number/boolean/non-iterable userdata | |
)) | |
(accumulate [C into-tgt k n (values gen param state)] | |
(let [n (if (= n nil) 1 n) | |
n- (rawget-or-0 C k)] | |
(doto C (rawset k (op n- (assert-int n)) ))))) | |
(local multi-set-mt nil) ; deferred 'til after *multi-set*' | |
(fn new-multi-set [src ...] | |
(setmetatable (count-into {} nil src ...) multi-set-mt)) | |
(local *multi-set* | |
{:new new-multi-set | |
:get rawget-or-0 ; (. t k) but bypass methods | |
:update (λ update [self op ?src ...] | |
(count-into (new-multi-set self) op (or ?src self) ...)) | |
:update! (λ [self op ?src ...] (count-into self op (or ?src self) ...)) | |
:keys (fn [self] (icollect [k (pairs self)] k)) | |
:add (fn [self addend] (update self #(+ $1 $2) addend)) | |
:sub (fn [self subtr] (update self #(- $1 $2) subtr))}) | |
(set-forcibly! multi-set-mt | |
{:__index (fn [self key] ; check methods, then fall back to 0 | |
(or (. *multi-set* key) 0)) | |
:__newindex (fn [self key n] (rawset self key (assert-int n))) | |
:__add *multi-set*.add | |
:__sub *multi-set*.sub}) | |
*multi-set* |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment