Adam Shaw 6 år sedan
förälder
incheckning
c5be885848

+ 1 - 1
packages-premium

@@ -1 +1 @@
-Subproject commit 934ff837fe9541abb409287bd622c5844f8abd5f
+Subproject commit da99fb938c5815e466cd5502ee57dab13cdbbb10

+ 2 - 2
packages/core/src/Calendar.tsx

@@ -9,7 +9,7 @@ import { createFormatter } from './datelib/formatting'
 import { createDuration, DurationInput, Duration } from './datelib/duration'
 import reduce from './reducers/main'
 import { parseDateSpan, DateSpanInput, DateSpan, buildDateSpanApi, DateSpanApi, buildDatePointApi, DatePointApi } from './structs/date-span'
-import { memoize, memoizeOutput } from './util/memoize'
+import { memoize } from './util/memoize'
 import { mapHash, isPropsEqual } from './util/object'
 import { DateRangeInput, DateRange } from './datelib/date-range'
 import DateProfileGenerator, { DateProfile } from './DateProfileGenerator'
@@ -91,7 +91,7 @@ export default class Calendar {
   private buildContext = memoize(buildContext)
   private buildEventUiSingleBase = memoize(buildEventUiSingleBase)
   private buildSelectionConfig = memoize(buildSelectionConfig)
-  private buildEventUiBySource = memoizeOutput(buildEventUiBySource, isPropsEqual)
+  private buildEventUiBySource = memoize(buildEventUiBySource, isPropsEqual)
   private buildEventUiBases = memoize(buildEventUiBases)
   private renderableEventStore: EventStore
   public eventUiBases: EventUiHash // needed for validation system

+ 3 - 3
packages/core/src/main.ts

@@ -42,7 +42,7 @@ export {
   isArraysEqual
 } from './util/array'
 
-export { memoize, memoizeOutput } from './util/memoize'
+export { memoize, memoizeParallel } from './util/memoize'
 
 export {
   intersectRects,
@@ -52,7 +52,7 @@ export {
   translateRect
 } from './util/geom'
 
-export { mapHash, filterHash, isPropsEqual } from './util/object'
+export { mapHash, filterHash, isPropsEqual, compareObjs } from './util/object'
 
 export {
   findElements,
@@ -171,7 +171,7 @@ export { default as EventApi } from './api/EventApi'
 export { default as requestJson } from './util/requestJson'
 
 export * from './vdom'
-export { subrenderer, SubRenderer, BaseComponent, setRef, renderVNodes, buildMapSubRenderer, componentNeedsResize } from './vdom-util'
+export { subrenderer, SubRenderer, BaseComponent, setRef, renderVNodes, buildMapSubRenderer } from './vdom-util'
 export { DelayedRunner } from './util/runner'
 
 export { default as SimpleScrollGrid, SimpleScrollGridSection } from './scrollgrid/SimpleScrollGrid'

+ 0 - 1
packages/core/src/scrollgrid/util.tsx

@@ -114,7 +114,6 @@ export function renderChunkContent(sectionConfig: SectionConfig, chunkConfig: Ch
 }
 
 
-// TODO: make this SuperColumn-only?
 export function renderMicroColGroup(cols: ColProps[], shrinkWidth?: number) {
   let colNodes: VNode[] = []
 

+ 3 - 2
packages/core/src/util/array.ts

@@ -37,7 +37,8 @@ export function removeExact(array, exactVal) {
   return removeCnt
 }
 
-export function isArraysEqual(a0, a1) {
+
+export function isArraysEqual(a0, a1, equalityFunc?: (v0, v1) => boolean) { // TODO: better typing
 
   if (a0 === a1) {
     return true
@@ -51,7 +52,7 @@ export function isArraysEqual(a0, a1) {
   }
 
   for (i = 0; i < len; i++) {
-    if (a0[i] !== a1[i]) {
+    if (!(equalityFunc ? equalityFunc(a0[i], a1[i]) : a0[i] === a1[i])) {
       return false
     }
   }

+ 34 - 37
packages/core/src/util/memoize.ts

@@ -1,60 +1,57 @@
+import { isArraysEqual } from './array'
 
-export function memoize<T>(workerFunc: T, equality?): T {
+
+// TODO: better typings!!!
+
+
+export function memoize<T>(workerFunc: T, resEquality?: (res0, res1) => boolean): T {
   let args
   let res
 
   return function() {
-    if (!args || !isArgsEqual(args, arguments, equality)) {
+    if (!args || !isArraysEqual(args, arguments)) { // the arguments have changed?...
       args = arguments
-      res = (workerFunc as any).apply(this, arguments)
+
+      let newRes = (workerFunc as any).apply(this, arguments)
+
+      if (res === undefined || !(resEquality ? resEquality(newRes, res) : newRes === res)) {
+        res = newRes // the result has changed
+      }
     }
 
     return res
   } as any
 }
 
-// TODO: merge with isArraysEqual?
-// TODO: better solution that links the function with the equality checks. like subrenderer?
-function isArgsEqual(args0, args1, equality?) {
-  let len = args0.length
-
-  if (len !== args1.length) {
-    return false
-  }
 
-  for (let i = 0; i < len; i++) {
-    let eq = equality && equality[i]
+export function memoizeParallel<Res>(workerFunc: (...args: any[]) => Res, resEquality?: (res0, res1) => boolean): (...args: any[]) => Res[] {
+  let memoizers = []
 
-    if (eq === true) {
-      ;
-    } else if (eq) {
-      if (!eq(args0[i], args1[i])) {
-        return false
-      }
-    } else if (args0[i] !== args1[i]) {
-      return false
-    }
-  }
+  return function() {
+    let argCnt = arguments.length
+    let memoizerCnt = arguments[0].length
+    let i
+    let allRes = []
 
-  return true
-}
+    memoizers.splice(memoizerCnt) // remove excess
 
+    // add new
+    for (i = memoizers.length; i < memoizerCnt; i++) {
+      memoizers[i] = memoize(workerFunc, resEquality)
+    }
 
-/*
-always executes the workerFunc, but if the result is equal to the previous result,
-return the previous result instead.
-TODO: somehow use memoize with equality funcs instead?
-*/
-export function memoizeOutput<T>(workerFunc: T, equalityFunc: (output0, output1) => boolean): T {
-  let cachedRes = null
+    for (i = 0; i < memoizerCnt; i++) {
+      let args = []
 
-  return function() {
-    let newRes = (workerFunc as any).apply(this, arguments)
+      for (let argIndex = 0; argIndex < argCnt; argIndex++) {
+        args.push(arguments[argIndex][i])
+      }
 
-    if (cachedRes === null || !(cachedRes === newRes || equalityFunc(cachedRes, newRes))) {
-      cachedRes = newRes
+      allRes.push(
+        memoizers[i].apply(this, args)
+      )
     }
 
-    return cachedRes
+    return allRes
   } as any
 }

+ 46 - 0
packages/core/src/util/object.ts

@@ -143,3 +143,49 @@ export function getUnequalProps(obj0, obj1) {
 
   return keys
 }
+
+
+
+export type EqualityFunc<T> = (a: T, b: T) => boolean
+export type EqualityThing<T> = EqualityFunc<T> | true
+
+export type EqualityFuncs<ObjType> = { // not really just a "func" anymore
+  [K in keyof ObjType]?: EqualityThing<ObjType[K]>
+}
+
+export function compareObjs(oldProps, newProps, equalityFuncs: EqualityFuncs<any> = {}) {
+
+  if (oldProps === newProps) {
+    return true
+  }
+
+  for (let key in newProps) {
+    if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) {
+      ; // equal
+    } else {
+      return false
+    }
+  }
+
+  // check for props that were omitted in the new
+  for (let key in oldProps) {
+    if (!(key in newProps)) {
+      return false
+    }
+  }
+
+  return true
+}
+
+/*
+assumed "true" equality for handler names like "onReceiveSomething"
+*/
+function isObjValsEqual<T>(val0: T, val1: T, comparator: EqualityThing<T>) {
+  if (val0 === val1 || comparator === true) {
+    return true
+  }
+  if (comparator) {
+    return comparator(val0, val1)
+  }
+  return false
+}

+ 1 - 70
packages/core/src/vdom-util.tsx

@@ -1,15 +1,7 @@
 import { Component, h, Fragment, Ref, ComponentChildren, render } from './vdom'
 import ComponentContext, { ComponentContextType } from './component/ComponentContext'
 import { __assign } from 'tslib'
-import { isPropsEqual, getUnequalProps } from './util/object'
-
-
-type EqualityFunc<T> = (a: T, b: T) => boolean
-type EqualityThing<T> = EqualityFunc<T> | true
-
-export type EqualityFuncs<ObjType> = { // not really just a "func" anymore
-  [K in keyof ObjType]?: EqualityThing<ObjType[K]>
-}
+import { compareObjs, EqualityFuncs } from './util/object'
 
 
 interface SubRendererOwner {
@@ -269,45 +261,6 @@ export function buildMapSubRenderer(subRendererClass: SubRendererClass<any>) {
 }
 
 
-function compareObjs(oldProps, newProps, equalityFuncs: EqualityFuncs<any> = {}) {
-
-  if (oldProps === newProps) {
-    return true
-  }
-
-  for (let key in newProps) {
-    if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) {
-      ; // equal
-    } else {
-      return false
-    }
-  }
-
-  // check for props that were omitted in the new
-  for (let key in oldProps) {
-    if (!(key in newProps)) {
-      return false
-    }
-  }
-
-  return true
-}
-
-
-/*
-assumed "true" equality for handler names like "onReceiveSomething"
-*/
-function isObjValsEqual<T>(val0: T, val1: T, comparator: EqualityThing<T>) {
-  if (val0 === val1 || comparator === true) {
-    return true
-  }
-  if (comparator) {
-    return comparator(val0, val1)
-  }
-  return false
-}
-
-
 export function setRef<RefType>(ref: Ref<RefType> | void, current: RefType) {
   if (typeof ref === 'function') {
     ref(current)
@@ -329,25 +282,3 @@ export function renderVNodes(children: ComponentChildren, context: ComponentCont
 
   return Array.prototype.slice.call(containerEl.childNodes)
 }
-
-
-// TODO: kill this at some pt???
-export function componentNeedsResize<P, S>(prevProps: P, props: P, prevState: S, state: S, stateIsSizing: { [K in keyof S]?: boolean }) {
-  if (!isPropsEqual(prevProps, props)) {
-    return true
-  }
-
-  let unequalState = getUnequalProps(prevState, state)
-
-  if (!unequalState.length) {
-    return true // if neither props nor state changed, that means context changed, so definitely do a resize!
-  }
-
-  for (let key of unequalState) {
-    if (!stateIsSizing[key]) {
-      return true
-    }
-  }
-
-  return false
-}