Add string concatenation function
Add variadic concat() function for concatenating char *, char, and string types.
This commit is contained in:
parent
b9d27b6a1f
commit
10e451b58d
139
include/nlohmann/detail/string_concat.hpp
Normal file
139
include/nlohmann/detail/string_concat.hpp
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstring> // strlen
|
||||||
|
#include <string> // string
|
||||||
|
#include <utility> // forward
|
||||||
|
|
||||||
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
#include <nlohmann/detail/meta/detected.hpp>
|
||||||
|
|
||||||
|
namespace nlohmann
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
inline std::size_t concat_length()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char* cstr, Args&& ... rest);
|
||||||
|
|
||||||
|
template<typename StringType, typename... Args>
|
||||||
|
inline std::size_t concat_length(const StringType& str, Args&& ... rest);
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char /*c*/, Args&& ... rest)
|
||||||
|
{
|
||||||
|
return 1 + concat_length(std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char* cstr, Args&& ... rest)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress ignoredReturnValue
|
||||||
|
return ::strlen(cstr) + concat_length(std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename StringType, typename... Args>
|
||||||
|
inline std::size_t concat_length(const StringType& str, Args&& ... rest)
|
||||||
|
{
|
||||||
|
return str.size() + concat_length(std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutStringType>
|
||||||
|
inline void concat_into(OutStringType& /*out*/)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append = is_detected<string_can_append, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ());
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_iter<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
|
||||||
|
|
||||||
|
template<typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>
|
||||||
|
inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)
|
||||||
|
{
|
||||||
|
out.append(std::forward<Arg>(arg));
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_op<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out += std::forward<Arg>(arg);
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_iter<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out.append(arg.begin(), arg.end());
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_iter<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_data<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out.append(arg.data(), arg.size());
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutStringType = std::string, typename... Args>
|
||||||
|
inline OutStringType concat(Args && ... args)
|
||||||
|
{
|
||||||
|
OutStringType str;
|
||||||
|
str.reserve(concat_length(std::forward<Args>(args)...));
|
||||||
|
concat_into(str, std::forward<Args>(args)...);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace nlohmann
|
||||||
@ -83,6 +83,7 @@ SOFTWARE.
|
|||||||
#include <nlohmann/detail/json_pointer.hpp>
|
#include <nlohmann/detail/json_pointer.hpp>
|
||||||
#include <nlohmann/detail/json_ref.hpp>
|
#include <nlohmann/detail/json_ref.hpp>
|
||||||
#include <nlohmann/detail/macro_scope.hpp>
|
#include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
#include <nlohmann/detail/string_concat.hpp>
|
||||||
#include <nlohmann/detail/string_escape.hpp>
|
#include <nlohmann/detail/string_escape.hpp>
|
||||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||||
|
|||||||
@ -13187,6 +13187,149 @@ class json_ref
|
|||||||
|
|
||||||
// #include <nlohmann/detail/macro_scope.hpp>
|
// #include <nlohmann/detail/macro_scope.hpp>
|
||||||
|
|
||||||
|
// #include <nlohmann/detail/string_concat.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstring> // strlen
|
||||||
|
#include <string> // string
|
||||||
|
#include <utility> // forward
|
||||||
|
|
||||||
|
// #include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
|
||||||
|
// #include <nlohmann/detail/meta/detected.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace nlohmann
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
inline std::size_t concat_length()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char* cstr, Args&& ... rest);
|
||||||
|
|
||||||
|
template<typename StringType, typename... Args>
|
||||||
|
inline std::size_t concat_length(const StringType& str, Args&& ... rest);
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char /*c*/, Args&& ... rest)
|
||||||
|
{
|
||||||
|
return 1 + concat_length(std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
inline std::size_t concat_length(const char* cstr, Args&& ... rest)
|
||||||
|
{
|
||||||
|
// cppcheck-suppress ignoredReturnValue
|
||||||
|
return ::strlen(cstr) + concat_length(std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename StringType, typename... Args>
|
||||||
|
inline std::size_t concat_length(const StringType& str, Args&& ... rest)
|
||||||
|
{
|
||||||
|
return str.size() + concat_length(std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutStringType>
|
||||||
|
inline void concat_into(OutStringType& /*out*/)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append = is_detected<string_can_append, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ());
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>;
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size()));
|
||||||
|
|
||||||
|
template<typename StringType, typename Arg>
|
||||||
|
using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_iter<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
|
||||||
|
|
||||||
|
template<typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>
|
||||||
|
inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)
|
||||||
|
{
|
||||||
|
out.append(std::forward<Arg>(arg));
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_op<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out += std::forward<Arg>(arg);
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_iter<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out.append(arg.begin(), arg.end());
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename OutStringType, typename Arg, typename... Args,
|
||||||
|
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_op<OutStringType, Arg>::value
|
||||||
|
&& !detect_string_can_append_iter<OutStringType, Arg>::value
|
||||||
|
&& detect_string_can_append_data<OutStringType, Arg>::value, int > >
|
||||||
|
inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
|
||||||
|
{
|
||||||
|
out.append(arg.data(), arg.size());
|
||||||
|
concat_into(out, std::forward<Args>(rest)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutStringType = std::string, typename... Args>
|
||||||
|
inline OutStringType concat(Args && ... args)
|
||||||
|
{
|
||||||
|
OutStringType str;
|
||||||
|
str.reserve(concat_length(std::forward<Args>(args)...));
|
||||||
|
concat_into(str, std::forward<Args>(args)...);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace nlohmann
|
||||||
|
|
||||||
// #include <nlohmann/detail/string_escape.hpp>
|
// #include <nlohmann/detail/string_escape.hpp>
|
||||||
|
|
||||||
// #include <nlohmann/detail/meta/cpp_future.hpp>
|
// #include <nlohmann/detail/meta/cpp_future.hpp>
|
||||||
|
|||||||
@ -37,6 +37,84 @@ using nlohmann::json;
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
struct alt_string_iter
|
||||||
|
{
|
||||||
|
alt_string_iter() = default;
|
||||||
|
alt_string_iter(const char* cstr)
|
||||||
|
: impl(cstr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void reserve(std::size_t s)
|
||||||
|
{
|
||||||
|
impl.reserve(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Iter>
|
||||||
|
void append(Iter first, Iter last)
|
||||||
|
{
|
||||||
|
impl.append(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string::const_iterator begin() const
|
||||||
|
{
|
||||||
|
return impl.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string::const_iterator end() const
|
||||||
|
{
|
||||||
|
return impl.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size() const
|
||||||
|
{
|
||||||
|
return impl.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
alt_string_iter& operator+=(const char c)
|
||||||
|
{
|
||||||
|
impl += c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string impl{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct alt_string_data
|
||||||
|
{
|
||||||
|
alt_string_data() = default;
|
||||||
|
alt_string_data(const char* cstr)
|
||||||
|
: impl(cstr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void reserve(std::size_t s)
|
||||||
|
{
|
||||||
|
impl.reserve(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const char* p, std::size_t s)
|
||||||
|
{
|
||||||
|
impl.append(p, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* data() const
|
||||||
|
{
|
||||||
|
return impl.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size() const
|
||||||
|
{
|
||||||
|
return impl.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
alt_string_data& operator+=(const char c)
|
||||||
|
{
|
||||||
|
impl += c;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string impl{};
|
||||||
|
};
|
||||||
|
|
||||||
void check_escaped(const char* original, const char* escaped = "", bool ensure_ascii = false);
|
void check_escaped(const char* original, const char* escaped = "", bool ensure_ascii = false);
|
||||||
void check_escaped(const char* original, const char* escaped, const bool ensure_ascii)
|
void check_escaped(const char* original, const char* escaped, const bool ensure_ascii)
|
||||||
{
|
{
|
||||||
@ -110,4 +188,39 @@ TEST_CASE("convenience functions")
|
|||||||
|
|
||||||
CHECK_THROWS_WITH_AS(check_escaped("\xC2"), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
|
CHECK_THROWS_WITH_AS(check_escaped("\xC2"), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("string concat")
|
||||||
|
{
|
||||||
|
using nlohmann::detail::concat;
|
||||||
|
|
||||||
|
const char* expected = "Hello, world!";
|
||||||
|
alt_string_iter hello_iter{"Hello, "};
|
||||||
|
alt_string_data hello_data{"Hello, "};
|
||||||
|
std::string world = "world";
|
||||||
|
|
||||||
|
SECTION("std::string")
|
||||||
|
{
|
||||||
|
std::string str1 = concat(hello_iter, world, '!');
|
||||||
|
std::string str2 = concat(hello_data, world, '!');
|
||||||
|
std::string str3 = concat("Hello, ", world, '!');
|
||||||
|
|
||||||
|
CHECK(str1 == expected);
|
||||||
|
CHECK(str2 == expected);
|
||||||
|
CHECK(str3 == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("alt_string_iter")
|
||||||
|
{
|
||||||
|
alt_string_iter str = concat<alt_string_iter>(hello_iter, world, '!');
|
||||||
|
|
||||||
|
CHECK(str.impl == expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("alt_string_data")
|
||||||
|
{
|
||||||
|
alt_string_data str = concat<alt_string_data>(hello_data, world, '!');
|
||||||
|
|
||||||
|
CHECK(str.impl == expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user