| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // -*- Mode: C++ -*- |
| // |
| // Copyright (C) 2013-2020 Red Hat, Inc. |
| |
| #include <cstring> |
| |
| #include "abg-fwd.h" |
| #include "abg-internal.h" |
| // <headers defining libabigail's API go under here> |
| ABG_BEGIN_EXPORT_DECLARATIONS |
| |
| #include "abg-diff-utils.h" |
| |
| ABG_END_EXPORT_DECLARATIONS |
| // </headers defining libabigail's API> |
| |
| /// @file |
| /// |
| /// This file defines the declarations found in abg-diff-utils.h |
| namespace abigail |
| { |
| |
| namespace diff_utils |
| { |
| /// @return true iff the end of a furthest forward d_path overlaps the |
| /// end of a furtherst reverse d_path on the same diagonal. This is |
| /// defined by the lemma 3 of the paper. |
| /// |
| /// @param forward_d_path_end |
| bool |
| ends_of_furthest_d_paths_overlap(const point& forward_d_path_end, |
| const point& reverse_d_path_end) |
| { |
| return ((forward_d_path_end.x() - forward_d_path_end.y()) |
| == (reverse_d_path_end.x() - reverse_d_path_end.y()) |
| && forward_d_path_end.x() >= reverse_d_path_end.x()); |
| } |
| //// Test if a point is within the boundaries of the edit graph. |
| /// |
| /// @param p the point to test. |
| /// |
| /// @param a_size the size of abscissas. That is, the size of the |
| /// first input to consider. |
| /// |
| /// @param b_size the of ordinates. That is, the size of the second |
| /// input to consider. |
| /// |
| /// @return true iff a point is within the boundaries of the edit |
| /// graph. |
| bool |
| point_is_valid_in_graph(point& p, |
| unsigned a_size, |
| unsigned b_size) |
| { |
| return (p.x() > -1 |
| && p.x() < (int) a_size |
| && p.y() > -1 |
| && p.y() < (int) b_size); |
| } |
| |
| /// Get the end points of the snake, as intended by the paper. |
| /// |
| /// @param s the snake to consider. |
| /// |
| /// @param x the starting point of the snake. |
| /// |
| /// @param u the end point of the snake. |
| bool |
| snake_end_points(const snake& s, point& x, point& u) |
| { |
| if (s.is_empty()) |
| return false; |
| |
| if (s.is_forward()) |
| { |
| x = s.intermediate(); |
| u = s.end(); |
| } |
| else |
| { |
| x = s.end(); |
| u = s.intermediate(); |
| } |
| return true; |
| } |
| |
| /// Returns the middle snake of two strings, as well as the length of |
| /// their shortest editing script. |
| /// |
| /// @param str1 the first string to consider. |
| /// |
| /// @param str2 the second string to consider. |
| /// |
| /// @param snake_begin the point representing the beginning |
| bool |
| compute_middle_snake(const char* str1, const char* str2, |
| snake& s, int& ses_len) |
| { |
| bool has_snake = false; |
| int str1_size = strlen(str1), str2_size = strlen(str2); |
| |
| if (compute_middle_snake<const char*, |
| default_eq_functor>(str1, str1 + str1_size, |
| str2 , str2 + str2_size, |
| s, ses_len)) |
| has_snake = true; |
| |
| return has_snake; |
| } |
| |
| /// Compute the length of the shortest edit script for two strings. |
| /// This is done using the "Greedy LCS/SES" of figure 2 in the paper. |
| /// It can walk the edit graph either foward (when reverse is false) |
| /// or backward starting from the end (when reverse is true). |
| /// |
| /// @param str1 the first string to consider. |
| /// |
| /// @param str2 the second string to consider. |
| /// |
| /// @param reverse when true, walk the edit graph backward, starting |
| /// from the point (M,N) (with M and N being the length of str1 and |
| /// str2). When false, walk the edit graph forward, starting from the |
| /// point (0,0). |
| /// |
| /// @return the length of the shortest edit script. |
| int |
| ses_len(const char* str1, |
| const char* str2, |
| bool reverse) |
| { |
| int str1_size = strlen(str1), str2_size = strlen(str2); |
| |
| d_path_vec v(str1_size, str2_size); |
| return ses_len(str1, str1 + str1_size, |
| str2, str2 + str2_size, |
| v, reverse); |
| } |
| |
| /// Compute the longest common subsequence of two strings and return |
| /// the length of the shortest edit script for transforming the first |
| /// string into the second. |
| /// |
| /// @param str1 the first string to consider. |
| /// |
| /// @param str2 the second string to consider. |
| /// |
| /// @param ses_len the length of the shortest edit script. This is |
| /// set by the function iff it returns true. |
| /// |
| /// @param the longest common subsequence of the two strings. This is |
| /// set the function iff it returns true. |
| /// |
| /// @return true if the function could compute an lcs, false |
| /// otherwise. |
| void |
| compute_lcs(const char* str1, const char* str2, int &ses_len, string& lcs) |
| { |
| vector<point> result; |
| edit_script ses; |
| |
| compute_diff(str1, str1 + strlen(str1), |
| str2, str2 + strlen(str2), |
| result, ses); |
| |
| ses_len = ses.length(); |
| |
| for (unsigned i = 0; i < result.size(); ++i) |
| { |
| int x = result[i].x(), y = result[i].y(); |
| ABG_ASSERT(str1[x] == str2[y]); |
| lcs.push_back(str1[x]); |
| } |
| } |
| |
| /// Compute the shortest edit script for transforming a string into |
| /// another. |
| /// |
| /// @param str1 the first string to consider. |
| /// |
| /// @param str2 the second string to consider. |
| /// |
| /// @param ses the resulting edit script. |
| /// |
| /// @pram ses_len the length of the edit script. |
| void |
| compute_ses(const char* str1, const char* str2, edit_script& ses) |
| { |
| vector<point> lcs; |
| compute_diff(str1, str1 + strlen(str1), |
| str2, str2 + strlen(str2), |
| lcs, ses); |
| } |
| |
| }//end namespace diff_utils |
| |
| }//end namespace abigail |