mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-28 00:25:41 +00:00
Common: Extract out ryml helpers
This commit is contained in:
parent
eb34f7f54f
commit
0f8d512732
|
@ -44,6 +44,7 @@ add_library(common
|
||||||
perf_scope.h
|
perf_scope.h
|
||||||
progress_callback.cpp
|
progress_callback.cpp
|
||||||
progress_callback.h
|
progress_callback.h
|
||||||
|
ryml_helpers.h
|
||||||
scoped_guard.h
|
scoped_guard.h
|
||||||
settings_interface.h
|
settings_interface.h
|
||||||
sha1_digest.cpp
|
sha1_digest.cpp
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
<ClInclude Include="path.h" />
|
<ClInclude Include="path.h" />
|
||||||
<ClInclude Include="perf_scope.h" />
|
<ClInclude Include="perf_scope.h" />
|
||||||
<ClInclude Include="progress_callback.h" />
|
<ClInclude Include="progress_callback.h" />
|
||||||
|
<ClInclude Include="ryml_helpers.h" />
|
||||||
<ClInclude Include="scoped_guard.h" />
|
<ClInclude Include="scoped_guard.h" />
|
||||||
<ClInclude Include="settings_interface.h" />
|
<ClInclude Include="settings_interface.h" />
|
||||||
<ClInclude Include="sha1_digest.h" />
|
<ClInclude Include="sha1_digest.h" />
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
<ClInclude Include="gsvector.h" />
|
<ClInclude Include="gsvector.h" />
|
||||||
<ClInclude Include="gsvector_formatter.h" />
|
<ClInclude Include="gsvector_formatter.h" />
|
||||||
<ClInclude Include="gsvector_nosimd.h" />
|
<ClInclude Include="gsvector_nosimd.h" />
|
||||||
|
<ClInclude Include="ryml_helpers.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="small_string.cpp" />
|
<ClCompile Include="small_string.cpp" />
|
||||||
|
|
124
src/common/ryml_helpers.h
Normal file
124
src/common/ryml_helpers.h
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
|
// SPDX-License-Identifier: PolyForm-Strict-1.0.0
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include "ryml.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
// RapidYAML utility routines.
|
||||||
|
|
||||||
|
[[maybe_unused]] ALWAYS_INLINE std::string_view to_stringview(const c4::csubstr& s)
|
||||||
|
{
|
||||||
|
return std::string_view(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] ALWAYS_INLINE std::string_view to_stringview(const c4::substr& s)
|
||||||
|
{
|
||||||
|
return std::string_view(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] ALWAYS_INLINE c4::csubstr to_csubstr(std::string_view sv)
|
||||||
|
{
|
||||||
|
return c4::csubstr(sv.data(), sv.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] static bool GetStringFromObject(const ryml::ConstNodeRef& object, std::string_view key,
|
||||||
|
std::string* dest)
|
||||||
|
{
|
||||||
|
dest->clear();
|
||||||
|
|
||||||
|
const ryml::ConstNodeRef member = object.find_child(to_csubstr(key));
|
||||||
|
if (!member.valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const c4::csubstr val = member.val();
|
||||||
|
if (!val.empty())
|
||||||
|
dest->assign(val.data(), val.size());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[maybe_unused]] static bool GetUIntFromObject(const ryml::ConstNodeRef& object, std::string_view key, T* dest)
|
||||||
|
{
|
||||||
|
*dest = 0;
|
||||||
|
|
||||||
|
const ryml::ConstNodeRef member = object.find_child(to_csubstr(key));
|
||||||
|
if (!member.valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const c4::csubstr val = member.val();
|
||||||
|
if (val.empty())
|
||||||
|
{
|
||||||
|
ERROR_LOG("Unexpected empty value in {}", key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::optional<T> opt_value = StringUtil::FromChars<T>(to_stringview(val));
|
||||||
|
if (!opt_value.has_value())
|
||||||
|
{
|
||||||
|
ERROR_LOG("Unexpected non-uint value in {}", key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest = opt_value.value();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[maybe_unused]] static std::optional<T> GetOptionalTFromObject(const ryml::ConstNodeRef& object, std::string_view key)
|
||||||
|
{
|
||||||
|
std::optional<T> ret;
|
||||||
|
|
||||||
|
const ryml::ConstNodeRef member = object.find_child(to_csubstr(key));
|
||||||
|
if (member.valid())
|
||||||
|
{
|
||||||
|
const c4::csubstr val = member.val();
|
||||||
|
if (!val.empty())
|
||||||
|
{
|
||||||
|
ret = StringUtil::FromChars<T>(to_stringview(val));
|
||||||
|
if (!ret.has_value())
|
||||||
|
{
|
||||||
|
if constexpr (std::is_floating_point_v<T>)
|
||||||
|
ERROR_LOG("Unexpected non-float value in {}", key);
|
||||||
|
else if constexpr (std::is_integral_v<T>)
|
||||||
|
ERROR_LOG("Unexpected non-int value in {}", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR_LOG("Unexpected empty value in {}", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[maybe_unused]] static std::optional<T>
|
||||||
|
ParseOptionalTFromObject(const ryml::ConstNodeRef& object, std::string_view key,
|
||||||
|
std::optional<T> (*from_string_function)(const char* str))
|
||||||
|
{
|
||||||
|
std::optional<T> ret;
|
||||||
|
|
||||||
|
const ryml::ConstNodeRef member = object.find_child(to_csubstr(key));
|
||||||
|
if (member.valid())
|
||||||
|
{
|
||||||
|
const c4::csubstr val = member.val();
|
||||||
|
if (!val.empty())
|
||||||
|
{
|
||||||
|
ret = from_string_function(TinyString(to_stringview(val)));
|
||||||
|
if (!ret.has_value())
|
||||||
|
ERROR_LOG("Unknown value for {}: {}", key, to_stringview(val));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR_LOG("Unexpected empty value in {}", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -33,6 +33,8 @@
|
||||||
|
|
||||||
Log_SetChannel(GameDatabase);
|
Log_SetChannel(GameDatabase);
|
||||||
|
|
||||||
|
#include "common/ryml_helpers.h"
|
||||||
|
|
||||||
namespace GameDatabase {
|
namespace GameDatabase {
|
||||||
|
|
||||||
enum : u32
|
enum : u32
|
||||||
|
@ -143,119 +145,6 @@ static PreferUnorderedStringMap<u32> s_code_lookup;
|
||||||
static TrackHashesMap s_track_hashes_map;
|
static TrackHashesMap s_track_hashes_map;
|
||||||
} // namespace GameDatabase
|
} // namespace GameDatabase
|
||||||
|
|
||||||
// RapidYAML utility routines.
|
|
||||||
|
|
||||||
ALWAYS_INLINE std::string_view to_stringview(const c4::csubstr& s)
|
|
||||||
{
|
|
||||||
return std::string_view(s.data(), s.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE std::string_view to_stringview(const c4::substr& s)
|
|
||||||
{
|
|
||||||
return std::string_view(s.data(), s.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE c4::csubstr to_csubstr(std::string_view sv)
|
|
||||||
{
|
|
||||||
return c4::csubstr(sv.data(), sv.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetStringFromObject(const ryml::ConstNodeRef& object, std::string_view key, std::string* dest)
|
|
||||||
{
|
|
||||||
dest->clear();
|
|
||||||
|
|
||||||
const ryml::ConstNodeRef member = object.find_child(to_csubstr(key));
|
|
||||||
if (!member.valid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const c4::csubstr val = member.val();
|
|
||||||
if (!val.empty())
|
|
||||||
dest->assign(val.data(), val.size());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static bool GetUIntFromObject(const ryml::ConstNodeRef& object, std::string_view key, T* dest)
|
|
||||||
{
|
|
||||||
*dest = 0;
|
|
||||||
|
|
||||||
const ryml::ConstNodeRef member = object.find_child(to_csubstr(key));
|
|
||||||
if (!member.valid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const c4::csubstr val = member.val();
|
|
||||||
if (val.empty())
|
|
||||||
{
|
|
||||||
ERROR_LOG("Unexpected empty value in {}", key);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::optional<T> opt_value = StringUtil::FromChars<T>(to_stringview(val));
|
|
||||||
if (!opt_value.has_value())
|
|
||||||
{
|
|
||||||
ERROR_LOG("Unexpected non-uint value in {}", key);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dest = opt_value.value();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static std::optional<T> GetOptionalTFromObject(const ryml::ConstNodeRef& object, std::string_view key)
|
|
||||||
{
|
|
||||||
std::optional<T> ret;
|
|
||||||
|
|
||||||
const ryml::ConstNodeRef member = object.find_child(to_csubstr(key));
|
|
||||||
if (member.valid())
|
|
||||||
{
|
|
||||||
const c4::csubstr val = member.val();
|
|
||||||
if (!val.empty())
|
|
||||||
{
|
|
||||||
ret = StringUtil::FromChars<T>(to_stringview(val));
|
|
||||||
if (!ret.has_value())
|
|
||||||
{
|
|
||||||
if constexpr (std::is_floating_point_v<T>)
|
|
||||||
ERROR_LOG("Unexpected non-float value in {}", key);
|
|
||||||
else if constexpr (std::is_integral_v<T>)
|
|
||||||
ERROR_LOG("Unexpected non-int value in {}", key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERROR_LOG("Unexpected empty value in {}", key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static std::optional<T> ParseOptionalTFromObject(const ryml::ConstNodeRef& object, std::string_view key,
|
|
||||||
std::optional<T> (*from_string_function)(const char* str))
|
|
||||||
{
|
|
||||||
std::optional<T> ret;
|
|
||||||
|
|
||||||
const ryml::ConstNodeRef member = object.find_child(to_csubstr(key));
|
|
||||||
if (member.valid())
|
|
||||||
{
|
|
||||||
const c4::csubstr val = member.val();
|
|
||||||
if (!val.empty())
|
|
||||||
{
|
|
||||||
ret = from_string_function(TinyString(to_stringview(val)));
|
|
||||||
if (!ret.has_value())
|
|
||||||
ERROR_LOG("Unknown value for {}: {}", key, to_stringview(val));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERROR_LOG("Unexpected empty value in {}", key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameDatabase::EnsureLoaded()
|
void GameDatabase::EnsureLoaded()
|
||||||
{
|
{
|
||||||
if (s_loaded)
|
if (s_loaded)
|
||||||
|
@ -1110,7 +999,7 @@ bool GameDatabase::LoadGameDBYaml()
|
||||||
const ryml::ConstNodeRef root = tree.rootref();
|
const ryml::ConstNodeRef root = tree.rootref();
|
||||||
s_entries.reserve(root.num_children());
|
s_entries.reserve(root.num_children());
|
||||||
|
|
||||||
for (const ryml::ConstNodeRef& current : root.children())
|
for (const ryml::ConstNodeRef& current : root.cchildren())
|
||||||
{
|
{
|
||||||
// TODO: binary sort
|
// TODO: binary sort
|
||||||
const u32 index = static_cast<u32>(s_entries.size());
|
const u32 index = static_cast<u32>(s_entries.size());
|
||||||
|
@ -1177,7 +1066,7 @@ bool GameDatabase::ParseYamlEntry(Entry* entry, const ryml::ConstNodeRef& value)
|
||||||
controllers.valid() && controllers.has_children())
|
controllers.valid() && controllers.has_children())
|
||||||
{
|
{
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (const ryml::ConstNodeRef& controller : controllers.children())
|
for (const ryml::ConstNodeRef& controller : controllers.cchildren())
|
||||||
{
|
{
|
||||||
const std::string_view controller_str = to_stringview(controller.val());
|
const std::string_view controller_str = to_stringview(controller.val());
|
||||||
if (controller_str.empty())
|
if (controller_str.empty())
|
||||||
|
@ -1230,7 +1119,7 @@ bool GameDatabase::ParseYamlEntry(Entry* entry, const ryml::ConstNodeRef& value)
|
||||||
|
|
||||||
if (const ryml::ConstNodeRef traits = value.find_child(to_csubstr("traits")); traits.valid() && traits.has_children())
|
if (const ryml::ConstNodeRef traits = value.find_child(to_csubstr("traits")); traits.valid() && traits.has_children())
|
||||||
{
|
{
|
||||||
for (const ryml::ConstNodeRef& trait : traits.children())
|
for (const ryml::ConstNodeRef& trait : traits.cchildren())
|
||||||
{
|
{
|
||||||
const std::string_view trait_str = to_stringview(trait.val());
|
const std::string_view trait_str = to_stringview(trait.val());
|
||||||
if (trait_str.empty())
|
if (trait_str.empty())
|
||||||
|
@ -1388,7 +1277,7 @@ bool GameDatabase::LoadTrackHashes()
|
||||||
s_track_hashes_map = {};
|
s_track_hashes_map = {};
|
||||||
|
|
||||||
size_t serials = 0;
|
size_t serials = 0;
|
||||||
for (const ryml::ConstNodeRef& current : root.children())
|
for (const ryml::ConstNodeRef& current : root.cchildren())
|
||||||
{
|
{
|
||||||
const std::string_view serial = to_stringview(current.key());
|
const std::string_view serial = to_stringview(current.key());
|
||||||
if (serial.empty() || !current.has_children())
|
if (serial.empty() || !current.has_children())
|
||||||
|
@ -1405,7 +1294,7 @@ bool GameDatabase::LoadTrackHashes()
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 revision = 0;
|
u32 revision = 0;
|
||||||
for (const ryml::ConstNodeRef& track_revisions : track_data.children())
|
for (const ryml::ConstNodeRef& track_revisions : track_data.cchildren())
|
||||||
{
|
{
|
||||||
const ryml::ConstNodeRef tracks = track_revisions.find_child(to_csubstr("tracks"));
|
const ryml::ConstNodeRef tracks = track_revisions.find_child(to_csubstr("tracks"));
|
||||||
if (!tracks.valid() || !tracks.has_children())
|
if (!tracks.valid() || !tracks.has_children())
|
||||||
|
|
Loading…
Reference in a new issue