File indexing completed on 2024-05-12 04:42:19

0001 /*
0002     SPDX-FileCopyrightText: 2020-2021 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef KOSM_STRINGPOOL_H
0008 #define KOSM_STRINGPOOL_H
0009 
0010 #include <kosm_export.h>
0011 
0012 #include <cstring>
0013 #include <vector>
0014 
0015 namespace OSM {
0016 
0017 enum class StringMemory { Persistent, Transient };
0018 
0019 /** @internal */
0020 class KOSM_EXPORT StringKeyRegistryBase
0021 {
0022 protected:
0023     explicit StringKeyRegistryBase();
0024     StringKeyRegistryBase(StringKeyRegistryBase&&) noexcept;
0025     StringKeyRegistryBase& operator=(StringKeyRegistryBase&&) noexcept;
0026     ~StringKeyRegistryBase();
0027 
0028     [[nodiscard]] const char* makeKeyInternal(const char *name, std::size_t len, StringMemory memOpt);
0029     [[nodiscard]] const char* keyInternal(const char *name) const;
0030 
0031     std::vector<char*> m_pool;
0032     std::vector<const char*> m_registry;
0033 };
0034 
0035 /** Registry of unique string keys.
0036  *  @tparam T Sub-classes of StringKey, to have a compile-time check against comparing keys from different pools.
0037  */
0038 template <typename T>
0039 class StringKeyRegistry : protected StringKeyRegistryBase
0040 {
0041 public:
0042     explicit StringKeyRegistry() = default;
0043     StringKeyRegistry(const StringKeyRegistry&) = delete;
0044     StringKeyRegistry(StringKeyRegistry&&) = default;
0045     ~StringKeyRegistry() = default;
0046     StringKeyRegistry& operator=(const StringKeyRegistry&) = delete;
0047     StringKeyRegistry& operator=(StringKeyRegistry&&) = default;
0048 
0049     /** Add a new string to the registry if needed, or returns an existing one if already present. */
0050     inline T makeKey(const char *name, StringMemory memOpt)
0051     {
0052         return makeKey(name, std::strlen(name), memOpt);
0053     }
0054     inline T makeKey(const char *name, std::size_t len, StringMemory memOpt)
0055     {
0056         T key;
0057         key.key = makeKeyInternal(name, len, memOpt);
0058         return key;
0059     }
0060 
0061     /** Looks up an existing key, if that doesn't exist an null key is returned. */
0062     inline T key(const char *name) const
0063     {
0064         T key;
0065         key.key = keyInternal(name);
0066         return key;
0067     }
0068 };
0069 
0070 /** Base class for unique string keys. */
0071 class StringKey
0072 {
0073 public:
0074     constexpr inline StringKey() = default;
0075     constexpr inline const char* name() const { return key; }
0076     constexpr inline bool isNull() const { return !key; }
0077 
0078     // yes, pointer compare is enough here
0079     inline constexpr bool operator<(StringKey other) const { return key < other.key; }
0080     inline constexpr bool operator==(StringKey other) const { return key == other.key; }
0081     inline constexpr bool operator!=(StringKey other) const { return key != other.key; }
0082 
0083 protected:
0084     explicit constexpr inline StringKey(const char *keyData) : key(keyData) {}
0085 
0086 private:
0087     template <typename T> friend class StringKeyRegistry;
0088     const char* key = nullptr;
0089 };
0090 
0091 }
0092 
0093 #endif // KOSM_STRINGPOOL_H