for path parts, use immutable slices (no memory alloc)
parent
85a9715ac3
commit
75e4f9b99a
164
ostd/path.hh
164
ostd/path.hh
|
@ -117,54 +117,56 @@ struct path {
|
||||||
return seps[std::size_t(p_fmt)];
|
return seps[std::size_t(p_fmt)];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string drive() const {
|
string_range drive() const {
|
||||||
if (is_win()) {
|
if (is_win()) {
|
||||||
if (p_path.substr(0, 2) == "\\\\") {
|
string_range path = p_path;
|
||||||
|
if (has_dslash(path)) {
|
||||||
char const *endp = strchr(p_path.data() + 2, '\\');
|
char const *endp = strchr(p_path.data() + 2, '\\');
|
||||||
if (!endp) {
|
if (!endp) {
|
||||||
return p_path;
|
return path;
|
||||||
}
|
}
|
||||||
char const *pendp = strchr(endp, '\\');
|
char const *pendp = strchr(endp, '\\');
|
||||||
if (!pendp) {
|
if (!pendp) {
|
||||||
return p_path;
|
return path;
|
||||||
}
|
}
|
||||||
return std::string{p_path.data(), pendp};
|
return string_range{path.data(), pendp};
|
||||||
} else if (has_letter(p_path)) {
|
} else if (has_letter(path)) {
|
||||||
return p_path.substr(0, 2);
|
return path.slice(0, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_drive() const {
|
bool has_drive() const {
|
||||||
if (is_win()) {
|
if (is_win()) {
|
||||||
return (has_letter(p_path) || (p_path.substr(0, 2) == "\\\\"));
|
return (has_letter(p_path) || has_dslash(p_path));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string root() const {
|
string_range root() const {
|
||||||
if (has_root()) {
|
char const *rootp = get_rootp();
|
||||||
char sep = separator();
|
if (rootp) {
|
||||||
return std::string{&sep, 1};
|
return string_range{rootp, rootp + 1};
|
||||||
}
|
}
|
||||||
return "";
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_root() const {
|
bool has_root() const {
|
||||||
if (is_win()) {
|
return !!get_rootp();
|
||||||
return (
|
|
||||||
(p_path.data()[0] == '\\') ||
|
|
||||||
(has_letter(p_path) && (p_path.data()[2] == '\\'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (p_path.data()[0] == '/');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string anchor() const {
|
string_range anchor() const {
|
||||||
auto ret = drive();
|
string_range dr = drive();
|
||||||
ret.append(root());
|
if (dr.empty()) {
|
||||||
return ret;
|
return root();
|
||||||
|
}
|
||||||
|
char const *datap = dr.data();
|
||||||
|
std::size_t datas = dr.size();
|
||||||
|
if (datap[datas] == separator()) {
|
||||||
|
return string_range{datap, datap + datas + 1};
|
||||||
|
}
|
||||||
|
return dr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_anchor() const {
|
bool has_anchor() const {
|
||||||
|
@ -193,52 +195,39 @@ struct path {
|
||||||
return (relative().p_path != ".");
|
return (relative().p_path != ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name() const {
|
string_range name() const {
|
||||||
path rel = relative_to(anchor());
|
string_range rel = relative_to_str(anchor());
|
||||||
auto pos = rel.p_path.rfind(separator());
|
string_range sep = ostd::find_last(rel, separator());
|
||||||
if (pos == std::string::npos) {
|
if (sep.empty()) {
|
||||||
return std::move(rel.p_path);
|
return rel;
|
||||||
}
|
}
|
||||||
return rel.p_path.substr(pos + 1);
|
sep.pop_front();
|
||||||
|
return sep;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_name() const {
|
bool has_name() const {
|
||||||
return !name().empty();
|
return !name().empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string suffix() const {
|
string_range suffix() const {
|
||||||
path rel = relative_to(anchor());
|
return ostd::find_last(relative_to_str(anchor()), '.');
|
||||||
auto pos = rel.p_path.rfind('.');
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return rel.p_path.substr(pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_suffix() const {
|
bool has_suffix() const {
|
||||||
return !suffix().empty();
|
return !suffix().empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string suffixes() const {
|
string_range suffixes() const {
|
||||||
auto nm = name();
|
return ostd::find(name(), '.');
|
||||||
auto pos = nm.find('.');
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return nm.substr(pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_suffixes() const {
|
bool has_suffixes() const {
|
||||||
return !suffixes().empty();
|
return !suffixes().empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string stem() const {
|
string_range stem() const {
|
||||||
auto nm = name();
|
auto nm = name();
|
||||||
auto pos = nm.find('.');
|
return nm.slice(0, nm.size() - ostd::find(nm, '.').size());
|
||||||
if (pos == std::string::npos) {
|
|
||||||
return nm;
|
|
||||||
}
|
|
||||||
return nm.substr(0, pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_stem() const {
|
bool has_stem() const {
|
||||||
|
@ -247,7 +236,7 @@ struct path {
|
||||||
|
|
||||||
bool is_absolute() const {
|
bool is_absolute() const {
|
||||||
if (is_win()) {
|
if (is_win()) {
|
||||||
if (p_path.substr(0, 2) == "\\\\") {
|
if (has_dslash(p_path)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return (has_letter(p_path) && (p_path.data()[2] == '\\'));
|
return (has_letter(p_path) && (p_path.data()[2] == '\\'));
|
||||||
|
@ -259,22 +248,12 @@ struct path {
|
||||||
return !is_absolute();
|
return !is_absolute();
|
||||||
}
|
}
|
||||||
|
|
||||||
path relative_to(path other) const {
|
path relative_to(path const &other) const {
|
||||||
if (other.p_path == ".") {
|
if (path_fmt(other.p_fmt) != path_fmt(p_fmt)) {
|
||||||
return *this;
|
return relative_to_str(path{other, p_fmt}.p_path);
|
||||||
|
} else {
|
||||||
|
return relative_to_str(other.p_path);
|
||||||
}
|
}
|
||||||
if (other.p_fmt != p_fmt) {
|
|
||||||
other = path{other, p_fmt};
|
|
||||||
}
|
|
||||||
if (p_path.substr(0, other.p_path.length()) == other.p_path) {
|
|
||||||
std::size_t oplen = other.p_path.length();
|
|
||||||
if ((p_path.length() > oplen) && (p_path[oplen] == separator())) {
|
|
||||||
++oplen;
|
|
||||||
}
|
|
||||||
return path{p_path.substr(oplen), p_fmt};
|
|
||||||
}
|
|
||||||
/* TODO: throw */
|
|
||||||
return path{""};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
path &remove_name() {
|
path &remove_name() {
|
||||||
|
@ -283,7 +262,7 @@ struct path {
|
||||||
/* TODO: throw */
|
/* TODO: throw */
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
p_path.erase(p_path.length() - nm.length() - 1, nm.length() + 1);
|
p_path.erase(p_path.size() - nm.size() - 1, nm.size() + 1);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +287,7 @@ struct path {
|
||||||
path &replace_suffix(string_range sfx) {
|
path &replace_suffix(string_range sfx) {
|
||||||
auto osfx = suffix();
|
auto osfx = suffix();
|
||||||
if (!osfx.empty()) {
|
if (!osfx.empty()) {
|
||||||
p_path.erase(p_path.length() - osfx.length(), osfx.length());
|
p_path.erase(p_path.size() - osfx.size(), osfx.size());
|
||||||
}
|
}
|
||||||
p_path.append(sfx);
|
p_path.append(sfx);
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -317,7 +296,7 @@ struct path {
|
||||||
path &replace_suffixes(string_range sfx) {
|
path &replace_suffixes(string_range sfx) {
|
||||||
auto sfxs = suffixes();
|
auto sfxs = suffixes();
|
||||||
if (!sfxs.empty()) {
|
if (!sfxs.empty()) {
|
||||||
p_path.erase(p_path.length() - sfxs.length(), sfxs.length());
|
p_path.erase(p_path.size() - sfxs.size(), sfxs.size());
|
||||||
}
|
}
|
||||||
p_path.append(sfx);
|
p_path.append(sfx);
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -403,7 +382,7 @@ private:
|
||||||
return path_fmt(p_fmt) == format::windows;
|
return path_fmt(p_fmt) == format::windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has_letter(std::string const &s) {
|
static bool has_letter(string_range s) {
|
||||||
if (s.size() < 2) {
|
if (s.size() < 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -411,6 +390,13 @@ private:
|
||||||
return (s[1] == ':') && (ltr >= 'a') && (ltr <= 'z');
|
return (s[1] == ':') && (ltr >= 'a') && (ltr <= 'z');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool has_dslash(string_range s) {
|
||||||
|
if (s.size() < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (s.slice(0, 2) == "\\\\");
|
||||||
|
}
|
||||||
|
|
||||||
void cleanup_str(std::string &s, char sep, bool allow_twoslash) {
|
void cleanup_str(std::string &s, char sep, bool allow_twoslash) {
|
||||||
std::size_t start = 0;
|
std::size_t start = 0;
|
||||||
/* replace multiple separator sequences and . parts */
|
/* replace multiple separator sequences and . parts */
|
||||||
|
@ -427,7 +413,7 @@ private:
|
||||||
s.erase(start, 2 - int(p[1] == '\0'));
|
s.erase(start, 2 - int(p[1] == '\0'));
|
||||||
}
|
}
|
||||||
/* replace // and /./ sequences as well as separators */
|
/* replace // and /./ sequences as well as separators */
|
||||||
for (; start < s.length(); ++start) {
|
for (; start < s.size(); ++start) {
|
||||||
p = &s[start];
|
p = &s[start];
|
||||||
if (is_sep(*p)) {
|
if (is_sep(*p)) {
|
||||||
std::size_t cnt = 0;
|
std::size_t cnt = 0;
|
||||||
|
@ -451,7 +437,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void strip_trailing(char sep) {
|
void strip_trailing(char sep) {
|
||||||
std::size_t plen = p_path.length();
|
std::size_t plen = p_path.size();
|
||||||
if (sep == '\\') {
|
if (sep == '\\') {
|
||||||
char const *p = p_path.data();
|
char const *p = p_path.data();
|
||||||
if ((plen <= 2) && (p[0] == '\\') && (p[1] == '\\')) {
|
if ((plen <= 2) && (p[0] == '\\') && (p[1] == '\\')) {
|
||||||
|
@ -528,6 +514,38 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string_range relative_to_str(string_range other) const {
|
||||||
|
if (other == ".") {
|
||||||
|
return p_path;
|
||||||
|
}
|
||||||
|
std::size_t oplen = other.size();
|
||||||
|
if (string_range{p_path}.slice(0, oplen) == other) {
|
||||||
|
if ((p_path.size() > oplen) && (p_path[oplen] == separator())) {
|
||||||
|
++oplen;
|
||||||
|
}
|
||||||
|
auto sl = string_range{p_path};
|
||||||
|
return sl.slice(oplen, sl.size());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char const *get_rootp() const {
|
||||||
|
char const *datap = p_path.data();
|
||||||
|
if (is_win()) {
|
||||||
|
if (*datap == '\\') {
|
||||||
|
return datap;
|
||||||
|
}
|
||||||
|
if (has_letter(p_path) && (datap[2] == '\\')) {
|
||||||
|
return datap + 2;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (*p_path.data() == '/') {
|
||||||
|
return datap;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
std::string p_path;
|
std::string p_path;
|
||||||
format p_fmt;
|
format p_fmt;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue