H1 - Checkup

H2 - Readable ?

H3 - Readable ?

p - Readable paragraph ?


// Readable code ?

template< class T>
clamp( T const & v, T const & lo, T const & hi );
    

Themes

reveal.js comes with a few themes built in:
Black (default) - White - League - Sky - Beige - Simple
Serif - Blood - Night - Moon - Solarized

 

 

 

Proposing

clamp()

for

C++ standardisation

1975

f 540

or... € 2345 to date

1978 - Exidy Sorcerer (Zilog Z80)

1982 - Commondore 64 (MOS 6510)

1990 - Next station (Motorola 68040)

My Hobby

1977-1981

HTS'A

Amsterdam

Elektrotechniek
Informatietechniek


'BEGIN'
    'COMMENT' Algol 60;
     OUTPUT(4,'(''('Hello, world')',/')')
'END'
    


The UvA Computer Museum. Algol mark sense card (about 1968)

Hello, world.

Let's eat Ma.

Let's eat, Ma.

Kevlin Henney

1982

Electronics
engineer

Wikipedia. MC6800.

1985

Bondwell 12

CP/M 2.2

f 4000

€ 4300 to date

 

Wordstar
JRT Pascal
BDS-C

1987-2004

Unix & Windows

SysAdmin

Programmer

2005-ish

Software
Developer

At Leiden University

What

  • Microprocessors - MC6802, MC6909, Z80 (80x86)
  • Microcontrollers - MC6805, Intel 8051 (Atmel)
  • Languages - Assembly, Basic, Pascal, C, C++, Python, KSH, AWK, SED, LabVIEW

Scanning Probe Microscopy (SPM)

CAMERA Application ~ 1998 onwards

Computer Aided Measurement Environment
for Realtime Atomic imaging


void FooFooFoo( unsigned int uiValue)
{
    unsigned int uiTrueValue = uiValue;

    if ( uiTrueValue < uiMinValue )
    {
        uiTrueValue = uiMinValue;
    }
    else if ( value > uiMaxValue )
    {
        uiTrueValue = uiMaxValue;
    }

    . . .
}
     

void foo( int value )
{
    int clamped_value = value;
    if      ( value < min_value ) clamped_value = min_value;
    else if ( value > max_value ) clamped_value = max_value;

    . . .
}
    

void foo( int value )
{
    int const clamped_value =
        std::min( std::max( value, min_value ), max_value );

    . . .
}
    

void foo( int value )
{
    int const clamped_value = clamp( value, min_value, max_value );

    . . .
}
    
``` > On 18-Feb-14 19:12, Jonathan Wakely wrote: > >> Any idea why something like this isn't in the standard library? > > Because noone has proposed it. _______________________________________________ accu-general mailing list accu-general@accu.org http://lists.accu.org/mailman/listinfo/accu-general ```

Because noone has proposed it.

But if you propose it I suggest you call it

clamp.

I expect that's the most well-known name.

Jonathan Wakely 

ACCU is an organisation for anyone interested in
developing and improving
programming skills.

ACCU welcomes everyone who is interested in
any programming language.

ACCU supports its members by hosting mailing lists, running a yearly conference, publishing journals and organising online study groups.

http://accu.org/

Standard C++ Foundation

Support the C++ software developer community and
promote the understanding and use of
modern Standard C++
on all compilers and platforms.

https://isocpp.org/

Standard C++ Foundation

Two near-term goals are to promote:

1. Spreading correct, up-to-date information
on modern C++.

2. High-quality C++ libraries: standard and community;
Adopting libraries in Standard C++ by
reducing barriers to submitting.

... submitting a proposal to
the ISO C++ standardization committee.

![](image/iso.png) [ISO]() is an independent, non-governmental international organization with a membership of 162 [national standards bodies](). Through its members, it brings together [experts]() to share knowledge and develop voluntary, [consensus-based](), market relevant [International Standards]() that support innovation and provide solutions to global challenges.

![](image/iso.png) ### [Key principles]() 1. ISO standards respond to a [need]() in the market, 2. are based on global [expert opinion](), 3. are developed through a [multi-stakeholder process](), 4. are based on a [consensus]().

Stages for standards development

  1. Proposal – Skip for revisions
  2. Preparatory – WD/ WDTS  optional
  3. Committee – CD / PDTS  optional
  4. Enquiry – DIS / DTS
  5. Approval – FDIS / FDTS  optional
  6. Publication – IS / TS
  7. Review – IS / TS
  8. Withdrawal

How to submit a proposal

  1. Float the idea on std-proposals forum.
  2. Post an initial draft using skeleton.
  3. Iterate and fine-tune.
[Float the idea - 21 Feb 2014](https://groups.google.com/a/isocpp.org/forum/?fromgroups#!searchin/std-proposals/clamp/std-proposals/NnijFrYABqc/4Wozg9BvtaMJ) ``` Are there plans to add a clamp algorithm[1,2] to the standard? (just curious for the moment.) Martin Moene ___ [1] Boost Algorithm, http://www.boost.org/libs/algorithm/doc/html/algorithm/Misc.html#the_boost_algorithm_library.Misc.clamp [2] Microsoft C++ AMP, http://msdn.microsoft.com/en-us/library/hh265137.aspx ```

As of today, the question still floats on std-proposals forum.

Zero reactions.

A viable idea?

Does it solve a problem?

[clamping] 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.

A viable idea?

What use cases do you have?

It is a common programming task to constrain a value to fall within certain limits, e.g. for GUI field values.

A viable idea?

Is there prior art?


Boost clamp(), Microsoft AMP clamp(),
QT qBound(), Python numpy clip().

| Document | Date | Discussed | |----------|------|-----------| | [N4536](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4536.html) | 17 May 2015 | BSI C++ panel | | [P0025R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0025r0.html) | 18 Sep 2015 | BSI C++ panel, Kona | | [P0025R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0025r1.html) | 29 Oct 2015 | Jacksonville |
[Structure]() of a proposal - Table of contents - Introduction - Motivation and scope - Impact on the standard - Design decisions - Technical specifications -  including "[standardese]()" wording - Acknowledgements - References
What the standardese essence looks like - N4536

template<class T, class Compare = std::less<>>
constexpr const T& 
clamp( const T& v, 
       const T& lo, const T& hi, Compare comp = Compare() );
    

 

  1. Requires: Type T is LessThanComparable (Table 18).
  2. Returns: The larger value of v and lo if v is smaller than hi,
    otherwise the smaller value of v and hi.
  3. Complexity: clamp will call comp either one or two times
    before returning one of the three parameters.
  4. Remarks: Returns the first argument when it is equivalent to
    one of the boundary arguments.

similar for clamp_range()

March 2014

Contacted Niels Dekker for help,

as he already has experience with writing a proposal.

 

N2819 - Ref-qualifiers for assignment operators of the Standard Library

https://github.com/martinmoene/clamp

Taking a look at Boost clamp(), simplified:


template< typename T >
T const & clamp( T const & val, T const & lo, T const & hi );

template< typename T, typename Pred >
T const & clamp( T const & val, T const & lo, T const & hi, Pred p );

template< typename InputIterator, typename OutputIterator >
OutputIterator
clamp_range( InputIterator, InputIterator, OutputIterator, T lo, T hi );

template< typename InputIterator, typename OutputIterator, typename Pred >
OutputIterator
clamp_range( InputIterator first, InputIterator last, OutputIterator out,
             T lo, T hi, Pred p );

// Plus two Range-based versions
    

template< typename T >
T const& clamp ( const T& val,
typename boost::mpl::identity<T>::type const & lo,
typename boost::mpl::identity<T>::type const & hi )
{
    return (clamp) ( val, lo, hi, std::less<T>() );
}

template< typename T, typename Pred >
T const & clamp ( T const& val,
typename boost::mpl::identity<T>::type const & lo,
typename boost::mpl::identity<T>::type const & hi, Pred p )
{
//  Can't assert p ( lo, hi ) b/c they might be equal
//  assert ( !p ( hi, lo ) );
    return p ( val, lo ) ? lo : p ( hi, val ) ? hi : val;
}
    

Boost clamp()

In clamp() lo and hi are taken by const &, whereas in clamp_range() lo and hi are value parameters.


template< typename T >
T const &
clamp(
    T const & val,
    typename boost::mpl::identity< T >::type const & lo,
    typename boost::mpl::identity< T >::type const & hi );
    
versus:

template< typename InputIterator, typename OutputIterator >
OutputIterator
clamp_range(
    InputIterator, InputIterator, OutputIterator,
    typename std::iterator_traits< InputIterator >::value_type lo,
    typename std::iterator_traits< InputIterator >::value_type hi );
    

Boost clamp()

And while the code reads


template< typename T >
T const & clamp( T const & val, idT const & lo, idT const & hi );
    
the documentation reads:


template< typename T >
T clamp ( T val, T lo, T hi );
    

 

Ticket: #10081: Boost.Algorithm: clamp: discrepancy in parameter & return types between code and online documentation

Towards std::clamp()


// A sibling of std::min() and std::max()

template< class T >
constexpr const T&
min( const T& a, const T& b );

template< class T, class Compare >
constexpr const T&
min( const T& a, const T& b, Compare comp );

// plus two initializer_list variants

template< class T, class Compare = less<> >
constexpr const T&
clamp( const T& v, const T& lo, const T& hi, Compare comp = Compare() );
    

std::less<> (C++14)

Missing constexpr on std::less<void> specialization

Working Draft N3797, 13 Oct 2013.

This appeared to be an editorial omission.


17 Mar 2014

ACCU Conference April 2014

Jonathan Wakely  Marshall Clow

 offers help with proposal  author of Boost clamp()

Time passes...

N4536 - interface of clamp()


// clamp value per predicate, default std::less<> (C++14):

template< class T, class Compare = less<> >
constexpr const T&
clamp( const T& val, const T& lo, const T& hi, Compare comp = Compare() );
    


17 May 2015

N4536 - example implementation for clamp()


template< class T, class Compare >
constexpr const T&
clamp( const T& val, const T& lo, const T& hi, Compare comp )
{
    return assert( !comp(hi, lo) ),
        comp(val, lo) ? lo : comp(hi, val) ? hi : val;
}
    

Example usage of clamp()


// Clamp according to default, alphabetic order: yields "10":

auto clamped_alphabetic = clamp("10"s, "0"s, "9"s);

// Clamp according to predicated, numeric order: yields "9":

auto clamped_numeric = clamp("10"s, "0"s, "9"s,
    [](const auto& a, const auto& b) { return stoi(a) < stoi(b); } );
    

Nonsensical original example usage of clamp()


struct rgb{ ... };

auto clamped_rgb = clamp( rgb_value, rgb_lo, rgb_hi, rgb_compare );
    

N4536 - interface of clamp_range()


// clamp range of values per predicate, default std::less<> (C++14):

template<
    class InputIterator,
    class OutputIterator,
    class Compare = less<> >
OutputIterator
clamp_range(
    InputIterator first, InputIterator last,
    OutputIterator out,
    typename std::iterator_traits<InputIterator>::value_type const& lo,
    typename std::iterator_traits<InputIterator>::value_type const& hi,
    Compare comp = Compare() );

N4536 - example implementation for clamp_range()


template< class InputIterator, class OutputIterator, class Compare >
OutputIterator
clamp_range(
    InputIterator first, InputIterator last,
    OutputIterator out,
    typename std::iterator_traits<InputIterator>::value_type const& lo,
    typename std::iterator_traits<InputIterator>::value_type const& hi,
    Compare comp )
{
    using arg_type = decltype(lo);

    return std::transform(
        first, last, out, [&](arg_type val) -> arg_type {
            return clamp(val, lo, hi, comp); }
    );
}
    

 BSI C++ panel 

We are in favour of the majority of the proposal.

However, we are not persuaded of the need for clamp_range; although it wouldn't stop us voting for the overall paper if left in. We would prefer to gain clamp_range indirectly as a consequence of improving C++'s support for composition of algorithms and predicates!


13 Aug 2015


#include <range/v3/all.hpp>

int main()
{
    using namespace ranges;

    auto && rng =
        view::iota(0, 20)
        | view::remove_if( is_odd() )
        | view::transform( [](int x) { return clamp(x, 5, 15); } );

    std::cout << rng;
}
// g++ -std=c++11 -I../clamp -I../range-v3/include -o clamp-range-v3.exe clamp-range-v3.cpp && clamp-range-v3.exe
// [5,5,5,6,8,10,12,14,15,15]
    

Eric Niebler, Casey Carter. N4560 Working Draft, C++ Extensions for Ranges


// clamp-range-v3

#include <iostream>

#include <clamp.hpp>

#include <range/v3/core.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/view/remove_if.hpp>
#include <range/v3/view/transform.hpp>

struct is_odd
{
    bool operator()(int i) const
    {
        return (i % 2) == 1;
    }
};

int main()
{
    using namespace ranges;

    auto && rng =
        view::iota(0, +20) |
        view::remove_if( is_odd() ) |
        view::transform( [](int x) { return clamp(x, 5, 15); } );

    std::cout << rng;
}

#if 0
g++ -std=c++11 -I"../clamp (Dropbox)" -I../range-v3/include -I.. -o clamp-range-v3.exe clamp-range-v3.cpp && clamp-range-v3.exe
[5,5,5,6,8,10,12,14,15,15]
#endif
    

P0025R0 - Follow interface of std::min(), std::max()


template< class T >
constexpr const T&
clamp( const T& v, const T& lo, const T& hi );

template< class T, class Compare >
constexpr const T&
clamp( const T& v, const T& lo, const T& hi, Compare comp );
    


"All the operations in 25.4 [alg.sorting] have two versions:
one that takes a function object of type Compare and
one that uses an operator<."

Omit clamp_range()


18 Sep 2015

25.4 Sorting and related operations [alg.sorting]

1 All the operations in 25.4 have two versions:
one that takes a function object of type Compare and
one that uses an operator<.

Lawrence Crowl

P0105 - Rounding and Overflow in C++


1 Oct 2015

clamp( 8, 2, 4 ) ~ limit<overflow::saturate>( 2, 4, 8 )


P0025 proposes a 'clamp' function that is similar in purpose to an overload in P0105 called 'limit'. The primary difference is that the latter has an 'overflow' parameter which specifies what to do about out-of-bounds values.


Make room for the limit proposal?

 BSI C++ panel 


We discussed the revised paper at the BSI C++ panel meeting on Monday
and we are in favour. We did have two comments...

(1) Must lo be no greater than hi ?

(2) We wondered whether the wording might be simplified by expressing the effects in terms of min and max?


7 Oct 2015

BSI  (1) Must lo be no greater than hi ?

The actual wording does not require lo to be no greater than hi, although the result in that case may not be what a naive user may expect.

"The larger value of v and lo if v is smaller than hi,
otherwise the smaller value of v and hi.
"

So clamp(5, 10, 8) would result in 10 as 5 is less than 8 so
it must return the larger of 5 and 10.

However the example has an assert( !comp(hi, lo) ) which
is not implied by the formal wording.

 Kona 

Post-review observations via Walter Brown

  • Allow lo > hi ?
  • Allow arbitrary parameter order?
  • clamp( a, b, c ) ~ middle( a, b, c )

Many users will avoid clamp if it costs more than
the sum of std::min and std::max.


19 Oct 2015


// 3-element median() expressed via min() and max():

template< class T >
constexpr const T& median( const T& a, const T& b, const T& c )
{
    return max( min(a, b), min( max(a, b), c ) );
}
    

median

[ 10, 11, 13, 15, 16, 23, 26 ]

The middle number in a sorted list of numbers.


template< typename Container >
auto median( Container const & cont ) -> typename Container::value_type
{
    Container r( cont );
    auto const middle = r.size() / 2;

    std::nth_element( r.begin(), r.begin() + middle, r.end() );

    return r[ middle ];
}
    

Has the same number of smaller and larger values to the left and to the right of it: only needs to be partially sorted.

median


#include <algorithm>
#include <iostream>
#include <vector>

template< typename Container >
auto median( Container const & cont ) -> typename Container::value_type
{
    Container r( cont );
    auto const middle = r.size() / 2;

    std::nth_element( r.begin(), r.begin() + middle, r.end() );

    return r[ middle ];
}

int main()
{
    using V = std::vector<int>;

    std::cout << median( V{ 1, 5, 3 } );
}

// cl -nologo -EHsc median-simple.cpp && median-simple.exe
// g++ -Wall -std=c++11 -o median-simple.exe median-simple.cpp && median-simple.exe
// 3
    

// Copyright (c) 1994
// Hewlett-Packard Company

template <class T>
inline T __median(T a, T b, T c) {
    if (a < b)
	if (b < c)
	    return b;
	else if (a < c)
	    return c;
	else
	    return a;
    else if (a < c)
	return a;
    else if (b < c)
	return c;
    else
	return b;
}

template <class T, class Compare>
inline T __median(T a, T b, T c, Compare comp) {
    if (comp(a, b))
	if (comp(b, c))
	    return b;
	else if (comp(a, c))
	    return c;
	else
	    return a;
    else if (comp(a, c))
	return a;
    else if (comp(b, c))
	return c;
    else
	return b;
}
    

// clamp() with free boundary order expressed via min() and max():

template< class T >
constexpr const T& clamp( const T& v, const T& bound1, const T& bound2 )
{
    return min( max( v, min(bound1, bound2) ), max(bound1, bound2) );
}
    
P0025R1

template< class T >
constexpr const T&
clamp( const T& v, const T& lo, const T& hi );

template< class T, class Compare >
constexpr const T&
clamp( const T& v, const T& lo, const T& hi, Compare comp );
    

 

  1. Requires: The value of lo shall be no greater than hi.
    For the first form, type T shall be LessThanComparable.
  2. Returns: The larger value of v and lo if v is smaller than hi,
    otherwise the smaller value of v and hi.
  3. Remarks: Returns v when it is equivalent to lo, hi, or both.
  4. Complexity: At most two comparisons.

29 Oct 2015

### [P0025R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0025r0.html) - changes since N4536 - Function [clamp_range()]() is considered superfluous in view of the Ranges proposal and has been dropped from this proposal. - The [declaration style]() of clamp() has been made consistent with the one of min() and max().
### [P0025R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0025r1.html) - changes since P0025R0 - The requirement for [lo]() to be no greater than [hi]() has been added per guidance from SG6 (Numerics) and LEWG. - The [example]() using the predicate form has been replaced. - The name [limit]() has been removed in favor of P0105, Rounding and Overflow in C++. - A brief discussion of [middle()]() and [median()]() has been added.

Walter Brown

Offers to shepherd the proposal in Jacksonville,
starting 29 Feb 2016 (!)

 Jacksonville 

[personal communication adapted for online version]

Reviewed by LWG; accepted in plenary (congrat's!) for the next C++17 Working Draft:

  • p0025r1 clamp()
  • p0030r1 hypot()
  • p0031r0 constexpr iterators, etc.
  • p0077r2 is_callable trait
  • P0226R0 math.special functions

5 Mar 2016

 Jacksonville 

[personal communication removed from online version]

Kind words. …

 Jacksonville 

[personal communication removed from online version]

… Encouraging words, words of thank.

Attending committee meetings is
a professional experience like few others.

All's well that ends well.

[personal communication adapted for online version]

Oh dear. The schedule for Tuesday in Jacksonville
included wording review for P0025R1.

… But the motion was to adopt P0025R0.

We probably need to get
the full committee to approve P0025R1 as well.

Jonathan Wakely 
Yesterday, 16 Mar 2016
## Wrap-up - We 'get' the standardization [process]() for our purpose. - Proposing takes [time](), easily two years. - [People]() are quite helpful, and may give differing advice ;-) - It's good to [team-up]() with someone else, preferably someone who already has proposed. - [clamp()]() was a relatively easy target. - Trust the committee's [consensus](). - [Appreciate]() proposers' and committee's investments.

Thanks, Questions ?

## References - [accu.org](http://accu.org/) - [isocpp.org](http://isocpp.org/) - BOOST. [clamp()]() - [N4536](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4536.html) - [P0025R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0025r0.html) - [P0025R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0025r1.html) [@MartinMoene](https://twitter.com/MartinMoene) etc.