198 lines
5.0 KiB
C++
198 lines
5.0 KiB
C++
// 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
|