JsonBuilder - convert string values to UTF-8 (#27)

* JsonBuilder - convert string values to UTF-8

Add support for converting data from UTF-NN to UTF-8 when the data is
added to the JsonBuilder, i.e. you can now `push_back` a UTF-16 or
UTF-32 string and it will be converted to UTF-8 as part of the
`push_back` process.

Alternative design would be to add new data types for JsonUtf16 and
JsonUtf32, and then store the string in the JsonBuilder using its
original encoding. This seems problematic -- anything reading string
values would need to check the string's encoding and have separate code
paths for each of the 3 encodings.

* Also support converting latin1 and cp1252 input.
This commit is contained in:
Doug Cook 2024-01-09 00:04:24 -08:00 коммит произвёл GitHub
Родитель 8eac958fc5
Коммит 1932340cd8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 551 добавлений и 16 удалений

Просмотреть файл

@ -1493,10 +1493,74 @@ class JsonBuilder
_In_reads_bytes_opt_(cbData) void const* pbData)
noexcept(false); // may throw bad_alloc, length_error
/*
Advanced scenarios: Should only be called by JsonImplementType<T>::AddValueCommit
that itself was called by JsonBuilder. This is the same as _newValueCommit but it
converts SBCS data into UTF-8.
type should usually be JsonUtf8.
sbcsData must contain data encoded using a single-byte character set (SBCS).
Characters < 0x80 are interpreted as ASCII. Characters >= 0x80 are looked up in the
provided high128 table, char16 = high128[(UCHAR)char8 - 0x80]. Values in the
high128 table should not be in the surrogate range 0xD800..0xDFFF.
*/
iterator
_newValueCommitSbcsAsUtf8(
JsonType type,
std::string_view sbcsData,
_In_reads_(128) char16_t const* high128)
noexcept(false); // may throw bad_alloc, length_error
/*
Advanced scenarios: Should only be called by JsonImplementType<T>::AddValueCommit
that itself was called by JsonBuilder. This is the same as _newValueCommit but it
converts UTF-8/16/32 data into UTF-8.
type should usually be JsonUtf8.
utfData must be a string-view-like thing (pointer to nul-terminated
array of CHARs, or contiguous container of CHARs), where CHAR is one
of char, char8_t, char16_t, char32_t, or wchar_t. The string is
assumed to be UTF-8, UTF-16, or UTF-32 based on sizeof(CHAR).
*/
template<
class DataStringView,
class DataChar = typename JsonInternal::StringTypeOk<DataStringView>::type>
iterator
_newValueCommitUtfAsUtf8(
JsonType type,
DataStringView const& utfData)
noexcept(false) // may throw bad_alloc, length_error
{
std::basic_string_view<DataChar> dataView{ utfData };
using char_type = typename JsonInternal::CharTypeOk<DataChar>::char_type;
return NewValueCommitUtfAsUtf8Impl(type, dataView.size(), reinterpret_cast<char_type const*>(dataView.data()));
}
private:
void CreateRoot() noexcept(false);
iterator
NewValueCommitUtfAsUtf8Impl(
JsonType type,
JsonInternal::JSON_SIZE_T cchData,
_In_reads_(cchData) char const* pchDataUtf8)
noexcept(false); // may throw bad_alloc, length_error
iterator
NewValueCommitUtfAsUtf8Impl(
JsonType type,
JsonInternal::JSON_SIZE_T cchData,
_In_reads_(cchData) char16_t const* pchDataUtf16)
noexcept(false); // may throw bad_alloc, length_error
iterator
NewValueCommitUtfAsUtf8Impl(
JsonType type,
JsonInternal::JSON_SIZE_T cchData,
_In_reads_(cchData) char32_t const* pchDataUtf32)
noexcept(false); // may throw bad_alloc, length_error
/*
Common implementation for NewValueInit.
If reallocation occurred and pName pointed into old storage, returns corresponding
@ -1743,6 +1807,22 @@ public:
}
};
/*
String view using Latin-1 (ISO-8859-1) encoding.
*/
struct latin1_view : std::string_view
{
using std::string_view::string_view;
};
/*
String view using cp1252 encoding.
*/
struct cp1252_view : std::string_view
{
using std::string_view::string_view;
};
// JsonImplementType
/*
@ -1817,6 +1897,17 @@ class JsonImplementType
static JsonIterator AddValueCommit(JsonBuilder& builder, T InRef data); \
}
#define JSON_DECLARE_JsonImplementType_AddValueSz(CH) \
template<> \
class JsonImplementType<CH*> \
{ \
public: \
static JsonIterator AddValueCommit(JsonBuilder& builder, _In_z_ CH const* psz); \
}; \
template<> \
class JsonImplementType<CH const*> \
: public JsonImplementType<CH*> {}; \
JSON_DECLARE_JsonImplementType(bool,, );
JSON_DECLARE_JsonImplementType(unsigned char,, );
@ -1837,17 +1928,77 @@ JSON_DECLARE_JsonImplementType(double,, );
JSON_DECLARE_JsonImplementType(TimeStruct,, );
JSON_DECLARE_JsonImplementType(std::chrono::system_clock::time_point,, );
JSON_DECLARE_JsonImplementType(UuidStruct, const&, const&);
JSON_DECLARE_JsonImplementType(std::string_view,, );
JSON_DECLARE_JsonImplementType_AddValue(latin1_view, );
JSON_DECLARE_JsonImplementType_AddValue(cp1252_view, );
JSON_DECLARE_JsonImplementType(std::string_view,, );
JSON_DECLARE_JsonImplementType_AddValue(std::wstring_view, );
JSON_DECLARE_JsonImplementType_AddValue(std::u16string_view, );
JSON_DECLARE_JsonImplementType_AddValue(std::u32string_view, );
JSON_DECLARE_JsonImplementType_AddValueSz(char);
JSON_DECLARE_JsonImplementType_AddValueSz(wchar_t);
JSON_DECLARE_JsonImplementType_AddValueSz(char16_t);
JSON_DECLARE_JsonImplementType_AddValueSz(char32_t);
#ifdef __cpp_lib_char8_t // Support u8string_view and char8_t, inline so they work even if lib builds as C++17.
// JSON_DECLARE_JsonImplementType(std::u8string_view,, ):
template<>
class JsonImplementType<char*>
class JsonImplementType<std::u8string_view>
{
public:
static JsonIterator AddValueCommit(JsonBuilder& builder, _In_z_ char const* psz);
static std::u8string_view
GetUnchecked(JsonValue const& value) noexcept
{
auto charResult = JsonImplementType<std::string_view>::GetUnchecked(value);
return { reinterpret_cast<char8_t const*>(charResult.data()), charResult.size() };
}
static bool
ConvertTo(JsonValue const& value, std::u8string_view& result) noexcept
{
bool success;
if (value.Type() == JsonUtf8)
{
result = GetUnchecked(value);
success = true;
}
else
{
result = std::u8string_view();
success = false;
}
return success;
}
static JsonIterator
AddValueCommit(JsonBuilder& builder, std::u8string_view data)
{
return builder._newValueCommitUtfAsUtf8(JsonUtf8, data);
}
};
// JSON_DECLARE_JsonImplementType_AddValueSz(char8_t):
template<>
class JsonImplementType<char8_t*>
{
public:
static JsonIterator
AddValueCommit(JsonBuilder& builder, _In_z_ char8_t const* psz)
{
return builder._newValueCommitUtfAsUtf8(JsonUtf8, psz);
}
};
template<>
class JsonImplementType<char const*> : public JsonImplementType<char*>
{};
class JsonImplementType<char8_t const*>
: public JsonImplementType<char8_t*> {};
#endif // __cpp_lib_char8_t
} // namespace jsonbuilder

Просмотреть файл

@ -115,6 +115,47 @@ Utf32ToUtf8(
return iDest;
}
static unsigned
SbcsToUtf8(
_Out_writes_to_(cchSrc * 3, return) char unsigned* pchDest,
_In_reads_(cchSrc) char const* pchSrc,
unsigned cchSrc,
_In_reads_(128) char16_t const* high128)
noexcept
{
unsigned iDest = 0;
for (unsigned iSrc = 0; iSrc != cchSrc; iSrc += 1)
{
char unsigned const ch8 = pchSrc[iSrc];
if (ch8 < 0x80)
{
// ASCII character - don't use lookup table.
pchDest[iDest++] = static_cast<char unsigned>(ch8);
continue;
}
char16_t const ch = high128[ch8 - 0x80];
if (ch < 0x80)
{
pchDest[iDest++] = static_cast<char unsigned>(ch);
}
else if (ch < 0x800)
{
pchDest[iDest++] = static_cast<char unsigned>(0xC0 | (ch >> 6));
pchDest[iDest++] = static_cast<char unsigned>(0x80 | (ch & 0x3F));
}
else
{
// It could be in the surrogate range, but we don't care.
pchDest[iDest++] = static_cast<char unsigned>(0xE0 | (ch >> 12));
pchDest[iDest++] = static_cast<char unsigned>(0x80 | ((ch >> 6) & 0x3F));
pchDest[iDest++] = static_cast<char unsigned>(0x80 | (ch & 0x3F));
}
}
return iDest;
}
// JsonValue
namespace jsonbuilder {
@ -1174,6 +1215,107 @@ JsonBuilder::_newValueCommit(
return iterator(const_iterator(this, newIndex));
}
JsonBuilder::iterator
JsonBuilder::_newValueCommitSbcsAsUtf8(
JsonType type,
std::string_view sbcsData,
_In_reads_(128) char16_t const* high128)
noexcept(false) // may throw bad_alloc, length_error
{
auto constexpr WorstCaseMultiplier = 3u; // 1 UTF-16 code unit -> 3 UTF-8 code units.
if (sbcsData.size() > DataMax / WorstCaseMultiplier)
{
JsonThrowLengthError("JsonBuilder - cchData too large");
}
// Create node. Reserve worst-case size for data.
auto const cchSrc = static_cast<unsigned>(sbcsData.size());
auto const valueIt = _newValueCommit(type, cchSrc * WorstCaseMultiplier, nullptr);
// Copy data into node, converting to UTF-8.
auto& value = GetValue(valueIt.m_index);
auto const valueDataIndex = valueIt.m_index + DATA_OFFSET(value.m_cchName);
auto const cbDest = SbcsToUtf8(reinterpret_cast<unsigned char*>(&m_storage[valueDataIndex]), sbcsData.data(), cchSrc, high128);
// Shrink to fit actual data size.
value.m_cbData = cbDest; // Shrink
m_storage.resize(valueDataIndex + (cbDest + StorageSize - 1) / StorageSize); // Shrink
return valueIt;
}
JsonBuilder::iterator
JsonBuilder::NewValueCommitUtfAsUtf8Impl(
JsonType type,
JsonInternal::JSON_SIZE_T cchData,
_In_reads_(cchData) char const* pchDataUtf8)
noexcept(false)
{
if (cchData > DataMax)
{
JsonThrowLengthError("JsonBuilder - cchData too large");
}
return _newValueCommit(type, static_cast<unsigned>(cchData), pchDataUtf8);
}
JsonBuilder::iterator
JsonBuilder::NewValueCommitUtfAsUtf8Impl(
JsonType type,
JsonInternal::JSON_SIZE_T cchData,
_In_reads_(cchData) char16_t const* pchDataUtf16)
noexcept(false) // may throw bad_alloc, length_error
{
auto constexpr WorstCaseMultiplier = 3u; // 1 UTF-16 code unit -> 3 UTF-8 code units.
if (cchData > DataMax / WorstCaseMultiplier)
{
JsonThrowLengthError("JsonBuilder - cchData too large");
}
// Create node. Reserve worst-case size for data.
auto const cchSrc = static_cast<unsigned>(cchData);
auto const valueIt = _newValueCommit(type, cchSrc * WorstCaseMultiplier, nullptr);
// Copy data into node, converting to UTF-8.
auto& value = GetValue(valueIt.m_index);
auto const valueDataIndex = valueIt.m_index + DATA_OFFSET(value.m_cchName);
auto const cbDest = Utf16ToUtf8(reinterpret_cast<unsigned char*>(&m_storage[valueDataIndex]), pchDataUtf16, cchSrc);
// Shrink to fit actual data size.
value.m_cbData = cbDest; // Shrink
m_storage.resize(valueDataIndex + (cbDest + StorageSize - 1) / StorageSize); // Shrink
return valueIt;
}
JsonBuilder::iterator
JsonBuilder::NewValueCommitUtfAsUtf8Impl(
JsonType type,
JsonInternal::JSON_SIZE_T cchData,
_In_reads_(cchData) char32_t const* pchDataUtf32)
noexcept(false) // may throw bad_alloc, length_error
{
auto constexpr WorstCaseMultiplier = 4u; // 1 UTF-32 code unit -> 4 UTF-8 code units.
if (cchData > DataMax / WorstCaseMultiplier)
{
JsonThrowLengthError("JsonBuilder - cchData too large");
}
// Create node. Reserve worst-case size for data.
auto const cchSrc = static_cast<unsigned>(cchData);
auto const valueIt = _newValueCommit(type, cchSrc * WorstCaseMultiplier, nullptr);
// Copy data into node, converting to UTF-8.
auto& value = GetValue(valueIt.m_index);
auto const valueDataIndex = valueIt.m_index + DATA_OFFSET(value.m_cchName);
auto const cbDest = Utf32ToUtf8(reinterpret_cast<unsigned char*>(&m_storage[valueDataIndex]), pchDataUtf32, cchSrc);
// Shrink to fit actual data size.
value.m_cbData = cbDest; // Shrink
m_storage.resize(valueDataIndex + (cbDest + StorageSize - 1) / StorageSize); // Shrink
return valueIt;
}
void JsonBuilder::AssertNotEnd(Index index) noexcept
{
(void) index; // Unreferenced parameter in release builds.
@ -1631,7 +1773,31 @@ JsonImplementType<char*>::AddValueCommit(
JsonBuilder& builder,
_In_z_ char const* psz)
{
return builder._newValueCommit(JsonUtf8, static_cast<unsigned>(strlen(psz)), psz);
return builder._newValueCommitUtfAsUtf8(JsonUtf8, psz);
}
JsonIterator
JsonImplementType<wchar_t*>::AddValueCommit(
JsonBuilder& builder,
_In_z_ wchar_t const* psz)
{
return builder._newValueCommitUtfAsUtf8(JsonUtf8, psz);
}
JsonIterator
JsonImplementType<char16_t*>::AddValueCommit(
JsonBuilder& builder,
_In_z_ char16_t const* psz)
{
return builder._newValueCommitUtfAsUtf8(JsonUtf8, psz);
}
JsonIterator
JsonImplementType<char32_t*>::AddValueCommit(
JsonBuilder& builder,
_In_z_ char32_t const* psz)
{
return builder._newValueCommitUtfAsUtf8(JsonUtf8, psz);
}
std::string_view
@ -1668,7 +1834,69 @@ JsonImplementType<std::string_view>::AddValueCommit(
JsonBuilder& builder,
std::string_view data)
{
return builder._newValueCommit(JsonUtf8, static_cast<unsigned>(data.size()), data.data());
return builder._newValueCommitUtfAsUtf8(JsonUtf8, data);
}
JsonIterator
JsonImplementType<std::wstring_view>::AddValueCommit(
JsonBuilder& builder,
std::wstring_view data)
{
return builder._newValueCommitUtfAsUtf8(JsonUtf8, data);
}
JsonIterator
JsonImplementType<std::u16string_view>::AddValueCommit(
JsonBuilder& builder,
std::u16string_view data)
{
return builder._newValueCommitUtfAsUtf8(JsonUtf8, data);
}
JsonIterator
JsonImplementType<std::u32string_view>::AddValueCommit(
JsonBuilder& builder,
std::u32string_view data)
{
return builder._newValueCommitUtfAsUtf8(JsonUtf8, data);
}
JsonIterator
JsonImplementType<latin1_view>::AddValueCommit(
JsonBuilder& builder,
latin1_view data)
{
static constexpr char16_t High128[] = {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
static_assert(sizeof(High128) == 128 * sizeof(High128[0]), "High128 size");
return builder._newValueCommitSbcsAsUtf8(JsonUtf8, data, High128);
}
JsonIterator
JsonImplementType<cp1252_view>::AddValueCommit(
JsonBuilder& builder,
cp1252_view data)
{
static constexpr char16_t High128[] = {
0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F,
0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
};
static_assert(sizeof(High128) == 128 * sizeof(High128[0]), "High128 size");
return builder._newValueCommitSbcsAsUtf8(JsonUtf8, data, High128);
}
// JsonTime

Просмотреть файл

@ -7,7 +7,7 @@ if(NOT WIN32)
endif()
add_executable(jsonbuilderTest CatchMain.cpp TestBuilder.cpp TestRenderer.cpp)
target_compile_features(jsonbuilderTest PRIVATE cxx_std_17)
target_compile_features(jsonbuilderTest PRIVATE cxx_std_20)
target_link_libraries(jsonbuilderTest PRIVATE jsonbuilder Catch2::Catch2 ${LIB_TARGET_UUID})
include(CTest)

Просмотреть файл

@ -5,6 +5,9 @@
#include <jsonbuilder/JsonBuilder.h>
#include <string.h>
#define USTRING(prefix) prefix ## "\u0024\u00A3\u0418\u0939\u20AC\uD55C\U00010348"
#define CHAR_USTRING() reinterpret_cast<char const*>(USTRING(u8))
#ifdef _WIN32
using uuid_t = char unsigned[16];
static void uuid_generate(uuid_t uuid)
@ -101,8 +104,6 @@ static void TestInputOutputScalar()
JsonBuilder b;
#define USTRING(prefix) prefix ## "\u0024\u00A3\u0418\u0939\u20AC\uD55C\U00010348"
b.push_back(b.root(), USTRING(u), InputLimits::lowest());
b.push_back(b.root(), USTRING(U), InputLimits::min());
b.push_back(b.root(), USTRING(L), InputLimits::max());
@ -115,25 +116,25 @@ static void TestInputOutputScalar()
InputType i;
auto it = b.begin();
REQUIRE(it->Name() == USTRING(u8));
REQUIRE(it->Name() == CHAR_USTRING());
REQUIRE(it->GetUnchecked<InputType>() == InputLimits::lowest());
REQUIRE(it->ConvertTo(i));
REQUIRE(i == InputLimits::lowest());
++it;
REQUIRE(it->Name() == USTRING(u8));
REQUIRE(it->Name() == CHAR_USTRING());
REQUIRE(it->GetUnchecked<InputType>() == InputLimits::min());
REQUIRE(it->ConvertTo(i));
REQUIRE(i == InputLimits::min());
++it;
REQUIRE(it->Name() == USTRING(u8));
REQUIRE(it->Name() == CHAR_USTRING());
REQUIRE(it->GetUnchecked<InputType>() == InputLimits::max());
REQUIRE(it->ConvertTo(i));
REQUIRE(i == InputLimits::max());
++it;
REQUIRE(it->Name() == USTRING(u8));
REQUIRE(it->Name() == CHAR_USTRING());
REQUIRE(
it->GetUnchecked<InputType>() ==
static_cast<InputType>(OutputLimits::lowest()));
@ -242,6 +243,8 @@ TEST_CASE("JsonBuilder string push_back")
{
JsonBuilder b;
// char
SECTION("push_back std::string_view")
{
auto itr = b.push_back(b.root(), "", std::string_view{ "ABCDE" });
@ -268,9 +271,162 @@ TEST_CASE("JsonBuilder string push_back")
SECTION("push_back const char[]")
{
auto itr = b.push_back(b.root(), "", "HIJ");
REQUIRE(itr->GetUnchecked<std::string_view>() == "HIJ");
auto itr = b.push_back(b.root(), "", CHAR_USTRING());
REQUIRE(itr->GetUnchecked<std::string_view>() == CHAR_USTRING());
}
SECTION("push_back latin1_view")
{
auto itr = b.push_back(b.root(), "", latin1_view{ "ABCDE\x80\x90\x9F\xA0\xB0\xF0\xFF" });
REQUIRE(itr->GetUnchecked<std::string_view>() == reinterpret_cast<char const*>(u8"ABCDE\u0080\u0090\u009F\u00A0\u00B0\u00F0\u00FF"));
}
SECTION("push_back cp1252_view")
{
auto itr = b.push_back(b.root(), "", cp1252_view{ "ABCDE\x80\x90\x9F\xA0\xB0\xF0\xFF" });
REQUIRE(itr->GetUnchecked<std::string_view>() == reinterpret_cast<char const*>(u8"ABCDE\u20AC\u0090\u0178\u00A0\u00B0\u00F0\u00FF"));
}
// wchar_t
SECTION("push_back std::wstring_view")
{
auto itr = b.push_back(b.root(), "", std::wstring_view{ L"ABCDE" });
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABCDE");
}
SECTION("push_back std::wstring")
{
auto itr = b.push_back<std::wstring_view>(b.root(), "", std::wstring{ L"ABCDE" });
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABCDE");
}
SECTION("push_back wchar_t*")
{
auto itr = b.push_back(b.root(), "", const_cast<wchar_t*>(L"ABC"));
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABC");
}
SECTION("push_back const wchar_t*")
{
auto itr = b.push_back(b.root(), "", static_cast<const wchar_t*>(L"DEF"));
REQUIRE(itr->GetUnchecked<std::string_view>() == "DEF");
}
SECTION("push_back const wchar_t[]")
{
auto itr = b.push_back(b.root(), "", USTRING(L));
REQUIRE(itr->GetUnchecked<std::string_view>() == CHAR_USTRING());
}
// char8_t
#ifdef __cpp_lib_char8_t // C++20
SECTION("push_back std::u8string_view")
{
auto itr = b.push_back(b.root(), "", std::u8string_view{ u8"ABCDE" });
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABCDE");
REQUIRE(itr->GetUnchecked<std::u8string_view>() == u8"ABCDE");
}
SECTION("push_back std::u8string")
{
auto itr = b.push_back<std::u8string_view>(b.root(), "", std::u8string{ u8"ABCDE" });
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABCDE");
REQUIRE(itr->GetUnchecked<std::u8string_view>() == u8"ABCDE");
}
SECTION("push_back char8_t*")
{
auto itr = b.push_back(b.root(), "", const_cast<char8_t*>(u8"ABC"));
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABC");
REQUIRE(itr->GetUnchecked<std::u8string_view>() == u8"ABC");
}
SECTION("push_back const char8_t*")
{
auto itr = b.push_back(b.root(), "", static_cast<const char8_t*>(u8"DEF"));
REQUIRE(itr->GetUnchecked<std::string_view>() == "DEF");
REQUIRE(itr->GetUnchecked<std::u8string_view>() == u8"DEF");
}
#endif // __cpp_lib_char8_t
SECTION("push_back const char8_t[]")
{
auto itr = b.push_back(b.root(), "", USTRING(u8));
REQUIRE(itr->GetUnchecked<std::string_view>() == CHAR_USTRING());
#ifdef __cpp_lib_char8_t // C++20
REQUIRE(itr->GetUnchecked<std::u8string_view>() == USTRING(u8));
#endif // __cpp_lib_char8_t
}
// char16_t
SECTION("push_back std::u16string_view")
{
auto itr = b.push_back(b.root(), "", std::u16string_view{ u"ABCDE" });
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABCDE");
}
SECTION("push_back std::u16string")
{
auto itr = b.push_back<std::u16string_view>(b.root(), "", std::u16string{ u"ABCDE" });
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABCDE");
}
SECTION("push_back char16_t*")
{
auto itr = b.push_back(b.root(), "", const_cast<char16_t*>(u"ABC"));
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABC");
}
SECTION("push_back const char16_t*")
{
auto itr = b.push_back(b.root(), "", static_cast<const char16_t*>(u"DEF"));
REQUIRE(itr->GetUnchecked<std::string_view>() == "DEF");
}
SECTION("push_back const char16_t[]")
{
auto itr = b.push_back(b.root(), "", USTRING(u));
REQUIRE(itr->GetUnchecked<std::string_view>() == CHAR_USTRING());
}
// char32_t
SECTION("push_back std::u32string_view")
{
auto itr = b.push_back(b.root(), "", std::u32string_view{ U"ABCDE" });
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABCDE");
}
SECTION("push_back std::u32string")
{
auto itr = b.push_back<std::u32string_view>(b.root(), "", std::u32string{ U"ABCDE" });
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABCDE");
}
SECTION("push_back char32_t*")
{
auto itr = b.push_back(b.root(), "", const_cast<char32_t*>(U"ABC"));
REQUIRE(itr->GetUnchecked<std::string_view>() == "ABC");
}
SECTION("push_back const char32_t*")
{
auto itr = b.push_back(b.root(), "", static_cast<const char32_t*>(U"DEF"));
REQUIRE(itr->GetUnchecked<std::string_view>() == "DEF");
}
SECTION("push_back const char32_t[]")
{
auto itr = b.push_back(b.root(), "", USTRING(U));
REQUIRE(itr->GetUnchecked<std::string_view>() == CHAR_USTRING());
}
b.ValidateData();
}
TEST_CASE("JsonBuilder chrono push_back", "[builder]")