import { kValue } from '../../../../../util/constants.js';
import { ScalarType, Type } from '../../../../../util/conversion.js';
import { FP } from '../../../../../util/floating_point.js';
import { maxBigInt, minBigInt } from '../../../../../util/math.js';
import { Case } from '../../case.js';
import { makeCaseCache } from '../../case_cache.js';
const u32Values = [0, 1, 2, 3, 0x70000000, 0x80000000, kValue.u32.max];
const i32Values = [
kValue.i32.negative.min,
-3,
-2,
-1,
0,
1,
2,
3,
0x70000000,
kValue.i32.positive.max,
];
const abstractFloatValues = [
kValue.i64.negative.min,
-3n,
-2n,
-1n,
0n,
1n,
2n,
3n,
0x70000000n,
kValue.i64.positive.max,
];
function generateConcreteIntegerTestCases(
test_values: Array<number>,
type: ScalarType,
stage: 'const' | 'non_const'
): Array<Case> {
return test_values.flatMap(low =>
test_values.flatMap(high =>
stage === 'const' && low > high
? []
: test_values.map(e => ({
input: [type.create(e), type.create(low), type.create(high)],
expected: type.create(Math.min(Math.max(e, low), high)),
}))
)
);
}
function generateAbstractIntegerTestCases(test_values: Array<bigint>): Array<Case> {
return test_values.flatMap(low =>
test_values.flatMap(high =>
low > high
? []
: test_values.map(e => ({
input: [
Type.abstractInt.create(e),
Type.abstractInt.create(low),
Type.abstractInt.create(high),
],
expected: Type.abstractInt.create(minBigInt(maxBigInt(e, low), high)),
}))
)
);
}
function generateFloatTestCases(
test_values: readonly number[],
trait: 'f32' | 'f16' | 'abstract',
stage: 'const' | 'non_const'
): Array<Case> {
return test_values.flatMap(low =>
test_values.flatMap(high =>
stage === 'const' && low > high
? []
: test_values.flatMap(e => {
const c = FP[trait].makeScalarTripleToIntervalCase(
e,
low,
high,
stage === 'const' ? 'finite' : 'unfiltered',
...FP[trait].clampIntervals
);
return c === undefined ? [] : [c];
})
)
);
}
const fp_cases = (['f32', 'f16', 'abstract'] as const)
.flatMap(trait =>
([true, false] as const).map(nonConst => ({
[`${trait}_${nonConst ? 'non_const' : 'const'}`]: () => {
if (trait === 'abstract' && nonConst) {
return [];
}
return generateFloatTestCases(
FP[trait].sparseScalarRange(),
trait,
nonConst ? 'non_const' : 'const'
);
},
}))
)
.reduce((a, b) => ({ ...a, ...b }), {});
export const d = makeCaseCache('clamp', {
u32_non_const: () => {
return generateConcreteIntegerTestCases(u32Values, Type.u32, 'non_const');
},
u32_const: () => {
return generateConcreteIntegerTestCases(u32Values, Type.u32, 'const');
},
i32_non_const: () => {
return generateConcreteIntegerTestCases(i32Values, Type.i32, 'non_const');
},
i32_const: () => {
return generateConcreteIntegerTestCases(i32Values, Type.i32, 'const');
},
abstract_int: () => {
return generateAbstractIntegerTestCases(abstractFloatValues);
},
...fp_cases,
});