blob: 519158b6ed78c1e04d377918cf32d2b990a21670 [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
kwiberg7885d3f2017-04-25 12:35:07 -070065enum DefaultE { kFoo = -17 };
66enum UInt8E : uint8_t { kBar = 17 };
kwibergdbb497a2017-06-02 04:24:11 -070067
68// SafeMin/SafeMax: Check that we can use enum types.
69static_assert(TypeCheckMinMax<unsigned, unsigned, unsigned, unsigned>(), "");
70static_assert(TypeCheckMinMax<unsigned, DefaultE, int, unsigned>(), "");
71static_assert(TypeCheckMinMax<unsigned, UInt8E, uint8_t, unsigned>(), "");
72static_assert(TypeCheckMinMax<DefaultE, unsigned, int, unsigned>(), "");
73static_assert(TypeCheckMinMax<DefaultE, DefaultE, int, int>(), "");
74static_assert(TypeCheckMinMax<DefaultE, UInt8E, int, int>(), "");
75static_assert(TypeCheckMinMax< UInt8E, unsigned, uint8_t, unsigned>(), "");
76static_assert(TypeCheckMinMax< UInt8E, DefaultE, int, int>(), "");
77static_assert(TypeCheckMinMax< UInt8E, UInt8E, uint8_t, uint8_t>(), "");
kwiberg7885d3f2017-04-25 12:35:07 -070078
79using ld = long double;
80
81// SafeMin/SafeMax: Check that all floating-point combinations give the
82// correct result type.
83static_assert(TypeCheckMinMax< float, float, float, float>(), "");
84static_assert(TypeCheckMinMax< float, double, double, double>(), "");
85static_assert(TypeCheckMinMax< float, ld, ld, ld>(), "");
86static_assert(TypeCheckMinMax<double, float, double, double>(), "");
87static_assert(TypeCheckMinMax<double, double, double, double>(), "");
88static_assert(TypeCheckMinMax<double, ld, ld, ld>(), "");
89static_assert(TypeCheckMinMax< ld, float, ld, ld>(), "");
90static_assert(TypeCheckMinMax< ld, double, ld, ld>(), "");
91static_assert(TypeCheckMinMax< ld, ld, ld, ld>(), "");
92
93// clang-format on
94
95// SafeMin/SafeMax: Check some cases of explicitly specified return type. The
96// commented-out lines give compilation errors due to the requested return type
97// being too small or requiring an int<->float conversion.
98static_assert(TypeCheckMinR<int8_t, int8_t, int16_t>(), "");
99// static_assert(TypeCheckMinR<int8_t, int8_t, float>(), "");
100static_assert(TypeCheckMinR<uint32_t, uint64_t, uint32_t>(), "");
101// static_assert(TypeCheckMaxR<uint64_t, float, float>(), "");
102// static_assert(TypeCheckMaxR<uint64_t, double, float>(), "");
103static_assert(TypeCheckMaxR<uint32_t, int32_t, uint32_t>(), "");
104// static_assert(TypeCheckMaxR<uint32_t, int32_t, int32_t>(), "");
105
106template <typename T1, typename T2, typename Tmin, typename Tmax>
107constexpr bool CheckMinMax(T1 a, T2 b, Tmin min, Tmax max) {
108 return TypeCheckMinMax<T1, T2, Tmin, Tmax>() && SafeMin(a, b) == min &&
109 SafeMax(a, b) == max;
110}
111
112// SafeMin/SafeMax: Check a few values.
113static_assert(CheckMinMax(int8_t{1}, int8_t{-1}, int8_t{-1}, int8_t{1}), "");
114static_assert(CheckMinMax(uint8_t{1}, int8_t{-1}, int8_t{-1}, uint8_t{1}), "");
115static_assert(CheckMinMax(uint8_t{5}, uint64_t{2}, uint8_t{2}, uint64_t{5}),
116 "");
117static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(),
118 std::numeric_limits<uint32_t>::max(),
119 std::numeric_limits<int32_t>::min(),
120 std::numeric_limits<uint32_t>::max()),
121 "");
122static_assert(CheckMinMax(std::numeric_limits<int32_t>::min(),
123 std::numeric_limits<uint16_t>::max(),
124 std::numeric_limits<int32_t>::min(),
125 int32_t{std::numeric_limits<uint16_t>::max()}),
126 "");
127// static_assert(CheckMinMax(1.f, 2, 1.f, 2.f), "");
128static_assert(CheckMinMax(1.f, 0.0, 0.0, 1.0), "");
129
130} // namespace
131
132// clang-format off
133
134// These functions aren't used in the tests, but it's useful to look at the
135// compiler output for them, and verify that (1) the same-signedness *Safe
136// functions result in exactly the same code as their *Ref counterparts, and
137// that (2) the mixed-signedness *Safe functions have just a few extra
138// arithmetic and logic instructions (but no extra control flow instructions).
139int32_t TestMinRef( int32_t a, int32_t b) { return std::min(a, b); }
140uint32_t TestMinRef( uint32_t a, uint32_t b) { return std::min(a, b); }
141int32_t TestMinSafe( int32_t a, int32_t b) { return SafeMin(a, b); }
142int32_t TestMinSafe( int32_t a, uint32_t b) { return SafeMin(a, b); }
143int32_t TestMinSafe(uint32_t a, int32_t b) { return SafeMin(a, b); }
144uint32_t TestMinSafe(uint32_t a, uint32_t b) { return SafeMin(a, b); }
145
146// clang-format on
147
148} // namespace rtc