irods  4.2.8
About: iRODS (the integrated Rule Oriented Data System) is a distributed data-management system for creating data grids, digital libraries, persistent archives, and real-time data systems.
  Fossies Dox: irods-4.2.8.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

path.cpp
Go to the documentation of this file.
1 #include "filesystem/path.hpp"
2 
3 #include "filesystem/detail.hpp"
4 
5 #include <iostream>
6 #include <iomanip>
7 #include <string>
8 #include <algorithm>
9 
10 #include <boost/algorithm/string.hpp>
11 #include <boost/functional/hash.hpp>
12 
14 {
15  // clang-format off
17  constexpr const path::value_type* const path::dot;
18  constexpr const path::value_type* const path::dot_dot;
19  // clang-format on
20 
21  namespace
22  {
23  auto join(path::iterator _first, path::iterator _last) -> path
24  {
25  path p;
26 
27  for (; _first != _last; ++_first) {
28  p /= *_first;
29  }
30 
31  return p;
32  }
33  } // anonymous namespace
34 
35  //
36  // Path
37  //
38 
39  auto path::operator/=(const path& _p) -> path&
40  {
41  if (_p.empty()) {
42  if (!value_.empty() && preferred_separator != value_.back()) {
43  value_ += preferred_separator;
44  }
45  }
46  else {
47  if (_p.is_absolute()) {
48  return *this = _p;
49  }
50 
51  append_separator_if_needed(_p);
52  value_ += _p.value_;
53  }
54 
55  return *this;
56  }
57 
59  {
60  if (has_object_name()) {
61  const auto pos = value_.find_last_of(preferred_separator);
62 
63  if (string_type::npos != pos) {
64  value_.erase(pos + 1);
65  }
66  }
67 
68  return *this;
69  }
70 
71  auto path::replace_object_name(const path& _replacement) -> path&
72  {
73  remove_object_name();
74  return *this /= _replacement;
75  }
76 
77  auto path::replace_extension(const path& _replacement) -> path&
78  {
79  if (has_extension()) {
80  const auto pos = value_.find_last_of(dot);
81 
82  if (string_type::npos != pos) {
83  value_.erase(pos);
84  }
85  }
86 
87  const char dot = '.';
88 
89  if (!_replacement.empty() && dot != _replacement.value_[0]) {
90  value_ += dot;
91  }
92 
93  return *this += _replacement;
94  }
95 
96  auto path::lexically_normal() const -> path
97  {
98  path p;
99 
100  if (empty()) {
101  return p;
102  }
103 
104  const path root_separator = std::string{&preferred_separator, 1};
105 
106  for (const auto& next_element : *this)
107  {
108  if (next_element == dot) {
109  p /= {};
110  }
111  else if (next_element == dot_dot) {
112  if (p.has_object_name() && p.object_name() != dot_dot) {
113  p.remove_object_name();
114  }
115  else if (root_separator != p) {
116  p /= next_element;
117  }
118  }
119  else {
120  p /= next_element;
121  }
122  }
123 
124  if (p.empty()) {
125  p = dot;
126  }
127  else {
128  auto it = std::rbegin(p);
129 
130  if (it->empty() && dot_dot == *std::next(it)) {
131  p = p.parent_path();
132  }
133  }
134 
135  return p;
136  }
137 
138  auto path::lexically_relative(const path& _base) const -> path
139  {
140  auto base_b = _base.begin();
141  auto base_e = _base.end();
142  auto mm = std::mismatch(begin(), end(), base_b, base_e);
143 
144  if (mm.first == end() && mm.second == base_e) {
145  return {dot};
146  }
147 
148  path p;
149 
150  for (; mm.second != base_e; ++mm.second) {
151  p /= dot_dot;
152  }
153 
154  for (; mm.first != end(); ++mm.first) {
155  p /= *mm.first;
156  }
157 
158  return p;
159  }
160 
161  auto path::lexically_proximate(const path& _base) const -> path
162  {
163  auto p = lexically_relative(_base);
164  return !p.empty() ? p : *this;
165  }
166 
167  auto path::compare(const path& _p) const noexcept -> int
168  {
169  auto first1 = begin();
170  const auto last1 = end();
171 
172  auto first2 = _p.begin();
173  const auto last2 = _p.end();
174 
175  for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
176  if (first1->value_ < first2->value_) {
177  return -1;
178  }
179 
180  if (first1->value_ > first2->value_) {
181  return 1;
182  }
183  }
184 
185  // Case 1: first1 == end1 && first2 == end2 => 0
186  // Case 2: first1 == end1 && first2 != end2 => -1
187  // Case 3: first1 != end1 && first2 == end2 => 1
188 
189  if (first1 == last1) {
190  if (first2 == last2) {
191  return 0;
192  }
193 
194  return -1;
195  }
196 
197  return 1;
198  }
199 
200  auto path::root_collection() const -> path
201  {
202  return is_absolute() ? *begin() : path{};
203  }
204 
205  auto path::relative_path() const -> path
206  {
207  if (has_root_collection()) {
208  return join(++begin(), end());
209  }
210 
211  return empty() ? path{} : *this;
212  }
213 
214  auto path::parent_path() const -> path
215  {
216  return !has_relative_path() ? *this : join(begin(), --end());
217  }
218 
219  auto path::object_name() const -> path
220  {
221  return relative_path().empty() ? path{} : *--end();
222  }
223 
224  auto path::stem() const -> path
225  {
226  if (empty() || object_name() == dot || object_name() == dot_dot)
227  {
228  return {};
229  }
230 
231  const auto n = object_name();
232 
233  auto pos = n.value_.find_last_of(dot);
234 
235  if (string_type::npos != pos)
236  {
237  return n.value_.substr(0, pos);
238  }
239 
240  return {};
241  }
242 
243  auto path::extension() const -> path
244  {
245  if (empty() || object_name() == dot || object_name() == dot_dot)
246  {
247  return {};
248  }
249 
250  const auto n = object_name();
251 
252  auto pos = n.value_.find_last_of(dot);
253 
254  if (string_type::npos != pos)
255  {
256  return n.value_.substr(pos);
257  }
258 
259  return {};
260  }
261 
262  auto path::begin() const -> iterator
263  {
264  return iterator{*this};
265  }
266 
267  auto path::end() const -> iterator
268  {
269  iterator it;
270  it.path_ptr_ = this;
271  it.pos_ = value_.size();
272  return it;
273  }
274 
276  {
277  return reverse_iterator{end()};
278  }
279 
280  auto path::rend() const -> reverse_iterator
281  {
282  return reverse_iterator{begin()};
283  }
284 
285  auto path::append_separator_if_needed(const path& _p) -> void
286  {
287  if (value_.empty() ||
288  preferred_separator == value_.back() ||
289  preferred_separator == _p.value_.front())
290  {
291  return;
292  }
293 
294  value_ += preferred_separator;
295  }
296 
297  //
298  // Iterator
299  //
300 
302  : path_ptr_{&_p}
303  , element_{}
304  , pos_{}
305  {
306  if (path_ptr_->empty())
307  {
308  return;
309  }
310 
311  // Does the path contain a leading forward slash "/"?
312  if (path_ptr_->is_absolute())
313  {
315  }
316  else
317  {
318  const auto& full_path = path_ptr_->value_;
319  const auto end = full_path.find_first_of(path::preferred_separator);
320 
321  element_.value_ = (path::string_type::npos != end)
322  ? full_path.substr(0, end)
323  : full_path;
324  }
325  }
326 
328  {
329  const auto& fp = path_ptr_->value_; // Full path
330  auto& e = element_.value_; // Path element
331 
332  // If we're just before the "end" iterator and the currrent value of
333  // the element is empty, then we know the path ended with a separator and
334  // therefore, the iterator should now be set to the "end" iterator.
335  if (fp.size() - 1 == pos_ && e.empty()) {
336  ++pos_;
337  return *this;
338  }
339 
340  // Skip the element currently pointed to.
341  pos_ += e.size();
342 
343  // If we're at the end of the path, then we're done.
344  if (fp.size() == pos_)
345  {
346  e.clear();
347  return *this;
348  }
349 
350  // If we're not at the end of the path, then we're most likely at a separator.
351  // Skip consecutive separators.
352  while (detail::is_separator(fp[pos_]))
353  {
354  ++pos_;
355  }
356 
357  if (fp.size() == pos_ && detail::is_separator(fp[fp.size() - 1]))
358  {
359  // Found a trailing separator.
360  e.clear();
361  pos_ = fp.size() - 1;
362  }
363  else
364  {
365  // Found a character that is not a separator.
366  const auto end = fp.find_first_of(preferred_separator, pos_);
367 
368  if (path::string_type::npos != end)
369  {
370  // Found a separator.
371  e = fp.substr(pos_, end - pos_);
372  }
373  else
374  {
375  // No trailing separator found.
376  e = fp.substr(pos_, fp.size() - pos_);
377  }
378  }
379 
380  return *this;
381  }
382 
384  {
385  const auto& fp = path_ptr_->value_; // Full path
386  auto& e = element_.value_; // Path element
387 
388  // Handle trailing separator at the end of the path.
389  // If the iterator represents the end iterator and the character preceding it
390  // is a separator, then set the current element to the dot path.
391  if (fp.size() == pos_ &&
392  fp.size() > 1 &&
393  detail::is_separator(fp[pos_ - 1]))
394  {
395  --pos_;
396  e.clear();
397  return *this;
398  }
399 
400  if (detail::is_separator(fp[pos_ - 1]))
401  {
402  // We've reached the root separator of the path.
403  if (0 == pos_ - 1)
404  {
405  --pos_;
407  return *this;
408  }
409 
410  // Point at the separator just after the preceding element.
411  // Separators represent the end of a path element.
412  while (pos_ > 0 && detail::is_separator(fp[pos_ - 1]))
413  {
414  --pos_;
415  }
416  }
417 
418  const auto end = pos_;
419 
420  // Find the start of the path element.
421  while (pos_ > 0 && !detail::is_separator(fp[pos_ - 1]))
422  {
423  --pos_;
424  }
425 
426  e = fp.substr(pos_, end - pos_);
427 
428  return *this;
429  }
430 
432  path::iterator _first2, path::iterator _last2) -> bool
433  {
434  for (; (_first1 != _last1) && (_first2 != _last2); ++_first1, ++_first2) {
435  if (_first1->string() < _first2->string()) {
436  return true;
437  }
438 
439  if (_first2->string() < _first1->string()) {
440  return false;
441  }
442  }
443 
444  return (_first1 == _last1) && (_first2 != _last2);
445  }
446 
447  auto operator<<(std::ostream& _os, const path& _p) -> std::ostream&
448  {
449  return _os << std::quoted(_p.string());
450  }
451 
452  auto operator>>(std::istream& _is, path& _p) -> std::istream&
453  {
455  _is >> std::quoted(t);
456  _p = t;
457  return _is;
458  }
459 
460  auto hash_value(const path& _p) noexcept -> std::size_t
461  {
462  const auto pstr = _p.string();
463  return boost::hash_range(std::begin(pstr), std::end(pstr));
464  }
465 } // namespace irods::experimental::filesystem
466 
irods::experimental::filesystem::hash_value
auto hash_value(const path &_p) noexcept -> std::size_t
Definition: path.cpp:460
irods::experimental::filesystem::path::dot
static constexpr const value_type *const dot
Definition: path.hpp:31
irods::experimental::filesystem::operator>>
auto operator>>(std::istream &_is, path &_p) -> std::istream &
Definition: path.cpp:452
irods::experimental::filesystem::path::iterator::operator--
auto operator--() -> iterator &
Definition: path.cpp:383
irods::experimental::filesystem::path::replace_extension
auto replace_extension(const path &_replacement={}) -> path &
Definition: path.cpp:77
irods::experimental::filesystem::path::lexically_proximate
auto lexically_proximate(const path &_base) const -> path
Definition: path.cpp:161
irods::experimental::filesystem::path::is_absolute
auto is_absolute() const -> bool
Definition: path.hpp:228
irods::experimental::filesystem::path::end
auto end() const -> iterator
Definition: path.cpp:267
irods::experimental::filesystem::path::operator/=
auto operator/=(const path &_p) -> path &
Definition: path.cpp:39
irods.six.next
next
Definition: six.py:518
irods::experimental::filesystem::path::remove_object_name
auto remove_object_name() -> path &
Definition: path.cpp:58
irods::experimental::filesystem::path
Definition: path.hpp:15
irods::experimental::filesystem::path::reverse_iterator
Definition: path.hpp:296
irods::experimental::filesystem::path::begin
auto begin() const -> iterator
Definition: path.cpp:262
irods::experimental::filesystem::path::iterator::path_ptr_
pointer path_ptr_
Definition: path.hpp:290
irods::experimental::filesystem::path::empty
auto empty() const -> bool
Definition: path.hpp:221
pid_age.p
p
Definition: pid_age.py:13
irods::experimental::filesystem::path::rend
auto rend() const -> reverse_iterator
Definition: path.cpp:280
irods::experimental::filesystem::path::iterator::pos_
path::string_type::size_type pos_
Definition: path.hpp:292
irods::experimental::filesystem::path::value_
string_type value_
Definition: path.hpp:243
irods::experimental::filesystem::path::dot_dot
static constexpr const value_type *const dot_dot
Definition: path.hpp:32
irods::experimental::filesystem::path::extension
auto extension() const -> path
Definition: path.cpp:243
irods::experimental::filesystem::path::has_relative_path
auto has_relative_path() const -> bool
Definition: path.hpp:223
irods::experimental::filesystem::path::stem
auto stem() const -> path
Definition: path.cpp:224
irods::experimental::filesystem::client::end
auto end(const collection_iterator &) noexcept -> const collection_iterator
Definition: collection_iterator.hpp:88
irods::experimental::filesystem::client::begin
auto begin(collection_iterator _iter) noexcept -> collection_iterator
Definition: collection_iterator.hpp:83
irods::experimental::filesystem::path::append_separator_if_needed
void append_separator_if_needed(const path &_p)
Definition: path.cpp:285
irods::experimental::filesystem::path::replace_object_name
auto replace_object_name(const path &_replacement={}) -> path &
Definition: path.cpp:71
irods::experimental::filesystem
Definition: collection_entry.hpp:12
irods::experimental::filesystem::operator<<
auto operator<<(std::ostream &_os, const path &_p) -> std::ostream &
Definition: path.cpp:447
irods::experimental::filesystem::path::compare
auto compare(const path &_p) const noexcept -> int
Definition: path.cpp:167
irods::experimental::filesystem::path::preferred_separator
static constexpr value_type preferred_separator
Definition: path.hpp:27
terminate_irods_processes.e
e
Definition: terminate_irods_processes.py:19
irods::experimental::filesystem::path::string_type
std::basic_string< value_type > string_type
Definition: path.hpp:22
irods::experimental::filesystem::path::iterator
Definition: path.hpp:247
irods::experimental::filesystem::path::relative_path
auto relative_path() const -> path
Definition: path.cpp:205
irods::experimental::filesystem::path::iterator::operator++
auto operator++() -> iterator &
Definition: path.cpp:327
irods::experimental::filesystem::path::has_root_collection
auto has_root_collection() const -> bool
Definition: path.hpp:222
irods::experimental::filesystem::path::value_type
char value_type
Definition: path.hpp:21
irods::experimental::filesystem::path::root_collection
auto root_collection() const -> path
Definition: path.cpp:200
irods::join
std::string join(std::vector< std::string > &strs, const std::string &separator)
Definition: irods_serialization.cpp:169
detail.hpp
irods::experimental::filesystem::detail::is_separator
auto is_separator(path::value_type _c) noexcept -> bool
Definition: detail.hpp:28
irods::experimental::filesystem::path::lexically_relative
auto lexically_relative(const path &_base) const -> path
Definition: path.cpp:138
irods::experimental::filesystem::path::rbegin
auto rbegin() const -> reverse_iterator
Definition: path.cpp:275
irods::experimental::filesystem::path::parent_path
auto parent_path() const -> path
Definition: path.cpp:214
irods::experimental::filesystem::lexicographical_compare
auto lexicographical_compare(path::iterator _first1, path::iterator _last1, path::iterator _first2, path::iterator _last2) -> bool
Definition: path.cpp:431
irods::experimental::filesystem::path::lexically_normal
auto lexically_normal() const -> path
Definition: path.cpp:96
path.hpp
irods::experimental::filesystem::path::object_name
auto object_name() const -> path
Definition: path.cpp:219
irods::experimental::filesystem::path::iterator::iterator
iterator()=default