11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
21PROMEKI_NAMESPACE_BEGIN
34 [[noreturn]]
void stringRegistryCollisionAbort(
const char *registryName,
const String &existing,
35 const String &incoming, uint64_t hash);
94template <CompiledString Name>
class StringRegistry;
111template <CompiledString Name>
class StringRegistryItem {
114 static constexpr uint64_t InvalidID = UINT64_MAX;
117 constexpr StringRegistryItem() =
default;
129 StringRegistryItem(
const String &name)
130 : _id(StringRegistry<Name>::instance().findOrCreateProbe(name)) {}
136 StringRegistryItem(
const char *name)
137 : _id(StringRegistry<Name>::instance().findOrCreateProbe(String(name))) {}
155 static constexpr StringRegistryItem literal(
const char *name) {
156 StringRegistryItem item;
157 item._id = fnv1a(name);
166 static StringRegistryItem find(
const String &name) {
167 StringRegistryItem item;
168 item._id = StringRegistry<Name>::instance().findId(name);
177 static constexpr StringRegistryItem fromId(uint64_t
id) {
178 StringRegistryItem item;
187 constexpr uint64_t id()
const {
return _id; }
193 String name()
const {
return StringRegistry<Name>::instance().name(_id); }
199 constexpr bool isValid()
const {
return _id != InvalidID; }
202 constexpr bool operator==(
const StringRegistryItem &other)
const {
return _id == other._id; }
205 constexpr bool operator!=(
const StringRegistryItem &other)
const {
return _id != other._id; }
208 constexpr bool operator<(
const StringRegistryItem &other)
const {
return _id < other._id; }
211 uint64_t _id = InvalidID;
214template <CompiledString Name>
class StringRegistry {
217 using Item = StringRegistryItem<Name>;
220 static constexpr uint64_t InvalidID = StringRegistryItem<Name>::InvalidID;
223 static StringRegistry &instance() {
224 static StringRegistry reg;
238 uint64_t findId(
const String &str)
const {
239 ReadWriteLock::ReadLocker lock(_lock);
240 uint64_t slot = fnv1a(str.cstr());
242 auto it = _names.find(slot);
243 if (it == _names.end())
return InvalidID;
244 if (it->second == str)
return slot;
266 uint64_t findOrCreateStrict(
const String &str) {
267 uint64_t h = fnv1a(str.cstr());
270 ReadWriteLock::ReadLocker lock(_lock);
271 auto it = _names.find(h);
272 if (it != _names.end()) {
273 if (it->second == str)
return h;
274 detail::stringRegistryCollisionAbort(Name.bytes(), it->second, str, h);
277 ReadWriteLock::WriteLocker lock(_lock);
278 auto it = _names.find(h);
279 if (it != _names.end()) {
280 if (it->second == str)
return h;
281 detail::stringRegistryCollisionAbort(Name.bytes(), it->second, str, h);
283 _names.insert(h, str);
299 uint64_t findOrCreateProbe(
const String &str) {
300 uint64_t start = fnv1a(str.cstr());
303 ReadWriteLock::ReadLocker lock(_lock);
304 uint64_t slot = start;
306 auto it = _names.find(slot);
307 if (it == _names.end())
break;
308 if (it->second == str)
return slot;
314 ReadWriteLock::WriteLocker lock(_lock);
315 uint64_t slot = start;
317 auto it = _names.find(slot);
318 if (it == _names.end()) {
319 _names.insert(slot, str);
322 if (it->second == str)
return slot;
332 String name(uint64_t
id)
const {
333 ReadWriteLock::ReadLocker lock(_lock);
334 auto it = _names.find(
id);
335 if (it == _names.end())
return String();
343 size_t count()
const {
344 ReadWriteLock::ReadLocker lock(_lock);
345 return _names.size();
353 bool contains(
const String &str)
const {
return findId(str) != InvalidID; }
356 StringRegistry() =
default;
358 mutable ReadWriteLock _lock;
359 Map<uint64_t, String> _names;
374template <promeki::CompiledString Name>
struct std::hash<promeki::StringRegistryItem<Name>> {
375 std::size_t operator()(
const promeki::StringRegistryItem<Name> &item)
const noexcept {
376 return static_cast<std::size_t
>(item.id());