<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="generator" content="pandoc">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
  <title>clamp: An algorithm to 'clamp' a value between a pair of boundary values (Draft) - </title>
  <style type="text/css">code{white-space: pre;}</style>
  <!--[if lt IE 9]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
  <![endif]-->
  <style>
  p {
      margin-top: 0;
  }
  h1, h2 {
      color: navy;
  }
  h2 {
      margin-top: 1em;
      margin-bottom: 0em;
  }
  code {
      color: navy;
  }
  pre code {
      display: block;
      margin-left: 2em;
  }
  div.std {
      background-color: #f8f8f8;
      border: 1px solid #d1d1d1;
      padding: 0 1em 1em;
      margin-top:0.5em;
      margin-left: 1em;
      margin-right: 1em;
  }
  div.std pre code {
      margin-left: 0em;
  }
  </style>
</head>
<body>
<!--
-- Created: 21 May 2014, Martin Moene
--
-- Note 1: edited with MarkdownPad2 (http://markdownpad.com/).
-- Note 2: take care of trailing double space for formatting newline.
-- Note 3: the interspersed HTML is added to support generating useful output via Pandoc (http://johnmacfarlane.net/pandoc/).
--
-- IsoCpp: https://isocpp.org/std/library-design-guidelines
--
-- ISO/IEC JTC1 SC22 WG21 D*dddd* *yyyy-mm-dd*
-->

<p><strong>Document number</strong>: N4536<br /><strong>Date</strong>: 2015-05-17<br /><strong>Project</strong>: Programming Language C++, Library Evolution Working Group<br /><!--**Revises**: Nxxx --> <strong>Reply to</strong>: Martin Moene &lt;martin.moene (at) gmail.com&gt;, Niels Dekker &lt;n.dekker (at) xs4all.nl&gt;</p>
<h1 id="an-algorithm-to-clamp-a-value-between-a-pair-of-boundary-values">An algorithm to &quot;clamp&quot; a value between a pair of boundary values</h1>
<p><a name="contents"></a></p>
<p><a href="#introduction">Introduction</a><br /><a href="#motivation">Motivation</a><br /><a href="#impact">Impact on the standard</a><br /><a href="#comparison">Comparison to clamp of Boost.Algorithm</a><br /><a href="#design">Design decisions</a><br /><a href="#wording">Proposed wording</a><br /><a href="#implementation">Possible implementation</a><br /><a href="#acknowledgements">Acknowledgements</a><br /><a href="#references">References</a></p>
<p><a name="introduction"></a></p>
<h2 id="introduction">Introduction</h2>
<p>The algorithm proposed here &quot;clamps&quot; a value between a pair of boundary values. The idea and interfaces are inspired by clamp in the Boost.Algorithm library authored by Marshall Clow.</p>
<p><a name="motivation"></a></p>
<h2 id="motivation">Motivation</h2>
<p>It is a common programming task to constrain a value to fall within certain limits. This can be expressed in numerous ways, but it would be good if such an operation can be easily recognized and doesn't appear in many guises just because it can.</p>
<p>So, we'd like to have a concise way to obtain a value that is forced to fall within a range we request, much like we can limit a value to a defined minimum or maximum. For example:</p>
<pre><code>auto clamped_value = clamp( value, min_value, max_value );</code></pre>
<p>Without a standardized way, people may (need to) define their own version of &quot;clamp&quot; or resort to a less clear solution such as<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a>:</p>
<pre><code>auto clamped_value = std::min( std::max( value, min_value ), max_value );</code></pre>
<p>For convenience we also propose an algorithm to clamp a series of values:</p>
<pre><code>std::vector&lt;int&gt; v{ 1,2,3,4,5,6,7,8,9 };

auto clamped_v = clamp_range( v.begin(), v.end(), v.begin(), 3, 7 );</code></pre>
<p>In addition to the boundary values, one can provide a predicate that evaluates if a value is within the boundary.</p>
<pre><code>struct rgb{ ... };

auto clamped_rgb = clamp( rgb_value, rgb_lo, rgb_hi, rgb_compare );</code></pre>
<p>Function <code>clamp()</code> already exists in C++ libraries such as Boost <a href="#ref1">[1]</a> and Microsoft AMP <a href="#ref2">[2]</a>. The Qt Project provides <code>qBound</code> <a href="#ref3">[3]</a> , and the Python library scipy/numpy provides <code>clip()</code> <a href="#ref4">[4]</a> for the same purpose.</p>
<p><a name="impact"></a></p>
<h2 id="impact-on-the-standard">Impact on the standard</h2>
<p>The clamp algorithms can be implemented as a pure library extension in C++14. The proposed wording is dependent on the void specialization of <code>&lt;functional&gt;</code>'s operator functors that is available since C++14 <a href="#ref5">[5]</a><a href="#ref6">[6]</a>.</p>
<p><a name="comparison"></a></p>
<h2 id="comparison-to-clamp-of-boost.algorithm">Comparison to clamp of Boost.Algorithm</h2>
<p>Our proposal defines a single function that can be used both with a user-defined predicate and without it. When no predicate is specified, the comparator defaults to <code>std::less&lt;void&gt;()</code>. The void specialization of <code>&lt;functional&gt;</code>'s operator functors introduced in C++14 enables comparison using the proper type <a href="#ref5">[5]</a><a href="#ref6">[6]</a>.</p>
<p>Boost's clamp on the other hand was conceived before C++14 and uses two separate functions. Also, supporting compatibility with different versions of C++ is a reason for a Boost library to not require C++14-specific properties.</p>
<p>Like <code>std::min()</code> and <code>std::max()</code>, <code>clamp()</code> requires its arguments to be of the same type, whereas, Boost's clamp accepts arguments of different type.</p>
<p><a name="motivation"></a></p>
<h2 id="design-decisions">Design decisions</h2>
<p>We chose the name <em>clamp</em> as it is expressive and is already being used in other libraries <a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a>. Another name could be <em>limit</em>. Other names for <em>clamp_range</em> could be <em>clamp_elements</em>, or <em>clamp_transform</em>.</p>
<p><code>clamp()</code> can be regarded as a sibling of <code>std::min()</code> and <code>std::max()</code>. This makes it desirable to follow their interface using constexpr, passing parameters by const reference and returning the result by const reference. Passing values by <code>const &amp;</code> is desired for types that have a possibly expensive copy constructor such as <code>cpp_int</code> of Boost.Multiprecision <a href="#ref7">[7]</a> and <code>std::seminumeric::integer</code> from the Proposal for Unbounded-Precision Integer Types [<a href="#8">8</a>].</p>
<p>With the void specialization of <code>&lt;functional&gt;</code>'s operator functors available in C++14, we chose to combine the predicate and non-predicate versions into a single function and make <code>std::less&lt;&gt;()</code> its default comparator.</p>
<p><a name="wording"></a></p>
<h2 id="proposed-wording">Proposed wording</h2>
<div class="std">
<h3>
X.Y.Z Bounded value<span style="float:right">[alg.clamp]</span>
</h3>

<pre><code>template&lt;class T, class Compare = std::less&lt;&gt;&gt;
constexpr const T&amp; clamp( const T&amp; v, const T&amp; lo, const T&amp; hi, Compare comp = Compare() );</code></pre>
<p>1 <em>Requires</em>: Type <code>T</code> is <code>LessThanComparable</code> (Table 18).</p>
<p>2 <em>Returns</em>: The larger value of <code>v</code> and <code>lo</code> if <code>v</code> is smaller than <code>hi</code>, otherwise the smaller value of <code>v</code> and <code>hi</code>.</p>
<p>3 <em>Complexity</em>: <code>clamp</code> will call <code>comp</code> either one or two times before returning one of the three parameters.</p>
<p>4 <em>Remarks</em>: Returns the first argument when it is equivalent to one of the boundary arguments.</p>
<pre><code>template&lt;class InputIterator, class OutputIterator, class Compare = std::less&lt;&gt;&gt;
OutputIterator clamp_range( InputIterator first, InputIterator last, OutputIterator result,
    typename std::iterator_traits&lt;InputIterator&gt;::value_type const&amp; lo,
    typename std::iterator_traits&lt;InputIterator&gt;::value_type const&amp; hi, Compare comp = Compare() );</code></pre>
<p>1 <em>Requires</em>: T is <code>LessThanComparable</code> (Table 18) and <code>CopyAssignable</code> (Table 23).</p>
<p>2 <em>Returns</em>: <code>result + (last - first)</code>.</p>
<p>3 <em>Complexity</em>: Exactly <code>last - first</code> applications of <code>clamp</code> with the corresponding predicate.</p>
<p>4 <em>Remarks</em>: <code>result</code> may be equal to <code>first</code>.</p>
</div>
<p><a name="implementation"></a></p>
<h2 id="possible-implementation">Possible implementation</h2>
<p>A reference implementation of this proposal can be found at GitHub <a href="#ref9">[9]</a>.</p>
<p>Clamp a value per predicate:</p>
<pre><code>template&lt;class T, class Compare&gt;
constexpr const T&amp; clamp( const T&amp; val, const T&amp; lo, const T&amp; hi, Compare comp )
{
    return assert( !comp(hi, lo) ),
        comp(val, lo) ? lo : comp(hi, val) ? hi : val;
}</code></pre>
<p>Clamp range of values per predicate:</p>
<pre><code>template&lt;class InputIterator, class OutputIterator, class Compare&gt;
OutputIterator clamp_range(
    InputIterator first, InputIterator last, OutputIterator result,
    typename std::iterator_traits&lt;InputIterator&gt;::value_type const&amp; lo,
    typename std::iterator_traits&lt;InputIterator&gt;::value_type const&amp; hi, Compare comp )
{
    using arg_type = decltype(lo);

    return std::transform(
        first, last, result, [&amp;](arg_type val) -&gt; arg_type { return clamp(val, lo, hi, comp); } );
}</code></pre>
<p><a name="acknowledgements"></a></p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>Thanks to Marshall Clow for Boost.Algorithm's clamp which inspired this proposal and to Jonathan Wakely for his help with the proposing process.</p>
<p><a name="references"></a></p>
<h2 id="references">References</h2>
<p><a name="ref1"></a>[1] Marshall Clow. <a href="http://www.boost.org/doc/libs/1_58_0/libs/algorithm/doc/html/algorithm/Misc.html#the_boost_algorithm_library.Misc.clamp">clamp in the Boost Algorithm Library</a>.<br />Note: the Boost documentation shows <code>clamp()</code> using pass by value, whereas the actual code in <a href="http://www.boost.org/doc/libs/1_58_0/boost/algorithm/clamp.hpp">boost/algorithm/clamp.hpp</a> uses <code>const &amp;</code>. See <a href="https://svn.boost.org/trac/boost/ticket/10081">ticket 10081</a>.<br /><a name="ref2"></a>[2] Microsoft. <a href="http://msdn.microsoft.com/en-us/library/hh265137.aspx">C++ Accelerated Massive Parallelism library (AMP)</a>.<br /><a name="ref3"></a>[3] Qt Project. <a href="http://qt-project.org/doc/qt-5/qtglobal.html#qBound">Documentation on qBound</a>.<br /><a name="ref4"></a>[4] Scipy.org. <a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.clip.html">Documentation on numpy.clip</a>.<br /><a name="ref5"></a>[5] Stephan T. Lavavej. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421.htm">Making Operator Functors greater&lt;&gt; (N3421, HTML)</a>. 2012-09-20.<br /><a name="ref6"></a>[6] ISO/IEC. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf">Working Draft, Standard for Programming Language C++ (N4296, PDF)</a>. Section 20.9.6. 2014-11-19.<br /><a name="ref7"></a>[7] John Maddock. <a href="http://www.boost.org/doc/libs/1_55_0/libs/multiprecision/">Boost.Multiprecision</a>.<br /><a name="8"></a>[8] Pete Becker. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4038.html">Proposal for Unbounded-Precision Integer Types (N4038)</a>.<br /><a name="ref9"></a>[9] Martin Moene. <a href="https://github.com/martinmoene/clamp">Clamp algorithm (GitHub)</a>.</p>
<section class="footnotes">
<hr />
<ol>
<li id="fn1">Or even:
<pre><code>auto clamped_value = value;
if      ( value &lt; min_value ) clamped_value = min_value;
else if ( value &gt; max_value ) clamped_value = max_value;
</code></pre>


<a href="#fnref1">↩</a></li>
<li id="fn2"><p>As suggested by Jonathan Wakely on mailing list accu-general on 18 February 2014.<a href="#fnref2">↩</a></p></li>
</ol>
</section>
</body>
</html>
