1
0
Fork 0
arangodb/lib/Basics/NumberUtils.h

256 lines
8.1 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGODB_BASICS_NUMBER_UTILS_H
#define ARANGODB_BASICS_NUMBER_UTILS_H 1
#include "Basics/Common.h"
#include <limits>
#include <type_traits>
namespace arangodb {
namespace NumberUtils {
// low-level worker function to convert the string value between p
// (inclusive) and e (exclusive) into a negative number value of type T,
// without validation of the input string - use this only for trusted input!
//
// the input string will always be interpreted as a base-10 number.
// expects the input string to contain only the digits '0' to '9'.
// there is no validation of the input string, and overflow or underflow
// of the result value will not be detected.
// this function will not modify errno.
template <typename T>
inline T atoi_negative_unchecked(char const* p, char const* e) noexcept {
T result = 0;
while (p != e) {
result = (result * 10) - (*(p++) - '0');
}
return result;
}
// low-level worker function to convert the string value between p
// (inclusive) and e (exclusive) into a positive number value of type T,
// without validation of the input string - use this only for trusted input!
//
// the input string will always be interpreted as a base-10 number.
// expects the input string to contain only the digits '0' to '9'.
// there is no validation of the input string, and overflow or underflow
// of the result value will not be detected.
// this function will not modify errno.
template <typename T>
inline T atoi_positive_unchecked(char const* p, char const* e) noexcept {
T result = 0;
while (p != e) {
result = (result * 10) + *(p++) - '0';
}
return result;
}
// function to convert the string value between p
// (inclusive) and e (exclusive) into a number value of type T, without
// validation of the input string - use this only for trusted input!
//
// the input string will always be interpreted as a base-10 number.
// expects the input string to contain only the digits '0' to '9'. an
// optional '+' or '-' sign is allowed too.
// there is no validation of the input string, and overflow or underflow
// of the result value will not be detected.
// this function will not modify errno.
template <typename T>
inline T atoi_unchecked(char const* p, char const* e) noexcept {
if (ADB_UNLIKELY(p == e)) {
return T();
}
if (*p == '-') {
if (!std::is_signed<T>::value) {
return T();
}
return atoi_negative_unchecked<T>(++p, e);
}
if (ADB_UNLIKELY(*p == '+')) {
++p;
}
return atoi_positive_unchecked<T>(p, e);
}
// low-level worker function to convert the string value between p
// (inclusive) and e (exclusive) into a negative number value of type T
//
// the input string will always be interpreted as a base-10 number.
// expects the input string to contain only the digits '0' to '9'.
// if any other character is found, the output parameter "valid" will
// be set to false. if the parsed value is less than what type T can
// store without truncation, "valid" will also be set to false.
// this function will not modify errno.
template <typename T>
inline T atoi_negative(char const* p, char const* e, bool& valid) noexcept {
if (ADB_UNLIKELY(p == e)) {
valid = false;
return T();
}
constexpr T cutoff = (std::numeric_limits<T>::min)() / 10;
constexpr char cutlim = -((std::numeric_limits<T>::min)() % 10);
T result = 0;
do {
char c = *p;
// we expect only '0' to '9'. everything else is unexpected
if (ADB_UNLIKELY(c < '0' || c > '9')) {
valid = false;
return result;
}
c -= '0';
// we expect the bulk of values to not hit the bounds restrictions
if (ADB_UNLIKELY(result < cutoff || (result == cutoff && c > cutlim))) {
valid = false;
return result;
}
result *= 10;
result -= c;
} while (++p < e);
valid = true;
return result;
}
// low-level worker function to convert the string value between p
// (inclusive) and e (exclusive) into a positive number value of type T
//
// the input string will always be interpreted as a base-10 number.
// expects the input string to contain only the digits '0' to '9'.
// if any other character is found, the output parameter "valid" will
// be set to false. if the parsed value is greater than what type T can
// store without truncation, "valid" will also be set to false.
// this function will not modify errno.
template <typename T>
inline T atoi_positive(char const* p, char const* e, bool& valid) noexcept {
if (ADB_UNLIKELY(p == e)) {
valid = false;
return T();
}
constexpr T cutoff = (std::numeric_limits<T>::max)() / 10;
constexpr char cutlim = (std::numeric_limits<T>::max)() % 10;
T result = 0;
do {
char c = *p;
// we expect only '0' to '9'. everything else is unexpected
if (ADB_UNLIKELY(c < '0' || c > '9')) {
valid = false;
return result;
}
c -= '0';
// we expect the bulk of values to not hit the bounds restrictions
if (ADB_UNLIKELY(result > cutoff || (result == cutoff && c > cutlim))) {
valid = false;
return result;
}
result *= 10;
result += c;
} while (++p < e);
valid = true;
return result;
}
// function to convert the string value between p
// (inclusive) and e (exclusive) into a number value of type T
//
// the input string will always be interpreted as a base-10 number.
// expects the input string to contain only the digits '0' to '9'. an
// optional '+' or '-' sign is allowed too.
// if any other character is found, the output parameter "valid" will
// be set to false. if the parsed value is less or greater than what
// type T can store without truncation, "valid" will also be set to
// false.
// this function will not modify errno.
template <typename T>
inline typename std::enable_if<std::is_signed<T>::value, T>::type atoi(char const* p,
char const* e,
bool& valid) noexcept {
if (ADB_UNLIKELY(p == e)) {
valid = false;
return T();
}
if (*p == '-') {
return atoi_negative<T>(++p, e, valid);
}
if (ADB_UNLIKELY(*p == '+')) {
++p;
}
return atoi_positive<T>(p, e, valid);
}
template <typename T>
inline typename std::enable_if<std::is_unsigned<T>::value, T>::type atoi(
char const* p, char const* e, bool& valid) noexcept {
if (ADB_UNLIKELY(p == e)) {
valid = false;
return T();
}
if (*p == '-') {
valid = false;
return T();
}
if (ADB_UNLIKELY(*p == '+')) {
++p;
}
return atoi_positive<T>(p, e, valid);
}
// function to convert the string value between p
// (inclusive) and e (exclusive) into a number value of type T
//
// the input string will always be interpreted as a base-10 number.
// expects the input string to contain only the digits '0' to '9'. an
// optional '+' or '-' sign is allowed too.
// if any other character is found, the result will be set to 0.
// if the parsed value is less or greater than what type T can store
// without truncation, return result will also be set to 0.
// this function will not modify errno.
template <typename T>
inline T atoi_zero(char const* p, char const* e) noexcept {
bool valid;
T result = atoi<T>(p, e, valid);
return valid ? result : 0;
}
} // namespace NumberUtils
} // namespace arangodb
#endif