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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
use crate::DefaultMutator;
use crate::Mutator;

/*
    These mutators try to achieve multiple things:
    * avoid repetitions, such that if the value “7” was already produced, then it will not appear again
    * cover most of the search space as quickly as possible. For example, for 8-bit unsigned integers,
      it is good to produce a sequence such as: 0, 255, 128, 192, 64, 224, 32, etc.
    * also produce values close to the original integer first. So mutating 100 will first produce numbers
      such as 101, 99, 102, 98, etc.
    * be very fast

    One idea to create arbitrary integers that don't repeat themselves and span the whole search space was
    to use a binary-search-like approach, as written in the function binary_search_arbitrary. However that
    turns out to be quite slow for an integer mutator. So what I do instead is create a sequence of 256
    random non-repeating integers, which I store in a variable called “shuffled integers”
    Now, for an 8-bit integer type, it is enough to simply index that vector to get an arbitrary value that
    respects all the criteria I laid above. But for types that have 16, 32, 64, or 128 bits, I can't do that.
    So I index the shuffled_integers vector multiple times until I have all the bits I need. For an u32, I need
    to index it four times. It is done in the following way:
    1. first I look at the lower 8 bits of steps to get the first index
        * so if step == 67, then I use the index 67
        * but if step == 259, then I use the index 3
    2. I get a number between 0 and 255 by getting shuffled_integers[first_index], I memorize that pick.
    3. I place the picked number on the highest 8 bits of the generated integer
        * so imagine the step was 259, then the index is 3 and shuffled_integers[3] is 192
        * so the generated integer, so far, is (192 << 24) == 3_221_225_472

    Let's stop to think about what that achieves. It means that for the first 256 steps, the
    8 highest bits of the generated integer will be [0, 256, 128, 192, ...]. So we are covering a huge part
    of the possible space in the first 256 steps alone. The goal is to use that strategy recursively for the
    remaining bits, while adding a little but of arbitrariness to it.

    4. Then I shift the step right by 8 bits. If it was 259 originally, it is now equal to (259 >> 8) == 3.
    5. And then I XOR that index with the the previous pick (the purpose of that
    is to make the generation a little bit more arbitrary/less predictable)
        * so the new index is (3 ^ 192) == 195
    6. I then get the next pick by getting shuffled_integers[192], let's say it is == 43.
    7. Then we update the generated integer, it is now (192 << 24) | (43 << 16)
    8. The next step is (259 >> 16) ^ 43 == 43
    9. etc.

    You can find more details on how it is done in `uniform_permutation`
*/

macro_rules! binary_search_arbitrary {
    ($name_function: ident, $uxx:ty) => {
        #[no_coverage]
        pub(crate) fn $name_function(low: $uxx, high: $uxx, step: u64) -> $uxx {
            let next = low.wrapping_add(high.wrapping_sub(low) / 2);
            if low.wrapping_add(1) >= high {
                if step % 2 == 0 {
                    high
                } else {
                    low
                }
            } else if step == 0 {
                next
            } else if step % 2 == 1 {
                $name_function(next.wrapping_add(1), high, step / 2)
            } else {
                // step % 2 == 0
                $name_function(low, next.wrapping_sub(1), (step - 1) / 2)
            }
        }
    };
}
binary_search_arbitrary!(binary_search_arbitrary_u8, u8);
binary_search_arbitrary!(binary_search_arbitrary_u16, u16);
binary_search_arbitrary!(binary_search_arbitrary_u32, u32);
binary_search_arbitrary!(binary_search_arbitrary_u64, u64);

const INITIAL_MUTATION_STEP: u64 = 0;

macro_rules! impl_int_mutator {
    ($name:ident, $name_unsigned: ident, $name_mutator:ident) => {
        #[derive(Clone)]
        pub struct $name_mutator {
            shuffled_integers: [u8; 256],
            rng: fastrand::Rng,
        }
        impl Default for $name_mutator {
            #[no_coverage]
            fn default() -> Self {
                let mut shuffled_integers = [0; 256];
                for i in 0..=255_u8 {
                    shuffled_integers[i as usize] = i;
                }
                let rng = fastrand::Rng::default();
                rng.shuffle(&mut shuffled_integers);
                $name_mutator {
                    shuffled_integers,
                    rng,
                }
            }
        }

        impl $name_mutator {
            #[no_coverage]
            fn uniform_permutation(&self, step: u64) -> $name_unsigned {
                let size = <$name>::BITS as u64;

                // granularity is the number of bits provided by shuffled_integers
                // in this case, it is fixed to 8 but I could use something different

                // xxxx ... xxxx xxxx xxxx xxxx     <- 64 bits for usize
                // 0000 ... 0000 0001 0000 0000     <- - 57 leading zeros for shuffled_integers.len()
                // ____ ... ____ ____ xxxx xxxx     <- - 1
                //                                   =  8
                const GRANULARITY: u64 = ((usize::BITS as usize) - (256u64.leading_zeros() as usize) - 1) as u64;

                const STEP_MASK: u64 = ((u8::MAX as usize) >> (8 - GRANULARITY)) as u64;
                // if I have a number, such as 983487234238, I can `AND` it with the step_mask
                // to get an index I can use on shuffled_integers.
                // in this case, the step_mask is fixed to
                // 0000 ... 0000 1111 1111
                // it gives a number between 0 and 256

                // step_i is used to index into shuffled_integers. The first value is the step
                // given as argument to this function.
                let step_i = (step & STEP_MASK) as usize;

                // now we start building the integer by taking bits from shuffled_integers
                // repeatedly. First by indexing it with step_i
                let mut prev = unsafe { *self.shuffled_integers.get_unchecked(step_i) as $name_unsigned };

                // I put those bits at the highest  position, then I will fill in the lower bits
                let mut result = (prev << (size - GRANULARITY)) as $name_unsigned;

                // remember, granularity is the number of bits we fill in at a time
                // and size is the total size of the generated integer, in bits
                // For u64 and a granularity of 8, we get
                // for i in [1, 2, 3, 4, 5, 6, 7] { ... }
                for i in 1..(size / GRANULARITY) {
                    // each time, we shift step by `granularity` (e.g. 8) more bits to the right

                    // so, for a step of 167 and a granularity of 8, then the next step will be 0
                    // it's only after steps larger than 255 that the next step will be greater than 0

                    // and then we XOR it with previous integer picked from shuffled_integers[step_i]
                    // to get the next index into shuffled_integers, which we insert into
                    // the generated integer at the right place
                    let step_i = (((step >> (i * GRANULARITY)) ^ prev as u64) & STEP_MASK) as usize;
                    prev = unsafe { *self.shuffled_integers.get_unchecked(step_i) as $name_unsigned };
                    result |= prev << (size - (i + 1) * GRANULARITY);
                }

                result
            }
        }

        impl Mutator<$name> for $name_mutator {
            #[doc(hidden)]
            type Cache = ();
            #[doc(hidden)]
            type MutationStep = u64; // mutation step
            #[doc(hidden)]
            type ArbitraryStep = u64;
            #[doc(hidden)]
            type UnmutateToken = $name; // old value
            #[doc(hidden)]
            #[no_coverage]
            fn default_arbitrary_step(&self) -> Self::ArbitraryStep {
                <_>::default()
            }
            #[doc(hidden)]
            #[no_coverage]
            fn validate_value(&self, _value: &$name) -> Option<Self::Cache> {
                Some(())
            }
            #[doc(hidden)]
            #[no_coverage]
            fn default_mutation_step(&self, _value: &$name, _cache: &Self::Cache) -> Self::MutationStep {
                INITIAL_MUTATION_STEP
            }
            /// The maximum complexity of an input of this type
            #[doc(hidden)]
            #[no_coverage]
            fn max_complexity(&self) -> f64 {
                <$name>::BITS as f64
            }
            /// The minimum complexity of an input of this type
            #[doc(hidden)]
            #[no_coverage]
            fn min_complexity(&self) -> f64 {
                <$name>::BITS as f64
            }
            #[doc(hidden)]
            #[no_coverage]
            fn complexity(&self, _value: &$name, _cache: &Self::Cache) -> f64 {
                <$name>::BITS as f64
            }
            #[doc(hidden)]
            #[no_coverage]
            fn ordered_arbitrary(&self, step: &mut Self::ArbitraryStep, max_cplx: f64) -> Option<($name, f64)> {
                if max_cplx < self.min_complexity() {
                    return None;
                }
                if *step > <$name_unsigned>::MAX as u64 {
                    None
                } else {
                    let value = self.uniform_permutation(*step) as $name;
                    *step += 1;
                    Some((value, <$name>::BITS as f64))
                }
            }
            #[doc(hidden)]
            #[no_coverage]
            fn random_arbitrary(&self, _max_cplx: f64) -> ($name, f64) {
                let value = self.rng.$name(..);
                (value, <$name>::BITS as f64)
            }
            #[doc(hidden)]
            #[no_coverage]
            fn ordered_mutate(
                &self,
                value: &mut $name,
                _cache: &mut Self::Cache,
                step: &mut Self::MutationStep,
                max_cplx: f64,
            ) -> Option<(Self::UnmutateToken, f64)> {
                if max_cplx < self.min_complexity() {
                    return None;
                }
                if *step > 10u64.saturating_add(<$name>::MAX as u64) {
                    return None;
                }
                let token = *value;
                *value = {
                    let mut tmp_step = *step;
                    if tmp_step < 8 {
                        let nudge = (tmp_step + 2) as $name;
                        if nudge % 2 == 0 {
                            value.wrapping_add(nudge / 2)
                        } else {
                            value.wrapping_sub(nudge / 2)
                        }
                    } else {
                        tmp_step -= 7;
                        self.uniform_permutation(tmp_step) as $name
                    }
                };
                *step = step.wrapping_add(1);

                Some((token, <$name>::BITS as f64))
            }
            #[doc(hidden)]
            #[no_coverage]
            fn random_mutate(
                &self,
                value: &mut $name,
                _cache: &mut Self::Cache,
                _max_cplx: f64,
            ) -> (Self::UnmutateToken, f64) {
                (std::mem::replace(value, self.rng.$name(..)), <$name>::BITS as f64)
            }
            #[doc(hidden)]
            #[no_coverage]
            fn unmutate(&self, value: &mut $name, _cache: &mut Self::Cache, t: Self::UnmutateToken) {
                *value = t;
            }

            #[doc(hidden)]
            type RecursingPartIndex = ();
            #[doc(hidden)]
            #[no_coverage]
            fn default_recursing_part_index(&self, _value: &$name, _cache: &Self::Cache) -> Self::RecursingPartIndex {}
            #[doc(hidden)]
            #[no_coverage]
            fn recursing_part<'a, V, N>(
                &self,
                _parent: &N,
                _value: &'a $name,
                _index: &mut Self::RecursingPartIndex,
            ) -> Option<&'a V>
            where
                V: Clone + 'static,
                N: Mutator<V> + 'static,
            {
                None
            }
        }

        impl DefaultMutator for $name {
            type Mutator = $name_mutator;
            #[no_coverage]
            fn default_mutator() -> Self::Mutator {
                <$name_mutator>::default()
            }
        }
    };
}

impl_int_mutator!(u8, u8, U8Mutator);
impl_int_mutator!(u16, u16, U16Mutator);
impl_int_mutator!(u32, u32, U32Mutator);
impl_int_mutator!(u64, u64, U64Mutator);
impl_int_mutator!(usize, usize, USizeMutator);
impl_int_mutator!(i8, u8, I8Mutator);
impl_int_mutator!(i16, u16, I16Mutator);
impl_int_mutator!(i32, u32, I32Mutator);
impl_int_mutator!(i64, u64, I64Mutator);
impl_int_mutator!(isize, isize, ISizeMutator);