Skip to content

Commit

Permalink
AK: Move path canonicalization into LexicalPath::canonicalized_path
Browse files Browse the repository at this point in the history
This moves the path canonicalization from the LexicalPath constructor to
canonicalized_path. This allows canonicalized path to no longer
construct a LexicalPath object and initialize all its member variables.
  • Loading branch information
MaxWipfli authored and awesomekling committed Jun 30, 2021
1 parent d8be530 commit dde888a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 57 deletions.
111 changes: 56 additions & 55 deletions AK/LexicalPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,9 @@ namespace AK {

char s_single_dot = '.';

LexicalPath::LexicalPath(String s)
: m_string(move(s))
LexicalPath::LexicalPath(String path)
: m_string(canonicalized_path(move(path)))
{
canonicalize();
}

Vector<String> LexicalPath::parts() const
{
Vector<String> vector;
vector.ensure_capacity(m_parts.size());
for (auto& part : m_parts)
vector.unchecked_append(part);
return vector;
}

void LexicalPath::canonicalize()
{
// NOTE: We never allow an empty m_string, if it's empty, we just set it to '.'.
if (m_string.is_empty()) {
m_string = ".";
m_dirname = m_string;
Expand All @@ -42,43 +27,6 @@ void LexicalPath::canonicalize()
return;
}

// NOTE: If there are no dots, no '//' and the path doesn't end with a slash, it is already canonical.
if (m_string.contains("."sv) || m_string.contains("//"sv) || m_string.ends_with('/')) {
auto parts = m_string.split_view('/');
size_t approximate_canonical_length = 0;
Vector<String> canonical_parts;

for (auto& part : parts) {
if (part == ".")
continue;
if (part == "..") {
if (canonical_parts.is_empty()) {
if (is_absolute()) {
// At the root, .. does nothing.
continue;
}
} else {
if (canonical_parts.last() != "..") {
// A .. and a previous non-.. part cancel each other.
canonical_parts.take_last();
continue;
}
}
}
approximate_canonical_length += part.length() + 1;
canonical_parts.append(part);
}

if (canonical_parts.is_empty() && !is_absolute())
canonical_parts.append(".");

StringBuilder builder(approximate_canonical_length);
if (is_absolute())
builder.append('/');
builder.join('/', canonical_parts);
m_string = builder.to_string();
}

m_parts = m_string.split_view('/');

auto last_slash_index = m_string.view().find_last_of('/');
Expand Down Expand Up @@ -110,14 +58,67 @@ void LexicalPath::canonicalize()
}
}

Vector<String> LexicalPath::parts() const
{
Vector<String> vector;
vector.ensure_capacity(m_parts.size());
for (auto& part : m_parts)
vector.unchecked_append(part);
return vector;
}

bool LexicalPath::has_extension(StringView const& extension) const
{
return m_string.ends_with(extension, CaseSensitivity::CaseInsensitive);
}

String LexicalPath::canonicalized_path(String path)
{
return LexicalPath(move(path)).string();
if (path.is_null())
return {};

// NOTE: We never allow an empty m_string, if it's empty, we just set it to '.'.
if (path.is_empty())
return ".";

// NOTE: If there are no dots, no '//' and the path doesn't end with a slash, it is already canonical.
if (!path.contains("."sv) && !path.contains("//"sv) && !path.ends_with('/'))
return path;

auto is_absolute = path[0] == '/';
auto parts = path.split_view('/');
size_t approximate_canonical_length = 0;
Vector<String> canonical_parts;

for (auto& part : parts) {
if (part == ".")
continue;
if (part == "..") {
if (canonical_parts.is_empty()) {
if (is_absolute) {
// At the root, .. does nothing.
continue;
}
} else {
if (canonical_parts.last() != "..") {
// A .. and a previous non-.. part cancel each other.
canonical_parts.take_last();
continue;
}
}
}
approximate_canonical_length += part.length() + 1;
canonical_parts.append(part);
}

if (canonical_parts.is_empty() && !is_absolute)
canonical_parts.append(".");

StringBuilder builder(approximate_canonical_length);
if (is_absolute)
builder.append('/');
builder.join('/', canonical_parts);
return builder.to_string();
}

String LexicalPath::relative_path(String absolute_path, String const& prefix)
Expand Down
2 changes: 0 additions & 2 deletions AK/LexicalPath.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ class LexicalPath {
}

private:
void canonicalize();

Vector<StringView> m_parts;
String m_string;
StringView m_dirname;
Expand Down

0 comments on commit dde888a

Please sign in to comment.