summaryrefslogtreecommitdiff
path: root/boost/algorithm/clamp.hpp
blob: ae98d15d2f3f7fdca3ada2ec41bb26c4f0474600 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* 
   Copyright (c) Marshall Clow 2008-2012.

   Distributed under the Boost Software License, Version 1.0. (See accompanying
   file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

 Revision history:
   27 June 2009 mtc First version
   23 Oct  2010 mtc Added predicate version
   
*/

/// \file clamp.hpp
/// \brief Clamp algorithm
/// \author Marshall Clow
///
/// Suggested by olafvdspek in https://svn.boost.org/trac/boost/ticket/3215

#ifndef BOOST_ALGORITHM_CLAMP_HPP
#define BOOST_ALGORITHM_CLAMP_HPP

#include <functional>       //  For std::less
#include <iterator>         //  For std::iterator_traits
#include <cassert>

#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/mpl/identity.hpp>      // for identity
#include <boost/utility/enable_if.hpp> // for boost::disable_if

namespace boost { namespace algorithm {

/// \fn clamp ( T const& val, 
///               typename boost::mpl::identity<T>::type const& lo, 
///               typename boost::mpl::identity<T>::type const& hi, Pred p )
/// \return the value "val" brought into the range [ lo, hi ]
///     using the comparison predicate p.
///     If p ( val, lo ) return lo.
///     If p ( hi, val ) return hi.
///     Otherwise, return the original value.
/// 
/// \param val   The value to be clamped
/// \param lo    The lower bound of the range to be clamped to
/// \param hi    The upper bound of the range to be clamped to
/// \param p     A predicate to use to compare the values.
///                 p ( a, b ) returns a boolean.
///
  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 )
  {
//    assert ( !p ( hi, lo ));    // Can't assert p ( lo, hi ) b/c they might be equal
    return p ( val, lo ) ? lo : p ( hi, val ) ? hi : val;
  } 


/// \fn clamp ( T const& val, 
///               typename boost::mpl::identity<T>::type const& lo, 
///               typename boost::mpl::identity<T>::type const& hi )
/// \return the value "val" brought into the range [ lo, hi ].
///     If the value is less than lo, return lo.
///     If the value is greater than "hi", return hi.
///     Otherwise, return the original value.
///
/// \param val   The value to be clamped
/// \param lo    The lower bound of the range to be clamped to
/// \param hi    The upper bound of the range to be clamped to
///
  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>());
  } 

/// \fn clamp_range ( InputIterator first, InputIterator last, OutputIterator out, 
///       std::iterator_traits<InputIterator>::value_type lo, 
///       std::iterator_traits<InputIterator>::value_type hi )
/// \return clamp the sequence of values [first, last) into [ lo, hi ]
/// 
/// \param first The start of the range of values
/// \param last  One past the end of the range of input values
/// \param out   An output iterator to write the clamped values into
/// \param lo    The lower bound of the range to be clamped to
/// \param hi    The upper bound of the range to be clamped to
///
  template<typename InputIterator, typename OutputIterator> 
  OutputIterator clamp_range ( InputIterator first, InputIterator last, OutputIterator out,
    typename std::iterator_traits<InputIterator>::value_type lo, 
    typename std::iterator_traits<InputIterator>::value_type hi )
  {
  // this could also be written with bind and std::transform
    while ( first != last )
        *out++ = clamp ( *first++, lo, hi );
    return out;
  } 

/// \fn clamp_range ( const Range &r, OutputIterator out, 
///       typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type lo,
///       typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type hi )
/// \return clamp the sequence of values [first, last) into [ lo, hi ]
/// 
/// \param r     The range of values to be clamped
/// \param out   An output iterator to write the clamped values into
/// \param lo    The lower bound of the range to be clamped to
/// \param hi    The upper bound of the range to be clamped to
///
  template<typename Range, typename OutputIterator> 
  typename boost::disable_if_c<boost::is_same<Range, OutputIterator>::value, OutputIterator>::type
  clamp_range ( const Range &r, OutputIterator out,
    typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type lo, 
    typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type hi )
  {
    return clamp_range ( boost::begin ( r ), boost::end ( r ), out, lo, hi );
  } 


/// \fn clamp_range ( InputIterator first, InputIterator last, OutputIterator out, 
///       std::iterator_traits<InputIterator>::value_type lo, 
///       std::iterator_traits<InputIterator>::value_type hi, Pred p )
/// \return clamp the sequence of values [first, last) into [ lo, hi ]
///     using the comparison predicate p.
/// 
/// \param first The start of the range of values
/// \param last  One past the end of the range of input values
/// \param out   An output iterator to write the clamped values into
/// \param lo    The lower bound of the range to be clamped to
/// \param hi    The upper bound of the range to be clamped to
/// \param p     A predicate to use to compare the values.
///                 p ( a, b ) returns a boolean.

///
  template<typename InputIterator, typename OutputIterator, typename Pred> 
  OutputIterator clamp_range ( InputIterator first, InputIterator last, OutputIterator out,
    typename std::iterator_traits<InputIterator>::value_type lo, 
    typename std::iterator_traits<InputIterator>::value_type hi, Pred p )
  {
  // this could also be written with bind and std::transform
    while ( first != last )
        *out++ = clamp ( *first++, lo, hi, p );
    return out;
  } 

/// \fn clamp_range ( const Range &r, OutputIterator out, 
///       typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type lo,
///       typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type hi,
///       Pred p )
/// \return clamp the sequence of values [first, last) into [ lo, hi ]
///     using the comparison predicate p.
/// 
/// \param r     The range of values to be clamped
/// \param out   An output iterator to write the clamped values into
/// \param lo    The lower bound of the range to be clamped to
/// \param hi    The upper bound of the range to be clamped to
/// \param p     A predicate to use to compare the values.
///                 p ( a, b ) returns a boolean.
//
//  Disable this template if the first two parameters are the same type;
//  In that case, the user will get the two iterator version.
  template<typename Range, typename OutputIterator, typename Pred> 
  typename boost::disable_if_c<boost::is_same<Range, OutputIterator>::value, OutputIterator>::type
  clamp_range ( const Range &r, OutputIterator out,
    typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type lo, 
    typename std::iterator_traits<typename boost::range_iterator<const Range>::type>::value_type hi,
    Pred p )
  {
    return clamp_range ( boost::begin ( r ), boost::end ( r ), out, lo, hi, p );
  } 


}}

#endif // BOOST_ALGORITHM_CLAMP_HPP