Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
testing::internal::edit_distance Namespace Reference

Enumerations

enum  EditType { kMatch , kAdd , kRemove , kReplace }
 

Functions

GTEST_API_ std::vector< EditTypeCalculateOptimalEdits (const std::vector< size_t > &left, const std::vector< size_t > &right)
 
GTEST_API_ std::vector< EditTypeCalculateOptimalEdits (const std::vector< std::string > &left, const std::vector< std::string > &right)
 
GTEST_API_ std::string CreateUnifiedDiff (const std::vector< std::string > &left, const std::vector< std::string > &right, size_t context=2)
 

Enumeration Type Documentation

◆ EditType

Function Documentation

◆ CalculateOptimalEdits() [1/2]

std::vector< EditType > testing::internal::edit_distance::CalculateOptimalEdits ( const std::vector< size_t > & left,
const std::vector< size_t > & right )

Definition at line 1042 of file gtest.cc.

1043 {
1044 std::vector<std::vector<double> > costs(
1045 left.size() + 1, std::vector<double>(right.size() + 1));
1046 std::vector<std::vector<EditType> > best_move(
1047 left.size() + 1, std::vector<EditType>(right.size() + 1));
1048
1049 // Populate for empty right.
1050 for (size_t l_i = 0; l_i < costs.size(); ++l_i) {
1051 costs[l_i][0] = static_cast<double>(l_i);
1052 best_move[l_i][0] = kRemove;
1053 }
1054 // Populate for empty left.
1055 for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) {
1056 costs[0][r_i] = static_cast<double>(r_i);
1057 best_move[0][r_i] = kAdd;
1058 }
1059
1060 for (size_t l_i = 0; l_i < left.size(); ++l_i) {
1061 for (size_t r_i = 0; r_i < right.size(); ++r_i) {
1062 if (left[l_i] == right[r_i]) {
1063 // Found a match. Consume it.
1064 costs[l_i + 1][r_i + 1] = costs[l_i][r_i];
1065 best_move[l_i + 1][r_i + 1] = kMatch;
1066 continue;
1067 }
1068
1069 const double add = costs[l_i + 1][r_i];
1070 const double remove = costs[l_i][r_i + 1];
1071 const double replace = costs[l_i][r_i];
1072 if (add < remove && add < replace) {
1073 costs[l_i + 1][r_i + 1] = add + 1;
1074 best_move[l_i + 1][r_i + 1] = kAdd;
1075 } else if (remove < add && remove < replace) {
1076 costs[l_i + 1][r_i + 1] = remove + 1;
1077 best_move[l_i + 1][r_i + 1] = kRemove;
1078 } else {
1079 // We make replace a little more expensive than add/remove to lower
1080 // their priority.
1081 costs[l_i + 1][r_i + 1] = replace + 1.00001;
1082 best_move[l_i + 1][r_i + 1] = kReplace;
1083 }
1084 }
1085 }
1086
1087 // Reconstruct the best path. We do it in reverse order.
1088 std::vector<EditType> best_path;
1089 for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) {
1090 EditType move = best_move[l_i][r_i];
1091 best_path.push_back(move);
1092 l_i -= move != kAdd;
1093 r_i -= move != kRemove;
1094 }
1095 std::reverse(best_path.begin(), best_path.end());
1096 return best_path;
1097}
bool remove(const path &p)
int add(int a, int b)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalculateOptimalEdits() [2/2]

std::vector< EditType > testing::internal::edit_distance::CalculateOptimalEdits ( const std::vector< std::string > & left,
const std::vector< std::string > & right )

Definition at line 1118 of file gtest.cc.

1120 {
1121 std::vector<size_t> left_ids, right_ids;
1122 {
1123 InternalStrings intern_table;
1124 for (size_t i = 0; i < left.size(); ++i) {
1125 left_ids.push_back(intern_table.GetId(left[i]));
1126 }
1127 for (size_t i = 0; i < right.size(); ++i) {
1128 right_ids.push_back(intern_table.GetId(right[i]));
1129 }
1130 }
1131 return CalculateOptimalEdits(left_ids, right_ids);
1132}
Here is the call graph for this function:

◆ CreateUnifiedDiff()

std::string testing::internal::edit_distance::CreateUnifiedDiff ( const std::vector< std::string > & left,
const std::vector< std::string > & right,
size_t context = 2 )

Definition at line 1217 of file gtest.cc.

1219 {
1220 const std::vector<EditType> edits = CalculateOptimalEdits(left, right);
1221
1222 size_t l_i = 0, r_i = 0, edit_i = 0;
1223 std::stringstream ss;
1224 while (edit_i < edits.size()) {
1225 // Find first edit.
1226 while (edit_i < edits.size() && edits[edit_i] == kMatch) {
1227 ++l_i;
1228 ++r_i;
1229 ++edit_i;
1230 }
1231
1232 // Find the first line to include in the hunk.
1233 const size_t prefix_context = std::min(l_i, context);
1234 Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1);
1235 for (size_t i = prefix_context; i > 0; --i) {
1236 hunk.PushLine(' ', left[l_i - i].c_str());
1237 }
1238
1239 // Iterate the edits until we found enough suffix for the hunk or the input
1240 // is over.
1241 size_t n_suffix = 0;
1242 for (; edit_i < edits.size(); ++edit_i) {
1243 if (n_suffix >= context) {
1244 // Continue only if the next hunk is very close.
1245 std::vector<EditType>::const_iterator it = edits.begin() + edit_i;
1246 while (it != edits.end() && *it == kMatch) ++it;
1247 if (it == edits.end() || (it - edits.begin()) - edit_i >= context) {
1248 // There is no next edit or it is too far away.
1249 break;
1250 }
1251 }
1252
1253 EditType edit = edits[edit_i];
1254 // Reset count when a non match is found.
1255 n_suffix = edit == kMatch ? n_suffix + 1 : 0;
1256
1257 if (edit == kMatch || edit == kRemove || edit == kReplace) {
1258 hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str());
1259 }
1260 if (edit == kAdd || edit == kReplace) {
1261 hunk.PushLine('+', right[r_i].c_str());
1262 }
1263
1264 // Advance indices, depending on edit type.
1265 l_i += edit != kAdd;
1266 r_i += edit != kRemove;
1267 }
1268
1269 if (!hunk.has_edits()) {
1270 // We are done. We don't want this hunk.
1271 break;
1272 }
1273
1274 hunk.PrintTo(&ss);
1275 }
1276 return ss.str();
1277}
static const Segment ss(Segment::ss)
Here is the call graph for this function:
Here is the caller graph for this function: