refactor(ivy): simplify differentiation of LView, RNode, LView, LContainer, StylingContext (#28947)

For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`,
`StylingContext`) in same location in `LView`. This is because we don't want to pre-allocate
space
for it because the storage is sparse. This file contains utilities for dealing with such data
types.
How do we know what is stored at a given location in `LView`.
- `Array.isArray(value) === false` => `RNode` (The normal storage value)
- `Array.isArray(value) === true` => than the `value[0]` represents the wrapped value.
  - `typeof value[TYPE] === 'object'` => `LView`
     - This happens when we have a component at a given location
  - `typeof value[TYPE] === 'number'` => `StylingContext`
     - This happens when we have style/class binding at a given location.
  - `typeof value[TYPE] === true` => `LContainer`
     - This happens when we have `LContainer` binding at a given location.
NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient.

PR Close #28947
This commit is contained in:
Misko Hevery
2019-02-23 11:14:35 -08:00
committed by Miško Hevery
parent bd65f58784
commit 3cb497c6ac
19 changed files with 225 additions and 112 deletions

View File

@ -9,25 +9,25 @@ import '../../util/ng_dev_mode';
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
import {getLContext} from '../context_discovery';
import {LCONTAINER_LENGTH, LContainer} from '../interfaces/container';
import {LContainer} from '../interfaces/container';
import {LContext} from '../interfaces/context';
import {AttributeMarker, TAttributes, TNode, TNodeFlags} from '../interfaces/node';
import {PlayState, Player, PlayerContext, PlayerIndex} from '../interfaces/player';
import {RElement} from '../interfaces/renderer';
import {InitialStylingValues, InitialStylingValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling';
import {InitialStylingValues, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling';
import {HEADER_OFFSET, HOST, LView, RootContext} from '../interfaces/view';
import {getTNode} from '../util/view_utils';
import {getTNode, isStylingContext} from '../util/view_utils';
import {CorePlayerHandler} from './core_player_handler';
export const ANIMATION_PROP_PREFIX = '@';
export function createEmptyStylingContext(
element?: RElement | null, sanitizer?: StyleSanitizeFn | null,
wrappedElement?: LContainer | LView | RElement | null, sanitizer?: StyleSanitizeFn | null,
initialStyles?: InitialStylingValues | null,
initialClasses?: InitialStylingValues | null): StylingContext {
const context: StylingContext = [
element || null, // Element
wrappedElement || null, // Element
0, // MasterFlags
[] as any, // DirectiveRefs (this gets filled below)
initialStyles || [null, null], // InitialStyles
@ -95,7 +95,7 @@ export function getStylingContext(index: number, viewData: LView): StylingContex
}
if (isStylingContext(wrapper)) {
return wrapper as StylingContext;
return wrapper;
} else {
// This is an LView or an LContainer
const stylingTemplate = getTNode(index - HEADER_OFFSET, viewData).stylingTemplate;
@ -110,15 +110,6 @@ export function getStylingContext(index: number, viewData: LView): StylingContex
}
}
export function isStylingContext(value: any): boolean {
// Not an LView or an LContainer
if (Array.isArray(value) && value.length >= StylingIndex.SingleStylesStartPosition) {
return typeof value[StylingIndex.MasterFlagPosition] === 'number' &&
value[StylingIndex.InitialClassValuesPosition]
[InitialStylingValuesIndex.DefaultNullValuePosition] === null;
}
return false;
}
export function isAnimationProp(name: string): boolean {
return name[0] === ANIMATION_PROP_PREFIX;