From 9fcd9a892322e40c38d7ca11562a10d69a09be99 Mon Sep 17 00:00:00 2001 From: yic <1012273699@qq.com> Date: Sat, 23 May 2026 16:34:01 +0800 Subject: [PATCH] fix: replace function expression with arrow callback Signed-off-by: yic <1012273699@qq.com> --- library/src/main/ets/index.ets | 512 ++++++++++++++++++++++++++++++++- 1 file changed, 506 insertions(+), 6 deletions(-) diff --git a/library/src/main/ets/index.ets b/library/src/main/ets/index.ets index 873948f..34f7308 100644 --- a/library/src/main/ets/index.ets +++ b/library/src/main/ets/index.ets @@ -1,13 +1,513 @@ // TS2ArkTS-SessionId-2 -export default function randomInteger(minimum: number, maximum?: number): number { + +export interface RandomIntegerOptions { + inclusiveMinimum?: boolean; + inclusiveMaximum?: boolean; + clamp?: boolean; + source?: () => number; +} + +export interface RandomIntegerRange { + minimum: number; + maximum: number; + inclusiveMinimum: boolean; + inclusiveMaximum: boolean; +} + +export interface RandomIntegerSequenceOptions extends RandomIntegerOptions { + unique?: boolean; + sorted?: boolean; +} + +export interface RandomIntegerStats { + count: number; + minimum: number; + maximum: number; + sum: number; + average: number; +} + +const DEFAULT_INCLUSIVE_MINIMUM: boolean = true; +const DEFAULT_INCLUSIVE_MAXIMUM: boolean = true; +const MAX_GENERATION_ATTEMPTS: number = 10000; + +function isNumber(value: number): boolean { + return typeof value === 'number' && Number.isFinite(value); +} + +function isInteger(value: number): boolean { + return isNumber(value) && Math.floor(value) === value; +} + +function fail(message: string): never { + throw new TypeError(message); +} + +function normalizeBoolean(value: boolean | undefined, fallback: boolean): boolean { + if (value === undefined) { + return fallback; + } + + if (typeof value !== 'boolean') { + fail('Expected option values to be booleans'); + } + + return value; +} + +function normalizeRandomSource(options?: RandomIntegerOptions): () => number { + if (options === undefined || options.source === undefined) { + return Math.random; + } + + if (typeof options.source !== 'function') { + fail('Expected source to be a function'); + } + + return options.source; +} + +function readRandomUnit(source: () => number): number { + const value = source(); + + if (!isNumber(value)) { + fail('Expected random source to return a finite number'); + } + + if (value < 0 || value >= 1) { + fail('Expected random source to return a value in the range [0, 1)'); + } + + return value; +} + +function normalizeEndpoint(value: number, label: string, clamp: boolean): number { + if (!isNumber(value)) { + fail('Expected ' + label + ' to be a finite number'); + } + + if (clamp) { + return Math.trunc(value); + } + + if (!isInteger(value)) { + fail('Expected ' + label + ' to be an integer'); + } + + return value; +} + +function normalizeRange(minimum: number, maximum: number, options?: RandomIntegerOptions): RandomIntegerRange { + const clamp = normalizeBoolean(options === undefined ? undefined : options.clamp, false); + const inclusiveMinimum = normalizeBoolean( + options === undefined ? undefined : options.inclusiveMinimum, + DEFAULT_INCLUSIVE_MINIMUM + ); + const inclusiveMaximum = normalizeBoolean( + options === undefined ? undefined : options.inclusiveMaximum, + DEFAULT_INCLUSIVE_MAXIMUM + ); + + let low = normalizeEndpoint(minimum, 'minimum', clamp); + let high = normalizeEndpoint(maximum, 'maximum', clamp); + + if (low > high) { + const temporary = low; + low = high; + high = temporary; + } + + if (!inclusiveMinimum) { + low += 1; + } + + if (!inclusiveMaximum) { + high -= 1; + } + + if (low > high) { + fail('Expected range to contain at least one integer'); + } + + return { + minimum: low, + maximum: high, + inclusiveMinimum: true, + inclusiveMaximum: true + }; +} + +function normalizeArguments(minimum: number, maximum?: number, options?: RandomIntegerOptions): RandomIntegerRange { if (maximum === undefined) { - maximum = minimum; - minimum = 0; + return normalizeRange(0, minimum, options); + } + + return normalizeRange(minimum, maximum, options); +} + +function rangeSize(range: RandomIntegerRange): number { + return range.maximum - range.minimum + 1; +} + +function ensureSafeRange(range: RandomIntegerRange): void { + const size = rangeSize(range); + + if (!Number.isSafeInteger(range.minimum) || !Number.isSafeInteger(range.maximum)) { + fail('Expected range endpoints to be safe integers'); + } + + if (!Number.isSafeInteger(size) || size <= 0) { + fail('Expected range size to be a positive safe integer'); + } +} + +export default function randomInteger(minimum: number, maximum?: number, options?: RandomIntegerOptions): number { + const range = normalizeArguments(minimum, maximum, options); + ensureSafeRange(range); + + const source = normalizeRandomSource(options); + const value = readRandomUnit(source); + const size = rangeSize(range); + + return Math.floor(value * size) + range.minimum; +} + +export function randomIntegerBetween(minimum: number, maximum: number, options?: RandomIntegerOptions): number { + return randomInteger(minimum, maximum, options); +} + +export function randomIntegerBelow(maximum: number, options?: RandomIntegerOptions): number { + return randomInteger(0, maximum, { + inclusiveMinimum: true, + inclusiveMaximum: false, + clamp: options === undefined ? undefined : options.clamp, + source: options === undefined ? undefined : options.source + }); +} + +export function randomIntegerAbove(minimum: number, options?: RandomIntegerOptions): number { + return randomInteger(minimum, Number.MAX_SAFE_INTEGER, { + inclusiveMinimum: false, + inclusiveMaximum: true, + clamp: options === undefined ? undefined : options.clamp, + source: options === undefined ? undefined : options.source + }); +} + +export function randomIntegerRange(minimum: number, maximum: number, options?: RandomIntegerOptions): RandomIntegerRange { + const range = normalizeRange(minimum, maximum, options); + ensureSafeRange(range); + return range; +} + +export function randomIntegerArray( + count: number, + minimum: number, + maximum: number, + options?: RandomIntegerSequenceOptions +): number[] { + if (!isInteger(count) || count < 0) { + fail('Expected count to be a non-negative integer'); + } + + const unique = normalizeBoolean(options === undefined ? undefined : options.unique, false); + const sorted = normalizeBoolean(options === undefined ? undefined : options.sorted, false); + const range = normalizeRange(minimum, maximum, options); + ensureSafeRange(range); + + if (unique && count > rangeSize(range)) { + fail('Expected unique count to fit inside the range'); + } + + const output: number[] = []; + + if (unique) { + const pool = integerRangeArray(range.minimum, range.maximum); + shuffleNumbers(pool, options); + + for (let index = 0; index < count; index++) { + output.push(pool[index]); + } + } else { + for (let index = 0; index < count; index++) { + output.push(randomInteger(range.minimum, range.maximum, options)); + } + } + + if (sorted) { + output.sort((left: number, right: number): number => left - right); + } + + return output; +} + +export function randomIntegerMatrix( + rows: number, + columns: number, + minimum: number, + maximum: number, + options?: RandomIntegerOptions +): number[][] { + if (!isInteger(rows) || rows < 0) { + fail('Expected rows to be a non-negative integer'); + } + + if (!isInteger(columns) || columns < 0) { + fail('Expected columns to be a non-negative integer'); } - if (typeof minimum !== 'number' || typeof maximum !== 'number') { - throw new TypeError('Expected all arguments to be numbers'); + const matrix: number[][] = []; + + for (let row = 0; row < rows; row++) { + const values: number[] = []; + + for (let column = 0; column < columns; column++) { + values.push(randomInteger(minimum, maximum, options)); + } + + matrix.push(values); + } + + return matrix; +} + +export function integerRangeArray(minimum: number, maximum: number, options?: RandomIntegerOptions): number[] { + const range = normalizeRange(minimum, maximum, options); + ensureSafeRange(range); + + const output: number[] = []; + + for (let value = range.minimum; value <= range.maximum; value++) { + output.push(value); + } + + return output; +} + +export function shuffleNumbers(values: number[], options?: RandomIntegerOptions): number[] { + if (!Array.isArray(values)) { + fail('Expected values to be an array'); + } + + for (let index = values.length - 1; index > 0; index--) { + const swapIndex = randomInteger(0, index, options); + const current = values[index]; + values[index] = values[swapIndex]; + values[swapIndex] = current; + } + + return values; +} + +export function shuffledNumbers(values: number[], options?: RandomIntegerOptions): number[] { + const copy: number[] = []; + + for (let index = 0; index < values.length; index++) { + copy.push(values[index]); + } + + return shuffleNumbers(copy, options); +} + +export function pickRandomNumber(values: number[], options?: RandomIntegerOptions): number { + if (!Array.isArray(values) || values.length === 0) { + fail('Expected values to be a non-empty array'); + } + + return values[randomInteger(0, values.length - 1, options)]; +} + +export function sampleRandomNumbers(values: number[], count: number, options?: RandomIntegerSequenceOptions): number[] { + if (!Array.isArray(values)) { + fail('Expected values to be an array'); + } + + if (!isInteger(count) || count < 0) { + fail('Expected count to be a non-negative integer'); + } + + const unique = normalizeBoolean(options === undefined ? undefined : options.unique, false); + + if (unique && count > values.length) { + fail('Expected unique count to fit inside the values array'); + } + + const output: number[] = []; + + if (unique) { + const copy = shuffledNumbers(values, options); + + for (let index = 0; index < count; index++) { + output.push(copy[index]); + } + + return output; + } + + for (let index = 0; index < count; index++) { + output.push(pickRandomNumber(values, options)); + } + + return output; +} + +export function randomIntegerStats(values: number[]): RandomIntegerStats { + if (!Array.isArray(values) || values.length === 0) { + fail('Expected values to be a non-empty array'); + } + + let minimum = values[0]; + let maximum = values[0]; + let sum = 0; + + for (let index = 0; index < values.length; index++) { + const value = values[index]; + + if (!isInteger(value)) { + fail('Expected every value to be an integer'); + } + + if (value < minimum) { + minimum = value; + } + + if (value > maximum) { + maximum = value; + } + + sum += value; + } + + return { + count: values.length, + minimum: minimum, + maximum: maximum, + sum: sum, + average: sum / values.length + }; +} + +export function createSeededRandomSource(seed: number): () => number { + if (!isInteger(seed)) { + fail('Expected seed to be an integer'); + } + + let state = seed >>> 0; + + if (state === 0) { + state = 0x6d2b79f5; + } + + return (): number => { + state += 0x6d2b79f5; + let value = state; + value = Math.imul(value ^ (value >>> 15), value | 1); + value ^= value + Math.imul(value ^ (value >>> 7), value | 61); + return ((value ^ (value >>> 14)) >>> 0) / 4294967296; + }; +} + +export class RandomIntegerGenerator { + private source: () => number; + + constructor(source?: () => number) { + if (source === undefined) { + this.source = Math.random; + return; + } + + if (typeof source !== 'function') { + fail('Expected source to be a function'); + } + + this.source = source; + } + + next(minimum: number, maximum?: number, options?: RandomIntegerOptions): number { + return randomInteger(minimum, maximum, this.mergeOptions(options)); + } + + below(maximum: number, options?: RandomIntegerOptions): number { + return randomIntegerBelow(maximum, this.mergeOptions(options)); + } + + between(minimum: number, maximum: number, options?: RandomIntegerOptions): number { + return randomIntegerBetween(minimum, maximum, this.mergeOptions(options)); + } + + array( + count: number, + minimum: number, + maximum: number, + options?: RandomIntegerSequenceOptions + ): number[] { + return randomIntegerArray(count, minimum, maximum, this.mergeSequenceOptions(options)); + } + + matrix( + rows: number, + columns: number, + minimum: number, + maximum: number, + options?: RandomIntegerOptions + ): number[][] { + return randomIntegerMatrix(rows, columns, minimum, maximum, this.mergeOptions(options)); + } + + shuffle(values: number[], options?: RandomIntegerOptions): number[] { + return shuffleNumbers(values, this.mergeOptions(options)); + } + + sample(values: number[], count: number, options?: RandomIntegerSequenceOptions): number[] { + return sampleRandomNumbers(values, count, this.mergeSequenceOptions(options)); + } + + private mergeOptions(options?: RandomIntegerOptions): RandomIntegerOptions { + return { + inclusiveMinimum: options === undefined ? undefined : options.inclusiveMinimum, + inclusiveMaximum: options === undefined ? undefined : options.inclusiveMaximum, + clamp: options === undefined ? undefined : options.clamp, + source: this.source + }; + } + + private mergeSequenceOptions(options?: RandomIntegerSequenceOptions): RandomIntegerSequenceOptions { + return { + inclusiveMinimum: options === undefined ? undefined : options.inclusiveMinimum, + inclusiveMaximum: options === undefined ? undefined : options.inclusiveMaximum, + clamp: options === undefined ? undefined : options.clamp, + source: this.source, + unique: options === undefined ? undefined : options.unique, + sorted: options === undefined ? undefined : options.sorted + }; + } +} + +export function createRandomIntegerGenerator(seed?: number): RandomIntegerGenerator { + if (seed === undefined) { + return new RandomIntegerGenerator(); + } + + return new RandomIntegerGenerator(createSeededRandomSource(seed)); +} + +export function retryRandomInteger( + minimum: number, + maximum: number, + predicate: (value: number) => boolean, + options?: RandomIntegerOptions +): number { + if (typeof predicate !== 'function') { + fail('Expected predicate to be a function'); + } + + for (let attempt = 0; attempt < MAX_GENERATION_ATTEMPTS; attempt++) { + const value = randomInteger(minimum, maximum, options); + + if (predicate(value)) { + return value; + } } - return Math.floor(Math.random() * (maximum - minimum + 1) + minimum); + fail('Unable to generate a matching integer'); } -- Gitee