1//===----------------------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// <algorithm>
11// XFAIL: c++98, c++03, c++11, c++14
12
13// template<class T, class Compare>
14//   const T&
15//   clamp(const T& v, const T& lo, const T& hi, Compare comp);
16
17#include <algorithm>
18#include <functional>
19#include <cassert>
20
21struct Tag {
22    Tag() : val(0), tag("Default") {}
23    Tag(int a, const char *b) : val(a), tag(b) {}
24    ~Tag() {}
25
26    int val;
27    const char *tag;
28    };
29
30bool eq(const Tag& rhs, const Tag& lhs) { return rhs.val == lhs.val && rhs.tag == lhs.tag; }
31// bool operator==(const Tag& rhs, const Tag& lhs) { return rhs.val == lhs.val; }
32bool comp (const Tag& rhs, const Tag& lhs) { return rhs.val <  lhs.val; }
33
34
35template <class T, class C>
36void
37test(const T& v, const T& lo, const T& hi, C c, const T& x)
38{
39    assert(&std::clamp(v, lo, hi, c) == &x);
40}
41
42int main()
43{
44    {
45    int x = 0;
46    int y = 0;
47    int z = 0;
48    test(x, y, z, std::greater<int>(), x);
49    test(y, x, z, std::greater<int>(), y);
50    }
51    {
52    int x = 0;
53    int y = 1;
54    int z = -1;
55    test(x, y, z, std::greater<int>(), x);
56    test(y, x, z, std::greater<int>(), x);
57    }
58    {
59    int x = 1;
60    int y = 0;
61    int z = 0;
62    test(x, y, z, std::greater<int>(), y);
63    test(y, x, z, std::greater<int>(), y);
64    }
65
66    {
67//  If they're all the same, we should get the value back.
68    Tag x{0, "Zero-x"};
69    Tag y{0, "Zero-y"};
70    Tag z{0, "Zero-z"};
71    assert(eq(std::clamp(x, y, z, comp), x));
72    assert(eq(std::clamp(y, x, z, comp), y));
73    }
74
75    {
76//  If it's the same as the lower bound, we get the value back.
77    Tag x{0, "Zero-x"};
78    Tag y{0, "Zero-y"};
79    Tag z{1, "One-z"};
80    assert(eq(std::clamp(x, y, z, comp), x));
81    assert(eq(std::clamp(y, x, z, comp), y));
82    }
83
84    {
85//  If it's the same as the upper bound, we get the value back.
86    Tag x{1, "One-x"};
87    Tag y{0, "Zero-y"};
88    Tag z{1, "One-z"};
89    assert(eq(std::clamp(x, y, z, comp), x));
90    assert(eq(std::clamp(z, y, x, comp), z));
91    }
92
93    {
94//  If the value is between, we should get the value back
95    Tag x{1, "One-x"};
96    Tag y{0, "Zero-y"};
97    Tag z{2, "Two-z"};
98    assert(eq(std::clamp(x, y, z, comp), x));
99    assert(eq(std::clamp(y, x, z, comp), x));
100    }
101
102    {
103//  If the value is less than the 'lo', we should get the lo back.
104    Tag x{0, "Zero-x"};
105    Tag y{1, "One-y"};
106    Tag z{2, "Two-z"};
107    assert(eq(std::clamp(x, y, z, comp), y));
108    assert(eq(std::clamp(y, x, z, comp), y));
109    }
110    {
111//  If the value is greater than 'hi', we should get hi back.
112    Tag x{2, "Two-x"};
113    Tag y{0, "Zero-y"};
114    Tag z{1, "One-z"};
115    assert(eq(std::clamp(x, y, z, comp), z));
116    assert(eq(std::clamp(y, z, x, comp), z));
117    }
118
119    {
120    typedef int T;
121    constexpr T x = 1;
122    constexpr T y = 0;
123    constexpr T z = 0;
124    static_assert(std::clamp(x, y, z, std::greater<T>()) == y, "" );
125    static_assert(std::clamp(y, x, z, std::greater<T>()) == y, "" );
126    }
127}
128