LibUnicode: Generalize the generators' unique string storage

UniqueStringStorage is used to ensure only one copy of a string will be
generated, and interested parties store just an index into the generated
storage. Generalize this class to allow any* type to be stored uniquely.

* To actually be storable, the type must have both an AK::Format and an
AK::Traits overload available.
This commit is contained in:
Timothy Flynn 2021-12-02 19:45:53 -05:00 committed by Andreas Kling
parent 152d455143
commit d8e6beb14f
Notes: sideshowbarker 2024-07-17 23:07:28 +09:00

View file

@ -19,60 +19,67 @@
#include <LibCore/File.h> #include <LibCore/File.h>
#include <LibUnicode/Locale.h> #include <LibUnicode/Locale.h>
template<typename StringIndexType> template<typename StorageType, typename IndexType>
class UniqueStringStorage { class UniqueStorage {
public: public:
StringIndexType ensure(String string) IndexType ensure(StorageType value)
{ {
// We maintain a set of unique strings in two structures: a vector which owns the unique string, // We maintain a set of unique values in two structures: a vector which stores the values in
// and a hash map which maps that string to its index in the vector. The vector is to ensure the // the order they are added, and a hash map which maps that value to its index in the vetor.
// strings are generated in an easily known order, and the map is to allow quickly deciding if a // The vector is to ensure the values are generated in an easily known order, and the map is
// string is actually unique (otherwise, we'd have to linear-search the vector for each string). // to allow quickly deciding if a value is actually unique (otherwise, we'd have to linearly
// search the vector for each value).
// //
// Also note that index 0 will be reserved for the empty string, so the index returned from this // Also note that index 0 will be reserved for the default-initialized value, so the index
// method is actually the real index in the vector + 1. // returned from this method is actually the real index in the vector + 1.
if (auto index = m_unique_string_indices.get(string); index.has_value()) if (auto index = m_storage_indices.get(value); index.has_value())
return *index; return *index;
m_unique_strings.append(move(string)); m_storage.append(move(value));
size_t index = m_unique_strings.size(); size_t index = m_storage.size();
VERIFY(index < NumericLimits<StringIndexType>::max()); VERIFY(index < NumericLimits<IndexType>::max());
auto string_index = static_cast<StringIndexType>(index); auto storage_index = static_cast<IndexType>(index);
m_unique_string_indices.set(m_unique_strings.last(), string_index); m_storage_indices.set(m_storage.last(), storage_index);
return string_index; return storage_index;
} }
StringView get(StringIndexType index) const StorageType const& get(IndexType index) const
{ {
if (index == 0) if (index == 0) {
return {}; static StorageType empty {};
return empty;
VERIFY(index <= m_unique_strings.size());
return m_unique_strings.at(index - 1);
} }
void generate(SourceGenerator& generator) VERIFY(index <= m_storage.size());
return m_storage.at(index - 1);
}
void generate(SourceGenerator& generator, StringView type, StringView name, size_t max_values_per_row)
{ {
generator.set("size"sv, String::number(m_unique_strings.size())); generator.set("type"sv, type);
generator.set("name"sv, name);
generator.set("size"sv, String::number(m_storage.size()));
generator.append(R"~~~( generator.append(R"~~~(
static constexpr Array<StringView, @size@ + 1> s_string_list { { static constexpr Array<@type@, @size@ + 1> @name@ { {
{})~~~"); {})~~~");
constexpr size_t max_strings_per_row = 40; size_t values_in_current_row = 1;
size_t strings_in_current_row = 1;
for (auto const& string : m_unique_strings) { for (auto const& value : m_storage) {
if (strings_in_current_row++ > 0) if (values_in_current_row++ > 0)
generator.append(", "); generator.append(", ");
generator.append(String::formatted("\"{}\"sv", string)); if constexpr (IsSame<StorageType, String>)
generator.append(String::formatted("\"{}\"sv", value));
else
generator.append(String::formatted("{}", value));
if (strings_in_current_row == max_strings_per_row) { if (values_in_current_row == max_values_per_row) {
strings_in_current_row = 0; values_in_current_row = 0;
generator.append(",\n "); generator.append(",\n ");
} }
} }
@ -83,8 +90,19 @@ static constexpr Array<StringView, @size@ + 1> s_string_list { {
} }
private: private:
Vector<String> m_unique_strings; Vector<StorageType> m_storage;
HashMap<StringView, StringIndexType> m_unique_string_indices; HashMap<StorageType, IndexType> m_storage_indices;
};
template<typename StringIndexType>
class UniqueStringStorage : public UniqueStorage<String, StringIndexType> {
using Base = UniqueStorage<String, StringIndexType>;
public:
void generate(SourceGenerator& generator)
{
Base::generate(generator, "StringView"sv, "s_string_list"sv, 40);
}
}; };
struct Alias { struct Alias {