// Copyright (c) 2019 PaddlePaddle 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. #pragma once #include #include #include #include #include // NOLINT #include "lite/utils/variant.h" // for likely namespace paddle { namespace lite { namespace utils { /* * The `std::string` handle can improve the encapsulation, but * `const char*` is still needed to improve efficiency in the * processing of small strings. This source code gives a simple * implementation of the std::from_chars helper function in the * C++ 17 standard. */ struct from_chars_result { const char* ptr{nullptr}; std::errc ec{}; }; /* * Reference: * https://github.com/VerizonDigital/json_parser * * Most C++ environments use ASCII as the development character * set. Array `kAsciiToInt` is the look-up table implementation * of the following functions: * * static inline uint8_t get_char_val(char c) { * if (LIKELY(c >= '0' && c <= '9')) * return c - '0'; * if (c >= 'A' && c <= 'Z') * return 10 + (c - 'A'); * if (c >= 'a' && c <= 'z') * return 10 + (c - 'a'); * return std::numeric_limits::max(); * } */ constexpr uint8_t kAsciiToInt[256] = { UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, 0 /* 0 */, 1, 2, 3, 4, 5, 6, 7, 8, 9, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, 10 /* A */, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, 10 /* a */, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; /* * function: aton_unsigned * brief: Convert a string constant to an unsigned integer. * parameters: * str(const char*): input string constant. * len(int): bytes of the string. * value(T): result value. * base(int): integer base to use, default to 10. * return(from_chars_result): * the error value and the current character pointer. */ template from_chars_result aton_unsigned(const char* str, int len, T& value, // NOLINT int base = 10) { from_chars_result result; result.ptr = str; if (UNLIKELY(!str || len <= 0)) { result.ec = std::errc::invalid_argument; return result; } uint64_t val = 0; if (UNLIKELY(*str == '-')) { result.ec = std::errc::result_out_of_range; return result; } if (UNLIKELY(*str == '+')) { ++str; --len; } int i = 0; for (; i < len; ++i) { uint8_t cv = kAsciiToInt[reinterpret_cast(str[i])]; if (UNLIKELY(cv >= base)) { value = static_cast(val); result.ptr = str + i; return result; } // Handling integer values that may exceed the range represented by the // basic type. if (UNLIKELY(i > std::numeric_limits::digits10 + 1) && i == std::numeric_limits::digits10) { uint64_t mx = static_cast(std::numeric_limits::max()); if (val > mx / 10 || mx - (val * base) < cv) { value = static_cast(std::numeric_limits::max()); result.ec = std::errc::result_out_of_range; return result; } } if (LIKELY(i != 10)) { val *= base; } val += cv; } if (UNLIKELY( i > std::numeric_limits::digits10 + 1 || (i > std::numeric_limits::digits10 && val > static_cast((std::numeric_limits::max)())))) { value = static_cast((std::numeric_limits::max)()); result.ec = std::errc::result_out_of_range; return result; } value = static_cast(val); return result; } /* function: aton_signed * brief: Convert a string constant to an signed integer. * parameters: * str(const char*): input string constant. * len(int): bytes of the string. * value(T): result value. * base(int): integer base to use, default to 10. * return(from_chars_result): * the error value and the current character pointer. */ template from_chars_result aton_signed(const char* str, int len, T& value, // NOLINT int base = 10) { from_chars_result result; result.ptr = str; if (UNLIKELY(!str || len <= 0)) { result.ec = std::errc::invalid_argument; return result; } uint64_t val = 0; bool negative = (*str == '-'); if (negative || *str == '+') { ++str; --len; } int i = 0; for (; i < len; ++i) { uint8_t cv = kAsciiToInt[reinterpret_cast(str[i])]; if (UNLIKELY(cv >= base)) { value = static_cast(val); result.ptr = str + i; return result; } if (LIKELY(i != 0)) { val *= base; } val += cv; } if (LIKELY(!negative)) { if (UNLIKELY( i > std::numeric_limits::digits10 + 1 || (i > std::numeric_limits::digits10 && val > static_cast((std::numeric_limits::max)())))) { value = static_cast((std::numeric_limits::max)()); result.ec = std::errc::result_out_of_range; return result; } value = static_cast(val); return result; } int64_t ret{static_cast(val)}; if (negative) { ret *= -1; } if (i > std::numeric_limits::digits10 + 1 || ret < static_cast(std::numeric_limits::min())) { value = static_cast(std::numeric_limits::min()); result.ec = std::errc::result_out_of_range; return result; } value = static_cast(ret); return result; } /* function: aton_float * brief: Convert a string constant to a float digit. * parameters: * str(const char*): input string constant. * len(int): bytes of the string. * value(T): result value. * return(from_chars_result): * the error value and the current character pointer. */ template from_chars_result aton_float(const char* str, int len, T& value) { // NOLINT from_chars_result result; result.ptr = str; const uint8_t base = 10; if (UNLIKELY(!str || len <= 0)) { result.ec = std::errc::invalid_argument; return result; } uint64_t lval = 0; uint64_t rval = 0; uint64_t rdiv = 1; bool negative = *str == '-'; if (negative || *str == '+') { ++str; --len; } ssize_t dot_pos = -1; int i = 0; for (; i < len; ++i) { char c = str[i]; if ('.' == c) { dot_pos = i; ++i; break; } uint8_t cv = kAsciiToInt[reinterpret_cast(c)]; if (UNLIKELY(cv >= base)) { value = static_cast(lval); result.ptr = str + i; return result; } if (i != 0) { lval *= 10; } lval += cv; } double val{static_cast(lval)}; if (-1 != dot_pos) { for (; i < len; ++i) { uint8_t cv = kAsciiToInt[reinterpret_cast(str[i])]; if (UNLIKELY(cv >= base)) { result.ptr = str + i; return result; } if (i - dot_pos > 1) { rval *= 10.0; } rval += cv; rdiv *= 10; } val += static_cast(rval) / rdiv; } if (!negative && val > static_cast(std::numeric_limits::max())) { value = static_cast(std::numeric_limits::max()); result.ec = std::errc::result_out_of_range; return result; } if (!negative) { value = static_cast(val); return result; } val *= -1; if (val < static_cast(-std::numeric_limits::max())) { value = static_cast(std::numeric_limits::min()); result.ec = std::errc::result_out_of_range; return result; } value = static_cast(val); return result; } // To simplify the number of interfaces, using template type // deduction here. template from_chars_result from_chars(const char* first, const char* last, T& value, // NOLINT int base = 10) = delete; #define UNSIGNED_FROM_CHARS_INSTANCE(T) \ template <> \ inline from_chars_result from_chars( \ const char* first, const char* last, T& value, int base) { \ return aton_unsigned(first, last - first, value, base); \ } #define SIGNED_FROM_CHARS_INSTANCE(T) \ template <> \ inline from_chars_result from_chars( \ const char* first, const char* last, T& value, int base) { \ return aton_signed(first, last - first, value, base); \ } #define FLOAT_FROM_CHARS_INSTANCE(T) \ template <> \ inline from_chars_result from_chars( \ const char* first, const char* last, T& value, int base) { \ return aton_float(first, last - first, value); \ } UNSIGNED_FROM_CHARS_INSTANCE(uint8_t); UNSIGNED_FROM_CHARS_INSTANCE(uint16_t); UNSIGNED_FROM_CHARS_INSTANCE(uint32_t); UNSIGNED_FROM_CHARS_INSTANCE(uint64_t); SIGNED_FROM_CHARS_INSTANCE(int8_t); SIGNED_FROM_CHARS_INSTANCE(int16_t); SIGNED_FROM_CHARS_INSTANCE(int32_t); SIGNED_FROM_CHARS_INSTANCE(int64_t); FLOAT_FROM_CHARS_INSTANCE(double); FLOAT_FROM_CHARS_INSTANCE(float); #undef FLOAT_FROM_CHARS_INSTANCE #undef SIGNED_FROM_CHARS_INSTANCE #undef UNSIGNED_FROM_CHARS_INSTANCE } // namespace utils } // namespace lite } // namespace paddle