src/vs/editor/common/model/textModel.ts/TextModel/_deltaDecorationsImpl
class TextModel:	private _deltaDecorationsImpl(ownerId: number, oldDecorationsIds: string[], newDecorations: model.IModelDeltaDecoration[]): string[] {
		const versionId = this.getVersionId();

		const oldDecorationsLen = oldDecorationsIds.length;
		let oldDecorationIndex = 0;

		const newDecorationsLen = newDecorations.length;
		let newDecorationIndex = 0;

		this._onDidChangeDecorations.beginDeferredEmit();
		try {
			const result = new Array<string>(newDecorationsLen);
			while (oldDecorationIndex < oldDecorationsLen || newDecorationIndex < newDecorationsLen) {

				let node: IntervalNode | null = null;

				if (oldDecorationIndex < oldDecorationsLen) {
					// (1) get ourselves an old node
					do {
						node = this._decorations[oldDecorationsIds[oldDecorationIndex++]];
					} while (!node && oldDecorationIndex < oldDecorationsLen);

					// (2) remove the node from the tree (if it exists)
					if (node) {
						if (node.options.after) {
							const nodeRange = this._decorationsTree.getNodeRange(this, node);
							this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.endLineNumber);
						}
						if (node.options.before) {
							const nodeRange = this._decorationsTree.getNodeRange(this, node);
							this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.startLineNumber);
						}

						this._decorationsTree.delete(node);

						this._onDidChangeDecorations.checkAffectedAndFire(node.options);
					}
				}

				if (newDecorationIndex < newDecorationsLen) {
					// (3) create a new node if necessary
					if (!node) {
						const internalDecorationId = (++this._lastDecorationId);
						const decorationId = `${this._instanceId};${internalDecorationId}`;
						node = new IntervalNode(decorationId, 0, 0);
						this._decorations[decorationId] = node;
					}

					// (4) initialize node
					const newDecoration = newDecorations[newDecorationIndex];
					const range = this._validateRangeRelaxedNoAllocations(newDecoration.range);
					const options = _normalizeOptions(newDecoration.options);
					const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
					const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);

					node.ownerId = ownerId;
					node.reset(versionId, startOffset, endOffset, range);
					node.setOptions(options);

					if (node.options.after) {
						this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.endLineNumber);
					}
					if (node.options.before) {
						this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.startLineNumber);
					}

					this._onDidChangeDecorations.checkAffectedAndFire(options);

					this._decorationsTree.insert(node);

					result[newDecorationIndex] = node.id;

					newDecorationIndex++;
				} else {
					if (node) {
						delete this._decorations[node.id];
					}
				}
			}

			return result;
		} finally {
			this._onDidChangeDecorations.endDeferredEmit();
		}
	}