aboutsummaryrefslogtreecommitdiffstats
path: root/mcgoron.iterator.list.scm
blob: b92689f2179678f59f87d9360ec59cf378ec60fa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#| Copyright 2024 Peter McGoron
 |
 | Licensed under the Apache License, Version 2.0 (the "License");
 | you may not use this file except in compliance with the License.
 | You may obtain a copy of the License at
 |
 |     http://www.apache.org/licenses/LICENSE-2.0
 |
 | Unless required by applicable law or agreed to in writing, software
 | distributed under the License is distributed on an "AS IS" BASIS,
 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | See the License for the specific language governing permissions and
 | limitations under the License.
 |-------------------------------------------------------------------------
 | This is a list iterator that allows for mutation list and improper
 | lists.
 |
 | The list iterator is made up of
 | * the `signifier`: the head of the list.
 | * the `previous` values, which is a list of all cons cells prior to the
 |   current cons cell, in reverse.
 | * the index, which is the index of the current element in the list. This
 |   is updated internally but not used internally, so the root index does
 |   not have to be 0.
 | * the `next` list, which is either empty or has as it's car the current
 |   item.
 |#

;;; TODO: handle IMPROPER-REST? properly
(define (forward num signifier previous idx rest)
  (cond
    ((= num 0)
     (make-list-iterator signifier previous idx rest))
    ((not (pair? rest)) #f)
    (else
     (forward (- num 1) (cons rest previous) (+ idx 1) (cdr rest)))))

(define (backward num signifier previous idx rest)
  (cond
    ((= num 0)
     (make-list-iterator signifier previous idx rest))
    ((not (pair? rest)) #f)
    (else
     (backward (+ num 1) (cdr previous) (- idx 1) (car previous)))))

(define (list-iterator? itr)
  (eq? (iterator-type itr) 'list-iterator))

(define-invocation list-iterator-signifier)

(define (make-list-iterator signifier previous idx rest)
  (if (not (or (pair? rest) (null? rest)))
      (list-iterator signifier (cdr previous) idx (car previous) #t)
      (list-iterator signifier previous idx rest #f)))

(define-iterator-implementation (list-iterator signifier
                                               previous
                                               idx
                                               rest
                                               improper-rest?)
  self
  ((iterator-at-start?) (null? previous))
  ((iterator-at-end?) (or improper-rest? (null? rest)))
  ((iterator-advance spaces)
   (cond
     ((not (integer? spaces))
      (raise (non-integer-movement-exception spaces)))
     ((negative? spaces)
      (backward spaces signifier previous idx rest))
     (else (forward spaces signifier previous idx rest))))
  ((iterator-ref)
   (cond
     ((null? rest)
      (raise (ref-at-end-exception self)))
     (improper-rest? (cdr rest))
     (else (car rest))))
  ((iterator-set! x)
   (cond
     ((null? rest)
      (raise (ref-at-end-exception self)))
     (improper-rest? (set-cdr! rest x))
     (else (set-car! rest x))))
  ((iterator->index) idx)
  ((get-signifier) signifier)
  ((get-iterator-comparator)
   (make-comparator
    (lambda (x)
      (and (list-iterator? itr)
           (eq? signifier (list-iterator-signifier x))))
    (lambda (x y)
      (= (iterator->index x) (iterator->index y)))
    (lambda (x y)
      (< (iterator->index x) (iterator->index y)))
    #f)))

(define-syntax define-with-list-or-iterator
  (syntax-rules ()
    ((_ (name first rest ...) body ...)
     (define (name first rest ...)
       (let ((first (cond
                      ((pair? first) first)
                      ((list-iterator? first)
                       (list-iterator-signifier first))
                      (else (raise (list-constructor-exception
                                    first))))))
         body ...)))))

(define (list-constructor-exception obj)
  (make-iterator-exception #f
                           'list-constructor
                           (list (cons 'obj obj))))

(define-with-list-or-iterator (list-iterator-start lst)
  (make-list-iterator lst '() 0 lst))

(define (list-iterator-to-end itr)
  (if (iterator-end? itr)
      itr
      (list-iterator-to-end (iterator-next itr))))

(define (list-iterator-end obj)
  (list-iterator-to-end (list-iterator-start obj)))