sequence 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +58 -0
- data/GPL +340 -0
- data/Manifest.txt +36 -0
- data/README.txt +320 -0
- data/Rakefile +32 -0
- data/lib/assert.rb +16 -0
- data/lib/sequence/arraylike.rb +57 -0
- data/lib/sequence/buffered.rb +188 -0
- data/lib/sequence/circular.rb +272 -0
- data/lib/sequence/enum.rb +260 -0
- data/lib/sequence/file.rb +172 -0
- data/lib/sequence/functional.rb +152 -0
- data/lib/sequence/generator.rb +290 -0
- data/lib/sequence/indexed.rb +234 -0
- data/lib/sequence/io.rb +102 -0
- data/lib/sequence/list.rb +292 -0
- data/lib/sequence/ofhash.rb +38 -0
- data/lib/sequence/ofobjectivars.rb +29 -0
- data/lib/sequence/ofobjectmethods.rb +87 -0
- data/lib/sequence/position.rb +100 -0
- data/lib/sequence/reversed.rb +180 -0
- data/lib/sequence/shifting.rb +190 -0
- data/lib/sequence/singleitem.rb +50 -0
- data/lib/sequence/stringlike.rb +482 -0
- data/lib/sequence/subseq.rb +90 -0
- data/lib/sequence/usedata.rb +35 -0
- data/lib/sequence/version.rb +5 -0
- data/lib/sequence.rb +721 -0
- data/lib/weakrefset.rb +254 -0
- data/test/test.rb +609 -0
- data/test/test_all.rb +6 -0
- data/test/test_changes.rb +44 -0
- data/test/test_circulars.rb +89 -0
- data/test/test_rexscan.rb +899 -0
- data/test/test_seqrex.rb +204 -0
- data/test/test_sequences.rb +106 -0
- metadata +90 -0
data/README.txt
ADDED
@@ -0,0 +1,320 @@
|
|
1
|
+
Sequence provides a unified api for access to sequential data types, like
|
2
|
+
Strings, Arrays, Files, IOs, and Enumerations. Each sequence encapsulates
|
3
|
+
some data and a current position within it. Some operations apply to data
|
4
|
+
at (or relative to) the position, others are independant of position. The
|
5
|
+
api contains operations for moving the position, reading and writing data
|
6
|
+
(with or without moving the position) forward or backward from the current
|
7
|
+
position or anywhere, scanning for patterns (like StringScanner, but it
|
8
|
+
works in Files too, among others), and saving a position that will remain
|
9
|
+
valid even after data is deleted or inserted elsewhere within the
|
10
|
+
sequence.
|
11
|
+
|
12
|
+
There are also some utility classes for making sequences reversed or
|
13
|
+
circular, turning one-way sequences into two-way, buffering, and making
|
14
|
+
sequences that are subsets or aggregations of existing sequences.
|
15
|
+
|
16
|
+
Sequence is based on Eric Mahurin's Cursor library. I'd like to thank Eric
|
17
|
+
for Cursor, without which Sequence would not have existed; my design is
|
18
|
+
very much a derivative of his.
|
19
|
+
|
20
|
+
|
21
|
+
Sequences always fall into one of two broad categories: string-like and
|
22
|
+
array- like. String-like cursors contain only character data, whereas
|
23
|
+
Array-like cursors contain objects.
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
Stuff that's unworking at the moment is marked with **
|
29
|
+
|
30
|
+
Reading a single element:
|
31
|
+
When any of these operations fail (at beginning/end), nil is returned.
|
32
|
+
(Note: nil can also be found inside array-like cursors, so a nil result
|
33
|
+
doesn't necessarily mean you're at eof.) A name with -back means
|
34
|
+
backwards, -ahead/-behind means lookahead/lookbehind (pos not moved).
|
35
|
+
|
36
|
+
#read1 #get next element and advance position
|
37
|
+
#readback1 #get previous element and move position back
|
38
|
+
#readahead1 #get next element, leaving position alone
|
39
|
+
#readbehind1 #get previous element, leaving position alone
|
40
|
+
|
41
|
+
|
42
|
+
Read methods:
|
43
|
+
These all come in forward and backward forms, and forms that can hold the
|
44
|
+
position in place. The element sequences are passed/returned in
|
45
|
+
Array/String like things.
|
46
|
+
|
47
|
+
A note on backwards operations: some methods move the position backward
|
48
|
+
instead of forward. They operate on data immediately before the position
|
49
|
+
instead of immediately after. Data is still read or processed in normal
|
50
|
+
order. To get data in backwards order, use Sequence::Reversed.
|
51
|
+
|
52
|
+
#read(len) #read +len+ elements. leaving position after the data read
|
53
|
+
#readback(len) #read data behind current position,
|
54
|
+
#leaving position before the data read.
|
55
|
+
|
56
|
+
#readahead(len) #like read, but position is left alone.
|
57
|
+
#readbehind(len) #like readback, but position is left alone.
|
58
|
+
#read!(reverse=false) # read the remaining elements.
|
59
|
+
|
60
|
+
Numeric position methods:
|
61
|
+
The methods below deal with numeric positions (a pos) to represent the
|
62
|
+
sequence location. A non-negative number represents the number of elements
|
63
|
+
from the beginning. A negative number represents the location relative to
|
64
|
+
the end.
|
65
|
+
|
66
|
+
#pos # number of elements from the beginning (0 is at the beginning).
|
67
|
+
#pos?(p) # this checks to see if p is a valid numeric position.
|
68
|
+
|
69
|
+
#pos=(p) # Set #pos to be +p+.
|
70
|
+
#goto p #go to an absolute position; identical to #pos=
|
71
|
+
|
72
|
+
#move(len) # move len elements, relative to the current position
|
73
|
+
#and return distance moved
|
74
|
+
|
75
|
+
#move!(reverse=false) # move to end of the remaining elements
|
76
|
+
# and return distance moved
|
77
|
+
#begin! #go to beginning
|
78
|
+
#end! #go to end
|
79
|
+
|
80
|
+
#rest_size #number of data items remaining
|
81
|
+
#eof? #are we at past the end of the data,
|
82
|
+
#with no more data ever to arrive?
|
83
|
+
|
84
|
+
Sequence::Position methods:
|
85
|
+
|
86
|
+
The position methods below use a Sequence::Position to hold the position
|
87
|
+
rather than simply a numeric position. These position objects hold a
|
88
|
+
#pos, which does not change when the parent sequence's position changes.
|
89
|
+
(Also, the #pos in these objects adjust based on insertions and
|
90
|
+
deletions.)
|
91
|
+
|
92
|
+
#position(_pos=pos) #returns a Sequence::Position to
|
93
|
+
#represent the current location.
|
94
|
+
#position=(p) #C Set the position to a Position +p+ (from #position)
|
95
|
+
#position?(p) # this queries whether a particular #position +p+
|
96
|
+
#is valid (is a child or self).
|
97
|
+
|
98
|
+
#-(other) #return new Position decreased by a length or
|
99
|
+
#distance between 2 positions.
|
100
|
+
#+(len) #Returns a new #position increased by +len+
|
101
|
+
#(positive or negative).
|
102
|
+
|
103
|
+
#succ # Return a new #position for next location
|
104
|
+
# or +nil+ if we are at the end.
|
105
|
+
#pred # Return a new #position for previous location
|
106
|
+
# or +nil+ if we are at the beginning.
|
107
|
+
|
108
|
+
#begin # Return a new #position for the beginning.
|
109
|
+
#end # Return a new #position for the end.
|
110
|
+
|
111
|
+
#<=>(other) # Compare +other+ (a #position) to the current position.
|
112
|
+
|
113
|
+
|
114
|
+
Access the entire collection:
|
115
|
+
#data, #return the data underlying the sequence.
|
116
|
+
#the type of the result depends on the sequence type
|
117
|
+
|
118
|
+
#data_class #return Array if this sequence can contain any object,
|
119
|
+
#String if it contains only characters
|
120
|
+
#new_data # Return an empty String or Array,
|
121
|
+
#depending on what #data_class is
|
122
|
+
|
123
|
+
|
124
|
+
#all_data #return a String or Array
|
125
|
+
#containing all the data of the sequence
|
126
|
+
|
127
|
+
#size/length # Returns the number of elements.
|
128
|
+
|
129
|
+
#empty? # is there any data in the sequence?
|
130
|
+
|
131
|
+
#each # Performs each just to make this class Enumerable.
|
132
|
+
|
133
|
+
|
134
|
+
Random access:
|
135
|
+
#<<(elem) #append to the end
|
136
|
+
|
137
|
+
#slice/[](index) # random access to sequence data like in Array/String
|
138
|
+
#slice/[](index,len) # random access to sequence data like in Array/String
|
139
|
+
#slice/[](range) # random access to sequence data like in Array/String
|
140
|
+
|
141
|
+
Modifying data:
|
142
|
+
#slice! # slice and delete data
|
143
|
+
#[]=/modify(sliceargs,newdata) #replace an arbitrary subsequence
|
144
|
+
#with a different one
|
145
|
+
|
146
|
+
#modify has a number of special subcases:
|
147
|
+
#insert -- len is 0 (all existing element are retained)
|
148
|
+
#delete -- newdata.size is 0
|
149
|
+
#append -- insert data after end
|
150
|
+
#prepend -- insert data before start
|
151
|
+
#push/pop -- insert/delete element(s) at end
|
152
|
+
#shift/unshift -- insert/delete elements at start
|
153
|
+
#overwrite -- replacedata.size == len, no shifting needed
|
154
|
+
|
155
|
+
#subcases that use the position:
|
156
|
+
#(over)write -- overwrite after current position and move ahead
|
157
|
+
#(over)writeback -- overwrite before current position and move back
|
158
|
+
#(over)writeahead/behind -- overwrite near location without moving it
|
159
|
+
#deletebehind/#deleteahead -- delete before or after the location **
|
160
|
+
#insertbehind/#insertahead -- insert before or after the location **
|
161
|
+
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
Taken from/inspired by StringScanner:
|
166
|
+
See the StringScanner documentation (ri StringScanner) for a description
|
167
|
+
of these methods. I have extended StringScanner's interface to take
|
168
|
+
Strings and character literals (Integers) as well as Regexps.
|
169
|
+
|
170
|
+
About anchors:
|
171
|
+
|
172
|
+
When going forward:
|
173
|
+
\A ^ match current position
|
174
|
+
\Z $ match end of data (String, File, whatever)
|
175
|
+
When going backward:
|
176
|
+
\A ^ match beginning of data
|
177
|
+
\Z $ match current position
|
178
|
+
|
179
|
+
^ and $ also match at line edges, as usual
|
180
|
+
|
181
|
+
|
182
|
+
My strategy is to rewrite the anchors in the regexp to make them conform
|
183
|
+
to the desired definition. For instance, \Z is replaced with (?!), unless
|
184
|
+
the last byte of the file is within the buffer to be compared against, in
|
185
|
+
which case it is left alone.
|
186
|
+
|
187
|
+
To counter the speed problem, there's a cache so the same regexp doesn't
|
188
|
+
have to be rewritten more than once.
|
189
|
+
|
190
|
+
about matchdata:
|
191
|
+
#pre_match/#post_match may not be what you expect; they are Sequences.
|
192
|
+
#offset contains numeric positions from the very beginning of the Sequence.
|
193
|
+
#anchored, forwards
|
194
|
+
#scan(pat) #if pat is right after current position,
|
195
|
+
#advance position and return what pat matched, else nil
|
196
|
+
#skip(pat) #like scan, but returns length instead of match data
|
197
|
+
#check(pat) #like scan, but doesn't move position
|
198
|
+
#match?(pat)#like scan, but returns length and doesn't move position
|
199
|
+
|
200
|
+
#unanchored, forwards
|
201
|
+
#scan_until(pat) #scan for pat somewhere after position
|
202
|
+
#(not necessarily right after)
|
203
|
+
#skip_until(pat) #skip til pattern somewhere after position
|
204
|
+
#check_until(pat) #check til pattern somewhere after position
|
205
|
+
#exist?(pat) #does pat exist somewhere after position? if so where?
|
206
|
+
|
207
|
+
#anchored, backwards
|
208
|
+
#scanback(pat) #scan for pat right before pos
|
209
|
+
#skipback(pat) #skip pat before pos
|
210
|
+
#checkback(pat) #check pat before pos
|
211
|
+
#matchback?(pat) #match pat before pos
|
212
|
+
|
213
|
+
#unanchored, backwards
|
214
|
+
#scanback_until(pat) #scan for pat somewhere before pos
|
215
|
+
#skipback_until(pat) #skip til pat somewhere before pos
|
216
|
+
#checkback_until(pat) #check for pat somewhere before pos
|
217
|
+
#existback?(pat) #does pat exist somewhere before pos? if so where?
|
218
|
+
|
219
|
+
#skip_literal
|
220
|
+
#skip_literals
|
221
|
+
|
222
|
+
#skip_until_literal **
|
223
|
+
#skip_until_literals **
|
224
|
+
|
225
|
+
#last_match
|
226
|
+
|
227
|
+
#maxmatchlen #query scan buffer size
|
228
|
+
#maxmatchlen= len #set scan buffer size
|
229
|
+
|
230
|
+
#split **
|
231
|
+
|
232
|
+
|
233
|
+
#index/#rindex
|
234
|
+
|
235
|
+
#stride **
|
236
|
+
|
237
|
+
#holding #hold current position while executing a block.
|
238
|
+
#The current pos is passed in.
|
239
|
+
#holding? #like #holding, but position is reset only if
|
240
|
+
#block returns false or nil
|
241
|
+
#holding! &block #like #holding, but block is instance_eval'd
|
242
|
+
#in the sequence.
|
243
|
+
|
244
|
+
|
245
|
+
#subseq(*args) #make a new seq out of a subrange of current seq data.
|
246
|
+
|
247
|
+
#reverse #make a new seq that reverses the order of data.
|
248
|
+
|
249
|
+
#close # Close the seq. This will also close/invalidate
|
250
|
+
#every child #position and derived sequence attached to
|
251
|
+
#this one.
|
252
|
+
#closed? # Is the seq closed?
|
253
|
+
|
254
|
+
|
255
|
+
|
256
|
+
#nearbegin(len) #is this seq within len elements of the beginning?
|
257
|
+
#nearend(len) #is this seq within len elements of the end?
|
258
|
+
|
259
|
+
#more_data? #is there any more data in the seq?
|
260
|
+
#was_data? #has any data been seen so far, or are
|
261
|
+
#we still at the beginning?
|
262
|
+
|
263
|
+
|
264
|
+
#first #return first element of data
|
265
|
+
#last #return last element of data
|
266
|
+
|
267
|
+
|
268
|
+
|
269
|
+
sequence classes:
|
270
|
+
base sequences:
|
271
|
+
Sequence #ancestor class
|
272
|
+
Indexed
|
273
|
+
OfArray #over data in an Array
|
274
|
+
OfString #over data in a String
|
275
|
+
File #over data in a File (no insert/delete)
|
276
|
+
IO (R/O) #over data in an IO (pipe/socket/tty/whatever)
|
277
|
+
Enum (R/O) #over data in an Enumeration
|
278
|
+
SingleItem #over a single scalar item
|
279
|
+
OfHash (**)
|
280
|
+
OfObjectIvars (**)
|
281
|
+
OfObjectMethods (**)
|
282
|
+
|
283
|
+
derived sequences:
|
284
|
+
Shifting #saves a copy of the base sequence data
|
285
|
+
#(in another sequence) as it is read
|
286
|
+
Buffered (**) #makes unidirectional sequences bidirectional
|
287
|
+
#(up to the buffer size)
|
288
|
+
Reversed #reverses the order of its base sequence
|
289
|
+
Circular #loops base sequence data over and over
|
290
|
+
SubSeq #extracts a contiguous subset of base sequence
|
291
|
+
#data into a new seq
|
292
|
+
List (**) #logically concatenates its base sequences
|
293
|
+
Overlay (**) #intercepts writes to the base seq
|
294
|
+
Position #an independant position within the base seq
|
295
|
+
|
296
|
+
Future:
|
297
|
+
Scanning (**)
|
298
|
+
Splitting (**)
|
299
|
+
Striding (**)
|
300
|
+
Transforming (**)
|
301
|
+
Branching (**)
|
302
|
+
LinkedList (**)
|
303
|
+
DoubleLinkedList (**)
|
304
|
+
BinaryTree (**)
|
305
|
+
|
306
|
+
Pipe (**) #a bidirectional communication channel
|
307
|
+
#with sequence api
|
308
|
+
IndexedList (**)
|
309
|
+
|
310
|
+
|
311
|
+
known problems:
|
312
|
+
Some unit tests fail
|
313
|
+
Buffered does not work at all
|
314
|
+
Shifting's modify methods don't work reliably
|
315
|
+
Some write operations failing for List
|
316
|
+
No unit tests at all for array-like sequences
|
317
|
+
(tho Reg's unit test does test OfArray at least somewhat...)
|
318
|
+
|
319
|
+
Copyright (C) 2006 Caleb Clausen
|
320
|
+
Distributed under the terms of Ruby's license.
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Copyright (C) 2006 Caleb Clausen
|
2
|
+
# Distributed under the terms of Ruby's license.
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require 'lib/sequence/version.rb'
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
Hoe.new("sequence", Sequence::VERSION) do |_|
|
11
|
+
|
12
|
+
_.author = "Caleb Clausen"
|
13
|
+
_.email = "sequence-owner @at@ inforadical .dot. net"
|
14
|
+
_.url = "http://sequence.rubyforge.org/"
|
15
|
+
_.summary = "A single api for reading and writing sequential data types."
|
16
|
+
_.description = <<-END
|
17
|
+
A unified wrapper api for accessing data in Strings, Arrays, Files, IOs,
|
18
|
+
and Enumerations. Each sequence encapsulates some data and a current position
|
19
|
+
within it. There are methods for moving the position, reading and writing data
|
20
|
+
(with or without moving the position) forward or backward from the current
|
21
|
+
position (or anywhere at all), scanning for patterns (like StringScanner, but
|
22
|
+
it works in Files too, among others), and saving a position that will remain
|
23
|
+
valid even after data is deleted or inserted elsewhere within the sequence.
|
24
|
+
|
25
|
+
There are also some utility classes for making sequences reversed or
|
26
|
+
circular, turning one-way sequences into two-way, buffering, and making
|
27
|
+
sequences that are subsets or aggregations of existing sequences.
|
28
|
+
END
|
29
|
+
end
|
30
|
+
|
31
|
+
# add other tasks here
|
32
|
+
|
data/lib/assert.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Copyright (C) 2006 Caleb Clausen
|
2
|
+
# Distributed under the terms of Ruby's license.
|
3
|
+
|
4
|
+
module Kernel
|
5
|
+
def assert(expr,msg="assertion failed")
|
6
|
+
defined? $Debug and $Debug and (expr or raise msg)
|
7
|
+
end
|
8
|
+
|
9
|
+
@@printed={}
|
10
|
+
def fixme(s)
|
11
|
+
unless @@printed[s]
|
12
|
+
@@printed[s]=1
|
13
|
+
defined? $Debug and $Debug and $stderr.print "FIXME: #{s}\n"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright (C) 2006 Caleb Clausen
|
2
|
+
# Distributed under the terms of Ruby's license.
|
3
|
+
class Sequence
|
4
|
+
module ArrayLike
|
5
|
+
def data_class; Array end
|
6
|
+
def like; ArrayLike end
|
7
|
+
|
8
|
+
def scan(pat)
|
9
|
+
elem=nil
|
10
|
+
more_data? and holding?{pat===(elem=read1)} and return [elem]
|
11
|
+
end
|
12
|
+
|
13
|
+
def scan_until pat
|
14
|
+
i=index(pat,pos) or return
|
15
|
+
read(i-pos)+scan(pat)
|
16
|
+
end
|
17
|
+
|
18
|
+
def scanback pat
|
19
|
+
elem=nil
|
20
|
+
was_data? and holding?{pat===(elem=readback1)} and return [elem]
|
21
|
+
end
|
22
|
+
|
23
|
+
def scanback_until pat
|
24
|
+
i=rindex(pat,pos) or return
|
25
|
+
readback(pos-i)
|
26
|
+
end
|
27
|
+
|
28
|
+
#I ought to have #match and #matchback like in StringLike too
|
29
|
+
|
30
|
+
def push(*arr)
|
31
|
+
append arr
|
32
|
+
end
|
33
|
+
|
34
|
+
def unshift(*arr)
|
35
|
+
prepend arr
|
36
|
+
end
|
37
|
+
|
38
|
+
def index pat,pos=0
|
39
|
+
pos=_normalize_pos(pos)
|
40
|
+
begin
|
41
|
+
pat===(slice pos) and return pos
|
42
|
+
pos+=1
|
43
|
+
end until pos>=size
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def rindex pat,pos=-1
|
48
|
+
pos=_normalize_pos(pos)
|
49
|
+
begin
|
50
|
+
pat===(slice pos) and return pos
|
51
|
+
pos-=1
|
52
|
+
end until pos<0
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# $Id$
|
2
|
+
# Copyright (C) 2006 Caleb Clausen
|
3
|
+
# Distributed under the terms of Ruby's license.
|
4
|
+
|
5
|
+
require 'sequence'
|
6
|
+
#require 'sequence/split'
|
7
|
+
|
8
|
+
class Sequence
|
9
|
+
# This class gives unidirectional sequences (i.e. IO pipes) some
|
10
|
+
# bidirectional capabilities. An input sequence (or input IO) and/or an output
|
11
|
+
# sequence (or output IO)
|
12
|
+
# can be specified. The #position, #position?, and #position! methods are
|
13
|
+
# used to control buffering. Full sequence capability (limited by the size of the buffer
|
14
|
+
# sequence) is accessible starting from the first #position. When the end of
|
15
|
+
# the buffer is reached more data is read from the input sequence (if not nil) . When no
|
16
|
+
# #position is outstanding, everything before the buffer sequence is written
|
17
|
+
# to the output sequence (if not nil). If the sequence is attempted
|
18
|
+
# to be moved before the buffer, the output sequence is read in reverse (which
|
19
|
+
# the output sequence may not like).
|
20
|
+
#how much of that should remain true?
|
21
|
+
class Buffered < Sequence
|
22
|
+
def initialize(input,buffer_size=1024,buffer=nil)
|
23
|
+
@input = input
|
24
|
+
huh #@input used incorrectly... it should be used kinda like a read-once data store
|
25
|
+
#and Buffered should have an independant position
|
26
|
+
@buffer_size=buffer_size
|
27
|
+
@buffer = buffer||@input.new_data
|
28
|
+
# @output_pos = output_pos
|
29
|
+
@buffer_pos=@pos=@input.pos
|
30
|
+
|
31
|
+
@input.on_change_notify self
|
32
|
+
end
|
33
|
+
|
34
|
+
def change_notification
|
35
|
+
huh #invalidate (part of) @buffer if it overlaps the changed area
|
36
|
+
huh #adjust @buffer_pos as necessary
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_accessor :buffer_size
|
40
|
+
attr :pos
|
41
|
+
|
42
|
+
# :stopdoc:
|
43
|
+
def new_data
|
44
|
+
@input.new_data
|
45
|
+
end
|
46
|
+
=begin
|
47
|
+
protected
|
48
|
+
def _delete1after?
|
49
|
+
v0 = @buffer.delete1after?
|
50
|
+
v0.nil? && @input && (v0 = @input.read(1)) && (v0 = v0[0])
|
51
|
+
v0
|
52
|
+
end
|
53
|
+
def _delete1before?
|
54
|
+
v0 = @buffer.delete1before?
|
55
|
+
v0.nil? && @output_pos>0 && (@output_pos -= 1;v0 = @output.read(-1)) && (v0 = v0[0])
|
56
|
+
v0
|
57
|
+
end
|
58
|
+
def _insert1before(v)
|
59
|
+
if not position?
|
60
|
+
len = @buffer.move!(true)
|
61
|
+
if @output
|
62
|
+
value = @buffer.read(len,nil)
|
63
|
+
value << v
|
64
|
+
@output.write(value)
|
65
|
+
else
|
66
|
+
@buffer.read(len,nil) if len
|
67
|
+
end
|
68
|
+
@output_pos += (len||0)+1
|
69
|
+
else
|
70
|
+
@buffer.insert1before(v)
|
71
|
+
end
|
72
|
+
true
|
73
|
+
end
|
74
|
+
def _insert1after(v)
|
75
|
+
@buffer.insert1after(v)
|
76
|
+
end
|
77
|
+
public
|
78
|
+
def close
|
79
|
+
if @output
|
80
|
+
@buffer.move!(true)
|
81
|
+
value = @buffer.read!(false) and @output.write(value)
|
82
|
+
end
|
83
|
+
super
|
84
|
+
end
|
85
|
+
=end
|
86
|
+
def _default_maxmatchlen; @buffer_size/2 end
|
87
|
+
|
88
|
+
attr :pos
|
89
|
+
|
90
|
+
def _pos=(pos)
|
91
|
+
if pos<@buffer_pos
|
92
|
+
@pos=@input.pos=pos #could raise exception, if @input doesn't support #pos=
|
93
|
+
elsif pos<=@buffer_pos+@buffer.size
|
94
|
+
@pos=pos
|
95
|
+
else #@pos > buffer_end_pos
|
96
|
+
assert @buffer_pos+@buffer.size==@input.pos
|
97
|
+
@buffer<<@input.read(pos-@input.pos)
|
98
|
+
buffer_begin_ageout!
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def history_mode?(pos=@pos)
|
103
|
+
pos<@buffer_pos+@buffer.size
|
104
|
+
end
|
105
|
+
|
106
|
+
def_delegators :@input, :size
|
107
|
+
|
108
|
+
def crude_read(len)
|
109
|
+
assert @buffer_pos+@buffer.size==@input.pos
|
110
|
+
result=@input.read(len)
|
111
|
+
@buffer<<result
|
112
|
+
buffer_begin_ageout!
|
113
|
+
result
|
114
|
+
end
|
115
|
+
|
116
|
+
def crude_read_before(len)
|
117
|
+
assert @buffer_pos+@buffer.size==@input.pos
|
118
|
+
result=@input.read(len)
|
119
|
+
@buffer.insert(0,*result)
|
120
|
+
buffer_end_ageout!
|
121
|
+
result
|
122
|
+
end
|
123
|
+
|
124
|
+
def read(len)
|
125
|
+
if @pos<@buffer_pos
|
126
|
+
if @buffer_pos-@pos >= @buffer_size
|
127
|
+
@buffer_pos=@pos
|
128
|
+
@buffer=new_data
|
129
|
+
return crude_read(len)
|
130
|
+
else
|
131
|
+
crude_read_before(@buffer_pos-@pos)
|
132
|
+
self._pos=@buffer_pos
|
133
|
+
|
134
|
+
#fall thru
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
if history_mode?
|
139
|
+
if history_mode?(pos+len-1)
|
140
|
+
result=@buffer[@pos-@buffer_pos,len]
|
141
|
+
@pos+=len
|
142
|
+
else
|
143
|
+
result=@buffer[@pos-@buffer.pos..0]
|
144
|
+
result<<crude_read(len-result.size)
|
145
|
+
end
|
146
|
+
|
147
|
+
result
|
148
|
+
else
|
149
|
+
crude_read len
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def buffer_begin_ageout!
|
154
|
+
diff=@buffer.size-@buffer_size
|
155
|
+
if diff>0
|
156
|
+
@buffer.slice!(0,diff)
|
157
|
+
@buffer_pos+=diff
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def buffer_end_ageout!
|
162
|
+
diff=@buffer.size-@buffer_size
|
163
|
+
if diff>0
|
164
|
+
@buffer.slice!(-diff..-1)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def modify(*args)
|
169
|
+
huh "what does it mean to write to a Buffered?"
|
170
|
+
repldata=args.pop
|
171
|
+
first,len,only1=_parse_slice_args(*args)
|
172
|
+
first<pos-@buffer.size and huh
|
173
|
+
result=new_data
|
174
|
+
if first<pos
|
175
|
+
result=@buffer[huh]
|
176
|
+
end
|
177
|
+
if first+len>pos
|
178
|
+
huh
|
179
|
+
end
|
180
|
+
huh
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
# :startdoc:
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
|