Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/typedObjects/arrayTypes.js

Issue 5728072976302080: Issue 151 - [Typed objects] Implement dynamically-sized array types (Closed)
Patch Set: Created July 11, 2014, 7:26 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/typedObjects.js ('k') | lib/typedObjects/objectTypes.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2014 Eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 "use strict";
19
20 let {ilog2, nextPow2, alloc, dealloc, addBuffer, removeBuffer} = require("typedO bjects/utils");
21
22 function defaultArrayConstructor()
23 {
24 this.arrayBufferIndex = -1;
25 };
26
27 function defaultArrayDestructor()
28 {
29 this.length = 0;
30 this.size = 0;
31 };
32
33 function createGetter(elementGetter, elementShift)
34 {
35 return function(index)
36 {
37 if (index < 0 || index >= this.length)
38 throw new Error("Array index out of bounds");
39 return elementGetter.call(this, this.arrayBufferIndex, this.arrayByteOffset + (index << elementShift));
40 };
41 }
42
43 function createSetter(elementSetter, elementShift)
44 {
45 return function(index, value)
46 {
47 if (index < 0 || index >= this.length)
48 throw new Error("Array index out of bounds");
49 return elementSetter.call(this, this.arrayBufferIndex, this.arrayByteOffset + (index << elementShift), value);
50 }
51 }
52
53 function createCombinedConstructor(customConstructor)
54 {
55 return function()
56 {
57 defaultArrayConstructor.apply(this);
58 customConstructor.apply(this, arguments);
59 }
60 }
61
62 function createCombinedDestructor(customDestructor)
63 {
64 return function()
65 {
66 try
67 {
68 customDestructor.apply(this);
69 }
70 finally
71 {
72 defaultArrayDestructor.apply(this);
73 }
74 }
75 }
76
77 function createLengthWatcher(elementType, elementSetter)
78 {
79 let {STATE_UNINITIALIZED} = require("typedObjects/objectTypes");
80 return function lengthWatcher(newLength)
81 {
82 newLength = newLength | 0;
83 if (newLength < 0)
84 newLength = 0;
85 if (newLength > this.size)
86 this.size = newLength;
87
88 let initialValue = elementType.initialValue;
89 if (typeof initialValue != "undefined")
90 {
91 let length = this.length;
92 if (newLength > length)
93 {
94 // We have to call element setter directly here, this.set() will
95 // complain because of writing out of bounds (new length isn't set yet).
96 // We also need to change state temporarily in order to avoid an attemt
97 // to release "existing" values.
98 let origState = this._state;
99 this._state = STATE_UNINITIALIZED;
100 try
101 {
102 let referenceLength = elementType.referenceLength | 0;
103 let bufferIndex = this.arrayBufferIndex | 0;
104 for (let i = length, offset = this.arrayByteOffset + length * referenc eLength;
105 i < newLength;
106 i++, offset += referenceLength)
107 {
108 elementSetter.call(this, bufferIndex, offset, initialValue);
109 }
110 }
111 finally
112 {
113 this._state = origState;
114 }
115 }
116 else
117 {
118 for (let i = newLength; i < length; i++)
119 this.set(i, initialValue);
120 }
121 }
122
123 return newLength;
124 }
125 }
126
127 function createSizeWatcher(elementType, minElements, bufferSize, buffers, viewTy pes, views, firstFree)
128 {
129 let referenceLength = elementType.referenceLength | 0;
130 minElements = minElements | 0;
131 bufferSize = bufferSize | 0;
132 return function sizeWatcher(newSize)
133 {
134 newSize = newSize | 0;
135 let length = this.length | 0;
136 if (newSize < length)
137 newSize = length;
138 if (newSize > 0 && newSize < minElements)
139 newSize = minElements;
140 newSize = nextPow2(newSize);
141
142 let size = this.size;
143 if (size != newSize)
144 {
145 let origBufferIndex = this.arrayBufferIndex;
146 let origByteOffset = this.arrayByteOffset;
147 if (newSize > 0)
148 {
149 // Allocate new buffer
150 let bufferIndex, byteOffset;
151 let reference = firstFree[newSize];
152 if (typeof reference != "undefined")
153 {
154 [bufferIndex, byteOffset] = alloc(reference,
155 referenceLength * newSize, (bufferSize / newSize) | 0,
156 buffers, viewTypes, views);
157 }
158 else
159 {
160 // This array is too large, it needs an individual buffer
161 bufferIndex = addBuffer(referenceLength * newSize, buffers, viewTypes, views);
162 bufferOffset = 0;
163 }
164
165 if (size > 0)
166 {
167 let copyBytes = length * referenceLength;
168 let src = new Uint8Array(buffers[this.arrayBufferIndex], this.arrayByt eOffset, copyBytes);
169 let dst = new Uint8Array(buffers[bufferIndex], byteOffset, copyBytes);
170 dst.set(src);
171 }
172
173 this.arrayBufferIndex = bufferIndex;
174 this.arrayByteOffset = byteOffset;
175 }
176 else
177 this.arrayBufferIndex = -1;
178
179 if (size > 0)
180 {
181 // Release old buffer
182 let reference = firstFree[size];
183 if (typeof reference != "undefined")
184 dealloc(reference, origBufferIndex, origByteOffset);
185 else
186 removeBuffer(origBufferIndex, buffers, views);
187 }
188 }
189
190 return newSize;
191 }
192 }
193
194 function createArrayType(elementType, typeDescriptor, meta)
195 {
196 if (typeof meta != "object" || meta == null)
197 meta = {};
198
199 // We need to make sure that all buffer chunks are big enough to hold a
200 // reference in order to manage the free chunks as a linked list. Each array
201 // buffer should be dedicated to arrays of particular size - the number of
202 // possible sizes is limited as the sizes can only be powers of two.
203 let {TypedReference} = require("typedObjects/references");
204 let minElements = nextPow2(Math.max(Math.ceil(TypedReference.byteLength / elem entType.referenceLength) | 0, 1));
205 let bufferSize = ("arrayBufferSize" in meta ? meta.arrayBufferSize | 0 : 1024) ;
206 bufferSize = nextPow2(Math.max(bufferSize, minElements * 2)) | 0;
207
208 let buffers = [];
209 let viewTypes = elementType.viewTypes.slice();
210 let views = [];
211 for (let i = 0, l = viewTypes.length | 0; i < l; i++)
212 views.push([]);
213
214 let elementGetter = elementType.createGetter.apply(elementType, [0].concat(vie ws));
215 let elementSetter = elementType.createSetter.apply(elementType, [0].concat(vie ws));
216
217 let typedReferenceTypes = TypedReference.viewTypes;
218 let typedReferenceViews = [];
219 for (let i = 0, l = typedReferenceTypes.length | 0; i < l; i++)
220 {
221 let type = typedReferenceTypes[i];
222 let index = viewTypes.indexOf(type);
223 if (index < 0)
224 {
225 viewTypes.push(type);
226 views.push([]);
227 index = viewTypes.length - 1;
228 }
229 typedReferenceViews.push(views[index]);
230 }
231
232 let firstFree = [];
233 for (let i = minElements; i < bufferSize; i <<= 1)
234 firstFree[i] = new TypedReference(-1, typedReferenceViews);
235
236 let {int16, uint32} = require("typedObjects/primitiveTypes");
237 typeDescriptor = Object.create(typeDescriptor || {});
238 typeDescriptor.arrayBufferIndex = int16;
239 typeDescriptor.arrayByteOffset = uint32;
240 typeDescriptor.length = uint32;
241 typeDescriptor.size = uint32;
242
243 let elementShift = ilog2(elementType.referenceLength | 0);
244 typeDescriptor.get = createGetter(elementGetter, elementShift);
245 typeDescriptor.set = createSetter(elementSetter, elementShift);
246
247 if (meta.hasOwnProperty("constructor") && typeof meta.constructor == "function ")
248 meta.constructor = createCombinedConstructor(meta.constructor);
249 else
250 meta.constructor = defaultArrayConstructor;
251
252 if (meta.hasOwnProperty("destructor") && typeof meta.destructor == "function")
253 meta.destructor = createCombinedDestructor(meta.destructor);
254 else
255 meta.destructor = defaultArrayDestructor;
256
257 if (!meta.watch || typeof meta.watch != "object")
258 meta.watch = {};
259
260 meta.watch.length = createLengthWatcher(elementType, elementSetter);
261 meta.watch.size = createSizeWatcher(elementType, minElements, bufferSize, buff ers, viewTypes, views, firstFree);
262
263 let {ObjectBase} = require("typedObjects/objectTypes");
264 return ObjectBase.extend(typeDescriptor, meta);
265 }
266
267 exports.createArrayType = createArrayType;
OLDNEW
« no previous file with comments | « lib/typedObjects.js ('k') | lib/typedObjects/objectTypes.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld