+int llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA,
+ const sys::PathWithStatus &FileB,
+ double AbsTol, double RelTol,
+ std::string *Error) {
+ const sys::FileStatus *FileAStat = FileA.getFileStatus(false, Error);
+ if (!FileAStat)
+ return 2;
+ const sys::FileStatus *FileBStat = FileB.getFileStatus(false, Error);
+ if (!FileBStat)
+ return 2;
+
+ // Check for zero length files because some systems croak when you try to
+ // mmap an empty file.
+ size_t A_size = FileAStat->getSize();
+ size_t B_size = FileBStat->getSize();
+
+ // If they are both zero sized then they're the same
+ if (A_size == 0 && B_size == 0)
+ return 0;
+
+ // If only one of them is zero sized then they can't be the same
+ if ((A_size == 0 || B_size == 0)) {
+ if (Error)
+ *Error = "Files differ: one is zero-sized, the other isn't";
+ return 1;
+ }
+
+ // Now its safe to mmap the files into memory becasue both files
+ // have a non-zero size.
+ OwningPtr<MemoryBuffer> F1(MemoryBuffer::getFile(FileA.c_str(), Error));
+ OwningPtr<MemoryBuffer> F2(MemoryBuffer::getFile(FileB.c_str(), Error));
+ if (F1 == 0 || F2 == 0)
+ return 2;
+
+ // Okay, now that we opened the files, scan them for the first difference.
+ const char *File1Start = F1->getBufferStart();
+ const char *File2Start = F2->getBufferStart();
+ const char *File1End = F1->getBufferEnd();
+ const char *File2End = F2->getBufferEnd();
+ const char *F1P = File1Start;
+ const char *F2P = File2Start;
+
+ if (A_size == B_size) {
+ // Are the buffers identical? Common case: Handle this efficiently.
+ if (std::memcmp(File1Start, File2Start, A_size) == 0)
+ return 0;
+
+ if (AbsTol == 0 && RelTol == 0) {
+ if (Error)
+ *Error = "Files differ without tolerance allowance";
+ return 1; // Files different!
+ }
+ }
+
+ bool CompareFailed = false;
+ while (1) {
+ // Scan for the end of file or next difference.
+ while (F1P < File1End && F2P < File2End && *F1P == *F2P)
+ ++F1P, ++F2P;
+
+ if (F1P >= File1End || F2P >= File2End) break;
+
+ // Okay, we must have found a difference. Backup to the start of the
+ // current number each stream is at so that we can compare from the
+ // beginning.
+ F1P = BackupNumber(F1P, File1Start);
+ F2P = BackupNumber(F2P, File2Start);
+
+ // Now that we are at the start of the numbers, compare them, exiting if
+ // they don't match.
+ if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error)) {
+ CompareFailed = true;
+ break;
+ }
+ }
+
+ // Okay, we reached the end of file. If both files are at the end, we
+ // succeeded.
+ bool F1AtEnd = F1P >= File1End;
+ bool F2AtEnd = F2P >= File2End;
+ if (!CompareFailed && (!F1AtEnd || !F2AtEnd)) {
+ // Else, we might have run off the end due to a number: backup and retry.
+ if (F1AtEnd && isNumberChar(F1P[-1])) --F1P;
+ if (F2AtEnd && isNumberChar(F2P[-1])) --F2P;
+ F1P = BackupNumber(F1P, File1Start);
+ F2P = BackupNumber(F2P, File2Start);
+
+ // Now that we are at the start of the numbers, compare them, exiting if
+ // they don't match.
+ if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error))
+ CompareFailed = true;
+
+ // If we found the end, we succeeded.
+ if (F1P < File1End || F2P < File2End)
+ CompareFailed = true;
+ }
+
+ return CompareFailed;