Es ist oft nützlich für Protokollierungszwecke in Echtzeitanwendungen wie Spielen, um jedem Unternehmen einen Namen zu geben. Dies erleichtert die Aufspürung von Fehlern, da das Finden von Entitäten über eindeutige Namen einfacher ist, als eindeutige Zahlen oder andere Erkennungsformen zu betrachten. Die Saiten sind jedoch riesig und das Kopieren und Vergleich ist langsam, so dass sie oft nicht im leistungskritischen Code verwendet werden können.
Eine Lösung sind Hashed -Saiten, die nur Ganzzahlen sind und damit klein, schnell zu kopieren und zu vergleichen. Aber Hashes erlauben nicht das Abrufen des ursprünglichen String -Wertes, was genau das ist, was für Protokollierung und Debugging -Zwecke benötigt wird! Darüber hinaus besteht die Wahrscheinlichkeit von Kollisionen, so dass der gleiche Hash -Code nicht unbedingt gleiche Zeichenfolgen bedeutet. Diese Chance ist klein, aber eine Quelle für schwer zu findende Fehler.
Eine andere Lösung ist die Schnittstelle zwischen String. String Pomming verwendet eine globale Nachschlagetabelle, in der jede Zeichenfolge nur einmal gespeichert wird und über einen Index oder ähnliches verwiesen wird. Das Kopieren und Vergleich ist auch schnell, aber sie sind immer noch nicht perfekt: Sie können nur zur Laufzeit auf sie zugreifen. Es ist nicht möglich, den Wert bei Kompilierungszeit-EG für einen Schalter zu erhalten.
Einerseits wollen wir schnelle und leichte Kennungen, andererseits auch Methoden, um den Namen zurückzubekommen.
Diese Open -Source -Bibliothek bietet einen Mix zwischen den beiden Lösungen in Form der Klasse String_ID . Jedes Objekt speichert einen Hashed -String -Wert und einen Zeiger auf die Datenbank, in der der ursprüngliche String -Wert gespeichert wird. Dies ermöglicht das Abrufen des Stringwerts bei Bedarf und erhalten gleichzeitig die Leistungsvorteile von Hashed -Saiten. Darüber hinaus kann die Datenbank Kollisionen erkennen, die über einen benutzerdefinierten Kollisionshandler behandelt werden können. Es gibt ein benutzerdefiniertes Literal, um einen Hashed-String-Wert für Kompilierzeit zu erstellen, um ihn als konstanter Ausdruck zu verwenden.
Die Datenbank kann jeder benutzerdefinierte Typ sein, der von einer bestimmten Schnittstellenklasse abgeleitet wird. Es gibt mehrere vordefinierte Datenbanken. Dies beinhaltet eine Dummy -Datenbank, die nichts speichert, ein Adapter für andere Datenbanken, mit denen sie Threadsafe erzeugen, und eine hoch optimierte Datenbank zum effizienten Speichern und Abrufen von Zeichenfolgen. Eine typedef default_database ist eine dieser Datenbanken und kann über die folgenden CMake -Optionen festgelegt werden:
Foonathan_string_id_database - Wenn ausgeschaltet , wird die Datenbank vollständig deaktiviert, z. B. wird die Dummy -Datenbank verwendet. Dies erlaubt nicht das Abrufen von Zeichenfolgen oder Kollisionsprüfung, benötigt jedoch nicht so viel Speicher. Es ist standardmäßig eingeschaltet .
Foonathan_string_id_multitHhreadede - Wenn eingeschaltet , wird der Datenbankzugriff über einen Mutex synchronisiert, z. B. wird der Thread -Safe -Adapter verwendet. Es hat keine Wirkung, wenn die Datenbank deaktiviert ist. Standardwert ist eingeschaltet .
Es gibt spezielle Generatorkurse. Sie haben eine ähnliche Schnittstelle zu den Zufallszahlengeneratoren in den Standardbibliotheken, generieren jedoch String -Identifikatoren. Dies wird verwendet, um eine Reihe von Kennungen automatisiert zu erzeugen. Die Generatoren kümmern sich auch darauf, dass immer neue Kennungen generiert werden. Dies kann auch über einen Handler kontrolliert werden, der auch dem Kollisionshandling ähnelt.
Ein Beispiel finden Sie Beispiel/Main.cpp.
Derzeit verwendet es einen FNV-1A 64-Bit-Hash. Kollisionen sind wirklich selten, ich habe 219.606 englische Wörter (in Kleinbuchstaben) mit einer Reihe von Zahlen getestet und keine einzige Kollision getroffen. Da dies der normale Anwendungsfall für Kennungen ist, ist die Hash -Funktion ziemlich gut. Darüber hinaus gibt es eine gute Verteilung der Hash -Werte und es ist leicht zu berechnen.
Die Datenbank verwendet eine spezielle Hash -Tabelle. Die Kollisionen des Bucket Index werden durch separate Verkettung mit einer einzelnen verknüpften Liste aufgelöst. Jeder Knoten enthält die Zeichenfolge direkt ohne zusätzliche Speicherzuweisung. Die Knoten in der verknüpften Liste werden mit dem Hash -Wert sortiert. Dies ermöglicht ein effizientes Abrufen und Überprüfen, ob bereits eine Zeichenfolge mit demselben Hash -Wert gespeichert ist. Dies macht es sehr effizient und schneller als die zuvor verwendete STD :: Under Ordered_Map (zumindest schneller als libstdc ++ Implementierung, die ich für die Benchmarks verwendet habe).
Diese Bibliothek wurde unter den folgenden Compilern zusammengestellt:
Es gibt die Kompatibilitätsoptionen und Ersatz -Marcos für Costexpr-, NoExcept-, Override- und Literalbetreiber. Atomic -Handler -Funktionen können optional deaktiviert werden und sind standardmäßig für GCC 4.6 ausgeschaltet, da sie sie nicht unterstützt.