diff options
author | Elliott Hughes <enh@google.com> | 2015-09-04 16:26:51 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2015-09-04 16:32:00 -0700 |
commit | afe151fb025bada5314cffd1bf7077d2860bf362 (patch) | |
tree | dc066c1f24fe072e974765feb294b10a12b38d49 /base | |
parent | 478da6374b5f4a5742566edfe3057c674a51615e (diff) |
Add ParseInt (and ParseUint).
strtol and family are hard to use correctly, and most callers don't
even try.
Change-Id: I2833622a92cccd4662c0c5bdbbef5eeb4e496914
Diffstat (limited to 'base')
-rw-r--r-- | base/Android.mk | 1 | ||||
-rw-r--r-- | base/include/base/parseint.h | 71 | ||||
-rw-r--r-- | base/parseint_test.cpp | 68 |
3 files changed, 140 insertions, 0 deletions
diff --git a/base/Android.mk b/base/Android.mk index 51dd73600..a09a747c8 100644 --- a/base/Android.mk +++ b/base/Android.mk @@ -26,6 +26,7 @@ libbase_src_files := \ libbase_test_src_files := \ file_test.cpp \ logging_test.cpp \ + parseint_test.cpp \ stringprintf_test.cpp \ strings_test.cpp \ test_main.cpp \ diff --git a/base/include/base/parseint.h b/base/include/base/parseint.h new file mode 100644 index 000000000..9ecbfbce9 --- /dev/null +++ b/base/include/base/parseint.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * 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 BASE_PARSEINT_H +#define BASE_PARSEINT_H + +#include <errno.h> +#include <stdlib.h> + +#include <limits> + +namespace android { +namespace base { + +// Parses the unsigned decimal integer in the string 's' and sets 'out' to +// that value. Optionally allows the caller to define a 'max' beyond which +// otherwise valid values will be rejected. Returns boolean success. +template <typename T> +bool ParseUint(const char* s, T* out, + T max = std::numeric_limits<T>::max()) { + errno = 0; + char* end; + unsigned long long int result = strtoull(s, &end, 10); + if (errno != 0 || s == end || *end != '\0') { + return false; + } + if (max < result) { + return false; + } + *out = static_cast<T>(result); + return true; +} + +// Parses the signed decimal integer in the string 's' and sets 'out' to +// that value. Optionally allows the caller to define a 'min' and 'max +// beyond which otherwise valid values will be rejected. Returns boolean +// success. +template <typename T> +bool ParseInt(const char* s, T* out, + T min = std::numeric_limits<T>::min(), + T max = std::numeric_limits<T>::max()) { + errno = 0; + char* end; + long long int result = strtoll(s, &end, 10); + if (errno != 0 || s == end || *end != '\0') { + return false; + } + if (result < min || max < result) { + return false; + } + *out = static_cast<T>(result); + return true; +} + +} // namespace base +} // namespace android + +#endif // BASE_PARSEINT_H diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp new file mode 100644 index 000000000..6a109f44c --- /dev/null +++ b/base/parseint_test.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * 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 "base/parseint.h" + +#include <gtest/gtest.h> + +TEST(parseint, signed_smoke) { + int i; + ASSERT_EQ(false, android::base::ParseInt("x", &i)); + ASSERT_EQ(false, android::base::ParseInt("123x", &i)); + + ASSERT_EQ(true, android::base::ParseInt("123", &i)); + ASSERT_EQ(123, i); + ASSERT_EQ(true, android::base::ParseInt("-123", &i)); + ASSERT_EQ(-123, i); + + short s; + ASSERT_EQ(true, android::base::ParseInt("1234", &s)); + ASSERT_EQ(1234, s); + + ASSERT_EQ(true, android::base::ParseInt("12", &i, 0, 15)); + ASSERT_EQ(12, i); + ASSERT_EQ(false, android::base::ParseInt("-12", &i, 0, 15)); + ASSERT_EQ(false, android::base::ParseInt("16", &i, 0, 15)); +} + +TEST(parseint, unsigned_smoke) { + unsigned int i; + ASSERT_EQ(false, android::base::ParseUint("x", &i)); + ASSERT_EQ(false, android::base::ParseUint("123x", &i)); + + ASSERT_EQ(true, android::base::ParseUint("123", &i)); + ASSERT_EQ(123u, i); + ASSERT_EQ(false, android::base::ParseUint("-123", &i)); + + unsigned short s; + ASSERT_EQ(true, android::base::ParseUint("1234", &s)); + ASSERT_EQ(1234u, s); + + ASSERT_EQ(true, android::base::ParseUint("12", &i, 15u)); + ASSERT_EQ(12u, i); + ASSERT_EQ(false, android::base::ParseUint("-12", &i, 15u)); + ASSERT_EQ(false, android::base::ParseUint("16", &i, 15u)); +} + +TEST(parseint, no_implicit_octal) { + int i; + ASSERT_EQ(true, android::base::ParseInt("0123", &i)); + ASSERT_EQ(123, i); + + unsigned int u; + ASSERT_EQ(true, android::base::ParseUint("0123", &u)); + ASSERT_EQ(123u, u); +} |