coan  6.0.1
A C/C++ Configuration Analyzer
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
path.h
Go to the documentation of this file.
1 #ifndef PATH_H
2 #define PATH_H
3 #pragma once
4 /***************************************************************************
5  * Copyright (C) 2007-2013 Mike Kinghan, imk@burroingroingjoing.com *
6  * All rights reserved. *
7  * *
8  * Contributed originally by Mike Kinghan, imk@burroingroingjoing.com *
9  * *
10  * Redistribution and use in source and binary forms, with or without *
11  * modification, are permitted provided that the following conditions *
12  * are met: *
13  * *
14  * Redistributions of source code must retain the above copyright *
15  * notice, this list of conditions and the following disclaimer. *
16  * *
17  * Redistributions in binary form must reproduce the above copyright *
18  * notice, this list of conditions and the following disclaimer in the *
19  * documentation and/or other materials provided with the distribution. *
20  * *
21  * Neither the name of Mike Kinghan nor the names of its contributors *
22  * may be used to endorse or promote products derived from this software *
23  * without specific prior written permission. *
24  * *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
32  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED *
33  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,*
34  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
35  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
36  * DAMAGE. *
37  * *
38  **************************************************************************/
39 #include "platform.h"
40 #include <vector>
41 #include <string>
42 #include <stdexcept>
43 
58 template<char Delim>
59 struct path {
60 
61  path() = default;
62 
64  explicit path(std::string const & path)
65  : _path(path) {
66  analyse();
67  }
68 
70  path & operator=(std::string const & str) {
71  cut();
72  _path = str;
73  analyse();
74  posn() = 0;
75  return *this;
76  }
77 
79  bool operator==(path const & other) const {
80  return _path == other._path;
81  }
82 
84  bool operator!=(path const & other) const {
85  return !(_path == other._path);
86  }
87 
89  bool operator<(path const & other) const {
90  return _path < other._path;
91  }
92 
101  size_t elements() const {
102  return _elements.size();
103  }
104 
106  std::string const & str() const {
107  return _path;
108  }
109 
111  size_t length() const {
112  return _path.length();
113  }
114 
122  std::string element(size_t which) const {
123  if (which >= elements()) {
124  throw std::out_of_range("Out of range in path::element(size_t)");
125  }
126  element_pos const & element = _elements[which];
127  return element.second == 0 ?
128  std::string(1,Delim) :
129  _path.substr(element.first,element.second);
130  }
131 
133  std::string cur_element() const {
134  return element(posn());
135  }
136 
138  std::string operator[](size_t which) const {
139  return element(which);
140  }
141 
149  bool is_prefix_of(path const & other) const {
150  path common = common_prefix(*this,other);
151  return *this == common;
152  }
153 
164  std::string
165  segment(size_t start = 0, size_t len = std::string::npos) const {
166  element_pos section = get_section(start,len);
167  return section.first != std::string::npos ?
168  _path.substr(section.first,section.second) : std::string();
169  }
170 
178  void push_back(std::string const & str) {
179  if (length() && _last != Delim) {
180  _path += Delim;
181  }
182  _path += str;
183  analyse();
184  }
185 
187  void pop_back() {
188  size_t parts = elements();
189  if (parts) {
190  size_t cut = _elements[parts - 1].first;
191  cut -= parts-- > 1;
192  _path.erase(cut);
193  analyse();
194  }
195  }
196 
204  void push_front(std::string const & str) {
205  if (_first != Delim) {
206  _path.insert(0,1,Delim);
207  }
208  _path.insert(0,str);
209  analyse();
210  }
211 
213  void pop_front() {
214  size_t parts = elements();
215  if (parts) {
216  size_t start = _elements[0].first;
217  size_t len = _elements[0].second;
218  len += parts-- > 1;
219  _path.erase(start,len);
220  analyse();
221  }
222  }
223 
224 
233  path operator+(std::string const & str) const {
234  path p(*this);
235  p.append(str);
236  return p;
237  }
238 
247  path operator+(path const & rhs) const {
248  return *this + rhs.str();
249  }
250 
252  path & operator+=(std::string const & str) {
253  push_back(str);
254  return *this;
255  }
256 
258  path & operator+=(path const & rhs) {
259  push_back(rhs.str());
260  return *this;
261  }
262 
272  void insert(size_t after,std::string const & str) {
273  if (after < elements() - 1) {
274  element_pos element = _elements[after];
275  after = element.first + element.second + 1;
276  _path.insert(after,str + Delim);
277  analyse();
278  } else {
279  push_back(str);
280  }
281  }
282 
291  void cut(size_t start = 0, size_t len = std::string::npos) {
292  element_pos section = get_section(start,len);
293  if (section.first != std::string::npos) {
294  if (section.first + section.second < _path.length()) {
295  ++section.second;
296  } else if (section.first > 0) {
297  --section.first;
298  }
299  _path.erase(section.first,section.second);
300  analyse();
301  }
302  }
303 
309  void rectify() {
310  std::string match(2,Delim);
311  for (size_t posn ; (posn = _path.find(match)) != std::string::npos; ) {
312  _path.erase(posn + 1);
313  }
314  size_t len = _path.length();
315  if (len > 1 && _path[len - 1] == Delim) {
316  _path.resize(len - 1);
317  }
318  analyse();
319  }
320 
322 
333  int & posn() {
334  return _cursor;
335  }
336  int const & posn() const {
337  return _cursor;
338  }
340 
344  int to_end() {
345  _cursor = elements() ? elements() - 1 : 0;
346  return _cursor;
347  }
348 
356  static path common_prefix(path const & lhs, path const & rhs) {
357  size_t count = std::min(lhs.elements(),rhs.elements());
358  path p;
359  for (size_t ndx = 0; ndx < count; ++ndx) {
360  if (rhs[ndx] == lhs[ndx]) {
361  p += rhs[ndx];
362  }
363  }
364  return p;
365  }
366 
367 private:
368 
374  using element_pos = std::pair<size_t,size_t>;
375 
377  void analyse() {
378  _elements.resize(0);
379  size_t start = 0;
380  size_t end;
381  for ( ; (end = _path.find(Delim,start)) != std::string::npos;
382  start = end + 1) {
383  _elements.push_back(element_pos(start,end - start));
384  }
385  if (start < _path.length()) {
386  _elements.push_back(element_pos(start,_path.length() - start));
387  }
388  if (_path.length()) {
389  _first = _path[0];
390  _last = _path[_path.length() - 1];
391  } else {
392  _first = _last = 0;
393  }
394  if (_cursor >= elements()) {
395  to_end();
396  }
397  }
398 
406  get_section(size_t start, size_t len = std::string::npos) const {
407  if (len && start < elements()) {
408  len = std::min(len,_path.length() - start);
409  element_pos const & first = _elements[start];
410  if (start + len <= elements()) {
411  element_pos const & last = _elements[(start + len) - 1];
412  len = (last.first + last.second) - first.first;
413  return len ?
414  element_pos(first.first,len) : element_pos(first.first,1);
415  }
416  return element_pos(first.first,len);
417  }
418  return element_pos(std::string::npos,std::string::npos);
419  }
420 
422  std::string _path;
424  std::vector<element_pos> _elements;
426  int _cursor = 0;
428  char _first = 0;
430  char _last = 0;
431 };
432 
443 template<char Delim>
444 path<Delim> operator+(std::string const & str, path<Delim> const & path)
445 {
446  return path<Delim>(str) + path;
447 }
448 
451 
452 
453 #endif /* EOF*/
path< Delim > operator+(std::string const &str, path< Delim > const &path)
Get a path by concatenation of a string with a path.
Definition: path.h:444
std::string _path
The string representation of the path.
Definition: path.h:422
size_t length() const
Get the length of the path.
Definition: path.h:111
bool operator==(path const &other) const
Equality.
Definition: path.h:79
int _cursor
The cursor of the path.
Definition: path.h:426
std::pair< size_t, size_t > element_pos
Type of an element or section locator in a path.
Definition: path.h:374
path & operator+=(path const &rhs)
operator+=(path) is equivalent to push_back(path.str())
Definition: path.h:258
std::string segment(size_t start=0, size_t len=std::string::npos) const
Get a sub-sequence of the path's elements as a string.
Definition: path.h:165
int to_end()
Set the cursor to index the final element, or to 0 if the path is empty.
Definition: path.h:344
void pop_front()
Remove the first element of the path, if any.
Definition: path.h:213
std::vector< element_pos > _elements
The structure of the path as a sequence of element_pos.
Definition: path.h:424
path operator+(std::string const &str) const
Get the concatenation of the path with a string.
Definition: path.h:233
void rectify()
Correct anomalies in the path.
Definition: path.h:309
std::string const & str() const
Get the path as a string.
Definition: path.h:106
char _first
The first character of the path.
Definition: path.h:428
bool operator<(path const &other) const
Less-than operator.
Definition: path.h:89
void pop_back()
Remove the last element of the path, if any.
Definition: path.h:187
bool operator!=(path const &other) const
Inequality.
Definition: path.h:84
std::string operator[](size_t which) const
The subscript operator is equivalent to element(which)
Definition: path.h:138
path & operator+=(std::string const &str)
operator+=(str) is equivalent to push_back(str)
Definition: path.h:252
void analyse()
Analyse the path to determine its composition.
Definition: path.h:377
bool is_prefix_of(path const &other) const
Say whether the path consists of an initial subsequence of the elements of another.
Definition: path.h:149
std::string cur_element() const
Get the path element at the cursor.
Definition: path.h:133
void insert(size_t after, std::string const &str)
Insert a string into the path.
Definition: path.h:272
void push_front(std::string const &str)
Prepend a string to the path.
Definition: path.h:204
static path common_prefix(path const &lhs, path const &rhs)
Get the common initial prefix of two paths.
Definition: path.h:356
element_pos get_section(size_t start, size_t len=std::string::npos) const
Get the location of a section of the path.
Definition: path.h:406
size_t elements() const
Get the number of elements in the path
Definition: path.h:101
void push_back(std::string const &str)
Append a string to the path.
Definition: path.h:178
Encapsulates a filesystem path.
Definition: path.h:59
path & operator=(std::string const &str)
Assign from a string.
Definition: path.h:70
char _last
The last character of the path.
Definition: path.h:430
path(std::string const &path)
Explicitly construct a path from a string.
Definition: path.h:64
path operator+(path const &rhs) const
Get the concatenation of the path with another.
Definition: path.h:247
std::string element(size_t which) const
Return a path element by index.
Definition: path.h:122
void cut(size_t start=0, size_t len=std::string::npos)
Remove a segment from the path.
Definition: path.h:291
int & posn()
Get a [const] reference to the path's cursor.
Definition: path.h:333