author | Jan Vrany <jan.vrany@fit.cvut.cz> |
Wed, 01 Feb 2012 00:56:17 +0000 | |
changeset 103 | 726bf2ca0b99 |
parent 67 | a87e5ce04545 |
child 109 | 9587e2df7029 |
permissions | -rw-r--r-- |
4 | 1 |
"{ Package: 'stx:goodies/xtreams/substreams' }" |
2 |
||
3 |
"{ NameSpace: Xtreams }" |
|
4 |
||
5 |
ReadSubstream subclass:#MatchReadSubstream |
|
6 |
instanceVariableNames:'substreamAtEnd pattern patternStart inclusive hasReread reread |
|
7 |
buffer backtrack' |
|
8 |
classVariableNames:'' |
|
9 |
poolDictionaries:'' |
|
22
e0653bbdbe61
added XtreamsPool to fix DefaultBufferSize; set proper category names
mkobetic
parents:
4
diff
changeset
|
10 |
category:'Xtreams-Substreams' |
4 | 11 |
! |
12 |
||
13 |
MatchReadSubstream comment:'This is a substream bounded by a string pattern. The algorithm used doesn''t need to peek or step back to detect the pattern, so it can be used on non-positionable streams. |
|
14 |
||
15 |
Instance Variables |
|
16 |
substreamAtEnd <Boolean> is this substream at end |
|
17 |
pattern <String> the bounding pattern |
|
18 |
patternStart <Integer> |
|
19 |
inclusive <Boolean> is the boundary part of the substream contents |
|
20 |
hasReread <Boolean> |
|
21 |
reread <Object> |
|
22 |
buffer <RingBuffer> read-ahead buffer (to be able to stop before pattern if inclusive is false) |
|
23 |
backtrack <Array> backtracking table for pattern |
|
24 |
||
25 |
' |
|
26 |
! |
|
27 |
||
28 |
||
29 |
!MatchReadSubstream class methodsFor:'instance creation'! |
|
30 |
||
31 |
on: aSource pattern: aPattern backtrack: aBacktrack inclusive: aBoolean |
|
32 |
^self new on: aSource pattern: aPattern backtrack: aBacktrack inclusive: aBoolean |
|
33 |
! ! |
|
34 |
||
35 |
!MatchReadSubstream methodsFor:'accessing'! |
|
36 |
||
37 |
get |
|
38 |
buffer hasDataToRead ifTrue: [^buffer get]. |
|
39 |
substreamAtEnd ifTrue: [Incomplete zero raise]. |
|
40 |
||
41 |
self gobble. |
|
42 |
buffer hasDataToRead ifFalse: [Incomplete zero raise]. |
|
43 |
^buffer get |
|
44 |
! |
|
45 |
||
46 |
read: anInteger into: aSequenceableCollection at: startIndex |
|
47 |
| count amount | |
|
48 |
||
49 |
count := 0. |
|
50 |
[count < anInteger and: [buffer hasDataToRead or: [substreamAtEnd not]]] whileTrue: |
|
51 |
[buffer hasDataToRead ifFalse: [self gobble]. |
|
52 |
buffer hasDataToRead ifFalse: [(Incomplete on: aSequenceableCollection count: count at: startIndex) raise]. |
|
53 |
amount := buffer readSize min: (anInteger - count). |
|
54 |
buffer read: amount into: aSequenceableCollection at: startIndex + count. |
|
55 |
count := count + amount]. |
|
56 |
count < anInteger ifTrue: [(Incomplete on: aSequenceableCollection count: count at: startIndex) raise]. |
|
57 |
^anInteger |
|
58 |
! ! |
|
59 |
||
60 |
!MatchReadSubstream methodsFor:'initialize-release'! |
|
61 |
||
62 |
close |
|
63 |
super close. |
|
64 |
buffer recycle |
|
65 |
! |
|
66 |
||
67 |
on: aSource pattern: aPattern backtrack: aBacktrack inclusive: aBoolean |
|
68 |
self on: aSource. |
|
69 |
pattern := aPattern. |
|
70 |
buffer := RingBuffer new: pattern size class: self contentsSpecies. |
|
71 |
hasReread := false. |
|
72 |
backtrack := aBacktrack. |
|
73 |
patternStart := 1. |
|
74 |
inclusive := aBoolean. |
|
75 |
substreamAtEnd := false |
|
76 |
! |
|
77 |
||
78 |
subseekend |
|
79 |
[buffer hasDataToRead or: [substreamAtEnd not]] whileTrue: |
|
80 |
[buffer hasDataToRead ifFalse: [self gobble]. |
|
81 |
buffer readSkip: buffer readSize] |
|
82 |
! ! |
|
83 |
||
84 |
!MatchReadSubstream methodsFor:'private'! |
|
85 |
||
86 |
gobble |
|
87 |
| object match patternStop progress | |
|
88 |
patternStop := patternStart. |
|
89 |
[hasReread |
|
90 |
ifTrue: [hasReread := false. object := reread. reread := nil] |
|
91 |
ifFalse: [object := source get]. |
|
92 |
[(match := object = (pattern at: patternStop)) ifTrue: [patternStop := patternStop + 1]. |
|
93 |
match and: [patternStop <= pattern size]] |
|
94 |
whileTrue: [object := source get]] |
|
95 |
on: Incomplete do: [:incomplete | |
|
96 |
sourceAtEnd := substreamAtEnd := true]. |
|
97 |
||
98 |
"A full pattern match" |
|
99 |
patternStop > pattern size ifTrue: [ |
|
100 |
inclusive ifTrue: [buffer write: pattern size from: pattern at: 1]. |
|
101 |
substreamAtEnd := true. |
|
102 |
^self]. |
|
103 |
||
104 |
"No match at all, write out the object we just read" |
|
105 |
progress := patternStop - patternStart. |
|
106 |
(patternStart = 1 and: [progress = 0]) ifTrue: [ |
|
107 |
sourceAtEnd ifFalse: [buffer put: object]. |
|
108 |
patternStart := 1. |
|
109 |
^self]. |
|
110 |
||
111 |
"Partial match, write out the part of the pattern previously matched and keep the object we just read to be re-read next time" |
|
112 |
hasReread := true. |
|
113 |
reread := object. |
|
114 |
buffer write: progress from: pattern at: patternStart. |
|
115 |
patternStart := backtrack at: patternStop |
|
116 |
! |
|
117 |
||
118 |
streamingInsert: anInteger into: aWriteStream |
|
119 |
| count amount | |
|
120 |
||
121 |
count := 0. |
|
122 |
[count < anInteger and: [buffer hasDataToRead or: [substreamAtEnd not]]] whileTrue: |
|
123 |
[buffer hasDataToRead ifFalse: [self gobble]. |
|
124 |
buffer hasDataToRead ifFalse: [(Incomplete count: count) raise]. |
|
125 |
amount := buffer readSize min: (anInteger - count). |
|
126 |
aWriteStream insert: amount from: buffer. |
|
127 |
count := count + amount]. |
|
128 |
count < anInteger ifTrue: [(Incomplete count: count) raise] |
|
129 |
! |
|
130 |
||
131 |
streamingInsertInto: aWriteStream |
|
132 |
| amount | |
|
133 |
||
134 |
[buffer hasDataToRead or: [substreamAtEnd not]] whileTrue: |
|
135 |
[buffer hasDataToRead ifFalse: [self gobble]. |
|
136 |
amount := buffer readSize. |
|
137 |
aWriteStream insert: amount from: buffer] |
|
138 |
! |
|
139 |
||
140 |
streamingWrite: anInteger into: aWriteStream |
|
141 |
| count amount | |
|
142 |
||
143 |
count := 0. |
|
144 |
[count < anInteger and: [buffer hasDataToRead or: [substreamAtEnd not]]] whileTrue: |
|
145 |
[buffer hasDataToRead ifFalse: [self gobble]. |
|
146 |
buffer hasDataToRead ifFalse: [(Incomplete count: count) raise]. |
|
147 |
amount := buffer readSize min: (anInteger - count). |
|
148 |
aWriteStream write: amount from: buffer. |
|
149 |
count := count + amount]. |
|
150 |
count < anInteger ifTrue: [(Incomplete count: count) raise]. |
|
151 |
^anInteger |
|
152 |
! |
|
153 |
||
154 |
streamingWriteInto: aWriteStream |
|
155 |
| amount count | |
|
156 |
count := 0. |
|
157 |
[buffer hasDataToRead or: [substreamAtEnd not]] whileTrue: |
|
158 |
[buffer hasDataToRead ifFalse: [self gobble]. |
|
159 |
amount := buffer readSize. |
|
160 |
aWriteStream write: amount from: buffer. |
|
161 |
count := count + amount ]. |
|
162 |
^count |
|
163 |
! ! |
|
164 |
||
165 |
!MatchReadSubstream methodsFor:'seeking'! |
|
166 |
||
167 |
-= anInteger |
|
168 |
^anInteger isZero |
|
169 |
ifTrue: [self subseekend. 0] |
|
170 |
ifFalse: [super -= anInteger] |
|
171 |
! ! |
|
172 |
||
173 |
!MatchReadSubstream methodsFor:'testing'! |
|
174 |
||
175 |
isPositionable |
|
176 |
^false |
|
177 |
! ! |
|
178 |
||
179 |
!MatchReadSubstream class methodsFor:'documentation'! |
|
180 |
||
181 |
version_SVN |
|
182 |
^ '$Id$' |
|
183 |
! ! |