Skip to content

Commit

Permalink
Implement faster versions of clone():
Browse files Browse the repository at this point in the history
- safe_clone(): a safe version of clone() tests non-object properties before calling recursively
- fast_clone(): a fast version of clone() does not test hasOwnProperty()

- extend.clone() is currently set to safe_clone(), a future test should allow to use fast_clone().
- extend.object_clone() is currently set to safe_object_clone()

- versions of clone working only on objects, not scalar values:
  - safe_object_clone(): used by safe_clone()
  - fast_object_clone(): used by fast_clone()

- add tests for safe_object_clone() and fast_object_clone()

- add test values into foo:
  - Limitation: NaN cannot currently be tested because mocha eql() function does not handle NaN, we could use value_equals() instead
  • Loading branch information
uiteoi committed Jun 23, 2015
1 parent 30ce793 commit 3197afb
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 18 deletions.
61 changes: 50 additions & 11 deletions lib/util/extend.js
Expand Up @@ -90,7 +90,15 @@
extend._2.safe = safe_extend;
extend._2.fast = fast_extend_2;

extend.clone = clone;
extend.clone = safe_clone;

extend.safe_clone = safe_clone;
extend.fast_clone = fast_clone;

extend.object_clone = safe_object_clone;

extend.safe_object_clone = safe_object_clone;
extend.fast_object_clone = fast_object_clone;

return extend;

Expand All @@ -105,7 +113,7 @@
d[ p ] = s[ p ];

return d;
} // extend()
} // safe_extend()

// Fast extend, does not check hasOwnProperty()
function fast_extend( d ) {
Expand All @@ -125,17 +133,48 @@
return d;
} // fast_extend_2()

// deep clone of object
function clone( o ) {
if( typeof o !== 'object' || o === null ) return o;
// Safe deep clone of value
function safe_clone( value ) {
return typeof value == 'object' && value ? safe_object_clone( value ) : value;
} // safe_clone()

// Fast deep clone of value
function fast_clone( value ) {
return typeof value == 'object' && value ? fast_object_clone( value ) : value;
} // fast_clone()

function safe_object_clone( object ) {
var clone = object instanceof Array ? [] : {}
, p
, value
;

for ( p in object ) {
if ( object.hasOwnProperty( p ) ) {
value = object[ p ];

// Duplicate fast_clone() code for performances
clone[ p ] = typeof value == 'object' && value ? safe_object_clone( value ) : value;
}
}

var r = o instanceof Array ? [] : {};
return clone;
} // safe_object_clone()

function fast_object_clone( object ) {
var clone = object instanceof Array ? [] : {}
, p
, value
;

for( p in o )
if( o.hasOwnProperty( p ) )
r[ p ] = clone( o[ p ]);
for ( p in object ) {
value = object[ p ];

// Duplicate fast_clone() code for performances
clone[ p ] = typeof value == 'object' && value ? fast_object_clone( value ) : value;
}

return r;
} // clone()
return clone;
} // fast_object_clone()

} ); // extend.js
64 changes: 57 additions & 7 deletions test/src/clone_tests.coffee
Expand Up @@ -45,22 +45,72 @@ clone = extend.clone

describe 'Test utilities', ->
describe 'clone():', ->
# ToDo: use value_equals() because mocha eql() does not handle NaN properly

foo =
id: 10
array: [ 1, 2, "a", "b", 3, { x: 10, y: undefined, z: null } ]
obj:
coordinate: 1
label: "Coordinate"
values: [ 24, null, undefined ]
array: [
0
1
2
true
false
"a"
"b"
3
undefined
null
# NaN
Infinity
+Infinity
-Infinity
{}
[]
""

{
a: 0
b: 1
c: 2
d: true
e: false
f: "a"
g: "b"
h: 3
i: undefined
j: null
# not_a_number: NaN
infinity: Infinity
plus_infinity: +Infinity
minus_infinity: -Infinity
empty_object: {}
empty_array: []
empty_string: ''
}
]

bar = clone foo

safe_bar = extend.safe_object_clone foo
fast_bar = extend.fast_object_clone foo

it 'should deep clone foo into bar', ->
expect( bar ).to.be.eql foo

it 'should not return self', ->
it 'should not be the same object foo', ->
expect( bar ).to.not.be foo

it 'should safely deep clone foo into safe_bar', ->
expect( safe_bar ).to.be.eql foo

it 'safe_bar should not be the same object foo', ->
expect( safe_bar ).to.not.be foo

it 'should fast deep clone foo into fast_bar', ->
expect( fast_bar ).to.be.eql foo

it 'fast_bar should not be the same object foo', ->
expect( fast_bar ).to.not.be foo

describe 'Aynchronous test check()', ->
it 'should succeed in 50 ms', ( done ) ->
setTimeout ( () -> check done, () -> expect( [] ).to.be.eql [] ), 50

0 comments on commit 3197afb

Please sign in to comment.