2 using System
.Collections
;
3 using System
.Collections
.Generic
;
10 * A simple structure that allows us to wrap *part* of a byte[] array.
11 * This is intended to be an efficient alternative to constantly
12 * reallocating and copying arrays just because we want to talk about
15 * In C/C++, manipulations on subsets of byte arrays are common using
16 * pointer arithmetic. We don't want to use pointers because it makes
17 * our code unsafe, but there's no need to be copying entire arrays
18 * around just because of that!
20 public struct WvBytes
: IEnumerable
<byte>
23 public int start
, len
;
26 * Wrap a particular section of the given bytes[] array.
28 public WvBytes(byte[] bytes
, int start
, int len
)
33 wv
.assert(start
>= 0);
35 wv
.assert(bytes
==null || start
+len
<= bytes
.Length
);
39 * Any byte array can produce a WvBytes object with no effort.
41 public static implicit operator WvBytes(byte[] b
)
43 return new WvBytes(b
, 0, b
!= null ? b
.Length
: 0);
47 * Any WvBytes object is enough to produce a byte array, but it
48 * might require an array copy. So we make it explicit to avoid
49 * doing it by accident.
51 public static explicit operator byte[](WvBytes b
)
57 * Convert this byte array to a simple byte[] structure. This
58 * *might* imply making a copy, but might not, so don't modify the
59 * resulting array. Of course, we can't stop you from modifying
60 * the array, because there's no const, so we'll have to trust you.
62 public byte[] ToArray()
64 if (start
== 0 && len
== bytes
.Length
)
68 byte[] b
= new byte[len
];
69 Array
.Copy(bytes
, start
, b
, 0, len
);
75 get { return bytes == null; }
78 /// parallels WvBuf.getall()
79 public byte[] getall()
84 /// get a subset of this set of bytes, without copying any actual data
85 public WvBytes
sub(int start
, int len
)
87 wv
.assert(start
>= 0);
89 wv
.assert(start
+len
<= this.len
);
90 if (start
== this.start
&& len
== this.len
)
92 int s
= this.start
+ start
;
93 wv
.assert(s
+len
<= bytes
.Length
);
95 return new WvBytes(bytes
, s
, len
);
98 public byte this[int i
] {
101 return bytes
[start
+i
];
105 public void put(int offset
, WvBytes b
)
107 wv
.assert(offset
>= 0);
108 wv
.assert(offset
+b
.len
<= len
);
109 Array
.Copy(b
.bytes
, b
.start
, this.bytes
, start
+offset
, b
.len
);
113 public IEnumerator
<byte> GetEnumerator()
116 for (int i
= start
; i
< end
; i
++)
117 yield return bytes
[i
];
121 IEnumerator IEnumerable
.GetEnumerator()
124 for (int i
= start
; i
< end
; i
++)
125 yield return bytes
[i
];
129 public class WvMiniBuf
134 public WvMiniBuf(int size
)
136 bytes
= new byte[size
];
141 public int size { get { return (int)bytes.Length; }
}
143 public int used { get { return next-first; }
}
145 public int avail { get { return (int)bytes.Length-next; }
}
147 public WvBytes
alloc(int size
)
149 wv
.assert(size
<= avail
);
150 var ret
= bytes
.sub(next
, size
);
155 public void unalloc(int size
)
157 wv
.assert(size
<= used
);
161 public void put(WvBytes b
)
163 wv
.assert(b
.len
<= avail
);
164 alloc(b
.len
).put(0, b
);
167 public WvBytes
peek(int len
)
169 return bytes
.sub(first
, len
);
172 public WvBytes
get(int len
)
179 public void unget(int len
)
181 wv
.assert(first
>= len
);
185 // Returns the number of bytes that would have to be read in order to
186 // get the first instance of 'b', or 0 if 'b' is not in the buffer.
187 public int strchr(byte b
)
189 for (int i
= first
; i
< next
; i
++)
203 List
<WvMiniBuf
> list
= new List
<WvMiniBuf
>();
206 public WvBuf(int startsize
)
208 this.startsize
= startsize
;
219 return (int)list
.Select(b
=> (long)b
.used
).Sum();
223 WvMiniBuf last { get { return list[list.Count-1]; }
}
228 list
.Add(new WvMiniBuf(startsize
));
233 int s
= last
.size
* 2;
236 list
.Add(new WvMiniBuf(s
));
239 public WvBytes
alloc(int size
)
241 if (last
.avail
< size
)
243 return last
.alloc(size
);
246 public void unalloc(int size
)
248 wv
.assert(last
.used
>= size
);
252 public void put(WvBytes b
)
254 alloc(b
.len
).put(0, b
);
257 public void put(char c
)
262 public void put(string s
)
267 public void put(byte b
)
269 // FIXME: this could be much more optimal :)
270 put(new byte[1] { b }
);
273 public void put(string fmt
, params object[] args
)
275 put(String
.Format(fmt
, args
));
278 public void eat(WvBuf buf
)
280 list
.AddRange(buf
.list
);
284 int min(int a
, int b
)
286 return (a
< b
) ? a
: b
;
289 void coagulate(int len
)
291 if (list
[0].used
< len
)
293 WvMiniBuf n
= new WvMiniBuf(len
);
296 int got
= min(len
, list
[0].used
);
297 n
.put(list
[0].get(got
));
299 if (list
[0].used
== 0)
300 list
.Remove(list
[0]);
306 public WvBytes
peek(int len
)
308 wv
.assert(used
>= len
);
310 return list
[0].peek(len
);
313 public WvBytes
peekall()
318 public WvBytes
get(int len
)
320 wv
.assert(used
>= len
);
322 return list
[0].get(len
);
325 public WvBytes
getall()
330 public string getstr()
332 return getall().FromUTF8();
335 public void unget(int len
)
340 // Returns the number of bytes that would have to be read in order to
341 // get the first instance of 'b', or 0 if 'b' is not in the buffer.
342 public int strchr(byte b
)
345 foreach (WvMiniBuf mb
in list
)
347 int r
= mb
.strchr(b
);
356 public int strchr(char b
)
358 return strchr(Convert
.ToByte(b
));