Skip to content

Commit 92b3b42

Browse files
author
Scott Switzer
committed
rewrote parse - 1000x improvement :)
1 parent 42956d3 commit 92b3b42

2 files changed

Lines changed: 155 additions & 151 deletions

File tree

src/object-mapper.js

Lines changed: 87 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@ var _undefined
66
function ObjectMapper(from_object, to_object, property_map)
77
{
88
global.elapsed['ObjectMapper'].n++ // performance monitoring
9+
let timer = performance.now()
910

1011
// There are a few different constructors - move around properties if needed
1112
if (typeof property_map === 'undefined') {
12-
property_map = to_object;
13+
property_map = to_object
1314
to_object = _undefined
1415
}
1516

16-
for (const [from_key, to_key] of Object.entries(property_map)) {
17+
// Loop through the map to process individual mapping instructions
18+
for (const [from_key_str, to_key_str] of Object.entries(property_map)) {
1719

18-
// Traverse the 'from' object
19-
var from_data = getKeyValue(from_object, from_key)
20-
21-
// Insert into the 'to' object
22-
to_object = setKeyValue(to_object, to_key, from_data)
20+
global.elapsed['ObjectMapper'].ms += (performance.now() - timer)
21+
const from_data = getKeyValue(from_object, from_key_str)
22+
to_object = setKeyValue(to_object, to_key_str, from_data)
23+
timer = performance.now()
2324
}
2425

26+
global.elapsed['ObjectMapper'].ms += (performance.now() - timer)
2527
return to_object
2628
}
2729

@@ -30,11 +32,14 @@ function update(obj, data, key_arr)
3032
{
3133
global.elapsed['update'].n++ // performance monitoring
3234
let timer = performance.now()
35+
3336
let x = 0 // index of the key array
3437

3538
var o
3639
// Get the object key and index that needs to be parsed
37-
var [key, ix] = process(key_arr.shift())
40+
global.elapsed['update'].ms += (performance.now() - timer)
41+
var [key, ix] = key_arr.shift()
42+
timer = performance.now()
3843

3944
// If there is a key, we need to traverse down to this part of the object
4045
if (key) {
@@ -59,8 +64,10 @@ function update_obj(obj, key, data, key_arr)
5964
let timer = performance.now()
6065

6166
// If the object is undefined, we need to create a new object
62-
if (obj == null) obj = {}
63-
// Set the key of the object equal to the recursive, or if at the end, the data
67+
if (obj == null)
68+
obj = {}
69+
70+
// Set the key of the object equal to the recursive, or if at the end, the data
6471
if (key_arr.length > 0) {
6572
global.elapsed['update_obj'].ms += (performance.now() - timer)
6673
obj[key] = update(obj[key], data, key_arr)
@@ -90,6 +97,7 @@ function update_arr(obj, key, ix, data, key_arr)
9097
return o
9198
}
9299
}, obj)
100+
global.elapsed['update_arr'].ms += (performance.now() - timer)
93101
return obj
94102
}
95103
// If there is more work to be done, push an object onto the array
@@ -115,33 +123,23 @@ function select(obj, key_arr)
115123
global.elapsed['select'].n++ // performance monitoring
116124
let timer = performance.now()
117125

118-
// Check to see if key_arr is not an array. If so, wrap it in an array.
119-
// This is done for backwards compatibility from external functions that pass in a string
120-
if (!Array.isArray(key_arr))
121-
key_arr = parse(key_arr)
122-
123-
// If we are at the end of the key array x`stack, return the object
124-
if (key_arr.length == 0) {
125-
global.elapsed['update_arr'].ms += (performance.now() - timer)
126-
return obj
127-
}
128-
129126
// Get the object key or index that needs to be parsed
130-
global.elapsed['update_arr'].ms += (performance.now() - timer)
131-
var [key, ix] = process(key_arr.shift())
127+
global.elapsed['select'].ms += (performance.now() - timer)
128+
var [key, ix] = key_arr.shift()
132129
timer = performance.now()
133130

134131
// If there is an object key, grab the object property
135132
if (key) {
136-
global.elapsed['update_arr'].ms += (performance.now() - timer)
133+
global.elapsed['select'].ms += (performance.now() - timer)
137134
return select_obj(obj, key, key_arr)
138135
}
139136

140137
// If we need to deal with an array, then loop through and return recursive select for each
141138
if (Array.isArray(obj)) {
142-
global.elapsed['update_arr'].ms += (performance.now() - timer)
139+
global.elapsed['select'].ms += (performance.now() - timer)
143140
return select_arr(obj, key, ix, key_arr)
144141
}
142+
global.elapsed['select'].ms += (performance.now() - timer)
145143
}
146144

147145
function select_obj(obj, key, key_arr)
@@ -172,8 +170,9 @@ function select_arr(obj, key, ix, key_arr)
172170
// Recursively loop through the array and grab the data
173171
obj = obj.map( function(o) {
174172
global.elapsed['select_arr'].ms += (performance.now() - timer)
175-
return select(o, key_arr.slice())
173+
let _o = select(o, key_arr.slice())
176174
timer = performance.now()
175+
return _o
177176
})
178177
// obj = obj.map( function(o) {
179178
// global.elapsed['select_arr'].ms += (performance.now() - timer)
@@ -191,78 +190,96 @@ function select_arr(obj, key, ix, key_arr)
191190

192191
// Turns a key string (like key1.key2[].key3 into ['key1','key2','[]','key3']...)
193192
//
194-
function parse(key, delimiter = '.')
193+
function parse(key_str, delimiter = '.')
195194
{
196195
global.elapsed['parse'].n++ // performance monitoring
197196
let timer = performance.now()
198-
199-
if (typeof(key) == 'string') {
200-
var key_array = key.split(delimiter)
201-
var keys = key_array.reduce(function(keys,current_key) {
202-
var [k,ix] = process(current_key)
203-
if (k) keys.push(k)
204-
if (ix !== null) keys.push('[' + ix + ']')
205-
return keys
206-
}, [])
207-
global.elapsed['parse'].ms += (performance.now() - timer)
208-
return keys
197+
let _default = null
198+
let _transpose = null
199+
200+
// If the value was passed in object notation, grab the default and transpose values, then rewrite as a string
201+
if (typeof(key) == 'object') {
202+
_default = key_str.default
203+
_transpose = key_str.transpose
204+
key_str = key_str.key
209205
}
210-
global.elapsed['parse'].ms += (performance.now() - timer)
211-
}
212-
213-
function process(k)
214-
{
215-
global.elapsed['process'].n++ // performance monitoring
216-
let timer = performance.now()
217206

218-
var arr
219-
try {
220-
var [_,key,ix] = k.match(/(.*?)\[(.*?)\]/)
221-
arr = [key,ix]
222-
} catch (e) {
223-
arr = [k,null]
207+
const key_arr = key_str.split(delimiter)
208+
let keys = []
209+
let n = 0
210+
for (let i=0, len1=key_arr.length; i<len1; i++) {
211+
// Build a object which is either an object key or an array
212+
// Note that this is not the most readable, but it is fastest way to parse the string (at this point in time)
213+
let begin=-1, end=-1, key=key_arr[i]
214+
for (let j=0, len2=key.length; j<len2; j++) {
215+
if (key[j] == '[') begin = j
216+
if (key[j] == ']' && begin > -1) {
217+
end = j
218+
break
219+
}
220+
}
221+
// No array - just add object key
222+
if (begin == -1) {
223+
keys[n++] = [key_arr[i] || null, null]
224+
}
225+
// No key - just add array index
226+
else if (begin == 0 && end > 0) {
227+
keys[n++] = [null, key_arr[i].substring(begin+1,end)]
228+
}
229+
// Both object and array key
230+
else if (begin > 0 && end > 0) {
231+
keys[n++] = [key.substring(0,begin), null]
232+
keys[n++] = [null, key.substring(begin+1,end)]
233+
}
224234
}
225235
global.elapsed['parse'].ms += (performance.now() - timer)
226-
return arr
227-
}
236+
return keys
237+
}
228238

229239
// A string of how to navigate through the incoming array is sent.
230240
// This is translated into an array of instructions for the recursive object
231241
function getKeyValue(obj, key_str)
232242
{
233243
global.elapsed['getKeyValue'].n++ // performance monitoring
244+
let timer = performance.now()
234245

235-
// String
236-
if (typeof(key_str) == 'string') return select(obj,parse(key_str))
237-
// Nothing else is valid
246+
// Convert the mapping string into an array of instructions
247+
// e.g. 'foo.bar[].baz => foo, bar, [], baz
248+
global.elapsed['getKeyValue'].ms += (performance.now() - timer)
249+
let key_arr = parse(key_str)
250+
timer = performance.now()
251+
252+
// Return the selected object
253+
global.elapsed['getKeyValue'].ms += (performance.now() - timer)
254+
return select(obj, key_arr)
238255
}
239256

240-
function setKeyValue(obj,key_str,data)
257+
function setKeyValue(obj, key_str, data)
241258
{
242259
global.elapsed['setKeyValue'].n++ // performance monitoring
243-
244-
// Key_str is written as a simple string
245-
if (typeof(key_str) == 'string')
246-
return update(obj, data, parse(key_str))
260+
let timer = performance.now()
247261

248262
// Key_str is an array of values
249263
if (Array.isArray(key_str)) {
250-
for (var i=0, len = key_str.length; i < len; i++) {
251-
obj = update(obj, data, parse(key_str[i]))
264+
for (let i=0, len=key_str.length; i<len; i++) {
265+
global.elapsed['setKeyValue'].ms += (performance.now() - timer)
266+
let key_arr = parse(to_key_str[i])
267+
obj = update(obj, data, key_arr)
268+
timer = performance.now()
252269
}
253-
return obj
270+
} else {
271+
global.elapsed['setKeyValue'].ms += (performance.now() - timer)
272+
let key_arr = parse(key_str)
273+
obj = update(obj, data, key_arr)
274+
timer = performance.now()
254275
}
255-
256-
// Key_str is written in object notation form
257-
if (typeof(key_str) == 'object')
258-
return update(obj, data, parse(key_str.key))
259-
276+
global.elapsed['setKeyValue'].ms += (performance.now() - timer)
277+
return obj
260278
// Nothing else is valid
261279
}
262280

263281
module.exports = ObjectMapper
264282
module.exports.getKeyValue = getKeyValue
265283
module.exports.setKeyValue = setKeyValue
266-
module.exports.process = process
267284
module.exports.parse = parse
268285
// module.exports.merge = ObjectMapper;

0 commit comments

Comments
 (0)