sm.exe: add bookmarks and default values.
[versaplex.git] / wvdotnet / wvbuf.cs
blobab1ef8bede370b3cbbfeac03b2a4bfdfb648bd24
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using Wv.Extensions;
7 namespace Wv
9 /**
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
13 * subsets of them.
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>
22 public byte[] bytes;
23 public int start, len;
25 /**
26 * Wrap a particular section of the given bytes[] array.
28 public WvBytes(byte[] bytes, int start, int len)
30 this.bytes = bytes;
31 this.start = start;
32 this.len = len;
33 wv.assert(start >= 0);
34 wv.assert(len >= 0);
35 wv.assert(bytes==null || start+len <= bytes.Length);
38 /**
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);
46 /**
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)
53 return b.ToArray();
56 /**
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)
65 return bytes;
66 else
68 byte[] b = new byte[len];
69 Array.Copy(bytes, start, b, 0, len);
70 return b;
74 public bool IsNull {
75 get { return bytes == null; }
78 /// parallels WvBuf.getall()
79 public byte[] getall()
81 return ToArray();
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);
88 wv.assert(len >= 0);
89 wv.assert(start+len <= this.len);
90 if (start == this.start && len == this.len)
91 return this;
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] {
99 get {
100 wv.assert(i < len);
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);
112 // IEnumerable<byte>
113 public IEnumerator<byte> GetEnumerator()
115 int end = start+len;
116 for (int i = start; i < end; i++)
117 yield return bytes[i];
120 // IEnumerable
121 IEnumerator IEnumerable.GetEnumerator()
123 int end = start+len;
124 for (int i = start; i < end; i++)
125 yield return bytes[i];
129 public class WvMiniBuf
131 byte[] bytes;
132 int first, next;
134 public WvMiniBuf(int size)
136 bytes = new byte[size];
137 first = 0;
138 next = 0;
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);
151 next += size;
152 return ret;
155 public void unalloc(int size)
157 wv.assert(size <= used);
158 next -= size;
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)
174 var ret = peek(len);
175 first += len;
176 return ret;
179 public void unget(int len)
181 wv.assert(first >= len);
182 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++)
190 if (bytes[i] == b)
191 return i-first+1;
192 return 0;
195 public void zap()
197 first = next = 0;
201 public class WvBuf
203 List<WvMiniBuf> list = new List<WvMiniBuf>();
204 int startsize = 10;
206 public WvBuf(int startsize)
208 this.startsize = startsize;
209 zap();
212 public WvBuf()
213 : this(10)
217 public int used {
218 get {
219 return (int)list.Select(b => (long)b.used).Sum();
223 WvMiniBuf last { get { return list[list.Count-1]; } }
225 public void zap()
227 list.Clear();
228 list.Add(new WvMiniBuf(startsize));
231 void addbuf(int len)
233 int s = last.size * 2;
234 while (s < len*2)
235 s *= 2;
236 list.Add(new WvMiniBuf(s));
239 public WvBytes alloc(int size)
241 if (last.avail < size)
242 addbuf(size);
243 return last.alloc(size);
246 public void unalloc(int size)
248 wv.assert(last.used >= size);
249 last.unalloc(size);
252 public void put(WvBytes b)
254 alloc(b.len).put(0, b);
257 public void put(char c)
259 put(c.ToUTF8());
262 public void put(string s)
264 put(s.ToUTF8());
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);
281 buf.zap();
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);
294 while (len > 0)
296 int got = min(len, list[0].used);
297 n.put(list[0].get(got));
298 len -= got;
299 if (list[0].used == 0)
300 list.Remove(list[0]);
302 list.Insert(0, n);
306 public WvBytes peek(int len)
308 wv.assert(used >= len);
309 coagulate(len);
310 return list[0].peek(len);
313 public WvBytes peekall()
315 return peek(used);
318 public WvBytes get(int len)
320 wv.assert(used >= len);
321 coagulate(len);
322 return list[0].get(len);
325 public WvBytes getall()
327 return get(used);
330 public string getstr()
332 return getall().FromUTF8();
335 public void unget(int len)
337 list[0].unget(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)
344 int i = 0;
345 foreach (WvMiniBuf mb in list)
347 int r = mb.strchr(b);
348 if (r > 0)
349 return i + r;
350 else
351 i += mb.used;
353 return 0;
356 public int strchr(char b)
358 return strchr(Convert.ToByte(b));