<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2936: Path comparison is defined in terms of the generic format</title>
<meta property="og:title" content="Issue 2936: Path comparison is defined in terms of the generic format">
<meta property="og:description" content="C++ library issue. Status: C++20">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2936.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++20">C++20</a> status.</em></p>
<h3 id="2936"><a href="lwg-defects.html#2936">2936</a>. Path comparison is defined in terms of the generic format</h3>
<p><b>Section:</b> 31.12.6.5.8 <a href="https://wg21.link/fs.path.compare">[fs.path.compare]</a> <b>Status:</b> <a href="lwg-active.html#C++20">C++20</a>
 <b>Submitter:</b> Billy Robert O'Neal III <b>Opened:</b> 2017-02-21 <b>Last modified:</b> 2021-02-25</p>
<p><b>Priority: </b>2
</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++20">C++20</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Currently, path comparison is defined elementwise, which implies a conversion from the native format (implied by
<code>native()</code> returning <code>const string&amp;</code>). However, the conversion from the native format to the generic
format might not be information preserving. This would allow two paths <code>a</code> and <code>b</code> to say
<code>a.compare(b) == 0</code>, but <code>a.native().compare(b.native()) != 0</code> as a result of this missing information,
which is undesirable. We only want that condition to happen if there are redundant directory separators. We also don't
want to change the path comparison to be in terms of the native format, due to Peter Dimov's example where we want
<code>path("a/b")</code> to sort earlier than <code>path("a.b")</code>, and we want <code>path("a/b") == path("a//////b")</code>.
<p/>
Citing a Windows example, conversion to the generic format is going to have to drop alternate data streams. This might
give <code>path("a/b:ads") == path("a/b")</code>. I think I should consider the alternate data streams as part of the path
element though, so this case might be fine, so long as I make <code>path("b:ads").native()</code> be <code>"b:ads"</code>.
This might not work for our z/OS friends though, or for folks where the native format looks nothing like the generic format.
<p/>
Additionally, this treats root-directory specially. For example, the current spec wants <code>path("c:/a/b") == path("c:/a////b")</code>,
but <code>path("c:/a/b") != path("c:///a/b")</code>, because <code>native()</code> for the root-directory path element will literally
be the slashes or preferred separators.
<p/>
This addresses similar issues to those raised in US 57 &mdash; it won't make absolute paths sort at the beginning or end
but it will make paths of the same kind sort together.
</p>

<p><i>[2017-03-04, Kona Saturday morning]</i></p>

<p>We decided that this had seen so much churn that we would postpone looking at this until Toronto</p>

<p><i>[2017-07 Toronto Thurs Issue Prioritization]</i></p>

<p>Priority 2</p>

<p><i>[2016-07, Toronto Saturday afternoon issues processing]</i></p>

<p>Billy to reword after Davis researches history about ordering. Status to Open.</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>This wording is relative to <a href="https://wg21.link/n4640">N4640</a>.</p>

<ol>
<li><p>Make the following edits to 31.12.6.5.8 <a href="https://wg21.link/fs.path.compare">[fs.path.compare]</a>:</p>

<blockquote>
<pre>
int compare(const path&amp; p) const noexcept;
</pre>
<blockquote>
<p>
-1- <em>Returns</em>:
</p>
<blockquote>
<p>
<ins>&mdash; Let <code>rootNameComparison</code> be the result of <code>this-&gt;root_name().native().compare(p.root_name().native())</code>. If <code>rootNameComparison</code> is not <code>0</code>, <code>rootNameComparison</code>; otherwise,</ins>
</p>
<p>
<ins>&mdash; If <code>this-&gt;has_root_directory()</code> and <code>!p.has_root_directory()</code>, a value less than <code>0</code>; otherwise,</ins>
</p>
<p>
<ins>&mdash; If <code>!this-&gt;has_root_directory()</code> and <code>p.has_root_directory()</code>, a value greater than <code>0</code>; otherwise,</ins>
</p>
<p>
<ins>&mdash; A value greater than, less than, or equal to 0, ordering the paths in a depth-first traversal order.</ins>
</p>
</blockquote>
<p>
<ins>-?- [<i>Note:</i> For POSIX and Windows platforms, this is accomplished by lexicographically ordering the half-open ranges <code>[begin(), end())</code> of <code>this-&gt;relative_path()</code> and <code>p.relative_path()</code> as follows:</ins></p>
<blockquote>
<p>
&mdash; A value less than <code>0</code>, if <code>native()</code> for the elements of <code><del>*</del>this<ins>-&gt;relative_path()</ins></code> are lexicographically less than <code>native()</code> for the elements of <code>p<ins>.relative_path()</ins></code>; otherwise,</p>
<p>
&mdash; a value greater than <code>0</code>, if <code>native()</code> for the elements of <code><del>*</del>this<ins>-&gt;relative_path()</ins></code> are lexicographically greater than <code>native()</code> for the elements of <code>p<ins>.relative_path()</ins></code>; otherwise,</p>
<p>
&mdash; <code>0</code>.</p>
</blockquote>
<p>
<ins>&mdash; <i>end note</i>]</ins>
</p>
<p>
<del>-2- <em>Remarks</em>: The elements are determined as if by iteration over the half-open range <code>[begin(), end())</code>
for <code>*this</code> and <code>p</code>.</del>
</p>
</blockquote>
<pre>
int compare(const string_type&amp; s) const
int compare(basic_string_view&lt;value_type&gt; s) const;
</pre>
<blockquote>
<p>
<del>-3- <em>Returns</em>: <code>compare(path(s))</code></del>
</p>
<blockquote class="note">
<p>
[Editor's note: Delete paragraph 3 entirely and merge the <code>value_type</code> overload with those above.]
</p>
</blockquote>
</blockquote>
<pre>
int compare(const value_type* s) const
</pre>
<blockquote>
<p>
-4- <em><del>Returns</del><ins>Effects</ins></em>: <ins>Equivalent to <code>return
</code></ins><code>compare(path(s))<ins>;</ins><del>.</del></code>
</p>
</blockquote>
</blockquote>

</li>
</ol>
</blockquote>

<p><i>[2018-01-26 issues processing telecon]</i></p>

<p>Status set to 'Review'. We like the wording, but would like to see some implementation experience.</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>This wording is relative to <a href="https://wg21.link/n4659">N4659</a>.</p>

<ol>
<li><p>Make the following edits to 31.12.6.5.8 <a href="https://wg21.link/fs.path.compare">[fs.path.compare]</a>:</p>

<blockquote>
<pre>
int compare(const path&amp; p) const noexcept;
</pre>
<blockquote>
<p>
-1- <em>Returns</em>:
</p>
<blockquote>
<p>
<ins>&mdash; Let <code>rootNameComparison</code> be the result of <code>this-&gt;root_name().native().compare(p.root_name().native())</code>. If <code>rootNameComparison</code> is not <code>0</code>, <code>rootNameComparison</code>; otherwise,</ins>
</p>
<p>
<ins>&mdash; If <code>this-&gt;has_root_directory()</code> and <code>!p.has_root_directory()</code>, a value less than <code>0</code>; otherwise,</ins>
</p>
<p>
<ins>&mdash; If <code>!this-&gt;has_root_directory()</code> and <code>p.has_root_directory()</code>, a value greater than <code>0</code>; otherwise,</ins>
</p>
<p>&mdash; <del>a value less than <code>0</code>, i</del><ins>I</ins>f <code>native()</code> for the elements of <code><del>*</del>this<ins>-&gt;relative_path()</ins></code> are lexicographically less than <code>native()</code> for the elements of <code>p<ins>.relative_path()</ins></code><ins>, a value less than <code>0</code></ins>; otherwise,</p>
<p>&mdash; <del>a value greater than <code>0</code>, i</del><ins>I</ins>f <code>native()</code> for the elements of <code><del>*</del>this<ins>-&gt;relative_path()</ins></code> are lexicographically greater than <code>native()</code> for the elements of <code>p<ins>.relative_path()</ins></code><ins>, a value greater than <code>0</code></ins>; otherwise,</p>
<p>
&mdash; <code>0</code>.</p>
</blockquote>
<p>
<del>-2- <em>Remarks</em>: The elements are determined as if by iteration over the half-open range <code>[begin(), end())</code>
for <code>*this</code> and <code>p</code>.</del>
</p>
</blockquote>
<pre>
int compare(const string_type&amp; s) const
int compare(basic_string_view&lt;value_type&gt; s) const;
</pre>
<blockquote>
<p>
<del>-3- <em>Returns</em>: <code>compare(path(s))</code></del>
</p>
<blockquote class="note">
<p>
[Editor's note: Delete paragraph 3 entirely and merge the <code>value_type</code> overload with those above.]
</p>
</blockquote>
</blockquote>
<pre>
int compare(const value_type* s) const
</pre>
<blockquote>
<p>
-4- <em><del>Returns</del><ins>Effects</ins></em>: <ins>Equivalent to <code>return
</code></ins><code>compare(path(s))<ins>;</ins><del>.</del></code>
</p>
</blockquote>
</blockquote>

</li>
</ol>
</blockquote>

<p><i>[2018-02-13 Billy improves wording]</i></p>

<p>
The revised wording has the effect to invert the ordering of the added new bullets (2) and (3),
the effect of this change is that
</p>
<blockquote><pre>
path("c:/").compare("c:")
</pre></blockquote>
<p>
compares greater, not less.
</p>

<p><i>[2018-06, Rapperswil Wednesday evening]</i></p>

<p>
Agreement to move that to Ready, Daniel rebased to N4750.
</p>
<p><i>[2018-11, Adopted in San Diego]</i></p>



<p id="res-2936"><b>Proposed resolution:</b></p>
<p>This wording is relative to <a href="https://wg21.link/n4750">N4750</a>.</p>

<ol>
<li><p>Make the following edits to 31.12.6.5.8 <a href="https://wg21.link/fs.path.compare">[fs.path.compare]</a>:</p>

<blockquote>
<pre>
int compare(const path&amp; p) const noexcept;
</pre>
<blockquote>
<p>
-1- <em>Returns</em>:
</p>
<blockquote>
<p>
<ins>&mdash; Let <code>rootNameComparison</code> be the result of <code>this-&gt;root_name().native().compare(p.root_name().native())</code>. If <code>rootNameComparison</code> is not <code>0</code>, <code>rootNameComparison</code>; otherwise,</ins>
</p>
<p>
<ins>&mdash; If <code>!this-&gt;has_root_directory()</code> and <code>p.has_root_directory()</code>, a value less than <code>0</code>; otherwise,</ins>
</p>
<p>
<ins>&mdash; If <code>this-&gt;has_root_directory()</code> and <code>!p.has_root_directory()</code>, a value greater than <code>0</code>; otherwise,</ins>
</p>
<p>&mdash; <del>a value less than <code>0</code>, i</del><ins>I</ins>f <code>native()</code> for the elements of <code><del>*</del>this<ins>-&gt;relative_path()</ins></code> are lexicographically less than <code>native()</code> for the elements of <code>p<ins>.relative_path()</ins></code><ins>, a value less than <code>0</code></ins>; otherwise,</p>
<p>&mdash; <del>a value greater than <code>0</code>, i</del><ins>I</ins>f <code>native()</code> for the elements of <code><del>*</del>this<ins>-&gt;relative_path()</ins></code> are lexicographically greater than <code>native()</code> for the elements of <code>p<ins>.relative_path()</ins></code><ins>, a value greater than <code>0</code></ins>; otherwise,</p>
<p>
&mdash; <code>0</code>.</p>
</blockquote>
<p>
<del>-2- <em>Remarks</em>: The elements are determined as if by iteration over the half-open range <code>[begin(), end())</code>
for <code>*this</code> and <code>p</code>.</del>
</p>
</blockquote>
<pre>
int compare(const string_type&amp; s) const
int compare(basic_string_view&lt;value_type&gt; s) const;
</pre>
<blockquote>
<p>
<del>-3- <em>Returns</em>: <code>compare(path(s))</code></del>
</p>
<blockquote class="note">
<p>
[Editor's note: Delete paragraph 3 entirely and merge the <code>value_type</code> overload with those above.]
</p>
</blockquote>
</blockquote>
<pre>
int compare(const value_type* s) const
</pre>
<blockquote>
<p>
-4- <em><del>Returns</del><ins>Effects</ins></em>: <ins>Equivalent to: <code>return
</code></ins><code>compare(path(s))<ins>;</ins><del>.</del></code>
</p>
</blockquote>
</blockquote>

</li>
</ol>







</body>
</html>
