1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 10:04:21 +03:00
inform7/docs/arch-module/2-vn.html
2020-03-11 00:21:09 +00:00

843 lines
121 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>1/am</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<!--Weave of '2/vn' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">&#9733;</a></li><li><a href="index.html">arch</a></li><li><a href="index.html#2">Chapter 2: Architectures</a></li><li><b>Version Numbers</b></li></ul><p class="purpose">Semantic version numbers such as 3.7.1.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Standard adoption</a></li><li><a href="#SP5">&#167;5. Printing and parsing</a></li><li><a href="#SP8">&#167;8. Precendence</a></li><li><a href="#SP11">&#167;11. Trichotomy</a></li><li><a href="#SP13">&#167;13. Ranges</a></li><li><a href="#SP22">&#167;22. Unit tests</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Standard adoption. </b>The Semantic Version Number standard, semver 2.0.0, provides a strict set
of rules for the format and meaning of version numbers: see <code class="display"><span class="extract">https://semver.org</span></code>.
</p>
<p class="inwebparagraph">Prior to the standard most version numbers in computing usage looked like
dot-divided runs of non-negative integers: for example, 4, 7.1, and 0.2.3.
The standard now requires exactly three: major, minor and patch. It's
therefore formally incorrect to have a version 2, or a version 2.3. We will
not be so strict on the textual form, which we will allow to be abbreviated.
Thus:
</p>
<p class="inwebparagraph"></p>
<ul class="items"><li>(a) The text <code class="display"><span class="extract">6.4.7</span></code> is understood to mean 6.4.7 and printed back as <code class="display"><span class="extract">6.4.7</span></code>
</li><li>(b) The text <code class="display"><span class="extract">6</span></code> is understood to mean 6.0.0 and printed back as <code class="display"><span class="extract">6</span></code>
</li><li>(c) The text <code class="display"><span class="extract">6.1</span></code> is understood to mean 6.1.0 and printed back as <code class="display"><span class="extract">6.1</span></code>
</li><li>(d) The text <code class="display"><span class="extract">6.1.0</span></code> is understood to mean 6.1.0 and printed back as <code class="display"><span class="extract">6.1.0</span></code>
</li></ul>
<p class="inwebparagraph">Similarly, the absence of a version number (called "null" below) will be
understood to mean 0.0.0, but will be distinguished from the explicit choice
to number something as 0.0.0.
</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>A complication is that Inform 7 extensions have for many years allowed two
forms of version number: either just <code class="display"><span class="extract">N</span></code>, which fits the scheme above, or
<code class="display"><span class="extract">N/DDDDDD</span></code>, which does not. This is a format which was chosen for sentimental
reasons: IF enthusiasts know it well from the banner text of the Infocom
titles of the 1980s. This story file, for instance, was compiled at the
time of the Reykjavik summit between Presidents Gorbachev and Reagan:
</p>
<p class="inwebparagraph"></p>
<pre class="display">
<span class="plain">Moonmist</span>
<span class="plain">Infocom interactive fiction - a mystery story</span>
<span class="plain">Copyright (c) 1986 by Infocom, Inc. All rights reserved.</span>
<span class="plain">Moonmist is a trademark of Infocom, Inc.</span>
<span class="plain">Release number 9 / Serial number 861022</span>
</pre>
<p class="inwebparagraph">Story file collectors customarily abbreviate this in catalogues to <code class="display"><span class="extract">9/861022</span></code>.
</p>
<p class="inwebparagraph">We will therefore allow this notation, and convert it silently each way.
<code class="display"><span class="extract">N/DDDDDD</span></code> is equivalent to <code class="display"><span class="extract">N.DDDDDD</span></code>. Thus, <code class="display"><span class="extract">9/861022</span></code> means 9.861022.0 in
semver precedence order.
</p>
<p class="inwebparagraph">In all non-textual respects, and in particular on precedence rules, we follow
the standard exactly. The only reason we allow these abbreviations is because
we don't want to force Inform extension writers to type "Version 3.4.1 of
Such-and-Such by Me begins here", and so on: it would break all existing
extensions, for one thing, and it looks unfriendly.
</p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>In the array below, unspecified numbers are stored as <code class="display"><span class="extract">-1</span></code>. The three
components are otherwise required to be non-negative integers.
</p>
<p class="inwebparagraph">Semver allows for more elaborate forms: for example <code class="display"><span class="extract">3.1.41-alpha.72.zeta+6Q45</span></code>
would mean 3.1.41 but with prerelease versioning <code class="display"><span class="extract">alpha.72.zeta</span></code> and build
metadata <code class="display"><span class="extract">6Q45</span></code>. The <code class="display"><span class="extract">prerelease_segments</span></code> list for this would be a list of
three texts: <code class="display"><span class="extract">alpha</span></code>, <code class="display"><span class="extract">72</span></code>, <code class="display"><span class="extract">zeta</span></code>.
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">SEMVER_NUMBER_DEPTH</span><span class="plain"> 3 </span> <span class="comment">major, minor, patch</span>
</pre>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">semantic_version_number</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">version_numbers</span><span class="plain">[</span><span class="constant">SEMVER_NUMBER_DEPTH</span><span class="plain">];</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">linked_list</span><span class="plain"> *</span><span class="identifier">prerelease_segments</span><span class="plain">; </span> <span class="comment">of <code class="display"><span class="extract">text_stream</span></code></span>
<span class="reserved">struct</span><span class="plain"> </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">build_metadata</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">semantic_version_number</span><span class="plain">;</span>
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">semantic_version_number_holder</span><span class="plain"> {</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">version</span><span class="plain">;</span>
<span class="identifier">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">semantic_version_number_holder</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure semantic_version_number is private to this section.</p>
<p class="endnote">The structure semantic_version_number_holder is accessed in 2/tvm, 2/cmp.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>All invalid strings of numbers &mdash; i.e., breaking the above rules &mdash; are
called "null" versions, and can never be valid as the version of anything.
Instead they are used to represent the absence of a version number.
(In particular, a string of <code class="display"><span class="extract">-1</span></code>s is null.)
</p>
<pre class="display">
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="plain">#</span><span class="identifier">pragma</span><span class="plain"> </span><span class="identifier">clang</span><span class="plain"> </span><span class="identifier">diagnostic</span><span class="plain"> </span><span class="identifier">push</span>
<span class="plain">#</span><span class="identifier">pragma</span><span class="plain"> </span><span class="identifier">clang</span><span class="plain"> </span><span class="identifier">diagnostic</span><span class="plain"> </span><span class="identifier">ignored</span><span class="plain"> </span><span class="string">"-Wconditional-uninitialized"</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">SEMVER_NUMBER_DEPTH</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = -1;</span>
<span class="identifier">V</span><span class="element">.prerelease_segments</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">V</span><span class="element">.build_metadata</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">;</span>
<span class="plain">#</span><span class="identifier">pragma</span><span class="plain"> </span><span class="identifier">clang</span><span class="plain"> </span><span class="identifier">diagnostic</span><span class="plain"> </span><span class="identifier">pop</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::is_null</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">) {</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0, </span><span class="identifier">allow</span><span class="plain">=</span><span class="identifier">TRUE</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">SEMVER_NUMBER_DEPTH</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] &lt; -1) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">; </span> <span class="comment">should never happen</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] == -1) </span><span class="identifier">allow</span><span class="plain"> = </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">allow</span><span class="plain"> == </span><span class="identifier">FALSE</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">; </span> <span class="comment">should never happen</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[0] &lt; 0) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::null is used in <a href="#SP7">&#167;7</a>, <a href="#SP7_1">&#167;7.1</a>, <a href="#SP15">&#167;15</a>, <a href="#SP16">&#167;16</a>.</p>
<p class="endnote">The function VersionNumbers::is_null is used in <a href="#SP5">&#167;5</a>, <a href="#SP16">&#167;16</a>, <a href="#SP18">&#167;18</a>, 2/tvm (<a href="2-tvm.html#SP1">&#167;1</a>), 2/cmp (<a href="2-cmp.html#SP1">&#167;1</a>).</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. Printing and parsing. </b>Printing is simple enough:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VersionNumbers::to_text</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::is_null</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">)) { </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"null"</span><span class="plain">); </span><span class="reserved">return</span><span class="plain">; }</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; (</span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">SEMVER_NUMBER_DEPTH</span><span class="plain">) &amp;&amp; (</span><span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] &gt;= 0); </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">&gt;0) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"."</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%d"</span><span class="plain">, </span><span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]);</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="element">.prerelease_segments</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = 0;</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">T</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain">, </span><span class="identifier">V</span><span class="element">.prerelease_segments</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain">++ == 0) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"-"</span><span class="plain">); </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"."</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%S"</span><span class="plain">, </span><span class="identifier">T</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="element">.build_metadata</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"+%S"</span><span class="plain">, </span><span class="identifier">V</span><span class="element">.build_metadata</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::to_text is used in <a href="#SP6">&#167;6</a>.</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. </b>And this provides for the <code class="display"><span class="extract">%v</span></code> escape, though we must be careful when
using this to pass a pointer to the version, not the version itself;
variadic macros are not carefully enough type-checked by <code class="display"><span class="extract">clang</span></code> or <code class="display"><span class="extract">gcc</span></code>
to catch this sort of slip.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VersionNumbers::writer</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">format_string</span><span class="plain">, </span><span class="reserved">void</span><span class="plain"> *</span><span class="identifier">vE</span><span class="plain">) {</span>
<span class="reserved">semantic_version_number</span><span class="plain"> *</span><span class="identifier">V</span><span class="plain"> = (</span><span class="reserved">semantic_version_number</span><span class="plain"> *) </span><span class="identifier">vE</span><span class="plain">;</span>
<span class="functiontext">VersionNumbers::to_text</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, *</span><span class="identifier">V</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::writer is used in 1/am (<a href="1-am.html#SP3_2">&#167;3.2</a>).</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. </b>Parsing is much more of a slog. The following returns a null version if
the text <code class="display"><span class="extract">T</span></code> is in any respect malformed, i.e., if it deviates from the
above specification in even the most trivial way. We parse the three parts
of a semver version in order: e.g. <code class="display"><span class="extract">3.1.41-alpha.72.zeta+6Q45</span></code> the first
part is up to the hyphen, the second part between the hyphen and the plus
sign, and the third part runs to the end. The second and third parts are
optional, but if both are given, they must be in that order.
</p>
<pre class="definitions">
<span class="definitionkeyword">enum</span> <span class="constant">MMP_SEMVERPART</span><span class="definitionkeyword"> from </span><span class="constant">1</span>
<span class="definitionkeyword">enum</span> <span class="constant">PRE_SEMVERPART</span>
<span class="definitionkeyword">enum</span> <span class="constant">BM_SEMVERPART</span>
</pre>
<pre class="display">
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="functiontext">VersionNumbers::from_text</span><span class="plain">(</span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">T</span><span class="plain">) {</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">component</span><span class="plain"> = 0, </span><span class="identifier">val</span><span class="plain"> = -1, </span><span class="identifier">dots_used</span><span class="plain"> = 0, </span><span class="identifier">slashes_used</span><span class="plain"> = 0, </span><span class="identifier">count</span><span class="plain"> = 0;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">part</span><span class="plain"> = </span><span class="constant">MMP_SEMVERPART</span><span class="plain">;</span>
<span class="identifier">TEMPORARY_TEXT</span><span class="plain">(</span><span class="identifier">prerelease</span><span class="plain">);</span>
<span class="identifier">LOOP_THROUGH_TEXT</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">T</span><span class="plain">) {</span>
<span class="identifier">wchar_t</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="identifier">Str::get</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">);</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">part</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">MMP_SEMVERPART</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'.'</span><span class="plain">) </span><span class="identifier">dots_used</span><span class="plain">++;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'/'</span><span class="plain">) </span><span class="identifier">slashes_used</span><span class="plain">++;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'.'</span><span class="plain">) || (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'/'</span><span class="plain">) || (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'-'</span><span class="plain">) || (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'+'</span><span class="plain">)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">val</span><span class="plain"> == -1) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">component</span><span class="plain"> &gt;= </span><span class="constant">SEMVER_NUMBER_DEPTH</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">component</span><span class="plain">] = </span><span class="identifier">val</span><span class="plain">;</span>
<span class="identifier">component</span><span class="plain">++; </span><span class="identifier">val</span><span class="plain"> = -1; </span><span class="identifier">count</span><span class="plain"> = 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'-'</span><span class="plain">) </span><span class="identifier">part</span><span class="plain"> = </span><span class="constant">PRE_SEMVERPART</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'+'</span><span class="plain">) </span><span class="identifier">part</span><span class="plain"> = </span><span class="constant">BM_SEMVERPART</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">c</span><span class="plain">)) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">digit</span><span class="plain"> = </span><span class="identifier">c</span><span class="plain"> - </span><span class="character">'0'</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">val</span><span class="plain"> == 0) &amp;&amp; (</span><span class="identifier">slashes_used</span><span class="plain"> == 0))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">val</span><span class="plain"> &lt; 0) </span><span class="identifier">val</span><span class="plain"> = </span><span class="identifier">digit</span><span class="plain">; </span><span class="reserved">else</span><span class="plain"> </span><span class="identifier">val</span><span class="plain"> = 10*</span><span class="identifier">val</span><span class="plain"> + </span><span class="identifier">digit</span><span class="plain">;</span>
<span class="identifier">count</span><span class="plain">++;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">PRE_SEMVERPART</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'.'</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Add prerelease content</span> <span class="cwebmacronumber">7.1</span>&gt;<span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'+'</span><span class="plain">) {</span>
&lt;<span class="cwebmacro">Add prerelease content</span> <span class="cwebmacronumber">7.1</span>&gt;<span class="plain">; </span><span class="identifier">part</span><span class="plain"> = </span><span class="constant">BM_SEMVERPART</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">prerelease</span><span class="plain">, </span><span class="identifier">c</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">BM_SEMVERPART</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="element">.build_metadata</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">V</span><span class="element">.build_metadata</span><span class="plain"> = </span><span class="identifier">Str::new</span><span class="plain">();</span>
<span class="identifier">PUT_TO</span><span class="plain">(</span><span class="identifier">V</span><span class="element">.build_metadata</span><span class="plain">, </span><span class="identifier">c</span><span class="plain">);</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">part</span><span class="plain"> == </span><span class="constant">PRE_SEMVERPART</span><span class="plain">) &amp;&amp; (</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">prerelease</span><span class="plain">) &gt; 0)) </span>&lt;<span class="cwebmacro">Add prerelease content</span> <span class="cwebmacronumber">7.1</span>&gt;<span class="plain">;</span>
<span class="identifier">DISCARD_TEXT</span><span class="plain">(</span><span class="identifier">prerelease</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">dots_used</span><span class="plain"> &gt; 0) &amp;&amp; (</span><span class="identifier">slashes_used</span><span class="plain"> &gt; 0)) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">slashes_used</span><span class="plain"> &gt; 0) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">component</span><span class="plain"> &gt; 1) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">count</span><span class="plain"> != 6) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">part</span><span class="plain"> == </span><span class="constant">MMP_SEMVERPART</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">val</span><span class="plain"> == -1) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">component</span><span class="plain"> &gt;= </span><span class="constant">SEMVER_NUMBER_DEPTH</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">component</span><span class="plain">] = </span><span class="identifier">val</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::from_text is used in <a href="#SP22">&#167;22</a>, 2/tvm (<a href="2-tvm.html#SP1">&#167;1</a>), 2/cmp (<a href="2-cmp.html#SP1">&#167;1</a>).</p>
<p class="inwebparagraph"><a id="SP7_1"></a><b>&#167;7.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Add prerelease content</span> <span class="cwebmacronumber">7.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">prerelease</span><span class="plain">) == 0) </span><span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">V</span><span class="element">.prerelease_segments</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">V</span><span class="element">.prerelease_segments</span><span class="plain"> = </span><span class="identifier">NEW_LINKED_LIST</span><span class="plain">(</span><span class="identifier">text_stream</span><span class="plain">);</span>
<span class="identifier">ADD_TO_LINKED_LIST</span><span class="plain">(</span><span class="identifier">Str::duplicate</span><span class="plain">(</span><span class="identifier">prerelease</span><span class="plain">), </span><span class="identifier">text_stream</span><span class="plain">, </span><span class="identifier">V</span><span class="element">.prerelease_segments</span><span class="plain">);</span>
<span class="identifier">Str::clear</span><span class="plain">(</span><span class="identifier">prerelease</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP7">&#167;7</a> (three times).</p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. Precendence. </b>The most important part of the semver standard is the rule on which versions
take precedence over which others, and we follow it exactly. The following
criteria are used in turn: major version; minor version; patch version;
any prerelease elements, which must be compared numerically if consisting
of digits only, and alphabetically otherwise; and finally the number of
prerelease elements. Build metadata is disregarded entirely.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::le</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain">, </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain">) {</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="constant">SEMVER_NUMBER_DEPTH</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">N1</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::floor</span><span class="plain">(</span><span class="identifier">V1</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">N2</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::floor</span><span class="plain">(</span><span class="identifier">V2</span><span class="element">.version_numbers</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">N1</span><span class="plain"> &gt; </span><span class="identifier">N2</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">N1</span><span class="plain"> &lt; </span><span class="identifier">N2</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="identifier">linked_list_item</span><span class="plain"> *</span><span class="identifier">I1</span><span class="plain"> = (</span><span class="identifier">V1</span><span class="element">.prerelease_segments</span><span class="plain">)?(</span><span class="identifier">LinkedLists::first</span><span class="plain">(</span><span class="identifier">V1</span><span class="element">.prerelease_segments</span><span class="plain">)):</span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">linked_list_item</span><span class="plain"> *</span><span class="identifier">I2</span><span class="plain"> = (</span><span class="identifier">V2</span><span class="element">.prerelease_segments</span><span class="plain">)?(</span><span class="identifier">LinkedLists::first</span><span class="plain">(</span><span class="identifier">V2</span><span class="element">.prerelease_segments</span><span class="plain">)):</span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">while</span><span class="plain"> ((</span><span class="identifier">I1</span><span class="plain">) &amp;&amp; (</span><span class="identifier">I2</span><span class="plain">)) {</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">T1</span><span class="plain"> = (</span><span class="identifier">text_stream</span><span class="plain"> *) </span><span class="identifier">LinkedLists::content</span><span class="plain">(</span><span class="identifier">I1</span><span class="plain">);</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">T2</span><span class="plain"> = (</span><span class="identifier">text_stream</span><span class="plain"> *) </span><span class="identifier">LinkedLists::content</span><span class="plain">(</span><span class="identifier">I2</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">N1</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::strict_atoi</span><span class="plain">(</span><span class="identifier">T1</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">N2</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::strict_atoi</span><span class="plain">(</span><span class="identifier">T2</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">N1</span><span class="plain"> &gt;= 0) &amp;&amp; (</span><span class="identifier">N2</span><span class="plain"> &gt;= 0)) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">N1</span><span class="plain"> &lt; </span><span class="identifier">N2</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">N1</span><span class="plain"> &gt; </span><span class="identifier">N2</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Str::ne</span><span class="plain">(</span><span class="identifier">T1</span><span class="plain">, </span><span class="identifier">T2</span><span class="plain">)) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="identifier">Str::cmp</span><span class="plain">(</span><span class="identifier">T1</span><span class="plain">, </span><span class="identifier">T2</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> &lt; 0) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> &gt; 0) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="identifier">I1</span><span class="plain"> = </span><span class="identifier">LinkedLists::next</span><span class="plain">(</span><span class="identifier">I1</span><span class="plain">);</span>
<span class="identifier">I2</span><span class="plain"> = </span><span class="identifier">LinkedLists::next</span><span class="plain">(</span><span class="identifier">I2</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">I1</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) &amp;&amp; (</span><span class="identifier">I2</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">I1</span><span class="plain">) &amp;&amp; (</span><span class="identifier">I2</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::le is used in <a href="#SP11">&#167;11</a>, <a href="#SP18">&#167;18</a>.</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. </b>The effect of this is to read unspecified versions of major, minor or patch
as if they were 0:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::floor</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">N</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">N</span><span class="plain"> &lt; 0) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">N</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::floor is used in <a href="#SP8">&#167;8</a>.</p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b>This returns a non-negative integer if <code class="display"><span class="extract">T</span></code> contains only digits, and <code class="display"><span class="extract">-1</span></code>
otherwise. If the value has more than about 10 digits, then the result will
not be meaningful, which I think is a technical violation of the standard.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::strict_atoi</span><span class="plain">(</span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">T</span><span class="plain">) {</span>
<span class="identifier">LOOP_THROUGH_TEXT</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">, </span><span class="identifier">T</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">Characters::isdigit</span><span class="plain">(</span><span class="identifier">Str::get</span><span class="plain">(</span><span class="identifier">pos</span><span class="plain">)) == </span><span class="identifier">FALSE</span><span class="plain">)</span>
<span class="reserved">return</span><span class="plain"> -1;</span>
<span class="identifier">wchar_t</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="identifier">Str::get_first_char</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">c</span><span class="plain"> == </span><span class="character">'0'</span><span class="plain">) &amp;&amp; (</span><span class="identifier">Str::len</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">) &gt; 1)) </span><span class="reserved">return</span><span class="plain"> -1;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">Str::atoi</span><span class="plain">(</span><span class="identifier">T</span><span class="plain">, 0);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::strict_atoi is used in <a href="#SP8">&#167;8</a>.</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. Trichotomy. </b>We now use the above function to construct ordering relations on semvers.
These are trichotomous, that is, for each pair <code class="display"><span class="extract">V1, V2</span></code>, exactly one of the
<code class="display"><span class="extract">VersionNumbers::eq(V1, V2)</span></code>, <code class="display"><span class="extract">VersionNumbers::gt(V1, V2)</span></code>, <code class="display"><span class="extract">VersionNumbers::lt(V1, V2)</span></code>
is true.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::eq</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain">, </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">VersionNumbers::le</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">)) &amp;&amp; (</span><span class="functiontext">VersionNumbers::le</span><span class="plain">(</span><span class="identifier">V2</span><span class="plain">, </span><span class="identifier">V1</span><span class="plain">)))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::ne</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain">, </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::eq</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">))?</span><span class="identifier">FALSE</span><span class="plain">:</span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::gt</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain">, </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::le</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">))?</span><span class="identifier">FALSE</span><span class="plain">:</span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::ge</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain">, </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> </span><span class="functiontext">VersionNumbers::le</span><span class="plain">(</span><span class="identifier">V2</span><span class="plain">, </span><span class="identifier">V1</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::lt</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain">, </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain">) {</span>
<span class="reserved">return</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::ge</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">))?</span><span class="identifier">FALSE</span><span class="plain">:</span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::eq is used in <a href="#SP12">&#167;12</a>, <a href="#SP22">&#167;22</a>, 2/tvm (<a href="2-tvm.html#SP1">&#167;1</a>), 2/cmp (<a href="2-cmp.html#SP1">&#167;1</a>).</p>
<p class="endnote">The function VersionNumbers::ne appears nowhere else.</p>
<p class="endnote">The function VersionNumbers::gt is used in <a href="#SP12">&#167;12</a>, <a href="#SP18">&#167;18</a>, <a href="#SP22">&#167;22</a>.</p>
<p class="endnote">The function VersionNumbers::ge is used in <a href="#SP18">&#167;18</a>.</p>
<p class="endnote">The function VersionNumbers::lt is used in <a href="#SP18">&#167;18</a>, <a href="#SP22">&#167;22</a>.</p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. </b>And the following can be used for sorting, following the <code class="display"><span class="extract">strcmp</span></code> convention.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::cmp</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain">, </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::eq</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::gt</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> 1;</span>
<span class="reserved">return</span><span class="plain"> -1;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::cmp is used in <a href="#SP20">&#167;20</a>, <a href="#SP21">&#167;21</a>.</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. Ranges. </b>We often want to check if a semver lies in a given precedence range, which we
store as an "interval" in the mathematical sense. For example, the range <code class="display"><span class="extract">[2,6)</span></code>
means all versions from 2.0.0 (inclusve) up to, but not equal to, 6.0.0. The
lower end is called "closed" because it includes the end-value 2.0.0, and the
upper end "open" because it does not. An infinite end means that there
os no restriction in that direction; an empty end means that, in fact, the
interval is the empty set, that is, that no version number can ever satisfy it.
</p>
<p class="inwebparagraph">The <code class="display"><span class="extract">end_value</span></code> element is meaningful only for <code class="display"><span class="extract">CLOSED_RANGE_END</span></code> and <code class="display"><span class="extract">OPEN_RANGE_END</span></code>
ends. If one end is marked <code class="display"><span class="extract">EMPTY_RANGE_END</span></code>, so must the other be: it makes
no sense for an interval to be empty seen from one end but not the other.
</p>
<pre class="definitions">
<span class="definitionkeyword">enum</span> <span class="constant">CLOSED_RANGE_END</span><span class="definitionkeyword"> from </span><span class="constant">1</span>
<span class="definitionkeyword">enum</span> <span class="constant">OPEN_RANGE_END</span>
<span class="definitionkeyword">enum</span> <span class="constant">INFINITE_RANGE_END</span>
<span class="definitionkeyword">enum</span> <span class="constant">EMPTY_RANGE_END</span>
</pre>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">range_end</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">end_type</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">end_value</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">range_end</span><span class="plain">;</span>
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">semver_range</span><span class="plain"> {</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">range_end</span><span class="plain"> </span><span class="identifier">lower</span><span class="plain">;</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">range_end</span><span class="plain"> </span><span class="identifier">upper</span><span class="plain">;</span>
<span class="identifier">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">semver_range</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure range_end is private to this section.</p>
<p class="endnote">The structure semver_range is private to this section.</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. </b>As hinted above, the notation <code class="display"><span class="extract">[</span></code> and <code class="display"><span class="extract">]</span></code> is used for closed ends, and <code class="display"><span class="extract">(</span></code>
and <code class="display"><span class="extract">)</span></code> for open ones.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VersionNumbers::write_range</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">R</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">internal_error</span><span class="plain">(</span><span class="string">"no range"</span><span class="plain">);</span>
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">CLOSED_RANGE_END</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"[%v,"</span><span class="plain">, &amp;(</span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_value</span><span class="plain">)); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">OPEN_RANGE_END</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"(%v,"</span><span class="plain">, &amp;(</span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_value</span><span class="plain">)); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"(-infty,"</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"empty"</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">switch</span><span class="plain">(</span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">CLOSED_RANGE_END</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%v]"</span><span class="plain">, &amp;(</span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_value</span><span class="plain">)); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">OPEN_RANGE_END</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%v)"</span><span class="plain">, &amp;(</span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_value</span><span class="plain">)); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">: </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"infty)"</span><span class="plain">); </span><span class="reserved">break</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::write_range is used in <a href="#SP22">&#167;22</a>.</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. </b>The "allow anything" range runs from minus to plus infinity. Every version
number lies in this range.
</p>
<pre class="display">
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="functiontext">VersionNumbers::any_range</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">semver_range</span><span class="plain">);</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> = </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">;</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_value</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> = </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">;</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_value</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">R</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::is_any_range</span><span class="plain">(</span><span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">R</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> == </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">) &amp;&amp; (</span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> == </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">))</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::any_range is used in <a href="#SP16">&#167;16</a>, <a href="#SP17">&#167;17</a>.</p>
<p class="endnote">The function VersionNumbers::is_any_range appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b>The "compatibility" range for a given version lies at the heart of semver:
to be compatible with version <code class="display"><span class="extract">V</span></code>, version <code class="display"><span class="extract">W</span></code> must be of equal or greater
precedence, and must have the same major version number. For example,
for <code class="display"><span class="extract">2.1.7</span></code> the range will be <code class="display"><span class="extract">[2.1.7, 3-A)</span></code>, all versions at least 2.1.7 but
not as high as 3.0.0-A.
</p>
<p class="inwebparagraph">Note that <code class="display"><span class="extract">3.0.0-A</span></code> is the least precendent version allowed by semver with
major version 3. The <code class="display"><span class="extract">-</span></code> gives it lower precedence than all release versions of
3.0.0; the fact that upper case <code class="display"><span class="extract">A</span></code> is alphabetically the earliest non-empty
alphanumeric string gives it lower precendence than all other prerelease
versions.
</p>
<pre class="display">
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="functiontext">VersionNumbers::compatibility_range</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">) {</span>
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::any_range</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::is_null</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">) == </span><span class="identifier">FALSE</span><span class="plain">) {</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> = </span><span class="constant">CLOSED_RANGE_END</span><span class="plain">;</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_value</span><span class="plain"> = </span><span class="identifier">V</span><span class="plain">;</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> = </span><span class="constant">OPEN_RANGE_END</span><span class="plain">;</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">W</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::null</span><span class="plain">();</span>
<span class="identifier">W</span><span class="element">.version_numbers</span><span class="plain">[0] = </span><span class="identifier">V</span><span class="element">.version_numbers</span><span class="plain">[0] + 1;</span>
<span class="identifier">W</span><span class="element">.prerelease_segments</span><span class="plain"> = </span><span class="identifier">NEW_LINKED_LIST</span><span class="plain">(</span><span class="identifier">text_stream</span><span class="plain">);</span>
<span class="identifier">ADD_TO_LINKED_LIST</span><span class="plain">(</span><span class="identifier">I</span><span class="string">"A"</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain">, </span><span class="identifier">W</span><span class="element">.prerelease_segments</span><span class="plain">);</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_value</span><span class="plain"> = </span><span class="identifier">W</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">R</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::compatibility_range is used in <a href="#SP22">&#167;22</a>.</p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. </b>More straightforwardly, these ranges are for anything from V, or up to V,
inclusive:
</p>
<pre class="display">
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="functiontext">VersionNumbers::at_least_range</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">) {</span>
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::any_range</span><span class="plain">();</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> = </span><span class="constant">CLOSED_RANGE_END</span><span class="plain">;</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower.end_value</span><span class="plain"> = </span><span class="identifier">V</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">R</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="functiontext">VersionNumbers::at_most_range</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">) {</span>
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::any_range</span><span class="plain">();</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> = </span><span class="constant">CLOSED_RANGE_END</span><span class="plain">;</span>
<span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper.end_value</span><span class="plain"> = </span><span class="identifier">V</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">R</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::at_least_range is used in <a href="#SP22">&#167;22</a>.</p>
<p class="endnote">The function VersionNumbers::at_most_range is used in <a href="#SP22">&#167;22</a>.</p>
<p class="inwebparagraph"><a id="SP18"></a><b>&#167;18. </b>Here we test whether V is at least a given end, and then at most:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::version_ge_end</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">range_end</span><span class="plain"> </span><span class="identifier">E</span><span class="plain">) {</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">E</span><span class="element">.end_type</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">CLOSED_RANGE_END</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::is_null</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::ge</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">E</span><span class="element">.end_value</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">OPEN_RANGE_END</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::is_null</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::gt</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">E</span><span class="element">.end_value</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::version_le_end</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">range_end</span><span class="plain"> </span><span class="identifier">E</span><span class="plain">) {</span>
<span class="reserved">switch</span><span class="plain"> (</span><span class="identifier">E</span><span class="element">.end_type</span><span class="plain">) {</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">CLOSED_RANGE_END</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::is_null</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::le</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">E</span><span class="element">.end_value</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">OPEN_RANGE_END</span><span class="plain">:</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::is_null</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">VersionNumbers::lt</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">E</span><span class="element">.end_value</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">break</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">case</span><span class="plain"> </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">: </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::version_ge_end is used in <a href="#SP19">&#167;19</a>.</p>
<p class="endnote">The function VersionNumbers::version_le_end is used in <a href="#SP19">&#167;19</a>.</p>
<p class="inwebparagraph"><a id="SP19"></a><b>&#167;19. </b>This allows a simple way to write:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::in_range</span><span class="plain">(</span><span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain">, </span><span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">R</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="functiontext">VersionNumbers::version_ge_end</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;lower</span><span class="plain">)) &amp;&amp;</span>
<span class="plain">(</span><span class="functiontext">VersionNumbers::version_le_end</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">, </span><span class="identifier">R</span><span class="plain">-</span><span class="element">&gt;upper</span><span class="plain">))) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::in_range appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP20"></a><b>&#167;20. </b>The following decides which end restriction is stricter: it returns 1
of <code class="display"><span class="extract">E1</span></code> is, -1 if <code class="display"><span class="extract">E2</span></code> is, and 0 if they are equally onerous.
</p>
<p class="inwebparagraph">The empty set is as strict as it gets: nothing qualifies.
</p>
<p class="inwebparagraph">Similarly, infinite ends are as relaxed as can be: everything qualifies.
</p>
<p class="inwebparagraph">And otherwise, we need to know which end we're looking at in order to decide:
a lower end of <code class="display"><span class="extract">[4, ...]</span></code> is stricter than a lower end of <code class="display"><span class="extract">[3, ...]</span></code>, but an
upper end of <code class="display"><span class="extract">[..., 4]</span></code> is not as strict as an upper end of <code class="display"><span class="extract">[..., 3]</span></code>. Where
the boundary value is the same, open ends are stricter than closed ends.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::stricter</span><span class="plain">(</span><span class="reserved">range_end</span><span class="plain"> </span><span class="identifier">E1</span><span class="plain">, </span><span class="reserved">range_end</span><span class="plain"> </span><span class="identifier">E2</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">lower</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">E1</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">) &amp;&amp; (</span><span class="identifier">E2</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">E1</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> 1;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">E2</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> -1;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">E1</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">) &amp;&amp; (</span><span class="identifier">E2</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">)) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">E1</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> -1;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">E2</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> 1;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::cmp</span><span class="plain">(</span><span class="identifier">E1</span><span class="element">.end_value</span><span class="plain">, </span><span class="identifier">E2</span><span class="element">.end_value</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">c</span><span class="plain"> != 0) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">lower</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">c</span><span class="plain">; </span><span class="reserved">else</span><span class="plain"> </span><span class="reserved">return</span><span class="plain"> -</span><span class="identifier">c</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">E1</span><span class="element">.end_type</span><span class="plain"> == </span><span class="identifier">E2</span><span class="element">.end_type</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> 0;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">E1</span><span class="element">.end_type</span><span class="plain"> == </span><span class="constant">CLOSED_RANGE_END</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> -1;</span>
<span class="reserved">return</span><span class="plain"> 1;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::stricter is used in <a href="#SP21">&#167;21</a>.</p>
<p class="inwebparagraph"><a id="SP21"></a><b>&#167;21. </b>And so we finally arrive at the following, which intersects two ranges:
that is, it changes <code class="display"><span class="extract">R1</span></code> to the range of versions which lie ibside both the
original <code class="display"><span class="extract">R1</span></code> and also <code class="display"><span class="extract">R2</span></code>. (This is used by Inbuild when an extension is
included in two different places in the source text, but with possibly
different version needs.) The return value is true if an actual change took
place, and false otherwise.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">VersionNumbers::intersect_range</span><span class="plain">(</span><span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R1</span><span class="plain">, </span><span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R2</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">lc</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::stricter</span><span class="plain">(</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;lower</span><span class="plain">, </span><span class="identifier">R2</span><span class="plain">-</span><span class="element">&gt;lower</span><span class="plain">, </span><span class="identifier">TRUE</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">uc</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::stricter</span><span class="plain">(</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;upper</span><span class="plain">, </span><span class="identifier">R2</span><span class="plain">-</span><span class="element">&gt;upper</span><span class="plain">, </span><span class="identifier">FALSE</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">lc</span><span class="plain"> &gt;= 0) &amp;&amp; (</span><span class="identifier">uc</span><span class="plain"> &gt;= 0)) </span><span class="reserved">return</span><span class="plain"> </span><span class="identifier">FALSE</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">lc</span><span class="plain"> &lt; 0) </span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;lower</span><span class="plain"> = </span><span class="identifier">R2</span><span class="plain">-</span><span class="element">&gt;lower</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">uc</span><span class="plain"> &lt; 0) </span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;upper</span><span class="plain"> = </span><span class="identifier">R2</span><span class="plain">-</span><span class="element">&gt;upper</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> == </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">) </span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> = </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> == </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">) </span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> = </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> != </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">) &amp;&amp; (</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> != </span><span class="constant">INFINITE_RANGE_END</span><span class="plain">)) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">c</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::cmp</span><span class="plain">(</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;lower.end_value</span><span class="plain">, </span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;upper.end_value</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">c</span><span class="plain"> &gt; 0) ||</span>
<span class="plain">((</span><span class="identifier">c</span><span class="plain"> == 0) &amp;&amp; ((</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> == </span><span class="constant">OPEN_RANGE_END</span><span class="plain">) ||</span>
<span class="plain">(</span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> == </span><span class="constant">OPEN_RANGE_END</span><span class="plain">)))) {</span>
<span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;lower.end_type</span><span class="plain"> = </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">; </span><span class="identifier">R1</span><span class="plain">-</span><span class="element">&gt;upper.end_type</span><span class="plain"> = </span><span class="constant">EMPTY_RANGE_END</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="plain">}</span>
<span class="reserved">return</span><span class="plain"> </span><span class="identifier">TRUE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::intersect_range is used in <a href="#SP22">&#167;22</a>.</p>
<p class="inwebparagraph"><a id="SP22"></a><b>&#167;22. Unit tests. </b>The Inbuild test case <code class="display"><span class="extract">semver</span></code> exercises the following.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VersionNumbers::test_range</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain">) {</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::from_text</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">);</span>
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::compatibility_range</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"Compatibility range of %v = "</span><span class="plain">, &amp;</span><span class="identifier">V</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">R</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="identifier">R</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::at_least_range</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"At-least range of %v = "</span><span class="plain">, &amp;</span><span class="identifier">V</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">R</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="identifier">R</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::at_most_range</span><span class="plain">(</span><span class="identifier">V</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"At-most range of %v = "</span><span class="plain">, &amp;</span><span class="identifier">V</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">R</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VersionNumbers::test_intersect</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">,</span>
<span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">text1</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">r1</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">text2</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">r2</span><span class="plain">) {</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::from_text</span><span class="plain">(</span><span class="identifier">text1</span><span class="plain">);</span>
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R1</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">r1</span><span class="plain"> == 0) </span><span class="identifier">R1</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::compatibility_range</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">r1</span><span class="plain"> &gt; 0) </span><span class="identifier">R1</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::at_least_range</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">r1</span><span class="plain"> &lt; 0) </span><span class="identifier">R1</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::at_most_range</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">);</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::from_text</span><span class="plain">(</span><span class="identifier">text2</span><span class="plain">);</span>
<span class="reserved">semver_range</span><span class="plain"> *</span><span class="identifier">R2</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">r2</span><span class="plain"> == 0) </span><span class="identifier">R2</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::compatibility_range</span><span class="plain">(</span><span class="identifier">V2</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">r2</span><span class="plain"> &gt; 0) </span><span class="identifier">R2</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::at_least_range</span><span class="plain">(</span><span class="identifier">V2</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">r2</span><span class="plain"> &lt; 0) </span><span class="identifier">R2</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::at_most_range</span><span class="plain">(</span><span class="identifier">V2</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">R1</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" intersect "</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">R2</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">" = "</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">changed</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::intersect_range</span><span class="plain">(</span><span class="identifier">R1</span><span class="plain">, </span><span class="identifier">R2</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::write_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">R1</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">changed</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain"> (</span><span class="string">" -- changed"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">text</span><span class="plain">) {</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::from_text</span><span class="plain">(</span><span class="identifier">text</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"'%S' --&gt; %v\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">text</span><span class="plain">, &amp;</span><span class="identifier">V</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">text1</span><span class="plain">, </span><span class="identifier">text_stream</span><span class="plain"> *</span><span class="identifier">text2</span><span class="plain">) {</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V1</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::from_text</span><span class="plain">(</span><span class="identifier">text1</span><span class="plain">);</span>
<span class="reserved">semantic_version_number</span><span class="plain"> </span><span class="identifier">V2</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::from_text</span><span class="plain">(</span><span class="identifier">text2</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">gt</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::gt</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">eq</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::eq</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">lt</span><span class="plain"> = </span><span class="functiontext">VersionNumbers::lt</span><span class="plain">(</span><span class="identifier">V1</span><span class="plain">, </span><span class="identifier">V2</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">lt</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%v &lt; %v"</span><span class="plain">, &amp;</span><span class="identifier">V1</span><span class="plain">, &amp;</span><span class="identifier">V2</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">eq</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%v = %v"</span><span class="plain">, &amp;</span><span class="identifier">V1</span><span class="plain">, &amp;</span><span class="identifier">V2</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">gt</span><span class="plain">) </span><span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"%v &gt; %v"</span><span class="plain">, &amp;</span><span class="identifier">V1</span><span class="plain">, &amp;</span><span class="identifier">V2</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">VersionNumbers::test</span><span class="plain">(</span><span class="identifier">OUTPUT_STREAM</span><span class="plain">) {</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2.3"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"71.0.45672"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2.3.4"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"9/861022"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"9/86102"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"9/8610223"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"9/861022.2"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"9/861022/2"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2.3-alpha.0.x45.1789"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1+lobster"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2+lobster"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2.3+lobster"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_read_write</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2.3-beta.2+shellfish"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"5"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.0"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.0.0"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.5"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.2.5"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41+arm64"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-pre.0.1"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-alpha.72"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-alpha.8"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-alpha.72a"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-alpha.8a"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-alpha.72"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-beta.72"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-alpha.72"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"3.1.41-alpha.72.zeta"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_precedence</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2.3+lobster.54"</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"1.2.3+lobster.100"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_range</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"6.4.2-kappa.17"</span><span class="plain">);</span>
<span class="identifier">WRITE</span><span class="plain">(</span><span class="string">"\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="functiontext">VersionNumbers::test_intersect</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"6.4.2-kappa.17"</span><span class="plain">, 0, </span><span class="identifier">I</span><span class="string">"3.5.5"</span><span class="plain">, 0);</span>
<span class="functiontext">VersionNumbers::test_intersect</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"6.4.2-kappa.17"</span><span class="plain">, 0, </span><span class="identifier">I</span><span class="string">"6.9.1"</span><span class="plain">, 0);</span>
<span class="functiontext">VersionNumbers::test_intersect</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"6.9.1"</span><span class="plain">, 0, </span><span class="identifier">I</span><span class="string">"6.4.2-kappa.17"</span><span class="plain">, 0);</span>
<span class="functiontext">VersionNumbers::test_intersect</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"6.4.2"</span><span class="plain">, 1, </span><span class="identifier">I</span><span class="string">"3.5.5"</span><span class="plain">, 1);</span>
<span class="functiontext">VersionNumbers::test_intersect</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"6.4.2"</span><span class="plain">, 1, </span><span class="identifier">I</span><span class="string">"3.5.5"</span><span class="plain">, -1);</span>
<span class="functiontext">VersionNumbers::test_intersect</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"6.4.2"</span><span class="plain">, -1, </span><span class="identifier">I</span><span class="string">"3.5.5"</span><span class="plain">, 1);</span>
<span class="functiontext">VersionNumbers::test_intersect</span><span class="plain">(</span><span class="identifier">OUT</span><span class="plain">, </span><span class="identifier">I</span><span class="string">"6.4.2"</span><span class="plain">, -1, </span><span class="identifier">I</span><span class="string">"3.5.5"</span><span class="plain">, -1);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function VersionNumbers::test_range appears nowhere else.</p>
<p class="endnote">The function VersionNumbers::test_intersect appears nowhere else.</p>
<p class="endnote">The function VersionNumbers::test_read_write appears nowhere else.</p>
<p class="endnote">The function VersionNumbers::test_precedence appears nowhere else.</p>
<p class="endnote">The function VersionNumbers::test appears nowhere else.</p>
<hr class="tocbar">
<ul class="toc"><li><i>(This section begins Chapter 2: Architectures.)</i></li><li><a href="2-arc.html">Continue with 'Architectures'</a></li></ul><hr class="tocbar">
<!--End of weave-->
</body>
</html>