"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.utf16LengthForCodePoints = exports.codePointCount = void 0;
const internal_1 = require("@fluidframework/telemetry-utils/internal");
/**
 * Returns the number of Unicode code points in `value`.
 * @remarks
 * Use this to translate a JavaScript string length (which is in UTF-16 code units) into
 * the atom/code-point space used by {@link TextAsTree}.
 *
 * @example
 * ```typescript
 * codePointCount("");     // 0
 * codePointCount("abc");  // 3
 * codePointCount("a😀b"); // 3 — emoji is one code point, but "a😀b".length === 4 (UTF-16 surrogate pair)
 * ```
 *
 * @internal
 */
function codePointCount(value) {
    // Iterate instead of spreading to avoid allocating an intermediate array.
    let count = 0;
    for (const _ of value) {
        count++;
    }
    return count;
}
exports.codePointCount = codePointCount;
/**
 * Returns the number of UTF-16 code units occupied by the first `count` Unicode code points in `value`,
 * starting at UTF-16 index `start`.
 * @remarks
 * Use this to translate {@link TextAsTree}-space counts (code points) into JavaScript string indices (UTF-16).
 * One code point outside the Basic Multilingual Plane (e.g. most emoji) occupies two UTF-16 code units.
 *
 * Validates that the requested `count` code points are fully consumable from `start`; silent truncation
 * would misalign delta offsets applied to strings rather than surface the drift to the caller.
 *
 * @example
 * ```typescript
 * utf16LengthForCodePoints("abc", 0, 3);  // 3 — three single-unit characters
 * utf16LengthForCodePoints("a😀b", 0, 3); // 4 — a (1) + 😀 (2) + b (1)
 * utf16LengthForCodePoints("a😀b", 1, 1); // 2 — just the emoji
 * utf16LengthForCodePoints("abc", 0, 0);  // 0 — no code points requested
 * ```
 *
 * @param value - The string to measure.
 * @param start - The UTF-16 index in `value` to start measuring from. Must be in `[0, value.length]`.
 * @param count - The number of Unicode code points to measure. Must be non-negative, and there must
 * be at least `count` code points available in `value` starting at `start`.
 * @throws A {@link @fluidframework/telemetry-utils#UsageError} if `start` is out of range,
 * `count` is negative, or fewer than `count` code points are available from `start`.
 * @internal
 */
function utf16LengthForCodePoints(value, start, count) {
    if (start < 0 || start > value.length) {
        throw new internal_1.UsageError(`start (${start}) must be within [0, ${value.length}] (value.length).`);
    }
    if (count < 0) {
        throw new internal_1.UsageError(`count (${count}) must be non-negative.`);
    }
    let utf16 = 0;
    let counted = 0;
    while (counted < count && start + utf16 < value.length) {
        // Code points above 0xFFFF are encoded in UTF-16 as a surrogate pair (2 units);
        // everything else takes a single UTF-16 unit.
        utf16 += (value.codePointAt(start + utf16) ?? 0) > 0xffff ? 2 : 1;
        counted++;
    }
    if (counted !== count) {
        throw new internal_1.UsageError(`count (${count}) exceeds the ${counted} code point(s) available from start (${start}) in a value of length ${value.length}.`);
    }
    return utf16;
}
exports.utf16LengthForCodePoints = utf16LengthForCodePoints;
//# sourceMappingURL=codePointUtils.js.map