# Global Metrics

path: .metrics.loc.ploc
old: 225.0
new: 474.0
path: .metrics.loc.cloc
old: 34.0
new: 52.0
path: .metrics.loc.blank
old: 48.0
new: 36.0
path: .metrics.loc.lloc
old: 100.0
new: 284.0
path: .metrics.loc.sloc
old: 307.0
new: 562.0
path: .metrics.cognitive.average
old: 2.533333333333333
new: 3.1142857142857143
path: .metrics.cognitive.sum
old: 38.0
new: 109.0
path: .metrics.nargs.average
old: 1.4
new: 2.857142857142857
path: .metrics.nargs.sum
old: 21.0
new: 100.0
path: .metrics.nom.functions
old: 15.0
new: 35.0
path: .metrics.nom.total
old: 15.0
new: 35.0
path: .metrics.cyclomatic.average
old: 3.0625
new: 3.972972972972973
path: .metrics.cyclomatic.sum
old: 49.0
new: 147.0
path: .metrics.halstead.n2
old: 154.0
new: 217.0
path: .metrics.halstead.N1
old: 533.0
new: 2020.0
path: .metrics.halstead.difficulty
old: 32.66883116883117
new: 135.8294930875576
path: .metrics.halstead.N2
old: 387.0
new: 1310.0
path: .metrics.halstead.bugs
old: 1.2337273611545891
new: 7.878400319314876
path: .metrics.halstead.length
old: 920.0
new: 3330.0
path: .metrics.halstead.estimated_program_length
old: 1241.2965599386832
new: 1931.3900067752877
path: .metrics.halstead.volume
old: 6892.504848623301
new: 26751.298595119708
path: .metrics.halstead.effort
old: 225170.07723002485
new: 3633615.327609002
path: .metrics.halstead.n1
old: 26.0
new: 45.0
path: .metrics.halstead.level
old: 0.030610216656728285
new: 0.00736217133163698
path: .metrics.halstead.purity_ratio
old: 1.349235391237699
new: 0.5799969990316178
path: .metrics.halstead.time
old: 12509.44873500138
new: 201867.5182005001
path: .metrics.halstead.vocabulary
old: 180.0
new: 262.0
path: .metrics.mi.mi_sei
old: -15.76922717229014
new: -64.5663487194969
path: .metrics.mi.mi_original
old: 20.996479288008288
new: -18.390889111418375
path: .metrics.mi.mi_visual_studio
old: 12.278642858484378
new: 0.0
path: .metrics.nexits.average
old: 1.2
new: 1.8571428571428572
path: .metrics.nexits.sum
old: 18.0
new: 65.0

# Spaces Data

## Minimal test - lines (18, 562)

path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 3.1142857142857143
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 109.0
path: .spaces[0].metrics.mi.mi_original
old: 126.04888820852534
new: -17.632231501351455
path: .spaces[0].metrics.mi.mi_sei
old: 106.25107379539855
new: -65.42668507755987
path: .spaces[0].metrics.mi.mi_visual_studio
old: 73.71280012194465
new: 0.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 4.055555555555555
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 146.0
path: .spaces[0].metrics.nexits.average
old: 0.0
new: 1.8571428571428572
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 65.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 35.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 35.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 284.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 42.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 35.0
path: .spaces[0].metrics.loc.sloc
old: 4.0
new: 545.0
path: .spaces[0].metrics.loc.ploc
old: 4.0
new: 468.0
path: .spaces[0].metrics.nargs.sum
old: 1.0
new: 100.0
path: .spaces[0].metrics.nargs.average
old: 1.0
new: 2.857142857142857
path: .spaces[0].metrics.halstead.vocabulary
old: 14.0
new: 256.0
path: .spaces[0].metrics.halstead.volume
old: 72.33974351909448
new: 26592.0
path: .spaces[0].metrics.halstead.n2
old: 8.0
new: 211.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 39.50977500432694
new: 1876.2853181520516
path: .spaces[0].metrics.halstead.level
old: 0.2962962962962963
new: 0.0071915473755964545
path: .spaces[0].metrics.halstead.N2
old: 9.0
new: 1304.0
path: .spaces[0].metrics.halstead.bugs
old: 0.013021046999192576
new: 7.970725436895819
path: .spaces[0].metrics.halstead.n1
old: 6.0
new: 45.0
path: .spaces[0].metrics.halstead.difficulty
old: 3.375
new: 139.0521327014218
path: .spaces[0].metrics.halstead.N1
old: 10.0
new: 2020.0
path: .spaces[0].metrics.halstead.effort
old: 244.1466343769439
new: 3697674.312796209
path: .spaces[0].metrics.halstead.length
old: 19.0
new: 3324.0
path: .spaces[0].metrics.halstead.purity_ratio
old: 2.079461842332997
new: 0.5644661005270913
path: .spaces[0].metrics.halstead.time
old: 13.563701909830217
new: 205426.3507109005

### Code

    namespace fuzzer {

    const size_t Dictionary::kMaxDictSize;

    static void PrintASCII(const Word &W, const char *PrintAfter) {
      PrintASCII(W.data(), W.size(), PrintAfter);
    }

    MutationDispatcher::MutationDispatcher(Random &Rand,
                                           const FuzzingOptions &Options)
        : Rand(Rand), Options(Options) {
      DefaultMutators.insert(
          DefaultMutators.begin(),
          {
              {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
              {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
              {&MutationDispatcher::Mutate_InsertRepeatedBytes,
               "InsertRepeatedBytes"},
              {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
              {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
              {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
              {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
              {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
              {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
              {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
              {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
               "ManualDict"},
              {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
               "PersAutoDict"},
          });
      if(Options.UseCmp)
        DefaultMutators.push_back(
            {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});

      if (EF->LLVMFuzzerCustomMutator)
        Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
      else
        Mutators = DefaultMutators;

      if (EF->LLVMFuzzerCustomCrossOver)
        Mutators.push_back(
            {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
    }

    static char RandCh(Random &Rand) {
      if (Rand.RandBool()) return Rand(256);
      const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
      return Special[Rand(sizeof(Special) - 1)];
    }

    size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
                                             size_t MaxSize) {
      return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand());
    }

    size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
                                                      size_t MaxSize) {
      if (Size == 0)
        return 0;
      if (!CrossOverWith) return 0;
      const Unit &Other = *CrossOverWith;
      if (Other.empty())
        return 0;
      CustomCrossOverInPlaceHere.resize(MaxSize);
      auto &U = CustomCrossOverInPlaceHere;
      size_t NewSize = EF->LLVMFuzzerCustomCrossOver(
          Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand());
      if (!NewSize)
        return 0;
      assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
      memcpy(Data, U.data(), NewSize);
      return NewSize;
    }

    size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
                                                   size_t MaxSize) {
      if (Size > MaxSize || Size == 0) return 0;
      size_t ShuffleAmount =
          Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
      size_t ShuffleStart = Rand(Size - ShuffleAmount);
      assert(ShuffleStart + ShuffleAmount <= Size);
      std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand);
      return Size;
    }

    size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,
                                                 size_t MaxSize) {
      if (Size <= 1) return 0;
      size_t N = Rand(Size / 2) + 1;
      assert(N < Size);
      size_t Idx = Rand(Size - N + 1);
      // Erase Data[Idx:Idx+N].
      memmove(Data + Idx, Data + Idx + N, Size - Idx - N);
      // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);
      return Size - N;
    }

    size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
                                                 size_t MaxSize) {
      if (Size >= MaxSize) return 0;
      size_t Idx = Rand(Size + 1);
      // Insert new value at Data[Idx].
      memmove(Data + Idx + 1, Data + Idx, Size - Idx);
      Data[Idx] = RandCh(Rand);
      return Size + 1;
    }

    size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,
                                                          size_t Size,
                                                          size_t MaxSize) {
      const size_t kMinBytesToInsert = 3;
      if (Size + kMinBytesToInsert >= MaxSize) return 0;
      size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);
      size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;
      assert(Size + N <= MaxSize && N);
      size_t Idx = Rand(Size + 1);
      // Insert new values at Data[Idx].
      memmove(Data + Idx + N, Data + Idx, Size - Idx);
      // Give preference to 0x00 and 0xff.
      uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255);
      for (size_t i = 0; i < N; i++)
        Data[Idx + i] = Byte;
      return Size + N;
    }

    size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
                                                 size_t MaxSize) {
      if (Size > MaxSize) return 0;
      size_t Idx = Rand(Size);
      Data[Idx] = RandCh(Rand);
      return Size;
    }

    size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
                                                size_t MaxSize) {
      if (Size > MaxSize) return 0;
      size_t Idx = Rand(Size);
      Data[Idx] ^= 1 << Rand(8);
      return Size;
    }

    size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
                                                                  size_t Size,
                                                                  size_t MaxSize) {
      return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);
    }

    size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
                                                    size_t MaxSize,
                                                    DictionaryEntry &DE) {
      const Word &W = DE.GetW();
      bool UsePositionHint = DE.HasPositionHint() &&
                             DE.GetPositionHint() + W.size() < Size &&
                             Rand.RandBool();
      if (Rand.RandBool()) {  // Insert W.
        if (Size + W.size() > MaxSize) return 0;
        size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
        memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
        memcpy(Data + Idx, W.data(), W.size());
        Size += W.size();
      } else {  // Overwrite some bytes with W.
        if (W.size() > Size) return 0;
        size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
        memcpy(Data + Idx, W.data(), W.size());
      }
      return Size;
    }

    // Somewhere in the past we have observed a comparison instructions
    // with arguments Arg1 Arg2. This function tries to guess a dictionary
    // entry that will satisfy that comparison.
    // It first tries to find one of the arguments (possibly swapped) in the
    // input and if it succeeds it creates a DE with a position hint.
    // Otherwise it creates a DE with one of the arguments w/o a position hint.
    DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
        const void *Arg1, const void *Arg2,
        const void *Arg1Mutation, const void *Arg2Mutation,
        size_t ArgSize, const uint8_t *Data,
        size_t Size) {
      bool HandleFirst = Rand.RandBool();
      const void *ExistingBytes, *DesiredBytes;
      Word W;
      const uint8_t *End = Data + Size;
      for (int Arg = 0; Arg < 2; Arg++) {
        ExistingBytes = HandleFirst ? Arg1 : Arg2;
        DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation;
        HandleFirst = !HandleFirst;
        W.Set(reinterpret_cast(DesiredBytes), ArgSize);
        const size_t kMaxNumPositions = 8;
        size_t Positions[kMaxNumPositions];
        size_t NumPositions = 0;
        for (const uint8_t *Cur = Data;
             Cur < End && NumPositions < kMaxNumPositions; Cur++) {
          Cur =
              (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize);
          if (!Cur) break;
          Positions[NumPositions++] = Cur - Data;
        }
        if (!NumPositions) continue;
        return DictionaryEntry(W, Positions[Rand(NumPositions)]);
      }
      DictionaryEntry DE(W);
      return DE;
    }

    template
    DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
        T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
      if (Rand.RandBool()) Arg1 = Bswap(Arg1);
      if (Rand.RandBool()) Arg2 = Bswap(Arg2);
      T Arg1Mutation = Arg1 + Rand(-1, 1);
      T Arg2Mutation = Arg2 + Rand(-1, 1);
      return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation,
                                        sizeof(Arg1), Data, Size);
    }

    DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
        const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) {
      return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(),
                                        Arg2.data(), Arg1.size(), Data, Size);
    }

    size_t MutationDispatcher::Mutate_AddWordFromTORC(
        uint8_t *Data, size_t Size, size_t MaxSize) {
      Word W;
      DictionaryEntry DE;
      switch (Rand(4)) {
      case 0: {
        auto X = TPC.TORC8.Get(Rand.Rand());
        DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
      } break;
      case 1: {
        auto X = TPC.TORC4.Get(Rand.Rand());
        if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
          DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size);
        else
          DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
      } break;
      case 2: {
        auto X = TPC.TORCW.Get(Rand.Rand());
        DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
      } break;
      case 3: if (Options.UseMemmem) {
        auto X = TPC.MMT.Get(Rand.Rand());
        DE = DictionaryEntry(X);
      } break;
      default:
        assert(0);
      }
      if (!DE.GetW().size()) return 0;
      Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
      if (!Size) return 0;
      DictionaryEntry &DERef =
          CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
                                    kCmpDictionaryEntriesDequeSize];
      DERef = DE;
      CurrentDictionaryEntrySequence.push_back(&DERef);
      return Size;
    }

    size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
        uint8_t *Data, size_t Size, size_t MaxSize) {
      return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
    }

    size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
                                                     size_t Size, size_t MaxSize) {
      if (Size > MaxSize) return 0;
      if (D.empty()) return 0;
      DictionaryEntry &DE = D[Rand(D.size())];
      Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
      if (!Size) return 0;
      DE.IncUseCount();
      CurrentDictionaryEntrySequence.push_back(&DE);
      return Size;
    }

    // Overwrites part of To[0,ToSize) with a part of From[0,FromSize).
    // Returns ToSize.
    size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize,
                                          uint8_t *To, size_t ToSize) {
      // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize).
      size_t ToBeg = Rand(ToSize);
      size_t CopySize = Rand(ToSize - ToBeg) + 1;
      assert(ToBeg + CopySize <= ToSize);
      CopySize = std::min(CopySize, FromSize);
      size_t FromBeg = Rand(FromSize - CopySize + 1);
      assert(FromBeg + CopySize <= FromSize);
      memmove(To + ToBeg, From + FromBeg, CopySize);
      return ToSize;
    }

    // Inserts part of From[0,ToSize) into To.
    // Returns new size of To on success or 0 on failure.
    size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,
                                            uint8_t *To, size_t ToSize,
                                            size_t MaxToSize) {
      if (ToSize >= MaxToSize) return 0;
      size_t AvailableSpace = MaxToSize - ToSize;
      size_t MaxCopySize = std::min(AvailableSpace, FromSize);
      size_t CopySize = Rand(MaxCopySize) + 1;
      size_t FromBeg = Rand(FromSize - CopySize + 1);
      assert(FromBeg + CopySize <= FromSize);
      size_t ToInsertPos = Rand(ToSize + 1);
      assert(ToInsertPos + CopySize <= MaxToSize);
      size_t TailSize = ToSize - ToInsertPos;
      if (To == From) {
        MutateInPlaceHere.resize(MaxToSize);
        memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize);
        memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
        memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize);
      } else {
        memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
        memmove(To + ToInsertPos, From + FromBeg, CopySize);
      }
      return ToSize + CopySize;
    }

    size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,
                                               size_t MaxSize) {
      if (Size > MaxSize || Size == 0) return 0;
      // If Size == MaxSize, `InsertPartOf(...)` will
      // fail so there's no point using it in this case.
      if (Size == MaxSize || Rand.RandBool())
        return CopyPartOf(Data, Size, Data, Size);
      else
        return InsertPartOf(Data, Size, Data, Size, MaxSize);
    }

    size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
                                                         size_t MaxSize) {
      if (Size > MaxSize) return 0;
      size_t B = Rand(Size);
      while (B < Size && !isdigit(Data[B])) B++;
      if (B == Size) return 0;
      size_t E = B;
      while (E < Size && isdigit(Data[E])) E++;
      assert(B < E);
      // now we have digits in [B, E).
      // strtol and friends don't accept non-zero-teminated data, parse it manually.
      uint64_t Val = Data[B] - '0';
      for (size_t i = B + 1; i < E; i++)
        Val = Val * 10 + Data[i] - '0';

      // Mutate the integer value.
      switch(Rand(5)) {
        case 0: Val++; break;
        case 1: Val--; break;
        case 2: Val /= 2; break;
        case 3: Val *= 2; break;
        case 4: Val = Rand(Val * Val); break;
        default: assert(0);
      }
      // Just replace the bytes with the new ones, don't bother moving bytes.
      for (size_t i = B; i < E; i++) {
        size_t Idx = E + B - i - 1;
        assert(Idx >= B && Idx < E);
        Data[Idx] = (Val % 10) + '0';
        Val /= 10;
      }
      return Size;
    }

    template
    size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
      if (Size < sizeof(T)) return 0;
      size_t Off = Rand(Size - sizeof(T) + 1);
      assert(Off + sizeof(T) <= Size);
      T Val;
      if (Off < 64 && !Rand(4)) {
        Val = Size;
        if (Rand.RandBool())
          Val = Bswap(Val);
      } else {
        memcpy(&Val, Data + Off, sizeof(Val));
        T Add = Rand(21);
        Add -= 10;
        if (Rand.RandBool())
          Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes.
        else
          Val = Val + Add;               // Add assuming current endiannes.
        if (Add == 0 || Rand.RandBool()) // Maybe negate.
          Val = -Val;
      }
      memcpy(Data + Off, &Val, sizeof(Val));
      return Size;
    }

    size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data,
                                                          size_t Size,
                                                          size_t MaxSize) {
      if (Size > MaxSize) return 0;
      switch (Rand(4)) {
        case 3: return ChangeBinaryInteger(Data, Size, Rand);
        case 2: return ChangeBinaryInteger(Data, Size, Rand);
        case 1: return ChangeBinaryInteger(Data, Size, Rand);
        case 0: return ChangeBinaryInteger(Data, Size, Rand);
        default: assert(0);
      }
      return 0;
    }

    size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
                                                size_t MaxSize) {
      if (Size > MaxSize) return 0;
      if (Size == 0) return 0;
      if (!CrossOverWith) return 0;
      const Unit &O = *CrossOverWith;
      if (O.empty()) return 0;
      MutateInPlaceHere.resize(MaxSize);
      auto &U = MutateInPlaceHere;
      size_t NewSize = 0;
      switch(Rand(3)) {
        case 0:
          NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size());
          break;
        case 1:
          NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize);
          if (!NewSize)
            NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
          break;
        case 2:
          NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
          break;
        default: assert(0);
      }
      assert(NewSize > 0 && "CrossOver returned empty unit");
      assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
      memcpy(Data, U.data(), NewSize);
      return NewSize;
    }

    void MutationDispatcher::StartMutationSequence() {
      CurrentMutatorSequence.clear();
      CurrentDictionaryEntrySequence.clear();
    }

    // Copy successful dictionary entries to PersistentAutoDictionary.
    void MutationDispatcher::RecordSuccessfulMutationSequence() {
      for (auto DE : CurrentDictionaryEntrySequence) {
        // PersistentAutoDictionary.AddWithSuccessCountOne(DE);
        DE->IncSuccessCount();
        assert(DE->GetW().size());
        // Linear search is fine here as this happens seldom.
        if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
          PersistentAutoDictionary.push_back({DE->GetW(), 1});
      }
    }

    void MutationDispatcher::PrintRecommendedDictionary() {
      Vector V;
      for (auto &DE : PersistentAutoDictionary)
        if (!ManualDictionary.ContainsWord(DE.GetW()))
          V.push_back(DE);
      if (V.empty()) return;
      Printf("###### Recommended dictionary. ######\n");
      for (auto &DE: V) {
        assert(DE.GetW().size());
        Printf("\"");
        PrintASCII(DE.GetW(), "\"");
        Printf(" # Uses: %zd\n", DE.GetUseCount());
      }
      Printf("###### End of recommended dictionary. ######\n");
    }

    void MutationDispatcher::PrintMutationSequence() {
      Printf("MS: %zd ", CurrentMutatorSequence.size());
      for (auto M : CurrentMutatorSequence)
        Printf("%s-", M.Name);
      if (!CurrentDictionaryEntrySequence.empty()) {
        Printf(" DE: ");
        for (auto DE : CurrentDictionaryEntrySequence) {
          Printf("\"");
          PrintASCII(DE->GetW(), "\"-");
        }
      }
    }

    size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
      return MutateImpl(Data, Size, MaxSize, Mutators);
    }

    size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
                                             size_t MaxSize) {
      return MutateImpl(Data, Size, MaxSize, DefaultMutators);
    }

    // Mutates Data in place, returns new size.
    size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
                                          size_t MaxSize,
                                          Vector &Mutators) {
      assert(MaxSize > 0);
      // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
      // in which case they will return 0.
      // Try several times before returning un-mutated data.
      for (int Iter = 0; Iter < 100; Iter++) {
        auto M = Mutators[Rand(Mutators.size())];
        size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
        if (NewSize && NewSize <= MaxSize) {
          if (Options.OnlyASCII)
            ToASCII(Data, NewSize);
          CurrentMutatorSequence.push_back(M);
          return NewSize;
        }
      }
      *Data = ' ';
      return 1;   // Fallback, should not happen frequently.
    }

    // Mask represents the set of Data bytes that are worth mutating.
    size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size,
                                              size_t MaxSize,
                                              const Vector &Mask) {
      size_t MaskedSize = std::min(Size, Mask.size());
      // * Copy the worthy bytes into a temporary array T
      // * Mutate T
      // * Copy T back.
      // This is totally unoptimized.
      auto &T = MutateWithMaskTemp;
      if (T.size() < Size)
        T.resize(Size);
      size_t OneBits = 0;
      for (size_t I = 0; I < MaskedSize; I++)
        if (Mask[I])
          T[OneBits++] = Data[I];

      if (!OneBits) return 0;
      assert(!T.empty());
      size_t NewSize = Mutate(T.data(), OneBits, OneBits);
      assert(NewSize <= OneBits);
      (void)NewSize;
      // Even if NewSize < OneBits we still use all OneBits bytes.
      for (size_t I = 0, J = 0; I < MaskedSize; I++)
        if (Mask[I])
          Data[I] = T[J++];
      return Size;
    }

    void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
      ManualDictionary.push_back(
          {W, std::numeric_limits::max()});
    }

    }  // namespace fuzzer