aboutsummaryrefslogtreecommitdiff
path: root/butl/path
diff options
context:
space:
mode:
Diffstat (limited to 'butl/path')
-rw-r--r--butl/path1136
1 files changed, 0 insertions, 1136 deletions
diff --git a/butl/path b/butl/path
deleted file mode 100644
index 6d054d5..0000000
--- a/butl/path
+++ /dev/null
@@ -1,1136 +0,0 @@
-// file : butl/path -*- C++ -*-
-// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#ifndef BUTL_PATH
-#define BUTL_PATH
-
-#include <string>
-#include <cstddef> // ptrdiff_t
-#include <utility> // move(), swap()
-#include <iterator>
-#include <exception>
-#include <functional> // hash
-
-#include <butl/export>
-
-#include <butl/utility>
-
-namespace butl
-{
- // Wish list/ideas for improvements.
- //
- // - Ability to convert to directory/leaf/base in-place, without dynamic
- // allocation. One idea is something like this:
- //
- // p -= "/*"; // directory
- // p -= "*/"; // leaf
- // p -= ".*"; // base
- //
- // - Faster normalize() implementation. In many cases (e.g., in build2)
- // the path is either already normal or the difference is just slashes
- // (i.e., there are no '.' or '..' components). So a fast path case
- // might be in order.
- //
- // - We duplicate the interface for path and dir_path while most of it
- // is common. Also, we can implicit-cast dir_path& to path& and use
- // non-dir-adapted implementation (see where we call K::cast()).
- //
-
- struct LIBBUTL_EXPORT invalid_path_base: public std::exception
- {
- virtual char const*
- what () const throw ();
- };
-
- template <typename C>
- struct invalid_basic_path: invalid_path_base
- {
- using string_type = std::basic_string<C>;
-
- string_type path;
-
- invalid_basic_path (const C* p): path (p) {}
- invalid_basic_path (const string_type& p): path (p) {}
- };
-
- template <typename C>
- struct path_traits
- {
- using string_type = std::basic_string<C>;
- using size_type = typename string_type::size_type;
-
- // Canonical directory and path seperators.
- //
-#ifdef _WIN32
- static const C directory_separator = '\\';
- static const C path_separator = ';';
-#else
- static C const directory_separator = '/';
- static C const path_separator = ':';
-#endif
-
- // Canonical and alternative directory separators. Canonical should be
- // first.
- //
-#ifdef _WIN32
- static constexpr const char* const directory_separators = "\\/";
-#else
- static constexpr const char* const directory_separators = "/";
-#endif
-
- // Directory separator tests. On some platforms there could be multiple
- // seperators. For example, on Windows we check for both '/' and '\'.
- //
- static bool
- is_separator (C c)
- {
-#ifdef _WIN32
- return c == '\\' || c == '/';
-#else
- return c == '/';
-#endif
- }
-
- // Return 1-based index in directory_separators string or 0 if not a
- // separator.
- //
- static size_type
- separator_index (C c)
- {
-#ifdef _WIN32
- return c == '\\' ? 1 : c == '/' ? 2 : 0;
-#else
- return c == '/' ? 1 : 0;
-#endif
- }
-
- static bool
- absolute (const string_type& s)
- {
- return absolute (s.c_str (), s.size ());
- }
-
- static bool
- absolute (const C* s, size_type n)
- {
-#ifdef _WIN32
- return n > 1 && s[1] == ':';
-#else
- return n != 0 && is_separator (s[0]);
-#endif
- }
-
- static bool
- current (const string_type& s)
- {
- return current (s.c_str (), s.size ());
- }
-
- static bool
- current (const C* s, size_type n)
- {
- return n == 1 && s[0] == '.';
- }
-
- static bool
- parent (const string_type& s)
- {
- return parent (s.c_str (), s.size ());
- }
-
- static bool
- parent (const C* s, size_type n)
- {
- return n == 2 && s[0] == '.' && s[1] == '.';
- }
-
- static bool
- root (const string_type& s)
- {
- return root (s.c_str (), s.size ());
- }
-
- static bool
- root (const C* s, size_type n)
- {
-#ifdef _WIN32
- return n == 2 && s[1] == ':';
-#else
- return n == 1 && is_separator (s[0]);
-#endif
- }
-
- static size_type
- find_separator (string_type const& s,
- size_type pos = 0,
- size_type n = string_type::npos)
- {
- if (n == string_type::npos)
- n = s.size ();
-
- const C* r (find_separator (s.c_str () + pos, n - pos));
- return r != nullptr ? r - s.c_str () : string_type::npos;
- }
-
- static const C*
- find_separator (const C* s, size_type n)
- {
- for (const C* e (s + n); s != e; ++s)
- {
- if (is_separator (*s))
- return s;
- }
-
- return nullptr;
- }
-
- static size_type
- rfind_separator (string_type const& s, size_type pos = string_type::npos)
- {
- if (pos == string_type::npos)
- pos = s.size ();
- else
- pos++;
-
- const C* r (rfind_separator (s.c_str (), pos));
- return r != nullptr ? r - s.c_str () : string_type::npos;
- }
-
- static const C*
- rfind_separator (const C* s, size_type n)
- {
- for (; n != 0; --n)
- {
- if (is_separator (s[n - 1]))
- return s + n - 1;
- }
-
- return nullptr;
- }
-
- // Return the position of '.' or npos if there is no extension.
- //
- static size_type
- find_extension (string_type const& s)
- {
- const C* r (find_extension (s.c_str (), s.size ()));
- return r != nullptr ? r - s.c_str () : string_type::npos;
- }
-
- static const C*
- find_extension (const C* s, size_type n)
- {
- size_type i (n);
-
- for (; i > 0; --i)
- {
- C c (s[i - 1]);
-
- if (c == '.')
- break;
-
- if (is_separator (c))
- {
- i = 0;
- break;
- }
- }
-
- // Weed out paths like ".txt" (and "/.txt") and "txt.".
- //
- if (i > 1 && !is_separator (s[i - 2]) && i != n)
- return s + i - 1;
- else
- return nullptr;
- }
-
- // Return the start of the leaf (last path component) in the path. Note
- // that the leaf will include the trailing separator, if any (i.e., the
- // leaf of /tmp/bar/ is bar/).
- //
- static size_type
- find_leaf (string_type const& s)
- {
- const C* r (find_leaf (s.c_str (), s.size ()));
- return r != nullptr ? r - s.c_str () : string_type::npos;
- }
-
- static const C*
- find_leaf (const C* s, size_type n)
- {
- const C* p;
- return n == 0
- ? nullptr
- : (p = rfind_separator (s, n - 1)) == nullptr ? s : ++p;
- }
-
- static int
- compare (string_type const& l, string_type const& r)
- {
- return compare (l.c_str (), l.size (), r.c_str (), r.size ());
- }
-
- // @@ Currently for case-insensitive filesystems (Windows) compare()
- // works properly only for ASCII.
- //
- static int
- compare (const C* l, size_type ln, const C* r, size_type rn)
- {
- for (size_type i (0), n (ln < rn ? ln : rn); i != n; ++i)
- {
-#ifdef _WIN32
- C lc (lcase (l[i])), rc (lcase (r[i]));
-#else
- C lc (l[i]), rc (r[i]);
-#endif
- if (is_separator (lc) && is_separator (rc))
- continue;
-
- if (lc < rc) return -1;
- if (lc > rc) return 1;
- }
-
- return ln < rn ? -1 : (ln > rn ? 1 : 0);
- }
-
- static void
- canonicalize (string_type& s)
- {
- //canonicalize (s.data (), s.size ()); // C++17
-
- for (size_t i (0), n (s.size ()); i != n; ++i)
- if (is_separator (s[i]) && s[i] != directory_separator)
- s[i] = directory_separator;
- }
-
- static void
- canonicalize (C* s, size_type n)
- {
- for (const C* e (s + n); s != e; ++s)
- if (is_separator (*s) && *s != directory_separator)
- *s = directory_separator;
- }
-
- // Get/set current working directory. Throw std::system_error to report
- // the underlying OS errors.
- //
- static string_type
- current_directory ();
-
- static void
- current_directory (string_type const&);
-
- // Return the user home directory. Throw std::system_error to report the
- // underlying OS errors.
- //
- static string_type
- home_directory ();
-
- // Return the temporary directory. Throw std::system_error to report the
- // underlying OS errors.
- //
- static string_type
- temp_directory ();
-
- // Return a temporary name. The name is constructed by starting with the
- // prefix followed by the process id following by a unique counter value
- // inside the process (MT-safe). Throw std::system_error to report the
- // underlying OS errors.
- //
- static string_type
- temp_name (string_type const& prefix);
-
- // Make the path real (by calling realpath(3)). Throw invalid_basic_path
- // if the path is invalid (e.g., some components do not exist) and
- // std::system_error to report other underlying OS errors.
- //
-#ifndef _WIN32
- static void
- realize (string_type&);
-#endif
-
- // Utilities.
- //
-#ifdef _WIN32
- static C
- tolower (C);
-
- static C
- toupper (C);
-#endif
- };
-
- // This implementation of a filesystem path has two types: path, which can
- // represent any path (file, directory, etc.) and dir_path, which is derived
- // from path. The internal representation of directories maintains a
- // trailing slash. However, it is ignored in path comparison, size, and
- // string spelling. For example:
- //
- // path p1 ("foo"); // File path.
- // path p2 ("bar/"); // Directory path.
- //
- // path p3 (p1 / p2); // Throw: p1 is not a directory.
- // path p4 (p2 / p1); // Ok, file "bar/foo".
- // path p5 (p2 / p2); // Ok, directory "bar/bar/".
- //
- // dir_path d1 ("foo"); // Directory path "foo/".
- // dir_path d2 ("bar\\"); // Directory path "bar\".
- //
- // dir_path d3 (d2 / d1); // "bar\\foo/"
- //
- // (p4 == d3); // true
- // d3.string (); // "bar\\foo"
- // d3.representation (); // "bar\\foo/"
- //
- template <typename C, typename K>
- class basic_path;
-
- template <typename C> struct any_path_kind;
- template <typename C> struct dir_path_kind;
-
- using path = basic_path<char, any_path_kind<char>>;
- using dir_path = basic_path<char, dir_path_kind<char>>;
- using invalid_path = invalid_basic_path<char>;
-
- // Cast from one path kind to another. Note that no checking is performed
- // (e.g., that there is a trailing slash if casting to dir_path) but the
- // representation is adjusted if necessary (e.g., the trailing slash is
- // added to dir_path if missing).
- //
- template <class P, class C, class K> P path_cast (const basic_path<C, K>&);
- template <class P, class C, class K> P path_cast (basic_path<C, K>&&);
-
- // Low-level path data storage. It is also by the implementation to pass
- // around initialized/valid paths.
- //
- template <typename C>
- struct path_data
- {
- using string_type = std::basic_string<C>;
- using size_type = typename string_type::size_type;
- using difference_type = typename string_type::difference_type;
-
- // The idea is as follows: path_ is always the "traditional" form; that
- // is, "/" for the root directory and "/tmp" (no trailing slash) for the
- // rest. This means we can return/store references to path_.
- //
- // Then we have tsep_ ("trailing separator") which is the size difference
- // between path_ and its "pure" part, that is, without any trailing
- // slashes, even for "/". So:
- //
- // tsep_ == -1 -- trailing slash in path_ (the "/" case)
- // tsep_ == 0 -- no trailing slash
- //
- // Finally, to represent non-root ("/") trailing slashes we use positive
- // tsep_ values. In this case tsep_ is interpreted as a 1-based index in
- // the path_traits::directory_separators string.
- //
- // Notes:
- // - If path_ is empty, then tsep_ can only be 0.
- // - We could have used a much narrower integer for tsep_.
- //
- string_type path_;
- difference_type tsep_;
-
- size_type
- _size () const {return path_.size () + (tsep_ < 0 ? -1 : 0);}
-
- void
- _swap (path_data& d) {path_.swap (d.path_); std::swap (tsep_, d.tsep_);}
-
- void
- _clear () {path_.clear (); tsep_ = 0;}
-
- // Constructors.
- //
- path_data (): tsep_ (0) {}
-
- path_data (string_type&& p, difference_type ts)
- : path_ (std::move (p)), tsep_ (path_.empty () ? 0 : ts) {}
-
- explicit
- path_data (string_type&& p)
- : path_ (std::move (p)), tsep_ (0)
- {
- size_type n (path_.size ()), i;
-
- if (n != 0 && (i = path_traits<C>::separator_index (path_[n - 1])) != 0)
- {
- if (n == 1) // The "/" case.
- tsep_ = -1;
- else
- {
- tsep_ = i;
- path_.pop_back ();
- }
- }
- }
- };
-
- template <typename C>
- struct any_path_kind
- {
- class base_type: protected path_data<C> // In essence protected path_data.
- {
- protected:
- using path_data<C>::path_data;
-
- base_type () = default;
- base_type (path_data<C>&& d): path_data<C> (std::move (d)) {}
- };
-
- using dir_type = basic_path<C, dir_path_kind<C>>;
-
- // Init and cast.
- //
- // If exact is true, return the path if the initialization was successful,
- // that is, the passed string is a valid path and no modifications were
- // necessary. Otherwise, return the empty object and leave the passed
- // string untouched.
- //
- // If extact is false, throw invalid_path if the string is not a valid
- // path (e.g., uses an unsupported path notation on Windows).
- //
- using data_type = path_data<C>;
- using string_type = std::basic_string<C>;
-
- static data_type
- init (string_type&&, bool exact = false);
-
- static void
- cast (data_type&) {}
- };
-
- template <typename C>
- struct dir_path_kind
- {
- using base_type = basic_path<C, any_path_kind<C>>;
- using dir_type = basic_path<C, dir_path_kind<C>>;
-
- // Init and cast.
- //
- using data_type = path_data<C>;
- using string_type = std::basic_string<C>;
-
- static data_type
- init (string_type&&, bool exact = false);
-
- static void
- cast (data_type&);
- };
-
- template <typename C, typename K>
- class basic_path: public K::base_type
- {
- public:
- using string_type = std::basic_string<C>;
- using size_type = typename string_type::size_type;
- using difference_type = typename string_type::difference_type;
- using traits = path_traits<C>;
-
- struct iterator;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using base_type = typename K::base_type;
- using dir_type = typename K::dir_type;
-
- // Create a special empty path. Note that we have to provide our own
- // implementation rather than using '=default' to make clang allow
- // default-initialized const instances of this type.
- //
- basic_path () {}
-
- // Constructors that initialize a path from a string argument throw the
- // invalid_path exception if the string is not a valid path (e.g., uses
- // unsupported path notations on Windows).
- //
- explicit
- basic_path (C const* s): base_type (K::init (s)) {}
-
- basic_path (C const* s, size_type n)
- : base_type (K::init (string_type (s, n))) {}
-
- explicit
- basic_path (string_type s): base_type (K::init (std::move (s))) {}
-
- basic_path (const string_type& s, size_type n)
- : base_type (K::init (string_type (s, 0, n))) {}
-
- basic_path (const string_type& s, size_type p, size_type n)
- : base_type (K::init (string_type (s, p, n))) {}
-
- // Create a path using the exact string representation. If the string is
- // not a valid path or if it would require a modification, then empty path
- // is created instead and the passed string rvalue-reference is left
- // untouched. Note that no exception is thrown if the path is invalid. See
- // also representation()&& below.
- //
- enum exact_type {exact};
- basic_path (string_type&& s, exact_type)
- : base_type (K::init (std::move (s), true)) {}
-
- // Create a path as a sub-path identified by the [begin, end) range of
- // components.
- //
- basic_path (const iterator& begin, const iterator& end);
-
- basic_path (const reverse_iterator& rbegin, const reverse_iterator& rend)
- : basic_path (rend.base (), rbegin.base ()) {}
-
- void
- swap (basic_path& p) {this->_swap (p);}
-
- void
- clear () {this->_clear ();}
-
- // Get/set current working directory. Throw std::system_error to report
- // the underlying OS errors.
- //
- static dir_type
- current_directory () {return dir_type (traits::current_directory ());}
-
- static void
- current_directory (basic_path const&);
-
- // Return the user home directory. Throw std::system_error to report the
- // underlying OS errors.
- //
- static dir_type
- home_directory () {return dir_type (traits::home_directory ());}
-
- // Return the temporary directory. Throw std::system_error to report the
- // underlying OS errors.
- //
- static dir_type
- temp_directory () {return dir_type (traits::temp_directory ());}
-
- // Return a temporary path. The path is constructed by starting with the
- // temporary directory and then appending a path component consisting of
- // the prefix followed by the process id following by a unique counter
- // value inside the process. Throw std::system_error to report the
- // underlying OS errors.
- //
- static basic_path
- temp_path (const string_type& prefix)
- {
- return temp_directory () / traits::temp_name (prefix);
- }
-
- public:
- bool
- empty () const {return this->path_.empty ();}
-
- // Note that size does not include the trailing separator except for
- // the root case.
- //
- size_type
- size () const {return this->path_.size ();}
-
- // Return true if this path doesn't have any directories. Note that "/foo"
- // is not a simple path (it is "foo" in root directory) while "/" is (it
- // is the root directory).
- //
- bool
- simple () const;
-
- bool
- absolute () const;
-
- bool
- relative () const {return !absolute ();}
-
- bool
- root () const;
-
- // The following predicates return true for the "." and ".." paths,
- // respectively. Note that the result doesn't depend on the presence or
- // spelling of the trailing directory separator.
- //
- // Also note that the path must literally match the specified values rather
- // than be semantically current or parent. For example for paths "foo/.."
- // or "bar/../.." the predicates return false.
- //
- bool
- current () const;
-
- bool
- parent () const;
-
- // Test, based on the presence/absence of the trailing separator, if the
- // path is to a directory.
- //
- bool
- to_directory () const {return this->tsep_ != 0;}
-
- // Return true if *this is a sub-path of the specified path (i.e.,
- // the specified path is a prefix). Expects both paths to be
- // normalized. Note that this function returns true if the paths
- // are equal. Empty path is considered a prefix of any path.
- //
- bool
- sub (const basic_path&) const;
-
- // Return true if *this is a super-path of the specified path (i.e.,
- // the specified path is a suffix). Expects both paths to be
- // normalized. Note that this function returns true if the paths
- // are equal. Empty path is considered a suffix of any path.
- //
- bool
- sup (const basic_path&) const;
-
- public:
- // Return the path without the directory part. Leaf of a directory is
- // itself a directory (contains trailing slash). Leaf of a root is the
- // path itself.
- //
- basic_path
- leaf () const;
-
- // Return the path without the specified directory part. Throws
- // invalid_path if the directory is not a prefix of *this. Expects both
- // paths to be normalized.
- //
- basic_path
- leaf (basic_path const&) const;
-
- // Return the directory part of the path or empty path if there is no
- // directory. Directory of a root is an empty path.
- //
- dir_type
- directory () const;
-
- // Return the directory part of the path without the specified leaf part.
- // Throws invalid_path if the leaf is not a suffix of *this. Expects both
- // paths to be normalized.
- //
- dir_type
- directory (basic_path const&) const;
-
- // Return the root directory of the path or empty path if the directory is
- // not absolute.
- //
- dir_type
- root_directory () const;
-
- // Return the path without the extension, if any.
- //
- basic_path
- base () const;
-
- // Return the extension or NULL if not present. If not empty, then the
- // result starts with the character past the dot.
- //
- string_type
- extension () const;
-
- // Return the in-place pointer to extension or NULL if not present. If not
- // NULL, then the result points to the character past the dot but it is
- // legal to decrement it once to obtain the value with the dot.
- //
- const C*
- extension_cstring () const;
-
- // Return a path relative to the specified path that is equivalent
- // to *this. Throws invalid_path if a relative path cannot be derived
- // (e.g., paths are on different drives on Windows).
- //
- basic_path
- relative (basic_path) const;
-
- // Iteration over path components.
- //
- public:
- struct iterator
- {
- using value_type = string_type ;
- using pointer = string_type*;
- using reference = string_type ;
- using size_type = typename string_type::size_type;
- using difference_type = std::ptrdiff_t ;
- using iterator_category = std::bidirectional_iterator_tag ;
-
- using data_type = path_data<C>;
-
- iterator (): p_ (nullptr) {}
- iterator (const data_type* p, size_type b, size_type e)
- : p_ (p), b_ (b), e_ (e) {}
-
- iterator&
- operator++ ()
- {
- const string_type& s (p_->path_);
-
- // Position past trailing separator, if any.
- //
- b_ = e_ != string_type::npos && ++e_ != s.size ()
- ? e_
- : string_type::npos;
-
- // Find next trailing separator.
- //
- e_ = b_ != string_type::npos ? traits::find_separator (s, b_) : b_;
-
- return *this;
- }
-
- iterator&
- operator-- ()
- {
- const string_type& s (p_->path_);
-
- // Find the new end.
- //
- e_ = b_ == string_type::npos // Past end?
- ? (traits::is_separator (s.back ()) // Have trailing slash?
- ? s.size () - 1
- : string_type::npos)
- : b_ - 1;
-
- // Find the new begin.
- //
- b_ = e_ == 0 // Empty component?
- ? string_type::npos
- : traits::rfind_separator (s, e_ != string_type::npos ? e_ - 1 : e_);
-
- b_ = b_ == string_type::npos // First component?
- ? 0
- : b_ + 1;
-
- return *this;
- }
-
- iterator
- operator++ (int) {iterator r (*this); operator++ (); return r;}
-
- iterator
- operator-- (int) {iterator r (*this); operator-- (); return r;}
-
- string_type
- operator* () const
- {
- return string_type (p_->path_,
- b_,
- e_ != string_type::npos ? e_ - b_ : e_);
- }
-
- // Return the directory separator after this component or '\0' if there
- // is none. This, for example, can be used to determine if the last
- // component is a directory.
- //
- C
- separator () const
- {
- return e_ != string_type::npos
- ? p_->path_[e_]
- : (p_->tsep_ > 0
- ? path_traits<C>::directory_separators[p_->tsep_ - 1]
- : 0);
- }
-
- pointer operator-> () const = delete;
-
- friend bool
- operator== (const iterator& x, const iterator& y)
- {
- return x.p_ == y.p_ && x.b_ == y.b_ && x.e_ == y.e_;
- }
-
- friend bool
- operator!= (const iterator& x, const iterator& y) {return !(x == y);}
-
- private:
- friend class basic_path;
-
- // b - first character of component
- // e - separator after component (or npos if none)
- // b == npos && e == npos - one past last component (end)
- //
- const data_type* p_;
- size_type b_;
- size_type e_;
- };
-
- iterator begin () const;
- iterator end () const;
-
- reverse_iterator rbegin () const {return reverse_iterator (end ());}
- reverse_iterator rend () const {return reverse_iterator (begin ());}
-
- public:
- // Canonicalize the path and return *this. Canonicalization involves
- // converting all directory separators to the canonical form. Note that
- // multiple directory separators are not collapsed.
- //
- basic_path&
- canonicalize ();
-
- // Normalize the path and return *this. Normalization involves collapsing
- // the '.' and '..' directories if possible, collapsing multiple
- // directory separators, and converting all directory separators to the
- // canonical form. If cur_empty is true then collapse relative paths
- // representing the current directory (for example, '.', './', 'foo/..')
- // to an empty path. Otherwise convert it to the canonical form (./ on
- // POSIX systems). Note that a non-empty path cannot become an empty one
- // in the latter case.
- //
- // If actual is true, then for case-insensitive filesystems obtain the
- // actual spelling of the path. Only an absolute path can be actualized.
- // If a path component does not exist, then its (and all subsequent)
- // spelling is unchanged. This is a potentially expensive operation.
- // Normally one can assume that "well-known" directories (current, home,
- // etc.) are returned in their actual spelling.
- //
- basic_path&
- normalize (bool actual = false, bool cur_empty = false);
-
- // Make the path absolute using the current directory unless it is already
- // absolute. Return *this.
- //
- basic_path&
- complete ();
-
- // Make the path real, that is, absolute, normalized, and with resolved
- // symlinks. On POSIX systems this is accomplished with the call to
- // realpath(3). On Windows -- complete() and normalize(). Return *this.
- //
- basic_path&
- realize ();
-
- public:
- basic_path&
- operator/= (basic_path const&);
-
- // Combine a single path component (must not contain directory separators)
- // as a string, without first constructing the path object.
- //
- basic_path&
- operator/= (string_type const&);
-
- basic_path&
- operator/= (const C*);
-
- // Append to the end of the path (normally an extension, etc).
- //
- basic_path&
- operator+= (string_type const&);
-
- basic_path&
- operator+= (const C*);
-
- basic_path&
- operator+= (C);
-
- void
- append (const C*, size_type);
-
- // Note that comparison is case-insensitive if the filesystem is not
- // case-sensitive (e.g., Windows). And it ignored trailing slashes
- // except for the root case.
- //
- template <typename K1>
- int
- compare (const basic_path<C, K1>& x) const {
- return traits::compare (this->path_, x.path_);}
-
- public:
- // Path string and representation. The string does not contain the
- // trailing slash except for the root case. In other words, it is the
- // "traditional" spelling of the path that can be passed to system calls,
- // etc. Representation, on the other hand is the "precise" spelling that
- // includes the trailing slash, if any. One cannot always round-trip a
- // path using string() but can using representation(). Note also that
- // representation() returns a copy while string() returns a (tracking)
- // reference.
- //
- const string_type&
- string () const& {return this->path_;}
-
- string_type
- representation () const&;
-
- // Moves the underlying path string out of the path object. The path
- // object becomes empty. Usage: std::move (p).string ().
- //
- string_type
- string () && {string_type r; r.swap (this->path_); return r;}
-
- string_type
- representation () &&;
-
- // Trailing directory separator or '\0' if there is none.
- //
- C
- separator () const;
-
- // As above but return it as a (potentially empty) string.
- //
- string_type
- separator_string () const;
-
- // If possible, return a POSIX version of the path. For example, for a
- // Windows path in the form foo\bar this function will return foo/bar. If
- // it is not possible to create a POSIX version for this path (e.g.,
- // c:\foo), this function will throw the invalid_path exception.
- //
- string_type
- posix_string () const&;
-
- string_type
- posix_representation () const&;
-
- string_type
- posix_string () &&;
-
- string_type
- posix_representation () &&;
-
- // Implementation details.
- //
- protected:
- using data_type = path_data<C>;
-
- // Direct initialization without init()/cast().
- //
- explicit
- basic_path (data_type&& d): base_type (std::move (d)) {}
-
- using base_type::_size;
-
- // Common implementation for operator/= and operator+=.
- //
- void
- combine (const C*, size_type, difference_type);
-
- void
- combine (const C*, size_type);
-
- // Friends.
- //
- template <class C1, class K1>
- friend class basic_path;
-
- template <class C1, class K1, class K2>
- friend basic_path<C1, K1>
- path_cast_impl (const basic_path<C1, K2>&, basic_path<C1, K1>*);
-
- template <class C1, class K1, class K2>
- friend basic_path<C1, K1>
- path_cast_impl (basic_path<C1, K2>&&, basic_path<C1, K1>*);
- };
-
- template <typename C, typename K>
- inline basic_path<C, K>
- operator/ (const basic_path<C, K>& x, const basic_path<C, K>& y)
- {
- basic_path<C, K> r (x);
- r /= y;
- return r;
- }
-
- template <typename C, typename K>
- inline basic_path<C, K>
- operator+ (const basic_path<C, K>& x, const std::basic_string<C>& y)
- {
- basic_path<C, K> r (x);
- r += y;
- return r;
- }
-
- template <typename C, typename K>
- inline basic_path<C, K>
- operator+ (const basic_path<C, K>& x, const C* y)
- {
- basic_path<C, K> r (x);
- r += y;
- return r;
- }
-
- template <typename C, typename K>
- inline basic_path<C, K>
- operator+ (const basic_path<C, K>& x, C y)
- {
- basic_path<C, K> r (x);
- r += y;
- return r;
- }
-
- template <typename C, typename K1, typename K2>
- inline bool
- operator== (const basic_path<C, K1>& x, const basic_path<C, K2>& y)
- {
- return x.compare (y) == 0;
- }
-
- template <typename C, typename K1, typename K2>
- inline bool
- operator!= (const basic_path<C, K1>& x, const basic_path<C, K2>& y)
- {
- return !(x == y);
- }
-
- template <typename C, typename K1, typename K2>
- inline bool
- operator< (const basic_path<C, K1>& x, const basic_path<C, K2>& y)
- {
- return x.compare (y) < 0;
- }
-
- // Additional operators for certain path kind combinations.
- //
- template <typename C>
- inline basic_path<C, any_path_kind<C>>
- operator/ (const basic_path<C, dir_path_kind<C>>& x,
- const basic_path<C, any_path_kind<C>>& y)
- {
- basic_path<C, any_path_kind<C>> r (x);
- r /= y;
- return r;
- }
-
-
- // Note that the result of (foo / "bar") is always a path, even if foo
- // is dir_path. An idiom to force it dir_path is this:
- //
- // dir_path foo_bar (dir_path (foo) /= "bar");
- //
- template <typename C, typename K>
- inline basic_path<C, any_path_kind<C>>
- operator/ (const basic_path<C, K>& x, const std::basic_string<C>& y)
- {
- basic_path<C, any_path_kind<C>> r (x);
- r /= y;
- return r;
- }
-
- template <typename C, typename K>
- inline basic_path<C, any_path_kind<C>>
- operator/ (const basic_path<C, K>& x, const C* y)
- {
- basic_path<C, any_path_kind<C>> r (x);
- r /= y;
- return r;
- }
-
- // For operator<< (ostream) see the path-io header.
-}
-
-namespace std
-{
- template <typename C, typename K>
- struct hash<butl::basic_path<C, K>>: hash<basic_string<C>>
- {
- using argument_type = butl::basic_path<C, K>;
-
- size_t
- operator() (const butl::basic_path<C, K>& p) const noexcept
- {
- return hash<basic_string<C>>::operator() (p.string ());
- }
- };
-}
-
-#include <butl/path.ixx>
-#include <butl/path.txx>
-
-#endif // BUTL_PATH