mathjs/test/unit-tests/utils/function.test.js
Flaviu Tamas a3360d316b
Improve performance of _findUnit (#2065)
* Add unit parser benchmark

* Add LRU to memoize function

* Memoize _findUnit

This fixes some performance issues in my heavily-unit-parsing app.
Another idea might be to do an index of reversed unit names, and search
in that, but this is much easier to implement and still should provide
an improvement in the majority of cases (since I'd imagine that most
users tend to prefer a few units at a time, depending on their
application).

* Optimize memoize function

This should be just a little bit faster than before by using Maps, which
have less overhead than javascript objects.
2020-12-24 09:10:53 +01:00

149 lines
4.3 KiB
JavaScript

import assert from 'assert'
import { maxArgumentCount, memoize, memoizeCompare } from '../../../src/utils/function.js'
import { deepStrictEqual } from '../../../src/utils/object.js'
describe('util.function', function () {
describe('memoize', function () {
it('should memoize a function with one argument', function () {
const f = function (x) { return x * x }
const m = memoize(f)
assert.strictEqual(m(2), 4)
assert.strictEqual(m(3), 9)
})
it('should memoize a function with two arguments', function () {
const f = function (x, y) { return x * y }
const m = memoize(f)
assert.strictEqual(m(2, 3), 6)
// hash should differ
assert.strictEqual(m(1, 23), 23)
assert.strictEqual(m(12, 3), 36)
})
it('should memoize a function with objects as arguments', function () {
const f = function (obj) { return obj.x * obj.y }
const m = memoize(f)
assert.strictEqual(m({ x: 2, y: 3 }), 6)
assert.deepStrictEqual([...m.cache.values.keys()], ['[{"x":2,"y":3}]'])
assert.strictEqual(m.cache.values.get('[{"x":2,"y":3}]'), 6)
})
it('should memoize a function with a custom hashIt function', function () {
const f = function (obj) { return obj.id }
const hashIt = function (args) {
return 'id:' + args[0].id
}
const m = memoize(f, { hasher: hashIt })
assert.strictEqual(m({ id: 2 }), 2)
assert.deepStrictEqual([...m.cache.values.keys()], ['id:2'])
assert.strictEqual(m.cache.values.get('id:2'), 2)
})
it('should really return the cached result', function () {
let a = 2
const f = function (x) { return a } // trick: no pure function
const m = memoize(f)
assert.strictEqual(m(4), 2)
a = 3
assert.strictEqual(m(4), 2)
})
})
it('should limit the number of values stored', function () {
let a = 1
const f = function (x) { a++; return a } // trick: no pure function
const m = memoize(f, { limit: 2 })
assert.strictEqual(m(1), 2)
assert.strictEqual(m(2), 3)
// this should evict m(1)
assert.strictEqual(m(3), 4)
assert.strictEqual(m(1), 5)
})
describe('memoizeCompare', function () {
it('should memoize using comparison', () => {
let execCount = 0
function multiply (obj) {
execCount++
return obj.x * obj.y
}
const m = memoizeCompare(multiply, deepStrictEqual)
assert.strictEqual(m({ x: 2, y: 3 }), 6)
assert.strictEqual(execCount, 1)
assert.strictEqual(m({ x: 2, y: 3 }), 6)
assert.strictEqual(execCount, 1)
assert.strictEqual(m({ x: 2, y: 3, z: 4 }), 6)
assert.strictEqual(execCount, 2)
const fn1 = (a, b) => a + b
const fn2 = (a, b) => a + b
assert.strictEqual(m({ x: 2, y: 3, add: fn1 }), 6)
assert.strictEqual(execCount, 3)
assert.strictEqual(m({ x: 2, y: 3, add: fn1 }), 6)
assert.strictEqual(execCount, 3)
assert.strictEqual(m({ x: 2, y: 3, add: fn2 }), 6)
assert.strictEqual(execCount, 4)
assert.strictEqual(m({ x: 2, y: 3, z: undefined }), 6)
assert.strictEqual(execCount, 5)
assert.strictEqual(m({ x: 2, y: 3, z: undefined }), 6)
assert.strictEqual(execCount, 5)
})
})
describe('maxArgumentCount', function () {
it('should calculate the max argument count of a typed function', function () {
const a = function () {}
a.signatures = {
'number, number': function () {},
number: function () {}
}
assert.strictEqual(maxArgumentCount(a), 2)
const b = function () {}
b.signatures = {
number: function () {},
'number, number': function () {}
}
assert.strictEqual(maxArgumentCount(b), 2)
const c = function () {}
c.signatures = {
number: function () {},
BigNumber: function () {}
}
assert.strictEqual(maxArgumentCount(c), 1)
const d = function () {}
d.signatures = {
'number,number': function () {},
number: function () {},
'number,any,number': function () {}
}
assert.strictEqual(maxArgumentCount(d), 3)
})
it('should return -1 for regular functions', function () {
assert.strictEqual(maxArgumentCount(function () {}), -1)
})
})
})