Skip to content

Commit

Permalink
[FOLD] in place algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
alandefreitas committed Aug 26, 2022
1 parent 579deee commit f9c5121
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 188 deletions.
188 changes: 2 additions & 186 deletions include/boost/url/impl/url.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -145,194 +145,10 @@ relative(
{
BOOST_ASSERT(&dest != &base);
BOOST_ASSERT(&dest != &href);

// Validate input
if (!href.is_path_absolute() ||
!base.is_path_absolute())
{
// href is already relative or
// cannot calculate a URI relative to another relative URI
BOOST_URL_RETURN_EC(error::not_a_base);
}

// Resolve scheme
if (href.scheme() == base.scheme() ||
!href.has_scheme())
{
dest.remove_scheme();
}
else
{
dest.set_scheme(href.scheme());
}

// Resolve authority
if (dest.has_scheme() ||
href.has_authority() != base.has_authority() ||
href.authority() != base.authority() ||
href.has_userinfo() ||
href.has_password())
{
// Otherwise, copy all but scheme from href
if (href.has_authority())
dest.set_encoded_authority(href.encoded_authority());
else
dest.remove_authority();
dest.set_encoded_path(href.encoded_path());
dest.normalize_path();
if (href.has_query())
dest.set_encoded_query(href.encoded_query());
else
dest.remove_query();
if (href.has_fragment())
dest.set_encoded_fragment(href.encoded_fragment());
else
dest.remove_fragment();
return {};
}
dest.remove_authority();

// Resolve new path
dest.set_encoded_path({});

// 0. Get segments
auto segs0 = base.segments();
auto segs1 = href.segments();

// Reference iterators
auto const begin0 = segs0.begin();
auto it0 = begin0;
auto const end0 = segs0.end();
auto const last0 = begin0 != end0 ? std::prev(end0) : end0;
auto const begin1 = segs1.begin();
auto it1 = begin1;
auto const end1 = segs1.end();
auto const last1 = begin0 != end1 ? std::prev(end1) : end1;

// Function to advance the dotdot segments
decode_view dotdot("..");
decode_view dot(".");
auto consume_dots = [dotdot, dot](
segments_view::iterator& first,
segments_view::iterator last)
{
if (*first == dotdot ||
*first == dot)
{
++first;
return true;
}
auto it = std::next(first);
std::size_t l = 1;
while (it != last)
{
if (*it == dotdot)
{
if (--l == 0)
{
++it;
first = it;
break;
}
}
else if (*it != dot)
{
++l;
}
++it;
}
return first == it;
};

// 1. Find the longest common path
while (
it0 != last0 &&
it1 != last1)
{
if (consume_dots(it0, last0))
continue;
if (consume_dots(it1, last1))
continue;
if (*it0 == *it1)
{
++it0;
++it1;
}
else
{
break;
}
}

// 1.b Check if parent paths are the same
if (it0 == last0 &&
it1 == last1 &&
it0 != end0 &&
it1 != end1 &&
*it0 == *it1)
{
// Return empty path
if (href.has_query())
dest.set_encoded_query(href.encoded_query());
else
dest.remove_query();
if (href.has_fragment())
dest.set_encoded_fragment(href.encoded_fragment());
else
dest.remove_fragment();
return {};
}

// 2. Append ".." for each segment left in base
segments_encoded segs = dest.encoded_segments();
if (it0 != end0)
{
dest.set_path_absolute(false);
while (it0 != last0)
{
if (*it0 == dotdot)
{
if (!segs.empty())
segs.pop_back();
}
else if (*it0 != dot)
{
segs.push_back(dotdot.encoded());
}
++it0;
}
}

// 3. Append segments left from the reference
while (it1 != end1)
{
if (*it1 == dotdot)
{
if (!segs.empty())
segs.pop_back();
}
else if (*it1 != dot)
{
segs.push_back((*it1).encoded());
}
++it1;
}

// Query and fragment comes from reference
if (href.has_query())
dest.set_encoded_query(href.encoded_query());
else
dest.remove_query();

if (href.has_fragment())
dest.set_encoded_fragment(href.encoded_fragment());
else
dest.remove_fragment();

return {};
dest.copy(base);
return dest.relative(href);
}


} // urls
} // boost

Expand Down
Loading

0 comments on commit f9c5121

Please sign in to comment.