|
1 // -*- mode: js2; indent-tabs-mode: nil; -*- |
|
2 |
|
3 // A RectArray<X,k> is a subclass of Array with 'width', 'height', |
|
4 // and 'payload' properties (where payload holds 'k'). |
|
5 // properties, and 'width*height*k' elements (each an X) in the array. |
|
6 // |
|
7 // A RectTypedByteArray<k> is a subclass of ArrayBuffer with 'width' |
|
8 // and 'height' properties, and 'width*height*k' bytes in the buffer. |
|
9 // |
|
10 // The 'payload' property is initialized with the value of 'k'. |
|
11 // |
|
12 // (Felix would have used Array or ArrayView, but for the following bug: |
|
13 // Bug 695438 - TypedArrays don't support new named properties |
|
14 // https://bugzilla.mozilla.org/show_bug.cgi?id=695438 |
|
15 // and so he is resorting to extending ArrayBuffer instead.) |
|
16 // |
|
17 // Both classes add a .get(x,y[,k]) method that eases access to the |
|
18 // contents, and a set(x,y[,k],value) method that eases modifying |
|
19 // their entries. |
|
20 // |
|
21 // In addition, for those who prefer functional-style, |
|
22 // RectArray.build, |
|
23 // and RectByteTypedArray.build |
|
24 |
|
25 var RectArray, RectByteTypedArray; |
|
26 |
|
27 // This is a variant of RectArray that supports the same interface, |
|
28 // but instead of attempting to extend Array (a practice fraught with |
|
29 // peril), it instead makes a wrapper around another array. |
|
30 |
|
31 var WrapArray, WrapByteTypedArray; |
|
32 |
|
33 (function (){ |
|
34 |
|
35 function defineReadOnly(x, name, value) { |
|
36 Object.defineProperty(x, name, { |
|
37 value: value, |
|
38 writable: false, |
|
39 enumerable: true, |
|
40 configurable: true }); |
|
41 } |
|
42 |
|
43 RectArray = function RectArray(w,h,k) { |
|
44 if (k === undefined) |
|
45 k = 1; |
|
46 this.length = w*h*k; |
|
47 defineReadOnly(this, "width", w); |
|
48 defineReadOnly(this, "height", h); |
|
49 defineReadOnly(this, "payload", k); |
|
50 }; |
|
51 |
|
52 RectByteTypedArray = function RectByteTypedArray(w,h,k) { |
|
53 if (k === undefined) |
|
54 k = 1; |
|
55 ArrayBuffer.call(this, w*h*k); |
|
56 defineReadOnly(this, "width", w); |
|
57 defineReadOnly(this, "height", h); |
|
58 defineReadOnly(this, "payload", k); |
|
59 }; |
|
60 |
|
61 WrapArray = function WrapArray(w,h,k) { |
|
62 if (k === undefined) |
|
63 k = 1; |
|
64 this.backingArray = new Array(w*h*k); |
|
65 defineReadOnly(this, "width", w); |
|
66 defineReadOnly(this, "height", h); |
|
67 defineReadOnly(this, "payload", k); |
|
68 }; |
|
69 |
|
70 WrapByteTypedArray = function WrapByteTypedArray(w,h,k) { |
|
71 if (k === undefined) |
|
72 k = 1; |
|
73 this.backingArray = new Uint8Array(new ArrayBuffer(w*h*k)); |
|
74 defineReadOnly(this, "width", w); |
|
75 defineReadOnly(this, "height", h); |
|
76 defineReadOnly(this, "payload", k); |
|
77 }; |
|
78 |
|
79 WrapArray.prototype.slice = function(a,b) this.backingArray.slice(a,b); |
|
80 WrapArray.prototype.join = function(a) this.backingArray.join(a); |
|
81 |
|
82 RectArray.prototype = new Array(); |
|
83 RectByteTypedArray.prototype = new ArrayBuffer(); |
|
84 |
|
85 RectArray.prototype.get = function get(x,y,j) { |
|
86 if (j === undefined) j = 0; |
|
87 return this[(y*this.width+x)*this.payload+j]; |
|
88 }; |
|
89 |
|
90 RectArray.prototype.set = function set(x,y,j,value) { |
|
91 if (value === undefined) { |
|
92 value = j; |
|
93 j = 0; |
|
94 } |
|
95 this[(y*this.width+x)*this.payload+j] = value; |
|
96 }; |
|
97 |
|
98 RectByteTypedArray.prototype.get = function get(x,y,j) { |
|
99 if (j === undefined) j = 0; |
|
100 return (new Uint8Array(this))[(y*this.width+x)*this.payload+j]; |
|
101 }; |
|
102 |
|
103 RectByteTypedArray.prototype.set = function set(x,y,j,value) { |
|
104 if (value === undefined) { |
|
105 value = j; |
|
106 j = 0; |
|
107 } |
|
108 (new Uint8Array(this))[(y*this.width+x)*this.payload+j] = value; |
|
109 }; |
|
110 |
|
111 WrapArray.prototype.get = function get(x,y,j) { |
|
112 if (j === undefined) j = 0; |
|
113 return this.backingArray[(y*this.width+x)*this.payload+j]; |
|
114 }; |
|
115 |
|
116 WrapArray.prototype.set = function set(x,y,j,value) { |
|
117 if (value === undefined) { |
|
118 value = j; |
|
119 j = 0; |
|
120 } |
|
121 this.backingArray[(y*this.width+x)*this.payload+j] = value; |
|
122 }; |
|
123 |
|
124 WrapByteTypedArray.prototype.get = function get(x,y,j) { |
|
125 if (j === undefined) j = 0; |
|
126 return this.backingArray[(y*this.width+x)*this.payload+j]; |
|
127 }; |
|
128 |
|
129 WrapByteTypedArray.prototype.set = function set(x,y,j,value) { |
|
130 if (value === undefined) { |
|
131 value = j; |
|
132 j = 0; |
|
133 } |
|
134 this.backingArray[(y*this.width+x)*this.payload+j] = value; |
|
135 }; |
|
136 |
|
137 function viewToSource(view, width, height, payload) { |
|
138 var ret = "["; |
|
139 var i=0; |
|
140 var matrixNeedsNewline = false; |
|
141 for (var row=0; row < height; row++) { |
|
142 if (matrixNeedsNewline) |
|
143 ret += ",\n "; |
|
144 ret += "["; |
|
145 var rowNeedsComma = false; |
|
146 for (var x=0; x < width; x++) { |
|
147 if (rowNeedsComma) |
|
148 ret += ", "; |
|
149 if (payload == 1) { |
|
150 if (view[i] !== undefined) |
|
151 ret += view[i]; |
|
152 i++; |
|
153 } else { |
|
154 var entryNeedsComma = false; |
|
155 ret += "("; |
|
156 for (var k=0; k < payload; k++) { |
|
157 // Might be inefficient (does JavaScript have |
|
158 // StringBuffers?, or use them internally, like Tamarin?) |
|
159 if (entryNeedsComma) |
|
160 ret += ", "; |
|
161 if (view[i] !== undefined) |
|
162 ret += view[i]; |
|
163 entryNeedsComma = true; |
|
164 i++; |
|
165 } |
|
166 ret += ")"; |
|
167 } |
|
168 rowNeedsComma = true; |
|
169 } |
|
170 ret += "]"; |
|
171 matrixNeedsNewline = true; |
|
172 } |
|
173 ret += "]"; |
|
174 return ret; |
|
175 } |
|
176 |
|
177 RectArray.prototype.toSource = function toSource() { |
|
178 return viewToSource(this, |
|
179 this.width, this.height, this.payload); |
|
180 }; |
|
181 |
|
182 RectByteTypedArray.prototype.toSource = function toSource() { |
|
183 return viewToSource(new Uint8Array(this), |
|
184 this.width, this.height, this.payload); |
|
185 }; |
|
186 |
|
187 WrapArray.prototype.toSource = function toSource() { |
|
188 return viewToSource(this.backingArray, |
|
189 this.width, this.height, this.payload); |
|
190 }; |
|
191 |
|
192 WrapByteTypedArray.prototype.toSource = function toSource() { |
|
193 return viewToSource(this.backingArray, |
|
194 this.width, this.height, this.payload); |
|
195 }; |
|
196 |
|
197 RectArray.prototype.map = function map(f) { |
|
198 var ret = Array.map(this, f); |
|
199 ret.__proto__ = RectArray.prototype; |
|
200 defineReadOnly(ret, "width", this.width); |
|
201 defineReadOnly(ret, "height", this.height); |
|
202 defineReadOnly(ret, "payload", this.payload); |
|
203 return ret; |
|
204 }; |
|
205 |
|
206 WrapArray.prototype.map = function map(f) { |
|
207 var ret = new WrapArray(this.width, this.height, this.payload); |
|
208 ret.backingArray = this.backingArray.map(f); |
|
209 return ret; |
|
210 }; |
|
211 |
|
212 // (Array<X>|ArrayView<X>) Nat Nat Nat (Nat Nat Nat -> X) -> void |
|
213 function fillArrayView(view, width, height, k, fill) { |
|
214 var i = 0; |
|
215 for (var y=0; y < height; y++) { |
|
216 for (var x=0; x < width; x++) { |
|
217 for (var j=0; j < k; j++) { |
|
218 view[i++] = fill(x, y, j); |
|
219 } |
|
220 } |
|
221 } |
|
222 } |
|
223 |
|
224 |
|
225 // Nat Nat (Nat Nat [Nat] -> X) -> RectArray<X,1> |
|
226 RectArray.build = |
|
227 function buildRectArray1(width, height, fill) { |
|
228 var a = new RectArray(width, height, 1); |
|
229 fillArrayView(a, width, height, 1, fill); |
|
230 return a; |
|
231 }; |
|
232 |
|
233 RectArray.buildA = |
|
234 function buildRectArrayA(width, height, fill) { |
|
235 var a = new Array(width*height); |
|
236 fillArrayView(a, width, height, 1, fill); |
|
237 a.width = width; |
|
238 a.height = height; |
|
239 a.payload = 1; |
|
240 function F() { } |
|
241 F.prototype = RectArray.prototype; |
|
242 a.__proto__ = new F(); |
|
243 return a; |
|
244 }; |
|
245 |
|
246 // Nat Nat (Nat Nat Nat -> X) -> RectArray<X,4> |
|
247 RectArray.build4 = |
|
248 function buildRectArray4(width, height, fill) { |
|
249 var a = new RectArray(width, height, 4); |
|
250 fillArrayView(a, width, height, 4, fill); |
|
251 return a; |
|
252 }; |
|
253 |
|
254 // Nat Nat (Nat Nat Nat -> X) -> RectArray<X,1> |
|
255 RectArray.buildN = |
|
256 function buildRectArrayN(width, height, n, fill) { |
|
257 var a = new RectArray(width, height, n); |
|
258 fillArrayView(a, width, height, n, fill); |
|
259 return a; |
|
260 }; |
|
261 |
|
262 |
|
263 // Nat Nat (Nat Nat [Nat] -> Byte) -> RectTypedByteArray<4> |
|
264 RectByteTypedArray.build = |
|
265 function buildRectByteTypedArray1(width, height, fill) { |
|
266 var buf = new RectByteTypedArray(width, height, 1); |
|
267 fillArrayView(new Uint8Array(buf), width, height, 1, fill); |
|
268 return buf; |
|
269 }; |
|
270 |
|
271 // Nat Nat (Nat Nat Nat -> Byte) -> RectTypedByteArray<4> |
|
272 RectByteTypedArray.build4 = |
|
273 function buildRectByteTypedArray4(width, height, fill) { |
|
274 var buf = new RectByteTypedArray(width, height, 4); |
|
275 fillArrayView(new Uint8Array(buf), width, height, 4, fill); |
|
276 return buf; |
|
277 }; |
|
278 |
|
279 // Nat Nat (Nat Nat Nat -> Byte) -> RectTypedByteArray<4> |
|
280 RectByteTypedArray.buildN = |
|
281 function buildRectByteTypedArray4(width, height, n, fill) { |
|
282 var buf = new RectByteTypedArray(width, height, n); |
|
283 fillArrayView(new Uint8Array(buf), width, height, n, fill); |
|
284 return buf; |
|
285 }; |
|
286 |
|
287 WrapArray.build = |
|
288 function buildWrapArray1(width, height, fill) { |
|
289 var a = new WrapArray(width, height, 1); |
|
290 fillArrayView(a, width, height, 1, fill); |
|
291 return a; |
|
292 }; |
|
293 |
|
294 WrapArray.build = |
|
295 function buildWrapArray1(width, height, fill) { |
|
296 var a = new WrapArray(width, height, 1); |
|
297 fillArrayView(a.backingArray, width, height, 1, fill); |
|
298 return a; |
|
299 }; |
|
300 |
|
301 WrapArray.build4 = |
|
302 function buildWrapArray1(width, height, fill) { |
|
303 var a = new WrapArray(width, height, 4); |
|
304 fillArrayView(a.backingArray, width, height, 4, fill); |
|
305 return a; |
|
306 }; |
|
307 |
|
308 WrapArray.buildN = |
|
309 function buildWrapArray1(width, height, n, fill) { |
|
310 var a = new WrapArray(width, height, n); |
|
311 fillArrayView(a.backingArray, width, height, n, fill); |
|
312 return a; |
|
313 }; |
|
314 |
|
315 })(); |