Add InRangeCast<> and its test.

InRangeCast<> is similar to base::saturated_cast<>, but it allows the
caller to specify the value to be returned in the event that the source
value can’t be converted to the destination data type without data loss.

TEST=util_test InRangeCast
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/467103002
This commit is contained in:
Mark Mentovai 2014-08-14 16:00:44 -07:00
parent 01f9e396b8
commit 6997418cd4
3 changed files with 164 additions and 0 deletions

View File

@ -0,0 +1,44 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_UTIL_NUMERIC_IN_RANGE_CAST_H_
#define CRASHPAD_UTIL_NUMERIC_IN_RANGE_CAST_H_
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
namespace crashpad {
//! \brief Casts to a different type if it can be done without data loss,
//! logging a warning message and returing a default value otherwise.
//!
//! \param[in] source The value to convert and return.
//! \param[in] default_value The default value to return, in the event that \a
//! source cannot be represented in the destination type.
//!
//! \return \a source if it can be represented in the destination type,
//! otherwise \a default_value.
template <typename Destination, typename Source>
Destination InRangeCast(Source source, Destination default_value) {
if (base::IsValueInRangeForNumericType<Destination>(source)) {
return source;
}
LOG(WARNING) << "value " << source << " out of range";
return default_value;
}
} // namespace crashpad
#endif // CRASHPAD_UTIL_NUMERIC_IN_RANGE_CAST_H_

View File

@ -0,0 +1,117 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/numeric/in_range_cast.h"
#include <stdint.h>
#include <limits>
#include "gtest/gtest.h"
namespace {
using namespace crashpad;
const int32_t kInt32Min = std::numeric_limits<int32_t>::min();
const int64_t kInt64Min = std::numeric_limits<int64_t>::min();
TEST(InRangeCast, Uint32) {
EXPECT_EQ(0u, InRangeCast<uint32_t>(0, 1));
EXPECT_EQ(1u, InRangeCast<uint32_t>(1, 1));
EXPECT_EQ(2u, InRangeCast<uint32_t>(2, 1));
EXPECT_EQ(0u, InRangeCast<uint32_t>(-1, 0));
EXPECT_EQ(1u, InRangeCast<uint32_t>(-1, 1));
EXPECT_EQ(2u, InRangeCast<uint32_t>(-1, 2));
EXPECT_EQ(0xffffffffu, InRangeCast<uint32_t>(0xffffffffu, 1));
EXPECT_EQ(0xffffffffu, InRangeCast<uint32_t>(UINT64_C(0xffffffff), 1));
EXPECT_EQ(1u, InRangeCast<uint32_t>(UINT64_C(0x100000000), 1));
EXPECT_EQ(1u, InRangeCast<uint32_t>(UINT64_C(0x100000001), 1));
EXPECT_EQ(1u, InRangeCast<uint32_t>(kInt32Min, 1));
EXPECT_EQ(0xffffffffu, InRangeCast<uint32_t>(-1, 0xffffffffu));
}
TEST(InRangeCast, Int32) {
EXPECT_EQ(0, InRangeCast<int32_t>(0, 1));
EXPECT_EQ(1, InRangeCast<int32_t>(1, 1));
EXPECT_EQ(2, InRangeCast<int32_t>(2, 1));
EXPECT_EQ(-1, InRangeCast<int32_t>(-1, 1));
EXPECT_EQ(0x7fffffff, InRangeCast<int32_t>(0x7fffffff, 1));
EXPECT_EQ(0x7fffffff, InRangeCast<int32_t>(0x7fffffffu, 1));
EXPECT_EQ(1, InRangeCast<int32_t>(0x80000000u, 1));
EXPECT_EQ(1, InRangeCast<int32_t>(0xffffffffu, 1));
EXPECT_EQ(1, InRangeCast<int32_t>(INT64_C(0x80000000), 1));
EXPECT_EQ(1, InRangeCast<int32_t>(INT64_C(0xffffffff), 1));
EXPECT_EQ(1, InRangeCast<int32_t>(INT64_C(0x100000000), 1));
EXPECT_EQ(kInt32Min, InRangeCast<int32_t>(kInt32Min, 1));
EXPECT_EQ(kInt32Min,
InRangeCast<int32_t>(static_cast<int64_t>(kInt32Min), 1));
EXPECT_EQ(1, InRangeCast<int32_t>(static_cast<int64_t>(kInt32Min) - 1, 1));
EXPECT_EQ(0, InRangeCast<int32_t>(0xffffffffu, 0));
EXPECT_EQ(-1, InRangeCast<int32_t>(0xffffffffu, -1));
EXPECT_EQ(kInt32Min, InRangeCast<int32_t>(0xffffffffu, kInt32Min));
EXPECT_EQ(0x7fffffff, InRangeCast<int32_t>(0xffffffffu, 0x7fffffff));
}
TEST(InRangeCast, Uint64) {
EXPECT_EQ(0u, InRangeCast<uint64_t>(0, 1));
EXPECT_EQ(1u, InRangeCast<uint64_t>(1, 1));
EXPECT_EQ(2u, InRangeCast<uint64_t>(2, 1));
EXPECT_EQ(0u, InRangeCast<uint64_t>(-1, 0));
EXPECT_EQ(1u, InRangeCast<uint64_t>(-1, 1));
EXPECT_EQ(2u, InRangeCast<uint64_t>(-1, 2));
EXPECT_EQ(0xffffffffu, InRangeCast<uint64_t>(0xffffffffu, 1));
EXPECT_EQ(0xffffffffu, InRangeCast<uint64_t>(UINT64_C(0xffffffff), 1));
EXPECT_EQ(UINT64_C(0x100000000),
InRangeCast<uint64_t>(UINT64_C(0x100000000), 1));
EXPECT_EQ(UINT64_C(0x100000001),
InRangeCast<uint64_t>(UINT64_C(0x100000001), 1));
EXPECT_EQ(1u, InRangeCast<uint64_t>(kInt32Min, 1));
EXPECT_EQ(1u, InRangeCast<uint64_t>(INT64_C(-1), 1));
EXPECT_EQ(1u, InRangeCast<uint64_t>(kInt32Min, 1));
EXPECT_EQ(1u, InRangeCast<uint64_t>(kInt64Min, 1));
EXPECT_EQ(UINT64_C(0xffffffffffffffff),
InRangeCast<uint64_t>(-1, UINT64_C(0xffffffffffffffff)));
}
TEST(InRangeCast, Int64) {
EXPECT_EQ(0, InRangeCast<int64_t>(0, 1));
EXPECT_EQ(1, InRangeCast<int64_t>(1, 1));
EXPECT_EQ(2, InRangeCast<int64_t>(2, 1));
EXPECT_EQ(-1, InRangeCast<int64_t>(-1, 1));
EXPECT_EQ(0x7fffffff, InRangeCast<int64_t>(0x7fffffff, 1));
EXPECT_EQ(0x7fffffff, InRangeCast<int64_t>(0x7fffffffu, 1));
EXPECT_EQ(INT64_C(0x80000000), InRangeCast<int64_t>(0x80000000u, 1));
EXPECT_EQ(INT64_C(0xffffffff), InRangeCast<int64_t>(0xffffffffu, 1));
EXPECT_EQ(INT64_C(0x80000000), InRangeCast<int64_t>(INT64_C(0x80000000), 1));
EXPECT_EQ(INT64_C(0xffffffff), InRangeCast<int64_t>(INT64_C(0xffffffff), 1));
EXPECT_EQ(INT64_C(0x100000000),
InRangeCast<int64_t>(INT64_C(0x100000000), 1));
EXPECT_EQ(INT64_C(0x7fffffffffffffff),
InRangeCast<int64_t>(INT64_C(0x7fffffffffffffff), 1));
EXPECT_EQ(1, InRangeCast<int64_t>(UINT64_C(0x8000000000000000), 1));
EXPECT_EQ(1, InRangeCast<int64_t>(UINT64_C(0xffffffffffffffff), 1));
EXPECT_EQ(kInt32Min, InRangeCast<int64_t>(kInt32Min, 1));
EXPECT_EQ(kInt32Min,
InRangeCast<int64_t>(static_cast<int64_t>(kInt32Min), 1));
EXPECT_EQ(0, InRangeCast<int64_t>(UINT64_C(0xffffffffffffffff), 0));
EXPECT_EQ(-1, InRangeCast<int64_t>(UINT64_C(0xffffffffffffffff), -1));
EXPECT_EQ(kInt64Min,
InRangeCast<int64_t>(UINT64_C(0xffffffffffffffff), kInt64Min));
EXPECT_EQ(INT64_C(0x7fffffffffffffff),
InRangeCast<int64_t>(UINT64_C(0xffffffffffffffff),
INT64_C(0x7fffffffffffffff)));
}
} // namespace

View File

@ -41,6 +41,8 @@
'misc/initialization_state_dcheck.h',
'misc/uuid.cc',
'misc/uuid.h',
'numeric/in_range_cast.h',
'numeric/safe_assignment.h',
'posix/process_util.h',
'posix/process_util_mac.cc',
'stdlib/cxx.h',
@ -88,6 +90,7 @@
'misc/initialization_state_dcheck_test.cc',
'misc/initialization_state_test.cc',
'misc/uuid_test.cc',
'numeric/in_range_cast_test.cc',
'posix/process_util_test.cc',
'stdlib/strlcpy_test.cc',
],