diff --git a/collections-lib/data/collection/indexable.rkt b/collections-lib/data/collection/indexable.rkt index 9c17b50..40150e2 100644 --- a/collections-lib/data/collection/indexable.rkt +++ b/collections-lib/data/collection/indexable.rkt @@ -7,15 +7,25 @@ (provide gen:indexable indexable? indexable/c - ref set-ref) + ref set-ref update-ref) (define-generics indexable (ref indexable . _) (set-ref indexable . _) + (update-ref indexable . _) #:defaults ([hash? (define ref hash-ref) - (define set-ref hash-set)] + (define set-ref hash-set) + (define update-ref hash-update)] [dict? (define ref dict-ref) - (define set-ref dict-set)] + (define set-ref dict-set) + (define update-ref dict-update)] [sequence? (define ref nth) - (define set-ref set-nth)])) + (define set-ref set-nth) + (define update-ref update-nth)]) + #:fallbacks + [(define/generic -ref ref) + (define/generic -set-ref set-ref) + (define (update-ref indexable index proc) + (let ([old (-ref indexable index)]) + (-set-ref indexable index (proc old))))]) diff --git a/collections-test/tests/data/collection/indexable.rkt b/collections-test/tests/data/collection/indexable.rkt new file mode 100644 index 0000000..8034033 --- /dev/null +++ b/collections-test/tests/data/collection/indexable.rkt @@ -0,0 +1,61 @@ +#lang racket/base + +(require rackunit + data/collection + racket/stream + racket/generic + racket/function) + +(struct my-list (items) + #:transparent + #:methods gen:indexable + [(define/generic -ref ref) + (define/generic -set-ref set-ref) + (define (ref indexable . args) + (define pos (car args)) + (list-ref (my-list-items indexable) + pos)) + (define (set-ref indexable . args) + (define pos (car args)) + (define item (cadr args)) + (define ls (my-list-items indexable)) + (my-list (-set-ref ls pos item)))]) + +(test-case "ref" + "list" + (check-equal? (ref '(a b) 1) 'b) + "vector" + (check-equal? (ref #(a b c) 1) 'b) + "hash" + (check-equal? (ref (hash 'a 'b) 'a) 'b) + "alist" + (check-equal? (ref '((a . b)) 'a) 'b) + "custom data type my-list" + (check-equal? (ref (my-list '(a b)) 1) 'b)) + +(test-case "set-ref" + "list" + (check-equal? (set-ref '(a b) 0 'c) + '(c b)) + "hash" + (check-equal? (set-ref (hash 'a 'b) 'a 'c) + (hash 'a 'c)) + "alist" + (check-equal? (set-ref '((a . b)) 'a 'c) + '((a . c))) + "custom data type my-list" + (check-equal? (set-ref (my-list '(a b)) 0 'c) + (my-list '(c b)))) + +(test-case "update-ref" + "list" + (check-equal? (update-ref '(a b) 0 identity) + '(a b)) + "hash" + (check-equal? (update-ref (hash 'a 'b) 'a identity) + (hash 'a (identity 'b))) + "alist" + (check-equal? (update-ref '((a . b)) 'a identity) + `((a . ,(identity 'b)))) + (check-equal? (update-ref (my-list '(a b)) 1 identity) + (my-list `(a ,(identity 'b)))))