Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf - use Lazy for comparers and 💄 Lazy to align with IdleValue #170866

Merged
merged 2 commits into from Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/vs/base/browser/markdownRenderer.ts
Expand Up @@ -438,7 +438,7 @@ export function renderMarkdownAsPlaintext(markdown: IMarkdownString) {
value = `${value.substr(0, 100_000)}…`;
}

const html = marked.parse(value, { renderer: plainTextRenderer.getValue() }).replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m);
const html = marked.parse(value, { renderer: plainTextRenderer.value }).replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m);

return sanitizeRenderedMarkdown({ isTrusted: false }, html).toString();
}
Expand Down
14 changes: 7 additions & 7 deletions src/vs/base/common/comparers.ts
Expand Up @@ -3,35 +3,35 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { IdleValue } from 'vs/base/common/async';
import { Lazy } from 'vs/base/common/lazy';
import { sep } from 'vs/base/common/path';

// When comparing large numbers of strings it's better for performance to create an
// Intl.Collator object and use the function provided by its compare property
// than it is to use String.prototype.localeCompare()

// A collator with numeric sorting enabled, and no sensitivity to case, accents or diacritics.
const intlFileNameCollatorBaseNumeric: IdleValue<{ collator: Intl.Collator; collatorIsNumeric: boolean }> = new IdleValue(() => {
const intlFileNameCollatorBaseNumeric: Lazy<{ collator: Intl.Collator; collatorIsNumeric: boolean }> = new Lazy(() => {
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
return {
collator: collator,
collator,
collatorIsNumeric: collator.resolvedOptions().numeric
};
});

// A collator with numeric sorting enabled.
const intlFileNameCollatorNumeric: IdleValue<{ collator: Intl.Collator }> = new IdleValue(() => {
const intlFileNameCollatorNumeric: Lazy<{ collator: Intl.Collator }> = new Lazy(() => {
const collator = new Intl.Collator(undefined, { numeric: true });
return {
collator: collator
collator
};
});

// A collator with numeric sorting enabled, and sensitivity to accents and diacritics but not case.
const intlFileNameCollatorNumericCaseInsensitive: IdleValue<{ collator: Intl.Collator }> = new IdleValue(() => {
const intlFileNameCollatorNumericCaseInsensitive: Lazy<{ collator: Intl.Collator }> = new Lazy(() => {
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'accent' });
return {
collator: collator
collator
};
});

Expand Down
27 changes: 2 additions & 25 deletions src/vs/base/common/lazy.ts
Expand Up @@ -3,20 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

/**
* A value that is resolved synchronously when it is first needed.
*/
export interface Lazy<T> {

hasValue(): boolean;


getValue(): T;


map<R>(f: (x: T) => R): Lazy<R>;
}

export class Lazy<T> {

private _didRun: boolean = false;
Expand All @@ -30,15 +16,15 @@ export class Lazy<T> {
/**
* True if the lazy value has been resolved.
*/
hasValue() { return this._didRun; }
get hasValue() { return this._didRun; }

/**
* Get the wrapped value.
*
* This will force evaluation of the lazy value if it has not been resolved yet. Lazy values are only
* resolved once. `getValue` will re-throw exceptions that are hit while resolving the value
*/
getValue(): T {
get value(): T {
if (!this._didRun) {
try {
this._value = this.executor();
Expand All @@ -58,13 +44,4 @@ export class Lazy<T> {
* Get the wrapped value without forcing evaluation.
*/
get rawValue(): T | undefined { return this._value; }

/**
* Create a new lazy value that is the result of applying `f` to the wrapped value.
*
* This does not force the evaluation of the current lazy value.
*/
map<R>(f: (x: T) => R): Lazy<R> {
return new Lazy<R>(() => f(this.getValue()));
}
}
6 changes: 3 additions & 3 deletions src/vs/base/common/strings.ts
Expand Up @@ -1134,7 +1134,7 @@ export class AmbiguousCharacters {
return result;
}

const data = this.ambiguousCharacterData.getValue();
const data = this.ambiguousCharacterData.value;

let filteredLocales = locales.filter(
(l) => !l.startsWith('_') && l in data
Expand All @@ -1160,12 +1160,12 @@ export class AmbiguousCharacters {
}

private static _locales = new Lazy<string[]>(() =>
Object.keys(AmbiguousCharacters.ambiguousCharacterData.getValue()).filter(
Object.keys(AmbiguousCharacters.ambiguousCharacterData.value).filter(
(k) => !k.startsWith('_')
)
);
public static getLocales(): string[] {
return AmbiguousCharacters._locales.getValue();
return AmbiguousCharacters._locales.value;
}

private constructor(
Expand Down
50 changes: 8 additions & 42 deletions src/vs/base/test/common/lazy.test.ts
Expand Up @@ -12,53 +12,19 @@ suite('Lazy', () => {
let counter = 0;
const value = new Lazy(() => ++counter);

assert.strictEqual(value.hasValue(), false);
assert.strictEqual(value.getValue(), 1);
assert.strictEqual(value.hasValue(), true);
assert.strictEqual(value.getValue(), 1); // make sure we did not evaluate again
assert.strictEqual(value.hasValue, false);
assert.strictEqual(value.value, 1);
assert.strictEqual(value.hasValue, true);
assert.strictEqual(value.value, 1); // make sure we did not evaluate again
});

test('lazy values handle error case', () => {
let counter = 0;
const value = new Lazy(() => { throw new Error(`${++counter}`); });

assert.strictEqual(value.hasValue(), false);
assert.throws(() => value.getValue(), /\b1\b/);
assert.strictEqual(value.hasValue(), true);
assert.throws(() => value.getValue(), /\b1\b/);
});

test('map should not cause lazy values to be re-resolved', () => {
let outer = 0;
let inner = 10;
const outerLazy = new Lazy(() => ++outer);
const innerLazy = outerLazy.map(x => [x, ++inner]);

assert.strictEqual(outerLazy.hasValue(), false);
assert.strictEqual(innerLazy.hasValue(), false);

assert.deepStrictEqual(innerLazy.getValue(), [1, 11]);
assert.strictEqual(outerLazy.hasValue(), true);
assert.strictEqual(innerLazy.hasValue(), true);
assert.strictEqual(outerLazy.getValue(), 1);

// make sure we did not evaluate again
assert.strictEqual(outerLazy.getValue(), 1);
assert.deepStrictEqual(innerLazy.getValue(), [1, 11]);
});

test('map should handle error values', () => {
let outer = 0;
let inner = 10;
const outerLazy = new Lazy(() => { throw new Error(`${++outer}`); });
const innerLazy = outerLazy.map(x => { throw new Error(`${++inner}`); });

assert.strictEqual(outerLazy.hasValue(), false);
assert.strictEqual(innerLazy.hasValue(), false);

assert.throws(() => innerLazy.getValue(), /\b1\b/); // we should get result from outer
assert.strictEqual(outerLazy.hasValue(), true);
assert.strictEqual(innerLazy.hasValue(), true);
assert.throws(() => outerLazy.getValue(), /\b1\b/);
assert.strictEqual(value.hasValue, false);
assert.throws(() => value.value, /\b1\b/);
assert.strictEqual(value.hasValue, true);
assert.throws(() => value.value, /\b1\b/);
});
});
Expand Up @@ -125,11 +125,11 @@ export class CodeActionController extends Disposable implements IEditorContribut
}

private update(newState: CodeActionsState.State): void {
this._ui.getValue().update(newState);
this._ui.value.update(newState);
}

public showCodeActions(_trigger: CodeActionTrigger, actions: CodeActionSet, at: IAnchor | IPosition) {
return this._ui.getValue().showCodeActionList(actions, at, { includeDisabledActions: false, fromLightbulb: false });
return this._ui.value.showCodeActionList(actions, at, { includeDisabledActions: false, fromLightbulb: false });
}

public manualTriggerAtCurrentPosition(
Expand Down
Expand Up @@ -54,7 +54,7 @@ export class CodeActionKeybindingResolver {

return (action) => {
if (action.kind) {
const binding = this.bestKeybindingForCodeAction(action, allCodeActionBindings.getValue());
const binding = this.bestKeybindingForCodeAction(action, allCodeActionBindings.value);
return binding?.resolvedKeybinding;
}
return undefined;
Expand Down
4 changes: 2 additions & 2 deletions src/vs/editor/contrib/codeAction/browser/codeActionUi.ts
Expand Up @@ -89,7 +89,7 @@ export class CodeActionUi extends Disposable {
return;
}

this._lightBulbWidget.getValue().update(actions, newState.trigger, newState.position);
this._lightBulbWidget.value.update(actions, newState.trigger, newState.position);

if (newState.trigger.type === CodeActionTriggerType.Invoke) {
if (newState.trigger.filter?.include) { // Triggered for specific scope
Expand All @@ -98,7 +98,7 @@ export class CodeActionUi extends Disposable {
const validActionToApply = this.tryGetValidActionToApply(newState.trigger, actions);
if (validActionToApply) {
try {
this._lightBulbWidget.getValue().hide();
this._lightBulbWidget.value.hide();
await this.delegate.applyCodeAction(validActionToApply, false, false);
} finally {
actions.dispose();
Expand Down
Expand Up @@ -45,8 +45,8 @@ class ParameterHintsController extends Disposable implements IEditorContribution

this._register(this.model.onChangedHints(newParameterHints => {
if (newParameterHints) {
this.widget.getValue().show();
this.widget.getValue().render(newParameterHints);
this.widget.value.show();
this.widget.value.render(newParameterHints);
} else {
this.widget.rawValue?.hide();
}
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/api/common/extHostTextEditor.ts
Expand Up @@ -428,7 +428,7 @@ export class ExtHostTextEditor {

this.value = Object.freeze({
get document(): vscode.TextDocument {
return document.getValue();
return document.value;
},
set document(_value) {
throw readonly('document');
Expand Down Expand Up @@ -482,7 +482,7 @@ export class ExtHostTextEditor {
if (that._disposed) {
return Promise.reject(new Error('TextEditor#edit not possible on closed editors'));
}
const edit = new TextEditorEdit(document.getValue(), options);
const edit = new TextEditorEdit(document.value, options);
callback(edit);
return that._applyEdit(edit);
},
Expand Down Expand Up @@ -513,7 +513,7 @@ export class ExtHostTextEditor {
}
}
}
return _proxy.$tryInsertSnippet(id, document.getValue().version, snippet.value, ranges, options);
return _proxy.$tryInsertSnippet(id, document.value.version, snippet.value, ranges, options);
},
setDecorations(decorationType: vscode.TextEditorDecorationType, ranges: Range[] | vscode.DecorationOptions[]): void {
const willBeEmpty = (ranges.length === 0);
Expand Down
Expand Up @@ -158,7 +158,7 @@ export class ExtHostVariableResolverProviderService extends Disposable implement
}

public getResolver(): Promise<IConfigurationResolverService> {
return this._resolver.getValue();
return this._resolver.value;
}

protected homeDir(): string | undefined {
Expand Down
Expand Up @@ -57,15 +57,15 @@ export class NotebookFindContrib extends Disposable implements INotebookEditorCo
}

show(initialInput?: string, options?: IShowNotebookFindWidgetOptions): Promise<void> {
return this.widget.getValue().show(initialInput, options);
return this.widget.value.show(initialInput, options);
}

hide() {
this.widget.rawValue?.hide();
}

replace(searchString: string | undefined) {
return this.widget.getValue().replace(searchString);
return this.widget.value.replace(searchString);
}
}

Expand Down
Expand Up @@ -338,7 +338,7 @@ export class NotebookOutputRendererInfoStore {

/** Update and remember the preferred renderer for the given mimetype in this workspace */
setPreferred(notebookProviderInfo: NotebookProviderInfo, mimeType: string, rendererId: string) {
const mementoObj = this.preferredMimetype.getValue();
const mementoObj = this.preferredMimetype.value;
const forNotebook = mementoObj[notebookProviderInfo.id];
if (forNotebook) {
forNotebook[mimeType] = rendererId;
Expand All @@ -358,7 +358,7 @@ export class NotebookOutputRendererInfoStore {
BuiltIn = 4 << 8,
}

const preferred = notebookProviderInfo && this.preferredMimetype.getValue()[notebookProviderInfo.id]?.[mimeType];
const preferred = notebookProviderInfo && this.preferredMimetype.value[notebookProviderInfo.id]?.[mimeType];
const notebookExtId = notebookProviderInfo?.extension?.value;
const notebookId = notebookProviderInfo?.id;
const renderers: { ordered: IOrderedMimeType; score: number }[] = Array.from(this.contributedRenderers.values())
Expand Down
Expand Up @@ -1005,8 +1005,8 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider<IAnyt
label,
ariaLabel: isDirty ? localize('filePickAriaLabelDirty', "{0} unsaved changes", labelAndDescription) : labelAndDescription,
description,
get iconClasses() { return iconClassesValue.getValue(); },
get buttons() { return buttonsValue.getValue(); },
get iconClasses() { return iconClassesValue.value; },
get buttons() { return buttonsValue.value; },
trigger: (buttonIndex, keyMods) => {
switch (buttonIndex) {

Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/search/common/searchModel.ts
Expand Up @@ -440,7 +440,7 @@ export class FileMatch extends Disposable implements IFileMatch {
}

name(): string {
return this._name.getValue();
return this._name.value;
}

addContext(results: ITextSearchResult[] | undefined) {
Expand Down Expand Up @@ -564,7 +564,7 @@ export class FolderMatch extends Disposable {
}

name(): string {
return this._name.getValue();
return this._name.value;
}

parent(): SearchResult | FolderMatch {
Expand Down
Expand Up @@ -81,7 +81,7 @@ export function removeLinkSuffix(link: string): string {
* @param link The link to parse.
*/
export function getLinkSuffix(link: string): { row: number | undefined; col: number | undefined; suffix: { index: number; text: string } } | null {
const matches = linkSuffixRegex.getValue().exec(link);
const matches = linkSuffixRegex.value.exec(link);
const groups = matches?.groups;
if (!groups || matches.length < 1) {
return null;
Expand Down