Merge 2876b7deb2 into c0d511ea50
This commit is contained in:
commit
b325b175fb
@ -20,6 +20,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
|||||||
|
|
||||||
# create and configure the library target
|
# create and configure the library target
|
||||||
add_library(${JSON_TARGET_NAME} INTERFACE)
|
add_library(${JSON_TARGET_NAME} INTERFACE)
|
||||||
|
|
||||||
target_include_directories(${JSON_TARGET_NAME} INTERFACE
|
target_include_directories(${JSON_TARGET_NAME} INTERFACE
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
||||||
$<INSTALL_INTERFACE:${JSON_INCLUDE_DESTINATION}>)
|
$<INSTALL_INTERFACE:${JSON_INCLUDE_DESTINATION}>)
|
||||||
@ -48,6 +49,7 @@ export(PACKAGE ${JSON_PACKAGE_NAME})
|
|||||||
install(TARGETS ${JSON_TARGET_NAME}
|
install(TARGETS ${JSON_TARGET_NAME}
|
||||||
EXPORT ${JSON_PACKAGE_NAME})
|
EXPORT ${JSON_PACKAGE_NAME})
|
||||||
install(FILES "src/json.hpp"
|
install(FILES "src/json.hpp"
|
||||||
|
"src/std_support.hpp"
|
||||||
DESTINATION ${JSON_INCLUDE_DESTINATION})
|
DESTINATION ${JSON_INCLUDE_DESTINATION})
|
||||||
install(EXPORT ${JSON_PACKAGE_NAME}
|
install(EXPORT ${JSON_PACKAGE_NAME}
|
||||||
FILE ${JSON_TARGETS_FILENAME}
|
FILE ${JSON_TARGETS_FILENAME}
|
||||||
|
|||||||
83
src/json.hpp
83
src/json.hpp
@ -25,7 +25,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef NLOHMANN_JSON_HPP
|
#ifndef NLOHMANN_JSON_HPP
|
||||||
#define NLOHMANN_JSON_HPP
|
#define NLOHMANN_JSON_HPP
|
||||||
|
|
||||||
@ -37,7 +36,7 @@ SOFTWARE.
|
|||||||
#include <cmath> // isfinite, labs, ldexp, signbit
|
#include <cmath> // isfinite, labs, ldexp, signbit
|
||||||
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
|
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
|
||||||
#include <cstdint> // int64_t, uint64_t
|
#include <cstdint> // int64_t, uint64_t
|
||||||
#include <cstdlib> // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull
|
#include <cstdlib> // abort, strtod, strtod, strtold, strtoul, strtoll, strtoull
|
||||||
#include <cstring> // strlen
|
#include <cstring> // strlen
|
||||||
#include <forward_list> // forward_list
|
#include <forward_list> // forward_list
|
||||||
#include <functional> // function, hash, less
|
#include <functional> // function, hash, less
|
||||||
@ -56,6 +55,8 @@ SOFTWARE.
|
|||||||
#include <type_traits> // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type
|
#include <type_traits> // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type
|
||||||
#include <utility> // declval, forward, make_pair, move, pair, swap
|
#include <utility> // declval, forward, make_pair, move, pair, swap
|
||||||
#include <vector> // vector
|
#include <vector> // vector
|
||||||
|
#include <errno.h>
|
||||||
|
#include <std_support.hpp>
|
||||||
|
|
||||||
// exclude unsupported compilers
|
// exclude unsupported compilers
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
@ -1159,7 +1160,7 @@ class basic_json
|
|||||||
#elif defined(__ICC) || defined(__INTEL_COMPILER)
|
#elif defined(__ICC) || defined(__INTEL_COMPILER)
|
||||||
result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
|
result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
|
||||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||||
result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}};
|
result["compiler"] = {{"family", "gcc"}, {"version", std_support::to_string(__GNUC__) + "." + std_support::to_string(__GNUC_MINOR__) + "." + std_support::to_string(__GNUC_PATCHLEVEL__)}};
|
||||||
#elif defined(__HP_cc) || defined(__HP_aCC)
|
#elif defined(__HP_cc) || defined(__HP_aCC)
|
||||||
result["compiler"] = "hp"
|
result["compiler"] = "hp"
|
||||||
#elif defined(__IBMCPP__)
|
#elif defined(__IBMCPP__)
|
||||||
@ -1175,7 +1176,7 @@ class basic_json
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
result["compiler"]["c++"] = std::to_string(__cplusplus);
|
result["compiler"]["c++"] = std_support::to_string(__cplusplus);
|
||||||
#else
|
#else
|
||||||
result["compiler"]["c++"] = "unknown";
|
result["compiler"]["c++"] = "unknown";
|
||||||
#endif
|
#endif
|
||||||
@ -3540,7 +3541,7 @@ class basic_json
|
|||||||
JSON_CATCH (std::out_of_range&)
|
JSON_CATCH (std::out_of_range&)
|
||||||
{
|
{
|
||||||
// create better exception explanation
|
// create better exception explanation
|
||||||
JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
|
JSON_THROW(std::out_of_range("array index " + std_support::to_string(idx) + " is out of range"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -3583,7 +3584,7 @@ class basic_json
|
|||||||
JSON_CATCH (std::out_of_range&)
|
JSON_CATCH (std::out_of_range&)
|
||||||
{
|
{
|
||||||
// create better exception explanation
|
// create better exception explanation
|
||||||
JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
|
JSON_THROW(std::out_of_range("array index " + std_support::to_string(idx) + " is out of range"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -4535,7 +4536,7 @@ class basic_json
|
|||||||
{
|
{
|
||||||
if (idx >= size())
|
if (idx >= size())
|
||||||
{
|
{
|
||||||
JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
|
JSON_THROW(std::out_of_range("array index " + std_support::to_string(idx) + " is out of range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
|
m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
|
||||||
@ -6627,7 +6628,7 @@ class basic_json
|
|||||||
{
|
{
|
||||||
if (current_index + sizeof(T) + 1 > vec.size())
|
if (current_index + sizeof(T) + 1 > vec.size())
|
||||||
{
|
{
|
||||||
JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"));
|
JSON_THROW(std::out_of_range("cannot read " + std_support::to_string(sizeof(T)) + " bytes from vector"));
|
||||||
}
|
}
|
||||||
|
|
||||||
T result;
|
T result;
|
||||||
@ -7425,7 +7426,7 @@ class basic_json
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))));
|
JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std_support::to_string(current_idx) + ": " + std_support::to_string(static_cast<int>(v[current_idx]))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7910,7 +7911,7 @@ class basic_json
|
|||||||
|
|
||||||
default: // anything else (0xFF is handled inside the other types)
|
default: // anything else (0xFF is handled inside the other types)
|
||||||
{
|
{
|
||||||
JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))));
|
JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std_support::to_string(current_idx) + ": " + std_support::to_string(static_cast<int>(v[current_idx]))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8331,14 +8332,9 @@ class basic_json
|
|||||||
// check if buffer was large enough
|
// check if buffer was large enough
|
||||||
assert(static_cast<size_t>(written_bytes) < m_buf.size());
|
assert(static_cast<size_t>(written_bytes) < m_buf.size());
|
||||||
|
|
||||||
// read information from locale
|
|
||||||
const auto loc = localeconv();
|
|
||||||
assert(loc != nullptr);
|
|
||||||
const char thousands_sep = !loc->thousands_sep ? '\0'
|
|
||||||
: loc->thousands_sep[0];
|
|
||||||
|
|
||||||
const char decimal_point = !loc->decimal_point ? '\0'
|
const char thousands_sep = '\0';
|
||||||
: loc->decimal_point[0];
|
const char decimal_point = '\0';
|
||||||
|
|
||||||
// erase thousands separator
|
// erase thousands separator
|
||||||
if (thousands_sep != '\0')
|
if (thousands_sep != '\0')
|
||||||
@ -8767,7 +8763,7 @@ class basic_json
|
|||||||
// use integer array index as key
|
// use integer array index as key
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
return std::to_string(array_index);
|
return std_support::to_string(array_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// use key from the object
|
// use key from the object
|
||||||
@ -11122,21 +11118,21 @@ basic_json_parser_74:
|
|||||||
|
|
||||||
// floating-point conversion
|
// floating-point conversion
|
||||||
|
|
||||||
// overloaded wrappers for strtod/strtof/strtold
|
// overloaded wrappers for strtod/strtod/strtold
|
||||||
// that will be called from parse<floating_point_t>
|
// that will be called from parse<floating_point_t>
|
||||||
static void strtof(float& f, const char* str, char** endptr)
|
static void strtof(float& f, const char* str, char** endptr)
|
||||||
{
|
{
|
||||||
f = std::strtof(str, endptr);
|
f = std_support::strtod(str, endptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void strtof(double& f, const char* str, char** endptr)
|
static void strtof(double& f, const char* str, char** endptr)
|
||||||
{
|
{
|
||||||
f = std::strtod(str, endptr);
|
f = std_support::strtod(str, endptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void strtof(long double& f, const char* str, char** endptr)
|
static void strtof(long double& f, const char* str, char** endptr)
|
||||||
{
|
{
|
||||||
f = std::strtold(str, endptr);
|
f = std_support::strtod(str, endptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -11152,12 +11148,7 @@ basic_json_parser_74:
|
|||||||
// lexer will reject empty numbers
|
// lexer will reject empty numbers
|
||||||
assert(len > 0);
|
assert(len > 0);
|
||||||
|
|
||||||
// since dealing with strtod family of functions, we're
|
const char decimal_point_char = '.';
|
||||||
// getting the decimal point char from the C locale facilities
|
|
||||||
// instead of C++'s numpunct facet of the current std::locale
|
|
||||||
const auto loc = localeconv();
|
|
||||||
assert(loc != nullptr);
|
|
||||||
const char decimal_point_char = (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0];
|
|
||||||
|
|
||||||
const char* data = m_start;
|
const char* data = m_start;
|
||||||
|
|
||||||
@ -11191,7 +11182,7 @@ basic_json_parser_74:
|
|||||||
// this calls appropriate overload depending on T
|
// this calls appropriate overload depending on T
|
||||||
strtof(value, data, &endptr);
|
strtof(value, data, &endptr);
|
||||||
|
|
||||||
// parsing was successful iff strtof parsed exactly the number
|
// parsing was successful iff strtod parsed exactly the number
|
||||||
// of characters determined by the lexer (len)
|
// of characters determined by the lexer (len)
|
||||||
const bool ok = (endptr == (data + len));
|
const bool ok = (endptr == (data + len));
|
||||||
|
|
||||||
@ -11208,12 +11199,12 @@ basic_json_parser_74:
|
|||||||
|
|
||||||
signed long long parse_integral(char** endptr, /*is_signed*/std::true_type) const
|
signed long long parse_integral(char** endptr, /*is_signed*/std::true_type) const
|
||||||
{
|
{
|
||||||
return std::strtoll(m_start, endptr, 10);
|
return std_support::strtoll(m_start, endptr, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long parse_integral(char** endptr, /*is_signed*/std::false_type) const
|
unsigned long long parse_integral(char** endptr, /*is_signed*/std::false_type) const
|
||||||
{
|
{
|
||||||
return std::strtoull(m_start, endptr, 10);
|
return std_support::strtoull(m_start, endptr, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -11778,7 +11769,7 @@ basic_json_parser_74:
|
|||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
// create an entry in the array
|
// create an entry in the array
|
||||||
result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
|
result = &result->operator[](static_cast<size_type>(std_support::stoi(reference_token)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11870,7 +11861,7 @@ basic_json_parser_74:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// convert array index to number; unchecked access
|
// convert array index to number; unchecked access
|
||||||
ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
|
ptr = &ptr->operator[](static_cast<size_type>(std_support::stoi(reference_token)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -11904,7 +11895,7 @@ basic_json_parser_74:
|
|||||||
{
|
{
|
||||||
// "-" always fails the range check
|
// "-" always fails the range check
|
||||||
JSON_THROW(std::out_of_range("array index '-' (" +
|
JSON_THROW(std::out_of_range("array index '-' (" +
|
||||||
std::to_string(ptr->m_value.array->size()) +
|
std_support::to_string(ptr->m_value.array->size()) +
|
||||||
") is out of range"));
|
") is out of range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11915,7 +11906,7 @@ basic_json_parser_74:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// note: at performs range check
|
// note: at performs range check
|
||||||
ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
|
ptr = &ptr->at(static_cast<size_type>(std_support::stoi(reference_token)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11956,7 +11947,7 @@ basic_json_parser_74:
|
|||||||
{
|
{
|
||||||
// "-" cannot be used for const access
|
// "-" cannot be used for const access
|
||||||
JSON_THROW(std::out_of_range("array index '-' (" +
|
JSON_THROW(std::out_of_range("array index '-' (" +
|
||||||
std::to_string(ptr->m_value.array->size()) +
|
std_support::to_string(ptr->m_value.array->size()) +
|
||||||
") is out of range"));
|
") is out of range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11967,7 +11958,7 @@ basic_json_parser_74:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// use unchecked array access
|
// use unchecked array access
|
||||||
ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
|
ptr = &ptr->operator[](static_cast<size_type>(std_support::stoi(reference_token)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12000,7 +11991,7 @@ basic_json_parser_74:
|
|||||||
{
|
{
|
||||||
// "-" always fails the range check
|
// "-" always fails the range check
|
||||||
JSON_THROW(std::out_of_range("array index '-' (" +
|
JSON_THROW(std::out_of_range("array index '-' (" +
|
||||||
std::to_string(ptr->m_value.array->size()) +
|
std_support::to_string(ptr->m_value.array->size()) +
|
||||||
") is out of range"));
|
") is out of range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12011,7 +12002,7 @@ basic_json_parser_74:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// note: at performs range check
|
// note: at performs range check
|
||||||
ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
|
ptr = &ptr->at(static_cast<size_type>(std_support::stoi(reference_token)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12156,7 +12147,7 @@ basic_json_parser_74:
|
|||||||
// iterate array and use index as reference string
|
// iterate array and use index as reference string
|
||||||
for (size_t i = 0; i < value.m_value.array->size(); ++i)
|
for (size_t i = 0; i < value.m_value.array->size(); ++i)
|
||||||
{
|
{
|
||||||
flatten(reference_string + "/" + std::to_string(i),
|
flatten(reference_string + "/" + std_support::to_string(i),
|
||||||
value.m_value.array->operator[](i), result);
|
value.m_value.array->operator[](i), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12547,11 +12538,11 @@ basic_json_parser_74:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto idx = std::stoi(last_path);
|
const auto idx = std_support::stoi(last_path);
|
||||||
if (static_cast<size_type>(idx) > parent.size())
|
if (static_cast<size_type>(idx) > parent.size())
|
||||||
{
|
{
|
||||||
// avoid undefined behavior
|
// avoid undefined behavior
|
||||||
JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range"));
|
JSON_THROW(std::out_of_range("array index " + std_support::to_string(idx) + " is out of range"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -12595,7 +12586,7 @@ basic_json_parser_74:
|
|||||||
else if (parent.is_array())
|
else if (parent.is_array())
|
||||||
{
|
{
|
||||||
// note erase performs range check
|
// note erase performs range check
|
||||||
parent.erase(static_cast<size_type>(std::stoi(last_path)));
|
parent.erase(static_cast<size_type>(std_support::stoi(last_path)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12796,7 +12787,7 @@ basic_json_parser_74:
|
|||||||
while (i < source.size() and i < target.size())
|
while (i < source.size() and i < target.size())
|
||||||
{
|
{
|
||||||
// recursive call to compare array values at index i
|
// recursive call to compare array values at index i
|
||||||
auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
|
auto temp_diff = diff(source[i], target[i], path + "/" + std_support::to_string(i));
|
||||||
result.insert(result.end(), temp_diff.begin(), temp_diff.end());
|
result.insert(result.end(), temp_diff.begin(), temp_diff.end());
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@ -12813,7 +12804,7 @@ basic_json_parser_74:
|
|||||||
result.insert(result.begin() + end_index, object(
|
result.insert(result.begin() + end_index, object(
|
||||||
{
|
{
|
||||||
{"op", "remove"},
|
{"op", "remove"},
|
||||||
{"path", path + "/" + std::to_string(i)}
|
{"path", path + "/" + std_support::to_string(i)}
|
||||||
}));
|
}));
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@ -12824,7 +12815,7 @@ basic_json_parser_74:
|
|||||||
result.push_back(
|
result.push_back(
|
||||||
{
|
{
|
||||||
{"op", "add"},
|
{"op", "add"},
|
||||||
{"path", path + "/" + std::to_string(i)},
|
{"path", path + "/" + std_support::to_string(i)},
|
||||||
{"value", target[i]}
|
{"value", target[i]}
|
||||||
});
|
});
|
||||||
++i;
|
++i;
|
||||||
|
|||||||
221
src/std_support.cpp
Normal file
221
src/std_support.cpp
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 1992, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "std_support.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long long std_support::strtoull(const char *nptr, char **endptr, int base) {
|
||||||
|
const char *s;
|
||||||
|
unsigned long long acc;
|
||||||
|
char c;
|
||||||
|
unsigned long long cutoff;
|
||||||
|
int neg, any, cutlim;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See strtoq for comments as to the logic used.
|
||||||
|
*/
|
||||||
|
s = nptr;
|
||||||
|
do {
|
||||||
|
c = *s++;
|
||||||
|
} while (isspace((unsigned char)c));
|
||||||
|
if (c == '-') {
|
||||||
|
neg = 1;
|
||||||
|
c = *s++;
|
||||||
|
} else {
|
||||||
|
neg = 0;
|
||||||
|
if (c == '+')
|
||||||
|
c = *s++;
|
||||||
|
}
|
||||||
|
if ((base == 0 || base == 16) &&
|
||||||
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||||
|
c = s[1];
|
||||||
|
s += 2;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
if (base == 0)
|
||||||
|
base = c == '0' ? 8 : 10;
|
||||||
|
acc = any = 0;
|
||||||
|
if (base < 2 || base > 36)
|
||||||
|
goto noconv;
|
||||||
|
|
||||||
|
cutoff = ULLONG_MAX / base;
|
||||||
|
cutlim = ULLONG_MAX % base;
|
||||||
|
for ( ; ; c = *s++) {
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
c -= '0';
|
||||||
|
else if (c >= 'A' && c <= 'Z')
|
||||||
|
c -= 'A' - 10;
|
||||||
|
else if (c >= 'a' && c <= 'z')
|
||||||
|
c -= 'a' - 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if (c >= base)
|
||||||
|
break;
|
||||||
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
||||||
|
any = -1;
|
||||||
|
else {
|
||||||
|
any = 1;
|
||||||
|
acc *= base;
|
||||||
|
acc += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (any < 0) {
|
||||||
|
acc = ULLONG_MAX;
|
||||||
|
errno = ERANGE;
|
||||||
|
} else if (!any) {
|
||||||
|
noconv:
|
||||||
|
errno = EINVAL;
|
||||||
|
} else if (neg)
|
||||||
|
acc = -acc;
|
||||||
|
if (endptr != NULL)
|
||||||
|
*endptr = (char *)(any ? s - 1 : nptr);
|
||||||
|
return (acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://opensource.apple.com/source/lukemftp/lukemftp-15/tnftp/libnetbsd/strtoll.c
|
||||||
|
long long std_support::strtoll(const char *nptr, char **endptr, int base) {
|
||||||
|
const char *s;
|
||||||
|
/* LONGLONG */
|
||||||
|
long long int acc, cutoff;
|
||||||
|
int c;
|
||||||
|
int neg, any, cutlim;
|
||||||
|
|
||||||
|
/* endptr may be NULL */
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
/* This outrageous construct just to shut up a GCC warning. */
|
||||||
|
(void) &acc; (void) &cutoff;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip white space and pick up leading +/- sign if any.
|
||||||
|
* If base is 0, allow 0x for hex and 0 for octal, else
|
||||||
|
* assume decimal; if base is already 16, allow 0x.
|
||||||
|
*/
|
||||||
|
s = nptr;
|
||||||
|
do {
|
||||||
|
c = (unsigned char) *s++;
|
||||||
|
} while (isspace(c));
|
||||||
|
if (c == '-') {
|
||||||
|
neg = 1;
|
||||||
|
c = *s++;
|
||||||
|
} else {
|
||||||
|
neg = 0;
|
||||||
|
if (c == '+')
|
||||||
|
c = *s++;
|
||||||
|
}
|
||||||
|
if ((base == 0 || base == 16) &&
|
||||||
|
c == '0' && (*s == 'x' || *s == 'X')) {
|
||||||
|
c = s[1];
|
||||||
|
s += 2;
|
||||||
|
base = 16;
|
||||||
|
}
|
||||||
|
if (base == 0)
|
||||||
|
base = c == '0' ? 8 : 10;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the cutoff value between legal numbers and illegal
|
||||||
|
* numbers. That is the largest legal value, divided by the
|
||||||
|
* base. An input number that is greater than this value, if
|
||||||
|
* followed by a legal input character, is too big. One that
|
||||||
|
* is equal to this value may be valid or not; the limit
|
||||||
|
* between valid and invalid numbers is then based on the last
|
||||||
|
* digit. For instance, if the range for long longs is
|
||||||
|
* [-9223372036854775808..9223372036854775807] and the input base
|
||||||
|
* is 10, cutoff will be set to 922337203685477580 and cutlim to
|
||||||
|
* either 7 (neg==0) or 8 (neg==1), meaning that if we have
|
||||||
|
* accumulated a value > 922337203685477580, or equal but the
|
||||||
|
* next digit is > 7 (or 8), the number is too big, and we will
|
||||||
|
* return a range error.
|
||||||
|
*
|
||||||
|
* Set any if any `digits' consumed; make it negative to indicate
|
||||||
|
* overflow.
|
||||||
|
*/
|
||||||
|
cutoff = neg ? LLONG_MIN : LLONG_MAX;
|
||||||
|
cutlim = (int)(cutoff % base);
|
||||||
|
cutoff /= base;
|
||||||
|
if (neg) {
|
||||||
|
if (cutlim > 0) {
|
||||||
|
cutlim -= base;
|
||||||
|
cutoff += 1;
|
||||||
|
}
|
||||||
|
cutlim = -cutlim;
|
||||||
|
}
|
||||||
|
for (acc = 0, any = 0;; c = (unsigned char) *s++) {
|
||||||
|
if (isdigit(c))
|
||||||
|
c -= '0';
|
||||||
|
else if (isalpha(c))
|
||||||
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if (c >= base)
|
||||||
|
break;
|
||||||
|
if (any < 0)
|
||||||
|
continue;
|
||||||
|
if (neg) {
|
||||||
|
if (acc < cutoff || (acc == cutoff && c > cutlim)) {
|
||||||
|
any = -1;
|
||||||
|
acc = LLONG_MIN;
|
||||||
|
errno = ERANGE;
|
||||||
|
} else {
|
||||||
|
any = 1;
|
||||||
|
acc *= base;
|
||||||
|
acc -= c;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (acc > cutoff || (acc == cutoff && c > cutlim)) {
|
||||||
|
any = -1;
|
||||||
|
acc = LLONG_MAX;
|
||||||
|
errno = ERANGE;
|
||||||
|
} else {
|
||||||
|
any = 1;
|
||||||
|
acc *= base;
|
||||||
|
acc += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (endptr != 0)
|
||||||
|
/* LINTED interface specification */
|
||||||
|
*endptr = (char *)(any ? s - 1 : nptr);
|
||||||
|
return (acc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int std_support::stoi(const std::string &str) {
|
||||||
|
return std::atoi(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
double std_support::strtod(const char *str, char **endptr) {
|
||||||
|
return std::strtod(str, endptr);
|
||||||
|
}
|
||||||
22
src/std_support.hpp
Normal file
22
src/std_support.hpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace std_support {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::string to_string(const T &n) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << n;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
double strtod(const char *str, char **endptr);
|
||||||
|
|
||||||
|
int stoi(const std::string &str);
|
||||||
|
|
||||||
|
long long strtoll(const char *str, char **endptr = nullptr, int base = 10);
|
||||||
|
|
||||||
|
unsigned long long strtoull(const char *str, char **endptr = nullptr, int base = 10);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user