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

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

Issue 5656302898380800: Issue 260 - [Typed objects] Implement type inheritance (Closed)
Patch Set: Fixed inheritance of non-overridden constructors Created April 28, 2014, 7:02 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/references.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2014 Eyeo GmbH 3 * Copyright (C) 2006-2014 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 104
105 function createSetter(typeId, offset) 105 function createSetter(typeId, offset)
106 { 106 {
107 typeId = typeId | 0; 107 typeId = typeId | 0;
108 offset = offset | 0; 108 offset = offset | 0;
109 109
110 let views = Array.prototype.slice.call(arguments, 2); 110 let views = Array.prototype.slice.call(arguments, 2);
111 let reference = new Reference(types, views); 111 let reference = new Reference(types, views);
112 return function(value) 112 return function(value)
113 { 113 {
114 if (value && value.typeId != typeId) 114 if (value && !isinstance(typeId, value))
115 throw new Error("Incompatible type"); 115 throw new Error("Incompatible type");
116 116
117 reference.bufferIndex = this.bufferIndex | 0; 117 reference.bufferIndex = this.bufferIndex | 0;
118 reference.byteOffset = (this.byteOffset | 0) + offset; 118 reference.byteOffset = (this.byteOffset | 0) + offset;
119 if (value) 119 if (value)
120 { 120 {
121 reference.typeId = value.typeId; 121 reference.typeId = value.typeId;
122 reference.targetBufferIndex = value.bufferIndex; 122 reference.targetBufferIndex = value.bufferIndex;
123 reference.targetByteOffset = value.byteOffset; 123 reference.targetByteOffset = value.byteOffset;
124 } 124 }
125 else 125 else
126 reference.typeId = -1; 126 reference.typeId = -1;
127 }; 127 };
128 } 128 }
129 129
130 function ObjectType(properties, meta) 130 /**
131 * Overridden methods get the respective method of the superclass as the first
132 * parameter. This function will create a wrapper function for the method that
133 * forwards all arguments to the actual methods but also injects super as first
134 * parameter.
135 */
136 function createSubclassMethod(method, super_)
137 {
138 return function()
139 {
140 let args = [].slice.apply(arguments);
141 args.unshift(() => super_.apply(this, arguments));
142 return method.apply(this, args);
143 };
144 }
145
146 function extend(parentTypeInfo, typeDescriptor, meta)
131 { 147 {
132 if (typeof meta != "object" || meta == null) 148 if (typeof meta != "object" || meta == null)
133 meta = {}; 149 meta = {};
134 150
135 let propList = []; 151 let properties = Object.create(parentTypeInfo && parentTypeInfo.properties);
136 let proto = {}; 152
153 // Methods have to be actually copied here, prototypes won't work correctly
154 // with Object.defineProperties().
155 let methods = Object.create(null);
156 if (parentTypeInfo)
157 for (let key in parentTypeInfo.methods)
158 methods[key] = parentTypeInfo.methods[key];
159
137 let maxReferenceLength = TypedReference.byteLength | 0; 160 let maxReferenceLength = TypedReference.byteLength | 0;
138 for (let name in properties) 161 for (let name in typeDescriptor)
139 { 162 {
140 let type = properties[name]; 163 let type = typeDescriptor[name];
141 if (type && typeof type.referenceLength == "number") 164 if (type && typeof type.referenceLength == "number")
142 { 165 {
166 if (name in methods)
167 throw new Error("Property " + name + " masks a method with the same name ");
168 if (name in properties)
169 {
170 if (properties[name] == type)
171 continue;
172 else
173 throw new Error("Cannot redefine type of property " + name + " in subc lass");
174 }
175
143 // Property with type 176 // Property with type
144 propList.push([name, type]); 177 properties[name] = type;
145 178
146 let referenceLength = type.referenceLength | 0; 179 let referenceLength = type.referenceLength | 0;
147 if (referenceLength > maxReferenceLength) 180 if (referenceLength > maxReferenceLength)
148 maxReferenceLength = referenceLength; 181 maxReferenceLength = referenceLength;
149 } 182 }
150 else if (typeof type == "function") 183 else if (typeof type == "function")
151 { 184 {
152 // Method 185 // Method
153 Object.defineProperty(proto, name, fixedPropertyDescriptor(type)); 186 if (name in properties)
187 throw new Error("Method " + name + " masks a property with the same name ");
188
189 if (name in methods)
190 type = createSubclassMethod(type, methods[name].value);
191 methods[name] = fixedPropertyDescriptor(type);
154 } 192 }
155 else 193 else
156 throw new Error("Unrecognized type " + type + " given for property " + nam e); 194 throw new Error("Unrecognized type " + type + " given for property " + nam e);
157 } 195 }
158 196
197 let proto = {};
159 let buffers = []; 198 let buffers = [];
160 let viewTypes = []; 199 let viewTypes = [];
161 let views = []; 200 let views = [];
162 let byteLength = defineProperties(proto, propList, viewTypes, views, 0); 201 let byteLength = defineProperties(proto, properties, viewTypes, views, 0);
202 Object.defineProperties(proto, methods);
163 203
164 // Round up to be a multiple of the maximal property size 204 // Round up to be a multiple of the maximal property size
165 byteLength = ((byteLength - 1) | (maxReferenceLength - 1)) + 1; 205 byteLength = ((byteLength - 1) | (maxReferenceLength - 1)) + 1;
166 206
167 // We need to be able to store a typed reference in the object's buffer 207 // We need to be able to store a typed reference in the object's buffer
168 byteLength = Math.max(byteLength, TypedReference.byteLength) | 0; 208 byteLength = Math.max(byteLength, TypedReference.byteLength) | 0;
169 let typedReferenceViews = getViewsForType(TypedReference, viewTypes, views); 209 let typedReferenceViews = getViewsForType(TypedReference, viewTypes, views);
170 210
211 // Take constructor from meta parameter, allow calling superclass constructor.
212 let constructor = parentTypeInfo && parentTypeInfo.constructor;
213 if (meta.hasOwnProperty("constructor") && typeof meta.constructor == "function ")
214 {
215 if (constructor)
216 constructor = createSubclassMethod(meta.constructor, constructor);
217 else
218 constructor = meta.constructor;
219 }
220
171 let typeId = types.length | 0; 221 let typeId = types.length | 0;
172 let typeInfo = { 222 let typeInfo = {
173 byteLength: byteLength, 223 byteLength: byteLength,
174 bufferSize: "bufferSize" in meta ? Math.max(meta.bufferSize | 0, 2) : 128, 224 bufferSize: "bufferSize" in meta ? Math.max(meta.bufferSize | 0, 2) : 128,
175 firstFree: new TypedReference(typeId, typedReferenceViews), 225 firstFree: new TypedReference(typeId, typedReferenceViews),
176 proto: proto, 226 proto: proto,
227 properties: properties,
228 methods: methods,
177 buffers: buffers, 229 buffers: buffers,
178 viewTypes: viewTypes, 230 viewTypes: viewTypes,
179 views: views, 231 views: views,
180 typeId: typeId, 232 typeId: typeId,
181 constructor: (meta.hasOwnProperty("constructor") && typeof meta.constructor == "function" ? meta.constructor : null) 233 parentTypeInfo: parentTypeInfo,
234 constructor: constructor
182 }; 235 };
183 236
184 let result = create.bind(typeInfo); 237 let result = create.bind(typeInfo);
185 Object.defineProperties(result, { 238 Object.defineProperties(result, {
186 byteLength: fixedPropertyDescriptor(byteLength), 239 byteLength: fixedPropertyDescriptor(byteLength),
187 240
188 referenceLength: fixedPropertyDescriptor(Reference.byteLength), 241 referenceLength: fixedPropertyDescriptor(Reference.byteLength),
189 viewTypes: fixedPropertyDescriptor(Reference.viewTypes), 242 viewTypes: fixedPropertyDescriptor(Reference.viewTypes),
190 243
191 typeId: fixedPropertyDescriptor(typeId), 244 typeId: fixedPropertyDescriptor(typeId),
245 extend: fixedPropertyDescriptor(extend.bind(null, typeInfo)),
246 isinstance: fixedPropertyDescriptor(isinstance.bind(null, typeId)),
René Jeschke 2014/05/02 16:16:37 Just wondering, every other member name you use is
Wladimir Palant 2014/05/02 19:14:31 It's really because the JavaScript operator is cal
192 247
193 createGetter: fixedPropertyDescriptor(createGetter), 248 createGetter: fixedPropertyDescriptor(createGetter),
194 createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId)) 249 createSetter: fixedPropertyDescriptor(createSetter.bind(null, typeId))
195 }); 250 });
196 types.push(typeInfo); 251 types.push(typeInfo);
197 return result; 252 return result;
198 } 253 }
199 exports.ObjectType = ObjectType; 254
255 function isinstance(typeId, obj)
256 {
257 typeId = typeId | 0;
258
259 // TODO: This could be optimized by compiling the list of all subclasses for
260 // each type up front. Question is whether this is worth it.
261 let typeInfo = types[obj.typeId | 0];
262 while (typeInfo)
263 {
264 if ((typeInfo.typeId | 0) == typeId)
265 return true;
266 typeInfo = typeInfo.parentTypeInfo;
267 }
268 return false;
269 }
270
271 let ObjectBase = exports.ObjectBase = extend(null, {
272 equals: function(obj)
273 {
274 if (!obj)
275 return false;
276 return this.typeId == obj.typeId && this.bufferIndex == obj.bufferIndex && t his.byteOffset == obj.byteOffset;
277 }
278 }, null);
279
280 exports.ObjectType = ObjectBase.extend;
OLDNEW
« no previous file with comments | « lib/typedObjects.js ('k') | lib/typedObjects/references.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld