p - Readable paragraph ?
// Readable code ?
template< class T>
clamp( T const & v, T const & lo, T const & hi );
reveal.js comes with a few themes built in:
Black (default) -
White -
League -
Sky -
Beige -
Simple
Serif -
Blood -
Night -
Moon -
Solarized
f 540
or... € 2345 to date
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.
Wikipedia. MC6800.
CP/M 2.2
f 4000
€ 4300 to date
Wordstar
JRT Pascal
BDS-C
SysAdmin
Programmer
At Leiden University
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 );
. . .
}
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/Support the C++ software developer community and
promote the understanding and use of
modern Standard C++
on all compilers and platforms.
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.
As of today, the question still floats on std-proposals forum.
Zero reactions.
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.
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.
Is there prior art?
Boost clamp(), Microsoft AMP clamp(),
QT qBound(), Python numpy clip().
template<class T, class Compare = std::less<>>
constexpr const T&
clamp( const T& v,
const T& lo, const T& hi, Compare comp = Compare() );
similar for clamp_range()
Contacted Niels Dekker for help,
as he already has experience with writing a proposal.
N2819 - Ref-qualifiers for assignment operators of the Standard Library
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 );
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
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
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 ) );
}
[ 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.
#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) );
}
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 );
29 Oct 2015
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:
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.
Thanks, Questions ?