mirror of
https://github.com/nlohmann/json.git
synced 2026-10-15 18:57:13 +00:00
* Speed up JSON pointer parsing, formatting, comparison and lookup Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Restore unflatten() speed after the linear-time rewrite The prefix tree introduced for linear unflatten() kept a std::map per prefix, copied each token into it and looked every token up a second time while creating the values. Replace the per-prefix maps by one open-addressing table keyed by (parent, token) that refers to the parsed tokens, skip the lookups for the prefix shared with the previous key (flattened objects are mostly sorted), and derive the prefix numbers of the second pass from parent links instead of lookups. Time and memory stay linear in the pointer depth, and the result is still independent of the iteration order of the flattened object. Signed-off-by: Niels Lohmann <mail@nlohmann.me> * Put [[noreturn]] before __attribute__ on the JSON pointer throw helpers Clang 18 on Linux rejects a C++11 attribute list after a GNU __attribute__ ("an attribute list cannot appear here"). Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
117 lines
3.0 KiB
C++
117 lines
3.0 KiB
C++
// __ _____ _____ _____
|
|
// __| | __| | | | JSON for Modern C++
|
|
// | | |__ | | | | | | version 3.12.0
|
|
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
|
//
|
|
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include <cstddef> // size_t
|
|
#include <utility> // move
|
|
|
|
#include <nlohmann/detail/abi_macros.hpp>
|
|
|
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
|
namespace detail
|
|
{
|
|
|
|
/*!
|
|
* @brief string escaping as described in RFC 6901 (Sect. 4)
|
|
* @param[in] s string to escape
|
|
* @return escaped string
|
|
*
|
|
* Note the order of escaping "~" to "~0" and "/" to "~1" is important.
|
|
*
|
|
* The string is rebuilt in a single pass, appending whole runs between the
|
|
* characters that need escaping, while repeated replace() calls would move
|
|
* the tail of the string once per escaped character. @ref escape_into appends
|
|
* the escaped string to an existing one.
|
|
*/
|
|
template<typename StringType>
|
|
inline void escape_into(StringType& out, const StringType& s)
|
|
{
|
|
const std::size_t size = s.size();
|
|
std::size_t run = 0;
|
|
for (std::size_t i = 0; i < size; ++i)
|
|
{
|
|
const char c = s[i];
|
|
if (c == '~' || c == '/')
|
|
{
|
|
out.append(s.data() + run, i - run);
|
|
out.append(c == '~' ? "~0" : "~1", 2);
|
|
run = i + 1;
|
|
}
|
|
}
|
|
out.append(s.data() + run, size - run);
|
|
}
|
|
|
|
template<typename StringType>
|
|
inline StringType escape(const StringType& s)
|
|
{
|
|
// a single scan for both special characters; nothing to escape is the common case
|
|
const std::size_t size = s.size();
|
|
std::size_t i = 0;
|
|
while (i < size && s[i] != '~' && s[i] != '/')
|
|
{
|
|
++i;
|
|
}
|
|
if (i == size)
|
|
{
|
|
return s;
|
|
}
|
|
|
|
StringType result;
|
|
result.reserve(size + 2);
|
|
escape_into(result, s);
|
|
return result;
|
|
}
|
|
|
|
/*!
|
|
* @brief string unescaping as described in RFC 6901 (Sect. 4)
|
|
* @param[in,out] s string to unescape in place
|
|
*
|
|
* Note the order of escaping "~1" to "/" and "~0" to "~" is important.
|
|
*
|
|
* Rebuilt in a single pass, see @ref escape. A "~" that is followed by
|
|
* neither "0" nor "1" is passed through unchanged; @ref json_pointer rejects
|
|
* such input before it gets here.
|
|
*/
|
|
template<typename StringType>
|
|
inline void unescape(StringType& s)
|
|
{
|
|
auto pos = s.find_first_of('~', 0);
|
|
if (pos == StringType::npos)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StringType result;
|
|
result.reserve(s.size());
|
|
|
|
std::size_t run = 0;
|
|
while (pos != StringType::npos)
|
|
{
|
|
result.append(s.data() + run, pos - run);
|
|
|
|
const auto next = pos + 1;
|
|
if (next < s.size() && (s[next] == '0' || s[next] == '1'))
|
|
{
|
|
result.append(s[next] == '0' ? "~" : "/", 1);
|
|
run = pos + 2;
|
|
}
|
|
else
|
|
{
|
|
result.append("~", 1);
|
|
run = pos + 1;
|
|
}
|
|
pos = s.find_first_of('~', run);
|
|
}
|
|
result.append(s.data() + run, s.size() - run);
|
|
s = std::move(result);
|
|
}
|
|
|
|
} // namespace detail
|
|
NLOHMANN_JSON_NAMESPACE_END
|