cursor 0.6 → 0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,89 @@
1
+ # $Id: buffered.rb,v 1.11 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+ require 'cursor/split'
5
+ require 'cursor/usedeleteinsert'
6
+ require 'cursor/useposition'
7
+
8
+ class Cursor
9
+ # This class gives unidirectional cursors (i.e. IO pipes) some
10
+ # bidirectional capabilities. An input cursor (or input IO) and/or an output
11
+ # cursor (or output IO)
12
+ # can be specified. The #position, #position?, and #position! methods are
13
+ # used to control buffering. Full cursor capability (limited by the buffer
14
+ # cursor) is accessible starting from the first #position. When the end of
15
+ # the buffer is reached more data is read from the input cursor (if not nil) . When no
16
+ # #position is outstanding, everything before the buffer cursor is written
17
+ # to the output cursor (if not nil). If the cursor is attempted
18
+ # to be moved before the buffer, the output cursor is read in reverse (which
19
+ # the output cursor may not like).
20
+ class Buffered < Cursor
21
+ include UseDeleteInsert
22
+ include UsePosition
23
+ def initialize(input,output=nil,output_pos=0,buffer=nil)
24
+ @input = input
25
+ @output = output
26
+ if buffer
27
+ @buffer = buffer
28
+ else
29
+ buffer = input||output
30
+ @buffer = Split.new(
31
+ buffer.respond_to?(:new_data) ? buffer.new_data : ""
32
+ )
33
+ end
34
+ @output_pos = output_pos
35
+ end
36
+ # :stopdoc:
37
+ def new_data
38
+ @buffer.new_data
39
+ end
40
+ protected
41
+ def _delete1after?
42
+ v0 = @buffer.delete1after?
43
+ v0.nil? && @input && (v0 = @input.read(1)) && (v0 = v0[0])
44
+ v0
45
+ end
46
+ def _delete1before?
47
+ v0 = @buffer.delete1before?
48
+ v0.nil? && @output_pos>0 && (@output_pos -= 1;v0 = @output.read(-1)) && (v0 = v0[0])
49
+ v0
50
+ end
51
+ def _insert1before(v)
52
+ if not position?
53
+ len = @buffer.skip!(true)
54
+ if @output
55
+ value = len ? @buffer.read(len,nil) : @buffer.new_data
56
+ value << v
57
+ @output.write(value)
58
+ else
59
+ @buffer.read(len,nil) if len
60
+ end
61
+ @output_pos += (len||0)+1
62
+ else
63
+ @buffer.insert1before(v)
64
+ end
65
+ true
66
+ end
67
+ def _insert1after(v)
68
+ @buffer.insert1after(v)
69
+ end
70
+ public
71
+ def pos(reverse=false) # :yield:
72
+ if reverse
73
+ super
74
+ else
75
+ @buffer.pos+@output_pos
76
+ end
77
+ end
78
+ def close
79
+ if @output
80
+ @buffer.skip!(true)
81
+ value = @buffer.read!(false) and @output.write(value)
82
+ end
83
+ super
84
+ end
85
+ # :startdoc:
86
+ end
87
+ end
88
+
89
+
@@ -0,0 +1,245 @@
1
+ # $Id: circular.rb,v 1.19 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor'
4
+
5
+ class Cursor
6
+ # This Cursor class is used to represent a circular buffer. You can think of
7
+ # this as having no beginning/end or the current location is always both at the
8
+ # beginning/end. Because of the circular nature, the methods
9
+ # #scan_until, #modify,
10
+ # #each, #collect!, and #map!
11
+ # are not defined.
12
+ class Circular < Cursor
13
+ # Create a circular cursor from a normal finite one.
14
+ def initialize(cursor)
15
+ @cursor = cursor
16
+ end
17
+ protected
18
+ def _adjust_delete(len=1,reverse=false)
19
+ pos = _pos(false)
20
+ ret = nil
21
+ @positions.each { |p| ret = p.__send__(:_deletion,pos,len,reverse,ret) }
22
+ end
23
+ def _adjust_insert(len=1)
24
+ pos = _pos(false)
25
+ ret = nil
26
+ @positions.each { |p| ret = p.__send__(:_insertion,pos,len,ret) }
27
+ end
28
+ def _pos(reverse=false)
29
+ @cursor.pos(reverse)
30
+ end
31
+ def _pos=(p)
32
+ len = p-_pos((p.nonzero?||1.0/p)<0)
33
+ len.to_i.abs==skip(len) or raise(IndexError,"invalid pos=#{p}")
34
+ end
35
+ public
36
+
37
+ # :stopdoc:
38
+ def new_data
39
+ @cursor.new_data
40
+ end
41
+ def read1next
42
+ v0 = @cursor.read1next
43
+ v0.nil? && @cursor.skip!(true) && (v0 = @cursor.read1next)
44
+ v0
45
+ end
46
+ def read1prev
47
+ v0 = @cursor.read1prev
48
+ v0.nil? && @cursor.skip!(false) && (v0 = @cursor.read1prev)
49
+ v0
50
+ end
51
+ def read1after
52
+ v0 = @cursor.read1after
53
+ v0.nil? && @cursor.skip!(true) && (v0 = @cursor.read1after)
54
+ v0
55
+ end
56
+ def read1before
57
+ v0 = @cursor.read1before
58
+ v0.nil? && @cursor.skip!(false) && (v0 = @cursor.read1before)
59
+ v0
60
+ end
61
+ def skip1next
62
+ @cursor.skip1next || @cursor.skip!(true) && @cursor.skip1next
63
+ end
64
+ def skip1prev
65
+ @cursor.skip1prev || @cursor.skip!(false) && @cursor.skip1prev
66
+ end
67
+ def skip1after
68
+ @cursor.skip1after || @cursor.skip!(true) && @cursor.skip1after
69
+ end
70
+ def skip1before
71
+ @cursor.skip1before || @cursor.skip!(false) && @cursor.skip1before
72
+ end
73
+ def delete1after
74
+ v0 = @cursor.delete1after || @cursor.skip!(true) && @cursor.delete1after
75
+ v0.nil? || @positions && _adjust_delete
76
+ v0
77
+ end
78
+ def delete1before
79
+ v0 = @cursor.delete1before || @cursor.skip!(false) && @cursor.delete1before
80
+ v0.nil? || @positions && _adjust_delete
81
+ v0
82
+ end
83
+ def delete1after?
84
+ v0 = @cursor.delete1after?
85
+ v0.nil? && @cursor.skip!(true) && (v0 = @cursor.delete1after?)
86
+ v0.nil? || @positions && _adjust_delete
87
+ v0
88
+ end
89
+ def delete1before?
90
+ v0 = @cursor.delete1before?
91
+ v0.nil? && @cursor.skip!(false) && (v0 = @cursor.delete1before?)
92
+ v0.nil? || @positions && _adjust_delete
93
+ v0
94
+ end
95
+ def write1next(v)
96
+ @cursor.write1next(v) || @cursor.skip!(true) && @cursor.write1next(v)
97
+ end
98
+ def write1prev(v)
99
+ @cursor.write1prev(v) || @cursor.skip!(false) && @cursor.write1prev(v)
100
+ end
101
+ def write1after(v)
102
+ @cursor.write1after(v) || @cursor.skip!(true) && @cursor.write1after(v)
103
+ end
104
+ def write1before(v)
105
+ @cursor.write1before(v) || @cursor.skip!(false) && @cursor.write1before(v)
106
+ end
107
+ def write1next?(v)
108
+ v0 = @cursor.write1next?(v)
109
+ v0.nil? && @cursor.skip!(true) && (v0 = @cursor.write1next?(v))
110
+ v0
111
+ end
112
+ def write1prev?(v)
113
+ v0 = @cursor.write1prev?(v)
114
+ v0.nil? && @cursor.skip!(false) && (v0 = @cursor.write1prev?(v))
115
+ v0
116
+ end
117
+ def write1after?(v)
118
+ v0 = @cursor.write1after?(v)
119
+ v0.nil? && @cursor.skip!(true) && (v0 = @cursor.write1after?(v))
120
+ v0
121
+ end
122
+ def write1before?(v)
123
+ v0 = @cursor.write1before?(v)
124
+ v0.nil? && @cursor.skip!(false) && (v0 = @cursor.write1before?(v))
125
+ v0
126
+ end
127
+ def insert1before(v)
128
+ @positions && _adjust_insert
129
+ @cursor.insert1before(v)
130
+ end
131
+ def insert1after(v)
132
+ @positions && _adjust_insert
133
+ @cursor.insert1after(v)
134
+ end
135
+ def scan1next(v)
136
+ v0 = read1next
137
+ (v0.nil? || v==v0) ? v0 : (skip1prev;nil)
138
+ end
139
+ def scan1prev(v)
140
+ v0 = read1prev
141
+ (v0.nil? || v==v0) ? v0 : (skip1next;nil)
142
+ end
143
+ def modify1next(r)
144
+ v0 = read1after
145
+ (v0.nil? || (v = r[v0]).nil?) ? nil : (write1next!(v);v0)
146
+ end
147
+ def modify1prev(r)
148
+ v0 = read1before
149
+ (v0.nil? || (v = r[v0]).nil?) ? nil : (write1prev!(v);v0)
150
+ end
151
+ # :startdoc:
152
+ # read over one pass of the data to return where you started
153
+ def read!(reverse=false,hold=false,value0=new_data)
154
+ read(reverse ? -size : size,hold,value0)
155
+ end
156
+ # skip over one pass of the data to return where you started
157
+ def skip!(reverse=false,hold=false)
158
+ hold.nil? ? skip(reverse ? -size : size,hold) : size
159
+ end
160
+ # treat the current pos as both the beginning (+0) and the end (-0.0)
161
+ def pos(reverse=false)
162
+ reverse ? -0.0 : 0
163
+ end
164
+ # any pos is treated as relative to the current pos (0)
165
+ def pos=(p)
166
+ skip(p)
167
+ p
168
+ end
169
+ # Compare to +other+. Return 0 for the same location and +1 for not.
170
+ def <=>(other)
171
+ position?(other) and begin
172
+ len = (_pos-other.__send__(:_pos)).to_i
173
+ (len.zero? || len.abs==size) ? 0 : +1
174
+ end
175
+ end
176
+ # positive distance between self and other
177
+ def -(other)
178
+ len = (_pos-other.__send__(:_pos)).to_i
179
+ len<0 ? size+len : len==size ? 0 : len
180
+ end
181
+ # insert an element before the cursor and return self
182
+ def << (value)
183
+ insert1before(value)
184
+ self
185
+ end
186
+ # insert an element after the cursor and return self
187
+ def >> (value)
188
+ insert1after(value)
189
+ self
190
+ end
191
+
192
+ # :stopdoc:
193
+ def size
194
+ _pos(false)-_pos(true).to_i
195
+ end
196
+ alias length size
197
+ def begin
198
+ position(false)
199
+ end
200
+ def end
201
+ position(true)
202
+ end
203
+ def empty?
204
+ skip1after.nil?
205
+ end
206
+ def clear
207
+ skip!(false,nil)||0
208
+ end
209
+ def data
210
+ read!(false)
211
+ end
212
+ def position(reverse=false,&code) # :yield:
213
+ p = Position.new(self,reverse)
214
+ (@positions||=WeakRefSet.new) << p
215
+ if code
216
+ begin
217
+ code[]
218
+ ensure
219
+ begin
220
+ self.position = p
221
+ ensure
222
+ p.close
223
+ end
224
+ end
225
+ else
226
+ p
227
+ end
228
+ end
229
+ def position=(p)
230
+ self._pos = p.__send__(:_pos,nil)
231
+ self.prop(nil,p.prop)
232
+ nil
233
+ end
234
+ # :startdoc:
235
+ undef_method(:scan_until)
236
+ undef_method(:modify)
237
+ undef_method(:each)
238
+ undef_method(:collect!)
239
+ undef_method(:map!)
240
+ end
241
+ end
242
+
243
+ require 'cursor/circular/position'
244
+
245
+
@@ -0,0 +1,51 @@
1
+ # $Id: indexed.rb,v 1.6 2005/07/18 14:46:28 eric_mahurin Exp $
2
+
3
+ require 'cursor/circular'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ class Circular
8
+ # This class implements a circular buffer using an Array or String.
9
+ class Indexed < Circular
10
+ include UseDeleteInsert
11
+ def initialize(data=[],pos=0)
12
+ @data = data
13
+ @pos = pos
14
+ end
15
+ # :stopdoc:
16
+ def new_data
17
+ @data.class.new
18
+ end
19
+ protected
20
+ def _delete1after?
21
+ @pos = 0 if @pos==@data.size
22
+ @data.slice!(@pos)
23
+ end
24
+ def _delete1before?
25
+ @pos = @data.size if @pos.zero?
26
+ @data.slice!(@pos -= 1)
27
+ ensure
28
+ @pos = 0 if @pos<0
29
+ end
30
+ def _insert1before(v)
31
+ @data[@pos,0] = (new_data << v)
32
+ @pos += 1
33
+ true
34
+ end
35
+ def _insert1after(v)
36
+ @data[@pos,0] = (new_data << v)
37
+ true
38
+ end
39
+ def _pos(reverse=false)
40
+ reverse ? (@pos-@data.size).nonzero?||-0.0 : @pos
41
+ end
42
+ def _pos=(p)
43
+ @pos = ((p.nonzero?||1.0/p)<0) ? (p+@data.size).to_i : p
44
+ p
45
+ end
46
+ # :startdoc:
47
+ end
48
+ end
49
+ end
50
+
51
+
@@ -0,0 +1,98 @@
1
+ # $Id: linked.rb,v 1.4 2005/07/21 15:15:38 eric_mahurin Exp $
2
+
3
+ require 'cursor/circular'
4
+ require 'cursor/usedeleteinsert'
5
+
6
+ class Cursor
7
+ class Circular
8
+ # Double-linked list
9
+ class Linked < Circular
10
+ include UseDeleteInsert
11
+ def initialize(before=[],after=before.class.new)
12
+ @next = nil
13
+ @prev = nil
14
+ @data_class = before.class
15
+ @pos0 = 0
16
+ @size = 0
17
+ write(before,false,nil)
18
+ write(after,true,nil)
19
+ end
20
+ # :stopdoc:
21
+ def new_data
22
+ @data_class.new
23
+ end
24
+ protected
25
+ def _delete1after?
26
+ @pos0 = (@size.nonzero?||return) if @pos0.zero?
27
+ @pos0 -= 1
28
+ @size -= 1
29
+ begin
30
+ @next[1]
31
+ ensure
32
+ if @next.equal?(@next[2])
33
+ @next = nil
34
+ @prev = nil
35
+ else
36
+ @next = @next[2]
37
+ @next[0] = @prev
38
+ @prev[2] = @next
39
+ end
40
+ end
41
+ end
42
+ def _delete1before?
43
+ if @pos0==@size
44
+ return if @size.zero?
45
+ @pos0 = 0
46
+ end
47
+ @size -= 1
48
+ begin
49
+ @prev[1]
50
+ ensure
51
+ if @prev.equal?(@prev[0])
52
+ @next = nil
53
+ @prev = nil
54
+ else
55
+ @prev = @prev[0]
56
+ @next[0] = @prev
57
+ @prev[2] = @next
58
+ end
59
+ end
60
+ end
61
+ def _insert1before(v)
62
+ @size += 1
63
+ if !@next
64
+ @prev = @next = [nil,v,nil]
65
+ @prev[2] = @next
66
+ @next[0] = @prev
67
+ else
68
+ node = [@prev,v,@next]
69
+ @prev[2] = node
70
+ @next[0] = node
71
+ @prev = node
72
+ end
73
+ true
74
+ end
75
+ def _insert1after(v)
76
+ @pos0 += 1
77
+ @size += 1
78
+ if !@next
79
+ @prev = @next = [nil,v,nil]
80
+ @prev[2] = @next
81
+ @next[0] = @prev
82
+ else
83
+ node = [@prev,v,@next]
84
+ @prev[2] = node if @prev
85
+ @next[0] = node if @next
86
+ @next = node
87
+ end
88
+ true
89
+ end
90
+ def _pos(reverse=false)
91
+ reverse ? -(@pos0.nonzero?||0.0) : @size-@pos0
92
+ end
93
+ # :startdoc:
94
+ end
95
+ end
96
+ end
97
+
98
+