diff options
-rw-r--r-- | butl/path | 9 | ||||
-rw-r--r-- | butl/path-map | 65 |
2 files changed, 61 insertions, 13 deletions
@@ -132,8 +132,13 @@ namespace butl static int compare (string_type const& l, string_type const& r) { - size_type ln (l.size ()), rn (r.size ()), n (ln < rn ? ln : rn); - for (size_type i (0); i != n; ++i) + return compare (l.c_str (), l.size (), r.c_str (), r.size ()); + } + + static int + compare (const C* l, size_type ln, const C* r, size_t rn) + { + for (size_type i (0), n (ln < rn ? ln : rn); i != n; ++i) { #ifdef _WIN32 C lc (tolower (l[i])), rc (tolower (r[i])); diff --git a/butl/path-map b/butl/path-map index fc66002..3852723 100644 --- a/butl/path-map +++ b/butl/path-map @@ -5,6 +5,8 @@ #ifndef BUTL_PATH_MAP #define BUTL_PATH_MAP +#include <algorithm> // min() + #include <butl/path> #include <butl/prefix-map> @@ -12,7 +14,8 @@ namespace butl { // prefix_map for filesystem paths // - // Important: the paths should be normalized and canonicalized. + // Important: the paths should be normalized but don't have to be + // canonicalized. // // Note that the path's representation of POSIX root ('/') is // inconsistent in that we have a trailing delimiter at the end of @@ -25,16 +28,17 @@ namespace butl // populate the map with it. // template <typename C, typename K> - struct compare_prefix<basic_path<C, K>>: compare_prefix<std::basic_string<C>> + struct compare_prefix<basic_path<C, K>> { typedef basic_path<C, K> key_type; typedef C delimiter_type; - typedef std::basic_string<C> string_type; - typedef compare_prefix<std::basic_string<C>> base; + typedef typename key_type::string_type string_type; + typedef typename key_type::size_type size_type; + typedef typename key_type::traits traits_type; explicit - compare_prefix (delimiter_type d): base (d) {} + compare_prefix (delimiter_type) {} bool operator() (const key_type& x, const key_type& y) const @@ -42,10 +46,10 @@ namespace butl const string_type& xs (x.string ()); const string_type& ys (y.string ()); - return base::compare (xs.c_str (), - root (xs) ? 0 : xs.size (), - ys.c_str (), - root (ys) ? 0 : ys.size ()) < 0; + return compare (xs.c_str (), + root (xs) ? 0 : xs.size (), + ys.c_str (), + root (ys) ? 0 : ys.size ()) < 0; } bool @@ -54,11 +58,47 @@ namespace butl const string_type& ps (p.string ()); const string_type& ks (k.string ()); - return base::prefix (root (ps) ? string_type () : ps, - root (ks) ? string_type () : ks); + return prefix (root (ps) ? string_type () : ps, + root (ks) ? string_type () : ks); } protected: + bool + prefix (const string_type& p, const string_type& k) const + { + // The same code as in prefix_map but using our compare(). + // + size_type pn (p.size ()), kn (k.size ()); + return pn == 0 || // Empty key is always a prefix. + (pn <= kn && + compare (p.c_str (), pn, k.c_str (), pn == kn ? pn : pn + 1) == 0); + } + + int + compare (const C* x, size_type xn, + const C* y, size_type yn) const + { + size_type n (std::min (xn, yn)); + int r (traits_type::compare (x, n, y, n)); + + if (r == 0) + { + // Pretend there is a delimiter characters at the end of the + // shorter string. + // + char xc (xn > n ? x[n] : (xn++, traits_type::directory_separator)); + char yc (yn > n ? y[n] : (yn++, traits_type::directory_separator)); + r = traits_type::compare (&xc, 1, &yc, 1); + + // If we are still equal, then compare the lengths. + // + if (r == 0) + r = (xn == yn ? 0 : (xn < yn ? -1 : 1)); + } + + return r; + } + static bool root (const string_type& p) { @@ -66,6 +106,9 @@ namespace butl } }; + // Note that the delimiter character is not used (is_delimiter() from + // path_traits is used instead). + // template <typename T> using path_map = prefix_map<path, T, path::traits::directory_separator>; |