File indexing completed on 2024-12-08 07:18:53

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef INDEXEDDATATABLE_H
0008 #define INDEXEDDATATABLE_H
0009 
0010 #include <QIODevice>
0011 
0012 #include <functional>
0013 #include <vector>
0014 
0015 class QByteArray;
0016 class QIODevice;
0017 class QString;
0018 
0019 /** Indexed data table, a generalized form of a string table.
0020  *  Entries are of varying length, so a terminating entry is required to separate them (such as a null byte in strings).
0021  *  Does suffix compression, ie. an entry "B" will be represented by pointing side another element "AB" if present.
0022  *  @tparam Entry must be iterable, element-wise comparable, copyable and have a size() method
0023  */
0024 template <typename Entry>
0025 class IndexedDataTable
0026 {
0027 public:
0028     inline void addEntry(const Entry &entry)
0029     {
0030         for (auto it = m_entries.begin(); it != m_entries.end(); ++it) {
0031             if (entry.size() <= (*it).size()) {
0032                 if (std::equal((*it).begin() + ((*it).size() - entry.size()), (*it).end(), entry.begin())) {
0033                     return; // new entry is a suffix of (or equal to) an existing element
0034                 }
0035             } else {
0036                 if (std::equal(entry.begin() + (entry.size() - (*it).size()), entry.end(), (*it).begin())) {
0037                     (*it) = entry; // an existing element is a suffix of the new element
0038                     return;
0039                 }
0040             }
0041         }
0042         m_entries.push_back(entry);
0043     }
0044 
0045     inline std::size_t entryOffset(const Entry &entry) const
0046     {
0047         std::size_t offset = 0;
0048         for (const auto &it : m_entries) {
0049             if (entry.size() <= it.size()) {
0050                 const auto subOffset = it.size() - entry.size();
0051                 if (std::equal(it.begin() + subOffset, it.end(), entry.begin())) {
0052                     return offset + subOffset;
0053                 }
0054             }
0055             offset += it.size() + 1;
0056         }
0057 
0058         return std::numeric_limits<std::size_t>::max();
0059     }
0060 
0061     /** @param entryWrite must write the terminating element at the end! */
0062     inline void writeCode(const char* type, const char *name, QIODevice *out, std::function<void(const Entry &entry, QIODevice *out)> entryWriter) const
0063     {
0064         out->write("static const ");
0065         out->write(type);
0066         out->write(" ");
0067         out->write(name);
0068         out->write("[] = {\n");
0069         for (const auto &it : m_entries) {
0070             out->write("    ");
0071             entryWriter(it, out);
0072             out->write("\n");
0073         }
0074         out->write("};\n\n");
0075     }
0076 
0077 private:
0078     std::vector<Entry> m_entries;
0079 };
0080 
0081 /** String table specialization. */
0082 class StringTable : IndexedDataTable<QByteArray>
0083 {
0084 public:
0085     void addString(const QString &s);
0086     std::size_t stringOffset(const QString &s) const;
0087     void writeCode(const char *name, QIODevice *out) const;
0088 };
0089 
0090 #endif // INDEXEDDATATABLE_H