jubilant-funicular
Path.h
1 #ifndef UTILS_PATH_H_INCLUDED
2 #define UTILS_PATH_H_INCLUDED
3 
4 #include <cassert>
5 #include <ostream>
6 #ifdef _UTILS_UNIX
7  #include <dirent.h>
8 #elif _UTILS_WINDOWS
9  #include <windows.h>
10 #endif
11 
12 namespace utils {
13  class Path;
14  extern std::ostream& operator<<(std::ostream& out, const Path& path);
16  class Path {
17  public:
20  friend class Path;
21  SetBeginEndKey() {}
23  SetBeginEndKey& operator=(const SetBeginEndKey&);
24  };
30  class iterator {
31  public:
32  using value_type = const Path;
33  using difference_type = std::ptrdiff_t;
34  using pointer = const Path*;
35  using reference = const Path;
36  using iterator_category = std::forward_iterator_tag;
37  #ifdef _UTILS_UNIX
38  using node = struct{ DIR* d; struct dirent* e; };
39  #elif _UTILS_WINDOWS
40  using node = struct{ HANDLE h; WIN32_FIND_DATA d; };
41  #endif
42  private:
43  pointer m_path;
44  node m_node;
45  public:
46  iterator() {}
47  iterator(pointer path) : m_path(path) {
48  assert(path != nullptr);
49  }
50  reference operator*() const {
51  if (m_path->is_file()) return *m_path;
52  #ifdef _UTILS_UNIX
53  return Path(m_node.e->d_name);
54  #elif _UTILS_WINDOWS
55  return Path(m_node.d.cFileName);
56  #endif
57  }
58  reference operator->() const {
59  return operator*();
60  }
61  iterator& operator++() {
62  if (m_path->is_file()) {
63  m_path = nullptr;
64  } else {
65  #ifdef _UTILS_UNIX
66  m_node.e = readdir(m_node.d);
67  if (!m_node.e) closedir(m_node.d);
68  #elif _UTILS_WINDOWS
69  if (FindNextFile(m_node.h, &m_node.d) == 0) {
70  FindClose(m_node.h);
71  m_path = nullptr;
72  }
73  #endif
74  }
75  return *this;
76  }
77  iterator operator++(int) {
78  auto ret = *this;
79  operator++();
80  return ret;
81  }
82  bool operator==(const iterator& rhs) const {
83  if (m_path != rhs.m_path) return false;
84  if (!m_path || m_path->is_file()) return true;
85  #ifdef _UTILS_UNIX
86  return m_node.e == rhs.m_node.e;
87  #elif _UTILS_WINDOWS
88  return strcmp(m_node.d.cFileName, rhs.m_node.d.cFileName) == 0;
89  #endif
90  }
91  bool operator!=(const iterator& rhs) const {
92  return !operator==(rhs);
93  }
94 
95  void set_begin(SetBeginEndKey _) {
96  if (!m_path->exists()) {
97  m_path = nullptr;
98  } else if (m_path->is_directory()) {
99  #ifdef _UTILS_UNIX
100  m_node.d = opendir(m_path->m_path.c_str());
101  m_node.e = readdir(m_node.d);
102  #elif _UTILS_WINDOWS
103  std::string pat = m_path->m_path + "/*";
104  m_node.h = FindFirstFile(pat.c_str(), &m_node.d);
105  #endif
106  }
107  }
108  void set_end(SetBeginEndKey _) {
109  if (m_path->is_file() || !m_path->exists()) {
110  m_path = nullptr;
111  } else {
112  #ifdef _UTILS_UNIX
113  m_node.e = nullptr;
114  #elif _UTILS_WINDOWS
115  m_path = nullptr;
116  #endif
117  }
118  }
119  };
120  private:
121  std::string m_path;
122  public:
123  Path() {}
124  Path(const std::string& path);
125  Path(const char* p) : Path(std::string(p)) {}
126 
128  static Path cwd();
129 
131  Path resolve() const;
133  Path parent() const;
137  std::string file_name(bool extension = true) const;
138 
139  bool exists() const;
140  bool empty() const { return is_empty(); }
141  bool is_empty() const { return m_path.empty(); }
142  bool is_file() const;
143  bool is_directory() const;
144  bool is_folder() const { return is_directory(); }
145  bool is_relative() const { return !is_absolute(); }
146  bool is_absolute() const;
147 
148  const std::string& to_string() const { return m_path; }
149 
150  Path& operator=(const char* p) { m_path = p; return *this; }
151  Path& operator=(const std::string& p) { return operator=(p.c_str()); }
152  bool operator==(const char* p) const;
153  bool operator==(const Path& p) const { return *this == p.m_path; }
154  bool operator==(const std::string& p) const { return operator==(p.c_str()); }
155  bool operator!=(const char* p) const { return !operator==(p); }
156  bool operator!=(const Path& p) const { return !operator==(p); }
157  bool operator!=(const std::string& p) const { return !operator==(p); }
158 
159  bool operator<(const Path& p) const { return resolve().to_string() < p.resolve().to_string(); }
160  bool operator<=(const Path& p) const { return operator==(p) || operator<(p); }
161 
162  Path operator+(const char* p) const;
163  Path& operator+=(const char* p) { return *this = *this + p; }
164  Path operator+(const std::string& p) const { return operator+(p.c_str()); }
165  Path& operator+=(const std::string& p) { return operator+=(p.c_str()); }
166  Path operator+(const Path& p) const { return operator+(p.m_path); }
167  Path& operator+=(const Path& p) { return operator+=(p.m_path); }
168 
169  Path::iterator begin() const;
170  Path::iterator end() const;
171  };
172 }
173 
174 namespace std {
175  template<>
176  struct hash<utils::Path> {
177  std::size_t operator()(const utils::Path& path) const {
178  return std::hash<std::string>()(path.resolve().to_string());
179  }
180  };
181 }
182 
183 #endif // UTILS_PATH_H_INCLUDED
utils::Path
A (case-sensitive) Path in a file system.
Definition: Path.h:16
utils::Path::parent
Path parent() const
Returns the folder containing this path.
Definition: Path.cpp:54
utils::Path::iterator
Definition: Path.h:30
utils::Path::file_name
std::string file_name(bool extension=true) const
Definition: Path.cpp:62
utils::Path::resolve
Path resolve() const
Returns an absolute path equivalent to this.
Definition: Path.cpp:28
utils::Path::SetBeginEndKey
Key unlocking the set_{begin,end}() "private" functions of class Path::iterator.
Definition: Path.h:19
utils::Path::cwd
static Path cwd()
Returns Path representing the current working directory.
Definition: Path.cpp:19