if(path.size()==1 && path[0]==DIRSEP)
return 1;
- unsigned count = 1;
- for(string::const_iterator i=path.begin(); i!=path.end(); ++i)
- if(*i==DIRSEP) ++count;
- return count;
+ return separators.size()+1;
}
bool Path::is_absolute() const
{
// Replace the path with the root directory
#ifdef WIN32
- unsigned slash = path.find(DIRSEP);
+ string::size_type slash = (separators.empty() ? string::npos : separators.front());
if(is_windows_drive(path.substr(0, slash)))
+ {
path = path.substr(0, 2);
+ separators.clear();
+ }
else
#endif
- path = comp;
+ {
+ path = comp;
+ separators.clear();
+ separators.push_back(0);
+ }
}
#ifdef WIN32
else if(is_windows_drive(comp))
+ {
path = comp;
+ separators.clear();
+ }
#endif
else if(comp=="..")
{
#endif
else
{
- string::size_type slash = path.rfind(DIRSEP);
- string::size_type start = (slash==string::npos ? 0 : slash+1);
+ string::size_type start = (separators.empty() ? 0 : separators.back()+1);
if(!path.compare(start, string::npos, ".."))
{
// If the last component already is a .., add another
+ separators.push_back(path.size());
path += DIRSEP;
path += comp;
}
- else if(slash==string::npos)
+ else if(separators.empty())
path = ".";
else
{
- if(slash==0)
- slash = 1;
// Otherwise, erase the last component
- path.erase(slash, string::npos);
+ path.erase(separators.back(), string::npos);
+ separators.pop_back();
}
}
}
if(comp!="." && path.empty())
path = ".";
if(path.size()>1 || (path.size()==1 && path[0]!=DIRSEP))
+ {
+ separators.push_back(path.size());
path += DIRSEP;
+ }
path += comp;
}
}
#endif
}
-Path::Iterator Path::begin() const
-{
- return Iterator(*this);
-}
-Path::Iterator Path::end() const
-{
- Iterator i(*this);
- i.start = i.end = std::string::npos;
- return i;
-}
-
-
-Path::Iterator::Iterator(const Path &p):
+Path::Iterator::Iterator(const Path &p, bool e):
path(&p),
- start(0)
-{
- if(path->path.empty())
- start = end = string::npos;
- else if(path->path[0]==DIRSEP)
- end = 1;
-#ifdef WIN32
- else if(path->path.size()>2 && path->path[2]==DIRSEP && is_windows_drive(path->path.substr(0, 2)))
- end = 2;
-#endif
- else
- end = path->path.find(DIRSEP);
-}
+ iter(e ? path->separators.end() : path->separators.begin()),
+ end(e || path->path.empty())
+{ }
Path::Iterator &Path::Iterator::operator++()
{
- start = end;
- if(start>=path->path.size())
- return *this;
- if(path->path[start]==DIRSEP)
- ++start;
- end = path->path.find(DIRSEP, start);
+ if(iter==path->separators.end())
+ end = true;
+ else
+ {
+ ++iter;
+ if(path->path.size()==1 && path->separators.size()==1)
+ end = true;
+ }
return *this;
}
Path::Iterator &Path::Iterator::operator--()
{
- if(start==0)
- return *this;
-
- end = start;
- if(end>1 && end<path->path.size() && path->path[end]!=DIRSEP)
- --end;
-
- start = path->path.rfind(DIRSEP, end-1);
- if(start==string::npos)
- start = 0;
- else if(start<end-1)
- ++start;
-
+ if(end)
+ {
+ end = false;
+ if(path->path.size()==1 && path->separators.size()==1)
+ --iter;
+ }
+ else if(iter!=path->separators.begin())
+ --iter;
return *this;
}
string Path::Iterator::operator*() const
{
- if(start>=path->path.size())
- return string();
- if(start==end)
- return string();
- return path->path.substr(start, end-start);
+ if(end)
+ throw logic_error("Path::Iterator::operator*");
+
+ string::size_type start = 0;
+ if(iter!=path->separators.begin())
+ {
+ PositionArray::const_iterator prev = iter;
+ start = *--prev+1;
+ }
+
+ string::size_type slash = string::npos;
+ if(iter!=path->separators.end())
+ slash = *iter;
+
+ if(slash==0)
+ return path->path.substr(start, 1);
+ return path->path.substr(start, slash-start);
}
} // namespace FS
#include <ostream>
#include <string>
+#include <vector>
namespace Msp {
namespace FS {
*/
class Path
{
+private:
+ typedef std::vector<std::string::size_type> PositionArray;
+
public:
class Iterator
{
- friend class Path;
-
private:
const Path *path;
- std::string::size_type start, end;
+ PositionArray::const_iterator iter;
+ bool end;
- Iterator(const Path &);
+ Iterator(const Path &, bool = false);
public:
+ static Iterator at_begin(const Path &p) { return Iterator(p); }
+ static Iterator at_end(const Path &p) { return Iterator(p, true); }
+
Iterator &operator++();
Iterator &operator--();
std::string operator*() const;
- bool operator==(const Iterator &i) const { return (start==i.start && end==i.end); }
+ bool operator==(const Iterator &i) const { return (iter==i.iter && end==i.end); }
bool operator!=(const Iterator &i) const { return !(*this==i); }
};
private:
std::string path;
+ std::vector<std::string::size_type> separators;
public:
Path();
bool operator>=(const Path &other) const { return !(*this<other); }
bool operator!=(const Path &other) const { return !(*this==other); }
- Iterator begin() const;
- Iterator end() const;
+ Iterator begin() const { return Iterator::at_begin(*this); }
+ Iterator end() const { return Iterator::at_end(*this); }
};
inline std::ostream &operator<<(std::ostream &o, const Path &p) { o<<p.str(); return o; }