1 
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29 
30 #pragma once
31 
32 // Standard headers.
33 #include <algorithm>
34 #include <cstddef>
35 
36 namespace foundation
37 {
38 
39 //
40 // Import std::min() and std::max() into the foundation namespace, otherwise they'll be shadowed.
41 //
42 
43 using std::min;
44 using std::max;
45 
46 
47 //
48 // Return the lesser of a set of objects.
49 //
50 
51 template <typename T>
52 T min(const T a, const T b, const T c);
53 
54 template <typename T>
55 T min(const T a, const T b, const T c, const T d);
56 
57 
58 //
59 // Return the greater of a set of objects.
60 //
61 
62 template <typename T>
63 T max(const T a, const T b, const T c);
64 
65 template <typename T>
66 T max(const T a, const T b, const T c, const T d);
67 
68 
69 //
70 // Return both the lesser and greater of a set of objects.
71 //
72 
73 template <typename T>
74 void minmax(const T a, const T b, T& min, T& max);
75 
76 template <typename T>
77 void minmax(const T a, const T b, const T c, T& min, T& max);
78 
79 
80 //
81 // Return the lesser (resp. greater) of two objects with the exact
82 // same semantics as the SSE instructions 'minps' (resp. 'maxps').
83 //
84 // An important property guaranteed by these functions is that if
85 // a, b or both are NaN, b will always be returned. Thus, if b is
86 // never NaN, the min/max of a and b is guaranteed not to be NaN.
87 //
88 // References:
89 //
90 //   http://www.sesp.cse.clrc.ac.uk/html/SoftwareTools/vtune/users_guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/mergedProjects/instructions/instruct32_hh/vc174.htm
91 //   http://www.sesp.cse.clrc.ac.uk/html/SoftwareTools/vtune/users_guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/mergedProjects/instructions/instruct32_hh/vc169.htm
92 //
93 
94 template <typename T>
95 T ssemin(const T a, const T b);
96 
97 template <typename T>
98 T ssemax(const T a, const T b);
99 
100 
101 //
102 // Return the index of the lesser or greater of a set of objects.
103 //
104 
105 template <typename T>
106 size_t min_index(const T& a, const T& b);
107 
108 template <typename T>
109 size_t min_index(const T& a, const T& b, const T& c);
110 
111 template <typename T>
112 size_t max_index(const T& a, const T& b);
113 
114 template <typename T>
115 size_t max_index(const T& a, const T& b, const T& c);
116 
117 
118 //
119 // Implementation.
120 //
121 
122 template <typename T>
min(const T a,const T b,const T c)123 inline T min(const T a, const T b, const T c)
124 {
125     return std::min(std::min(a, b), c);
126 }
127 
128 template <typename T>
min(const T a,const T b,const T c,const T d)129 inline T min(const T a, const T b, const T c, const T d)
130 {
131     return std::min(std::min(std::min(a, b), c), d);
132 }
133 
134 template <typename T>
max(const T a,const T b,const T c)135 inline T max(const T a, const T b, const T c)
136 {
137     return std::max(std::max(a, b), c);
138 }
139 
140 template <typename T>
max(const T a,const T b,const T c,const T d)141 inline T max(const T a, const T b, const T c, const T d)
142 {
143     return std::max(std::max(std::max(a, b), c), d);
144 }
145 
146 template <typename T>
minmax(const T a,const T b,T & min,T & max)147 inline void minmax(const T a, const T b, T& min, T& max)
148 {
149     if (a < b)
150     {
151         min = a;
152         max = b;
153     }
154     else
155     {
156         min = b;
157         max = a;
158     }
159 }
160 
161 template <typename T>
minmax(const T a,const T b,const T c,T & min,T & max)162 inline void minmax(const T a, const T b, const T c, T& min, T& max)
163 {
164     minmax(a, b, min, max);
165 
166     if (c < min) min = c;
167     if (c > max) max = c;
168 }
169 
170 template <typename T>
ssemin(const T a,const T b)171 inline T ssemin(const T a, const T b)
172 {
173     return a < b ? a : b;
174 }
175 
176 template <typename T>
ssemax(const T a,const T b)177 inline T ssemax(const T a, const T b)
178 {
179     return a > b ? a : b;
180 }
181 
182 template <typename T>
min_index(const T & a,const T & b)183 inline size_t min_index(const T& a, const T& b)
184 {
185     return a < b ? 0 : 1;
186 }
187 
188 template <typename T>
min_index(const T & a,const T & b,const T & c)189 inline size_t min_index(const T& a, const T& b, const T& c)
190 {
191     if (a < b)
192         return a < c ? 0 : 2;
193     else return b < c ? 1 : 2;
194 }
195 
196 template <typename T>
max_index(const T & a,const T & b)197 inline size_t max_index(const T& a, const T& b)
198 {
199     return a > b ? 0 : 1;
200 }
201 
202 template <typename T>
max_index(const T & a,const T & b,const T & c)203 inline size_t max_index(const T& a, const T& b, const T& c)
204 {
205     if (a > b)
206         return a > c ? 0 : 2;
207     else return b > c ? 1 : 2;
208 }
209 
210 }   // namespace foundation
211