blob: 6fcbf00332970fc8002baf6dff072fa34d0fb8c2 [file] [log] [blame]
kwiberg7885d3f2017-04-25 12:35:07 -07001/*
2 * Copyright 2017 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <algorithm>
12#include <limits>
13
14#include "webrtc/base/safe_minmax.h"
15#include "webrtc/test/gtest.h"
16
17namespace rtc {
18
19namespace {
20
21// Functions that check that SafeMin() and SafeMax() return the specified type.
22// The functions that end in "R" use an explicitly given return type.
23
24template <typename T1, typename T2, typename Tmin, typename Tmax>
25constexpr bool TypeCheckMinMax() {
26 return std::is_same<decltype(SafeMin(std::declval<T1>(), std::declval<T2>())),
27 Tmin>::value &&
28 std::is_same<decltype(SafeMax(std::declval<T1>(), std::declval<T2>())),
29 Tmax>::value;
30}
31
32template <typename T1, typename T2, typename R>
33constexpr bool TypeCheckMinR() {
34 return std::is_same<
35 decltype(SafeMin<R>(std::declval<T1>(), std::declval<T2>())), R>::value;
36}
37
38template <typename T1, typename T2, typename R>
39constexpr bool TypeCheckMaxR() {
40 return std::is_same<
41 decltype(SafeMax<R>(std::declval<T1>(), std::declval<T2>())), R>::value;
42}
43
44// clang-format off
45
46// SafeMin/SafeMax: Check that all combinations of signed/unsigned 8/64 bits
47// give the correct default result type.
48static_assert(TypeCheckMinMax< int8_t, int8_t, int8_t, int8_t>(), "");
49static_assert(TypeCheckMinMax< int8_t, uint8_t, int8_t, uint8_t>(), "");
50static_assert(TypeCheckMinMax< int8_t, int64_t, int64_t, int64_t>(), "");
51static_assert(TypeCheckMinMax< int8_t, uint64_t, int8_t, uint64_t>(), "");
52static_assert(TypeCheckMinMax< uint8_t, int8_t, int8_t, uint8_t>(), "");
53static_assert(TypeCheckMinMax< uint8_t, uint8_t, uint8_t, uint8_t>(), "");
54static_assert(TypeCheckMinMax< uint8_t, int64_t, int64_t, int64_t>(), "");
55static_assert(TypeCheckMinMax< uint8_t, uint64_t, uint8_t, uint64_t>(), "");
56static_assert(TypeCheckMinMax< int64_t, int8_t, int64_t, int64_t>(), "");
57static_assert(TypeCheckMinMax< int64_t, uint8_t, int64_t, int64_t>(), "");
58static_assert(TypeCheckMinMax< int64_t, int64_t, int64_t, int64_t>(), "");
59static_assert(TypeCheckMinMax< int64_t, uint64_t, int64_t, uint64_t>(), "");
60static_assert(TypeCheckMinMax<uint64_t, int8_t, int8_t, uint64_t>(), "");
61static_assert(TypeCheckMinMax<uint64_t, uint8_t, uint8_t, uint64_t>(), "");
62static_assert(TypeCheckMinMax<uint64_t, int64_t, int64_t, uint64_t>(), "");
63static_assert(TypeCheckMinMax<uint64_t, uint64_t, uint64_t, uint64_t>(), "");
64
65// SafeMin/SafeMax: Check that we can use enum types.
66enum DefaultE { kFoo = -17 };
67enum UInt8E : uint8_t { kBar = 17 };
68static_assert(TypeCheckMinMax<unsigned, DefaultE, int, unsigned>(), "");
69static_assert(TypeCheckMinMax<unsigned, UInt8E, uint8_t, unsigned>(), "");
70static_assert(TypeCheckMinMax<DefaultE, UInt8E, int, int>(), "");
71
72using ld = long double;
73
74// SafeMin/SafeMax: Check that all floating-point combinations give the
75// correct result type.
76static_assert(TypeCheckMinMax< float, float, float, float>(), "");
77static_assert(TypeCheckMinMax< float, double, double, double>(), "");
78static_assert(TypeCheckMinMax< float, ld, ld, ld>(), "");
79static_assert(TypeCheckMinMax<double, float, double, double>(), "");
80static_assert(TypeCheckMinMax<double, double, double, double>(), "");
81static_assert(TypeCheckMinMax<double, ld, ld, ld>(), "");
82static_assert(TypeCheckMinMax< ld, float, ld, ld>(), "");
83static_assert(TypeCheckMinMax< ld, double, ld, ld>(), "");
84static_assert(TypeCheckMinMax< ld, ld, ld, ld>(), "");
85
86// clang-format on
87
88// SafeMin/SafeMax: Check some cases of explicitly specified return type. The
89// commented-out lines give compilation errors due to the requested return type
90// being too small or requiring an int<->float conversion.
91static_assert(TypeCheckMinR<int8_t, int8_t, int16_t>(), "");
92// static_assert(TypeCheckMinR<int8_t, int8_t, float>(), "");
93static_assert(TypeCheckMinR<uint32_t, uint64_t, uint32_t>(), "");
94// static_assert(TypeCheckMaxR<uint64_t, float, float>(), "");
95// static_assert(TypeCheckMaxR<uint64_t, double, float>(), "");
96static_assert(TypeCheckMaxR<uint32_t, int32_t, uint32_t>(), "");
97// static_assert(TypeCheckMaxR<uint32_t, int32_t, int32_t>(), "");
98
99template <typename T1, typename T2, typename Tmin, typename Tmax>
100constexpr bool CheckMinMax(T1 a, T2 b, Tmin min, Tmax max) {
101 return TypeCheckMinMax<T1, T2, Tmin, Tmax>() && SafeMin(a, b) == min &&
102 SafeMax(a, b) == max;
103}
104
105// SafeMin/SafeMax: Check a few values.
106static_assert(CheckMinMax(int8_t{1}, int8_t{-1}, int8_t{-1}, int8_t{1}), "");
107static_assert(CheckMinMax(uint8_t{1}, int8_t{-1}, int8_t{-1}, uint8_t{1}), "");
108static_assert(CheckMinMax(uint8_t{5}, uint64_t{2}, uint8_t{2}, uint64_t{5}),
109 "");
110static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(),
111 std::numeric_limits<uint32_t>::max(),
112 std::numeric_limits<int32_t>::min(),
113 std::numeric_limits<uint32_t>::max()),
114 "");
115static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(),
116 std::numeric_limits<uint16_t>::max(),
117 std::numeric_limits<int32_t>::min(),
118 int32_t{std::numeric_limits<uint16_t>::max()}),
119 "");
120// static_assert(CheckMinMax(1.f, 2, 1.f, 2.f), "");
121static_assert(CheckMinMax(1.f, 0.0, 0.0, 1.0), "");
122
123} // namespace
124
125// clang-format off
126
127// These functions aren't used in the tests, but it's useful to look at the
128// compiler output for them, and verify that (1) the same-signedness *Safe
129// functions result in exactly the same code as their *Ref counterparts, and
130// that (2) the mixed-signedness *Safe functions have just a few extra
131// arithmetic and logic instructions (but no extra control flow instructions).
132int32_t TestMinRef( int32_t a, int32_t b) { return std::min(a, b); }
133uint32_t TestMinRef( uint32_t a, uint32_t b) { return std::min(a, b); }
134int32_t TestMinSafe( int32_t a, int32_t b) { return SafeMin(a, b); }
135int32_t TestMinSafe( int32_t a, uint32_t b) { return SafeMin(a, b); }
136int32_t TestMinSafe(uint32_t a, int32_t b) { return SafeMin(a, b); }
137uint32_t TestMinSafe(uint32_t a, uint32_t b) { return SafeMin(a, b); }
138
139// clang-format on
140
141} // namespace rtc