| 153 | |
| 154 | template <typename SrcIterT, typename DstIterT, class PatchCoderT> |
| 155 | void Diff(SrcIterT const srcBeg, SrcIterT const srcEnd, DstIterT const dstBeg, DstIterT const dstEnd, |
| 156 | PatchCoderT & patchCoder) |
| 157 | { |
| 158 | if (srcEnd - srcBeg < static_cast<decltype(srcEnd - srcBeg)>(m_BlockSize) || |
| 159 | dstEnd - dstBeg < static_cast<decltype(dstEnd - dstBeg)>(m_BlockSize)) |
| 160 | { |
| 161 | m_FineGrainedDiff.Diff(srcBeg, srcEnd, dstBeg, dstEnd, patchCoder); |
| 162 | return; |
| 163 | } |
| 164 | HasherT hasher; |
| 165 | HashPosMultiMapT srcHashes; |
| 166 | for (SrcIterT src = srcBeg; srcEnd - src >= static_cast<decltype(srcEnd - src)>(m_BlockSize); src += m_BlockSize) |
| 167 | srcHashes.insert(HashPosMultiMapValue(hasher.Init(src, m_BlockSize), src - srcBeg)); |
| 168 | SrcIterT srcLastDiff = srcBeg; |
| 169 | DstIterT dst = dstBeg, dstNext = dstBeg + m_BlockSize, dstLastDiff = dstBeg; |
| 170 | hash_type h = hasher.Init(dst, m_BlockSize); |
| 171 | while (dstNext != dstEnd) |
| 172 | { |
| 173 | std::pair<HashPosMultiMapIterator, HashPosMultiMapIterator> iters = srcHashes.equal_range(h); |
| 174 | if (iters.first != iters.second) |
| 175 | { |
| 176 | pos_type const srcLastDiffPos = srcLastDiff - srcBeg; |
| 177 | HashPosMultiMapIterator it = srcHashes.end(); |
| 178 | for (HashPosMultiMapIterator i = iters.first; i != iters.second; ++i) |
| 179 | if (i->second >= srcLastDiffPos && (it == srcHashes.end() || i->second < it->second)) |
| 180 | it = i; |
| 181 | if (it != srcHashes.end() && std::equal(srcBeg + it->second, srcBeg + it->second + m_BlockSize, dst)) |
| 182 | { |
| 183 | pos_type srcBlockEqualPos = it->second; |
| 184 | m_FineGrainedDiff.Diff(srcLastDiff, srcBeg + srcBlockEqualPos, dstLastDiff, dst, patchCoder); |
| 185 | patchCoder.Copy(m_BlockSize); |
| 186 | srcLastDiff = srcBeg + srcBlockEqualPos + m_BlockSize; |
| 187 | dst = dstLastDiff = dstNext; |
| 188 | if (dstEnd - dstNext < static_cast<decltype(dstEnd - dstNext)>(m_BlockSize)) |
| 189 | break; |
| 190 | dstNext = dst + m_BlockSize; |
| 191 | h = hasher.Init(dst, m_BlockSize); |
| 192 | continue; |
| 193 | } |
| 194 | } |
| 195 | h = hasher.Scroll(*(dst++), *(dstNext++)); |
| 196 | } |
| 197 | if (srcLastDiff != srcEnd || dstLastDiff != dstEnd) |
| 198 | m_FineGrainedDiff.Diff(srcLastDiff, srcEnd, dstLastDiff, dstEnd, patchCoder); |
| 199 | } |
| 200 | |
| 201 | private: |
| 202 | typedef typename HasherT::hash_type hash_type; |