SPH
Path.cpp
Go to the documentation of this file.
1 #include "io/Path.h"
2 
4 
5 Path::Path(const std::string& path)
6  : path(path) {
7  this->convert();
8 }
9 
10 bool Path::empty() const {
11  return path.empty();
12 }
13 
14 bool Path::isHidden() const {
15  Path name = this->fileName();
16  return !name.empty() && name.path[0] == '.';
17 }
18 
19 bool Path::isAbsolute() const {
20  return !path.empty() && path[0] == SEPARATOR;
21 }
22 
23 bool Path::isRelative() const {
24  return !path.empty() && !this->isAbsolute();
25 }
26 
27 bool Path::isRoot() const {
28  return path.size() == 1 && path[0] == '/';
29 }
30 
31 bool Path::hasExtension() const {
32  return !this->extension().empty();
33 }
34 
36  std::size_t n = path.rfind(SEPARATOR);
37  if (n == std::string::npos) {
38  return Path();
39  }
40  if (n == path.size() - 1) {
41  // last character, find again without it
42  return Path(path.substr(0, n)).parentPath();
43  }
44  return Path(path.substr(0, n + 1));
45 }
46 
48  std::size_t n = path.rfind(SEPARATOR);
49  if (n == std::string::npos) {
50  // path is just a filename
51  return Path(path);
52  } else if (n == path.size() - 1) {
53  // directory, extract the name without the ending separator
54  return Path(path.substr(0, path.size() - 1)).fileName();
55  }
56  return Path(path.substr(n + 1));
57 }
58 
60  const Path name = this->fileName();
61  if (name.path.size() <= 1) {
62  return Path();
63  }
64  const std::size_t n = name.path.find_last_of('.');
65  if (n == 0 || n == std::string::npos) {
66  return Path();
67  }
68  return Path(name.path.substr(n + 1));
69 }
70 
71 std::string Path::native() const {
73  return path;
74 }
75 
76 Path& Path::replaceExtension(const std::string& newExtension) {
77  const Path name = this->fileName();
78  if (name.empty() || name.path == "." || name.path == "..") {
79  return *this;
80  }
81  // skip first character, files like '.gitignore' are hidden, not just extension without filename
82  const std::size_t n = name.path.find_last_of('.');
83  if (n == 0 || n == std::string::npos) {
84  // no extension, append the new one
85  if (!newExtension.empty()) {
86  path += "." + newExtension;
87  }
88  return *this;
89  } else {
90  const std::size_t indexInPath = path.size() - name.path.size() + n;
91  if (!newExtension.empty()) {
92  path.replace(indexInPath + 1, std::string::npos, newExtension);
93  } else {
94  path = path.substr(0, indexInPath);
95  }
96  }
97  return *this;
98 }
99 
101  const Path name = this->fileName();
102  if (name.empty() || name.path == "." || name.path == "..") {
103  return *this;
104  }
105  const std::size_t n = name.path.find_last_of('.');
106  if (n == 0 || n == std::string::npos) {
107  // no extension, do nothing
108  return *this;
109  } else {
110  path = path.substr(0, path.size() - name.path.size() + n);
111  }
112  return *this;
113 }
114 
116  std::size_t n;
117  while ((n = this->findFolder("..")) != std::string::npos) {
118  Path parent = Path(path.substr(0, std::max(0, int(n) - 1))).parentPath();
119  Path tail(path.substr(std::min(n + 3, path.size())));
120  *this = parent / tail;
121  }
122  while ((n = this->findFolder(".")) != std::string::npos) {
123  Path parent = Path(path.substr(0, n));
124  Path tail(path.substr(std::min(n + 2, path.size())));
125  *this = parent / tail;
126  }
127  return *this;
128 }
129 
131  if (this->empty() || this->isAbsolute()) {
132  return *this;
133  }
134  *this = Path::currentPath() / *this;
135  return this->removeSpecialDirs();
136 }
137 
139  if (this->empty() || this->isRelative()) {
140  return *this;
141  }
142  Path wd = Path::currentPath();
143  SPH_ASSERT(wd.isAbsolute() && this->isAbsolute());
144  std::size_t n = 0;
145  // find shared part of the path
146  while (true) {
147  const std::size_t m = wd.path.find(SEPARATOR, n);
148  if (m == std::string::npos || wd.path.substr(0, m) != path.substr(0, m)) {
149  break;
150  } else {
151  n = m + 1;
152  }
153  }
154  const Path sharedPath(path.substr(0, n));
155  Path newPath;
156  // add .. for every directory not in path
157  while (wd.path.substr(0, n + 1) != sharedPath.path) {
158  wd = wd.parentPath();
159  newPath /= Path("..");
160  }
161  // add the remaining path of the original path
162  newPath /= Path(path.substr(n));
163  return *this = std::move(newPath);
164 }
165 
167  constexpr Size bufferCnt = 1024;
168  char buffer[bufferCnt];
169  if (getcwd(buffer, sizeof(buffer))) {
170  std::string path(buffer);
171  return Path(path + SEPARATOR);
172  } else {
173  return Path();
174  }
175 }
176 
177 Path Path::operator/(const Path& other) const {
178  if (path.empty()) {
179  return Path(other.path);
180  } else if (other.path.empty()) {
181  return Path(path);
182  } else {
183  return Path(path + "/" + other.path);
184  }
185 }
186 
187 Path& Path::operator/=(const Path& other) {
188  *this = *this / other;
189  return *this;
190 }
191 
192 bool Path::operator==(const Path& other) const {
193  return path == other.path;
194 }
195 
196 bool Path::operator!=(const Path& other) const {
197  return path != other.path;
198 }
199 
200 bool Path::operator<(const Path& other) const {
201  return path < other.path;
202 }
203 
204 std::ostream& operator<<(std::ostream& stream, const Path& path) {
205  stream << path.path;
206  return stream;
207 }
208 
209 void Path::convert() {
210  for (char& c : path) {
211  if (c == '\\' || c == '/') {
212  c = SEPARATOR;
213  }
214  }
215  std::string duplicates = { SEPARATOR, SEPARATOR };
216  std::size_t n;
217  while ((n = path.find(duplicates)) != std::string::npos) {
218  path.replace(n, 2, 1, SEPARATOR);
219  }
220 }
221 
222 std::size_t Path::findFolder(const std::string& folder) {
223  if (path == folder || path.substr(0, std::min(path.size(), folder.size() + 1)) == folder + SEPARATOR) {
224  return 0;
225  }
226  const size_t n = path.find(SEPARATOR + folder + SEPARATOR);
227  if (n != std::string::npos) {
228  return n + 1;
229  }
230  if (path.substr(std::max(0, int(path.size()) - int(folder.size()) - 1)) == SEPARATOR + folder) {
231  return path.size() - folder.size();
232  }
233  return std::string::npos;
234 }
235 
236 Path operator"" _path(const char* nativePath, const std::size_t size) {
237  SPH_ASSERT(size > 0);
238  return Path(nativePath);
239 }
240 
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
constexpr INLINE T max(const T &f1, const T &f2)
Definition: MathBasic.h:20
NAMESPACE_SPH_BEGIN constexpr INLINE T min(const T &f1, const T &f2)
Minimum & Maximum value.
Definition: MathBasic.h:15
#define NAMESPACE_SPH_END
Definition: Object.h:12
std::ostream & operator<<(std::ostream &stream, const Path &path)
Definition: Path.cpp:204
Object representing a path on a filesystem, similar to std::filesystem::path in c++17.
Object representing a path on a filesystem.
Definition: Path.h:17
bool isRelative() const
Checks if the path is relative. Empty path is not considered relative.
Definition: Path.cpp:23
Path operator/(const Path &other) const
Appends two paths together.
Definition: Path.cpp:177
static Path currentPath()
Returns the current working directory, or empty path if the function failed.
Definition: Path.cpp:166
Path & replaceExtension(const std::string &newExtension)
Changes the extension of the file.
Definition: Path.cpp:76
Path & removeExtension()
Removes the extension from the path.
Definition: Path.cpp:100
std::string native() const
Returns the native version of the path.
Definition: Path.cpp:71
bool operator<(const Path &other) const
Does lexicographical comparison of two paths.
Definition: Path.cpp:200
bool isRoot() const
Checks if the object holds root path.
Definition: Path.cpp:27
Path & makeAbsolute()
Turns the path into an absolute path.
Definition: Path.cpp:130
Path()=default
Constructs an empty path.
Path & removeSpecialDirs()
Removes . and .. directories from the path.
Definition: Path.cpp:115
bool isHidden() const
Checks if the file is hidden, i.e. starts with a dot (makes only sense on Unit based systems).
Definition: Path.cpp:14
bool empty() const
Checks if the path is empty.
Definition: Path.cpp:10
Path & operator/=(const Path &other)
Appends another path to this one.
Definition: Path.cpp:187
Path fileName() const
Returns the filename of the path.
Definition: Path.cpp:47
Path parentPath() const
Returns the parent directory. If the path is empty or root, return empty path.
Definition: Path.cpp:35
bool isAbsolute() const
Definition: Path.cpp:19
Path extension() const
Returns the extension of the filename.
Definition: Path.cpp:59
bool operator==(const Path &other) const
Checks if two objects represent the same path.
Definition: Path.cpp:192
bool hasExtension() const
Checks if the file has an extension.
Definition: Path.cpp:31
bool operator!=(const Path &other) const
Checks if two objects represent different paths.
Definition: Path.cpp:196
Path & makeRelative()
Turns the path into a relative path.
Definition: Path.cpp:138