File size: 5,888 Bytes
96af7c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.arrayInt64 = arrayInt64;
const Stream_1 = require("../../stream/Stream");
const Arbitrary_1 = require("../../check/arbitrary/definition/Arbitrary");
const Value_1 = require("../../check/arbitrary/definition/Value");
const ArrayInt64_1 = require("./helpers/ArrayInt64");
class ArrayInt64Arbitrary extends Arbitrary_1.Arbitrary {
    constructor(min, max) {
        super();
        this.min = min;
        this.max = max;
        this.biasedRanges = null;
    }
    generate(mrng, biasFactor) {
        const range = this.computeGenerateRange(mrng, biasFactor);
        const uncheckedValue = mrng.nextArrayInt(range.min, range.max);
        if (uncheckedValue.data.length === 1) {
            uncheckedValue.data.unshift(0);
        }
        return new Value_1.Value(uncheckedValue, undefined);
    }
    computeGenerateRange(mrng, biasFactor) {
        if (biasFactor === undefined || mrng.nextInt(1, biasFactor) !== 1) {
            return { min: this.min, max: this.max };
        }
        const ranges = this.retrieveBiasedRanges();
        if (ranges.length === 1) {
            return ranges[0];
        }
        const id = mrng.nextInt(-2 * (ranges.length - 1), ranges.length - 2);
        return id < 0 ? ranges[0] : ranges[id + 1];
    }
    canShrinkWithoutContext(value) {
        const unsafeValue = value;
        return (typeof value === 'object' &&
            value !== null &&
            (unsafeValue.sign === -1 || unsafeValue.sign === 1) &&
            Array.isArray(unsafeValue.data) &&
            unsafeValue.data.length === 2 &&
            (((0, ArrayInt64_1.isStrictlySmaller64)(this.min, unsafeValue) && (0, ArrayInt64_1.isStrictlySmaller64)(unsafeValue, this.max)) ||
                (0, ArrayInt64_1.isEqual64)(this.min, unsafeValue) ||
                (0, ArrayInt64_1.isEqual64)(this.max, unsafeValue)));
    }
    shrinkArrayInt64(value, target, tryTargetAsap) {
        const realGap = (0, ArrayInt64_1.substract64)(value, target);
        function* shrinkGen() {
            let previous = tryTargetAsap ? undefined : target;
            const gap = tryTargetAsap ? realGap : (0, ArrayInt64_1.halve64)(realGap);
            for (let toremove = gap; !(0, ArrayInt64_1.isZero64)(toremove); toremove = (0, ArrayInt64_1.halve64)(toremove)) {
                const next = (0, ArrayInt64_1.substract64)(value, toremove);
                yield new Value_1.Value(next, previous);
                previous = next;
            }
        }
        return (0, Stream_1.stream)(shrinkGen());
    }
    shrink(current, context) {
        if (!ArrayInt64Arbitrary.isValidContext(current, context)) {
            const target = this.defaultTarget();
            return this.shrinkArrayInt64(current, target, true);
        }
        if (this.isLastChanceTry(current, context)) {
            return Stream_1.Stream.of(new Value_1.Value(context, undefined));
        }
        return this.shrinkArrayInt64(current, context, false);
    }
    defaultTarget() {
        if (!(0, ArrayInt64_1.isStrictlyPositive64)(this.min) && !(0, ArrayInt64_1.isStrictlyNegative64)(this.max)) {
            return ArrayInt64_1.Zero64;
        }
        return (0, ArrayInt64_1.isStrictlyNegative64)(this.min) ? this.max : this.min;
    }
    isLastChanceTry(current, context) {
        if ((0, ArrayInt64_1.isZero64)(current)) {
            return false;
        }
        if (current.sign === 1) {
            return (0, ArrayInt64_1.isEqual64)(current, (0, ArrayInt64_1.add64)(context, ArrayInt64_1.Unit64)) && (0, ArrayInt64_1.isStrictlyPositive64)((0, ArrayInt64_1.substract64)(current, this.min));
        }
        else {
            return (0, ArrayInt64_1.isEqual64)(current, (0, ArrayInt64_1.substract64)(context, ArrayInt64_1.Unit64)) && (0, ArrayInt64_1.isStrictlyNegative64)((0, ArrayInt64_1.substract64)(current, this.max));
        }
    }
    static isValidContext(_current, context) {
        if (context === undefined) {
            return false;
        }
        if (typeof context !== 'object' || context === null || !('sign' in context) || !('data' in context)) {
            throw new Error(`Invalid context type passed to ArrayInt64Arbitrary (#1)`);
        }
        return true;
    }
    retrieveBiasedRanges() {
        if (this.biasedRanges != null) {
            return this.biasedRanges;
        }
        if ((0, ArrayInt64_1.isEqual64)(this.min, this.max)) {
            this.biasedRanges = [{ min: this.min, max: this.max }];
            return this.biasedRanges;
        }
        const minStrictlySmallerZero = (0, ArrayInt64_1.isStrictlyNegative64)(this.min);
        const maxStrictlyGreaterZero = (0, ArrayInt64_1.isStrictlyPositive64)(this.max);
        if (minStrictlySmallerZero && maxStrictlyGreaterZero) {
            const logMin = (0, ArrayInt64_1.logLike64)(this.min);
            const logMax = (0, ArrayInt64_1.logLike64)(this.max);
            this.biasedRanges = [
                { min: logMin, max: logMax },
                { min: (0, ArrayInt64_1.substract64)(this.max, logMax), max: this.max },
                { min: this.min, max: (0, ArrayInt64_1.substract64)(this.min, logMin) },
            ];
        }
        else {
            const logGap = (0, ArrayInt64_1.logLike64)((0, ArrayInt64_1.substract64)(this.max, this.min));
            const arbCloseToMin = { min: this.min, max: (0, ArrayInt64_1.add64)(this.min, logGap) };
            const arbCloseToMax = { min: (0, ArrayInt64_1.substract64)(this.max, logGap), max: this.max };
            this.biasedRanges = minStrictlySmallerZero
                ? [arbCloseToMax, arbCloseToMin]
                : [arbCloseToMin, arbCloseToMax];
        }
        return this.biasedRanges;
    }
}
function arrayInt64(min, max) {
    const arb = new ArrayInt64Arbitrary(min, max);
    return arb;
}