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

Unified Diff: lib/typedObjects/utils.js

Issue 5728072976302080: Issue 151 - [Typed objects] Implement dynamically-sized array types (Closed)
Patch Set: Created July 11, 2014, 7:26 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/typedObjects/primitiveTypes.js ('k') | test/index.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/typedObjects/utils.js
===================================================================
--- a/lib/typedObjects/utils.js
+++ b/lib/typedObjects/utils.js
@@ -82,28 +82,66 @@ let getViewsForType = exports.getViewsFo
index = (viewTypes.push(viewType) | 0) - 1;
views.push([]);
}
result.push(views[index]);
}
return result;
};
+ /**
+ * Creates a wrapper function for a setter that will call the watcher function
+ * with the new value of the property before executing the actual setter.
+ */
+function watchSetter(/**Function*/ setter, /**Function*/ watcher) /**Function*/
+{
+ return function(value)
+ {
+ setter.call(this, watcher.call(this, value));
+ }
+}
+
+/**
+ * Creates a parameter-less wrapper function around a getter that will get
+ * bufferIndex and byteOffset parameters from object properties.
+ */
+function wrapGetter(/**Function*/ getter) /**Function*/
+{
+ return function()
+ {
+ return getter.call(this, this.bufferIndex, this.byteOffset);
+ }
+}
+
+/**
+ * Creates a wrapper function around a setter with value as the only parameter,
+ * the bufferIndex and byteOffset parameters will be retrieved from object
+ * properties.
+ */
+function wrapSetter(/**Function*/ setter) /**Function*/
+{
+ return function(value)
+ {
+ return setter.call(this, this.bufferIndex, this.byteOffset, value);
+ }
+}
+
/**
* Defines properties with given name and type on an object.
*
* @param obj object to define properties on
* @param properties object mapping property names to their respective types
* @param viewTypes see getViewsForType()
* @param views see getViewsForType()
* @param [offset] byte array offset at which the properties should start
- * @param [cleanupValues] array of property/value combinations to be set when the object is created or destroyed
+ * @param [watchers] map of watcher functions to be called when a particular property is being set
+ * @param [initialValues] array of property/value combinations to be set when the object is created or destroyed
* @return new start offset for additional properties
*/
-exports.defineProperties = function defineProperties(obj, properties, viewTypes, views, offset, cleanupValues)
+exports.defineProperties = function defineProperties(obj, properties, viewTypes, views, offset, watchers, initialValues)
{
offset = offset | 0;
let propList = [];
for (let name in properties)
propList.push([name, properties[name]]);
// Put larger properties first to make sure alignment requirements are met.
@@ -115,23 +153,125 @@ exports.defineProperties = function defi
// Generates getters and setters for each property.
let descriptors = {};
for (let i = 0, l = propList.length | 0; i < l; i++)
{
let [name, type] = propList[i];
let viewParams = getViewsForType(type, viewTypes, views);
descriptors[name] = {
- get: type.createGetter.apply(type, [offset].concat(viewParams)),
- set: type.createSetter.apply(type, [offset].concat(viewParams)),
+ get: wrapGetter(type.createGetter.apply(type, [offset].concat(viewParams))),
+ set: wrapSetter(type.createSetter.apply(type, [offset].concat(viewParams))),
configurable: false,
enumerable: true
};
+
+ if (watchers && typeof watchers[name] == "function")
+ descriptors[name].set = watchSetter(descriptors[name].set, watchers[name]);
+
offset += type.referenceLength;
- if (cleanupValues && typeof type.cleanupValue != "undefined")
- cleanupValues.push([name, type.cleanupValue]);
+ if (initialValues && typeof type.initialValue != "undefined")
+ initialValues.push([name, type.initialValue]);
}
// Define properties
Object.defineProperties(obj, descriptors);
return offset;
};
+
+/**
+ * Creates a new array buffer and adds the necessary views.
+ *
+ * @param {Integer} byteSize bytes to allocate for the buffer
+ * @param {Array} buffers existing buffers (will be modified)
+ * @param {Array} viewTypes view types for the buffers
+ * @param {Array} views existing buffer views (will be modified)
+ * @result {Integer} index of the buffer created
+ */
+let addBuffer = exports.addBuffer = function(byteSize, buffers, viewTypes, views)
+{
+ let buffer = new ArrayBuffer(byteSize | 0);
+ buffers.push(buffer);
+ for (let i = 0, l = viewTypes.length | 0; i < l; i++)
+ views[i].push(new viewTypes[i](buffer));
+ return (buffers.length | 0) - 1;
+}
+
+/**
+ * Releases an array buffer.
+ *
+ * @param {Integer} bufferIndex index of the buffer to be released.
+ * @param {Array} buffers existing buffers (will be modified)
+ * @param {Array} views existing buffer views (will be modified)
+ */
+exports.removeBuffer = function(bufferIndex, buffers, views)
+{
+ delete buffers[bufferIndex];
+ for (let i = 0, l = views.length | 0; i < l; i++)
+ delete views[i][bufferIndex];
+}
+
+/**
+ * Allocates a new fixed-size element. It will return the first available free
+ * block or create a new buffer if the existing ones have no space left.
+ *
+ * @param {TypedReference} firstFree head of the linked list pointing to unallocated elements
+ * @param {Integer} byteLength size of an element
+ * @param {Integer} bufferSize number of elements in a buffer
+ * @param {Array} buffers existing buffers (might be modified in necessary)
+ * @param {Array} viewTypes view types for the buffers
+ * @param {Array} views existing buffer views (might be modified if necessary)
+ * @result {Array} [bufferIndex, byteOffset] parameters of the newly allocated block
+ */
+exports.alloc = function(firstFree, byteLength, bufferSize, buffers, viewTypes, views)
+{
+ let bufferIndex = firstFree.bufferIndex | 0;
+ let byteOffset = firstFree.byteOffset | 0;
+ if (bufferIndex >= 0)
+ {
+ // There is still a free spot, simply move on firstFree reference
+ [firstFree.bufferIndex, firstFree.byteOffset] =
+ [firstFree.targetBufferIndex, firstFree.targetByteOffset];
+ }
+ else
+ {
+ byteLength = byteLength | 0;
+ bufferSize = bufferSize | 0;
+
+ // Create new buffer and use the first element of it
+ bufferIndex = addBuffer(byteLength * bufferSize, buffers, viewTypes, views);
+ byteOffset = 0;
+
+ // Mark last element of the new buffer as the last free spot
+ firstFree.bufferIndex = bufferIndex;
+ firstFree.byteOffset = (bufferSize - 1) * byteLength;
+ firstFree.targetBufferIndex = -1;
+
+ // Make each remaining element of the new buffer point to the next one
+ for (let i = bufferSize - 2; i >= 1; i--)
+ {
+ let nextByteOffset = firstFree.byteOffset;
+ firstFree.byteOffset = nextByteOffset - byteLength;
+ firstFree.targetBufferIndex = bufferIndex;
+ firstFree.targetByteOffset = nextByteOffset;
+ }
+ }
+ return [bufferIndex, byteOffset];
+};
+
+/**
+ * Releases the block at given offset so that it can be allocated again.
+ *
+ * @param {TypedReference} firstFree head of the linked list pointing to unallocated elements
+ * @param {Integer} bufferIndex buffer index of the block to be released
+ * @param {Integer} byteOffset byte offset o fthe block to be released
+ */
+exports.dealloc = function(firstFree, bufferIndex, byteOffset)
+{
+ let oldFreeBufferIndex = firstFree.bufferIndex | 0;
+ let oldFreeByteOffset = firstFree.byteOffset | 0;
+
+ firstFree.bufferIndex = bufferIndex | 0;
+ firstFree.byteOffset = byteOffset | 0;
+ firstFree.targetBufferIndex = oldFreeBufferIndex;
+ firstFree.targetByteOffset = oldFreeByteOffset;
+}
« no previous file with comments | « lib/typedObjects/primitiveTypes.js ('k') | test/index.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld