mergeData.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. var arrayCopy = require('./arrayCopy'),
  2. composeArgs = require('./composeArgs'),
  3. composeArgsRight = require('./composeArgsRight'),
  4. replaceHolders = require('./replaceHolders');
  5. /** Used to compose bitmasks for wrapper metadata. */
  6. var BIND_FLAG = 1,
  7. CURRY_BOUND_FLAG = 4,
  8. CURRY_FLAG = 8,
  9. ARY_FLAG = 128,
  10. REARG_FLAG = 256;
  11. /** Used as the internal argument placeholder. */
  12. var PLACEHOLDER = '__lodash_placeholder__';
  13. /* Native method references for those with the same name as other `lodash` methods. */
  14. var nativeMin = Math.min;
  15. /**
  16. * Merges the function metadata of `source` into `data`.
  17. *
  18. * Merging metadata reduces the number of wrappers required to invoke a function.
  19. * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
  20. * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
  21. * augment function arguments, making the order in which they are executed important,
  22. * preventing the merging of metadata. However, we make an exception for a safe
  23. * common case where curried functions have `_.ary` and or `_.rearg` applied.
  24. *
  25. * @private
  26. * @param {Array} data The destination metadata.
  27. * @param {Array} source The source metadata.
  28. * @returns {Array} Returns `data`.
  29. */
  30. function mergeData(data, source) {
  31. var bitmask = data[1],
  32. srcBitmask = source[1],
  33. newBitmask = bitmask | srcBitmask,
  34. isCommon = newBitmask < ARY_FLAG;
  35. var isCombo =
  36. (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) ||
  37. (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) ||
  38. (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG);
  39. // Exit early if metadata can't be merged.
  40. if (!(isCommon || isCombo)) {
  41. return data;
  42. }
  43. // Use source `thisArg` if available.
  44. if (srcBitmask & BIND_FLAG) {
  45. data[2] = source[2];
  46. // Set when currying a bound function.
  47. newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
  48. }
  49. // Compose partial arguments.
  50. var value = source[3];
  51. if (value) {
  52. var partials = data[3];
  53. data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
  54. data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
  55. }
  56. // Compose partial right arguments.
  57. value = source[5];
  58. if (value) {
  59. partials = data[5];
  60. data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
  61. data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
  62. }
  63. // Use source `argPos` if available.
  64. value = source[7];
  65. if (value) {
  66. data[7] = arrayCopy(value);
  67. }
  68. // Use source `ary` if it's smaller.
  69. if (srcBitmask & ARY_FLAG) {
  70. data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
  71. }
  72. // Use source `arity` if one is not provided.
  73. if (data[9] == null) {
  74. data[9] = source[9];
  75. }
  76. // Use source `func` and merge bitmasks.
  77. data[0] = source[0];
  78. data[1] = newBitmask;
  79. return data;
  80. }
  81. module.exports = mergeData;