Trie-Implementierung basierend auf dem „HAT-Trie: Eine Cache-bewusste Trie-basierte Datenstruktur für Strings“. (Askitis Nikolas und Sinha Ranjan, 2007) Artikel. Derzeit ist nur der reine HAT-Trie implementiert, die Hybridversion könnte später eintreffen. Details zur HAT-Trie-Datenstruktur finden Sie hier.
Die Bibliothek bietet eine effiziente und kompakte Möglichkeit, einen Satz oder eine Zuordnung von Zeichenfolgen zu speichern, indem die gemeinsamen Präfixe komprimiert werden. Es ermöglicht auch die Suche nach Schlüsseln, die einem Präfix entsprechen. Beachten Sie jedoch, dass die Standardparameter der Struktur auf die Optimierung exakter Suchvorgänge ausgerichtet sind. Wenn Sie viele Präfixsuchen durchführen, möchten Sie möglicherweise den Burst-Schwellenwert mithilfe der Methode burst_threshold
reduzieren.
Es handelt sich um eine gut angepasste Struktur zum Speichern einer großen Anzahl von Zeichenfolgen.
Für den Array-Hash-Teil wird das Array-Hash-Projekt verwendet und in das Repository aufgenommen.
Die Bibliothek stellt zwei Klassen bereit: tsl::htrie_map
und tsl::htrie_set
.
tsl::hat_trie
aus CMakeLists.txt verwenden.equal_prefix_range
(nützlich zum Beispiel für die automatische Vervollständigung) und Präfixlöschungen über erase_prefix
.longest_prefix
.serialize/deserialize
in der API).max_load_factor
geändert werden. Ein niedrigerer maximaler Lastfaktor erhöht die Geschwindigkeit, ein höherer verringert die Speichernutzung. Der Standardwert ist auf 8,0 eingestellt.burst_threshold
zu erreichen.KeySizeT
erhöht werden.Thread-Sicherheits- und Ausnahmegarantien ähneln den STL-Containern.
Die von der Struktur verwendete Standard-Hash-Funktion hängt vom Vorhandensein von std::string_view
ab. Wenn es verfügbar ist, wird std::hash<std::string_view>
verwendet, andernfalls wird eine einfache FNV-1a-Hash-Funktion verwendet, um jegliche Abhängigkeit zu vermeiden.
Wenn Sie C++17 oder höher nicht verwenden können, empfehlen wir, die Hash-Funktion durch etwas wie CityHash, MurmurHash, FarmHash usw. zu ersetzen, um eine bessere Leistung zu erzielen. Bei den von uns durchgeführten Tests bietet CityHash64 im Vergleich zu FNV-1a eine Verbesserung der Lesevorgänge um ca. 20 %.
# include < city.h >
struct str_hash {
std:: size_t operator ()( const char * key, std:: size_t key_size) const {
return CityHash64 (key, key_size);
}
};
tsl::htrie_map< char , int , str_hash> map;
Der std::hash<std::string>
kann nicht effizient verwendet werden, da die Struktur kein std::string
Objekt speichert. Jedes Mal, wenn ein Hash benötigt würde, müsste ein temporärer std::string
erstellt werden.
Der Benchmark besteht darin, alle Titel aus dem Hauptnamensraum des Wikipedia-Archivs in die Datenstruktur einzufügen, den belegten Speicherplatz nach dem Einfügen zu überprüfen (einschließlich möglicher Speicherfragmentierung) und erneut in der Datenstruktur nach allen Titeln zu suchen. Die maximale Speichernutzung während des Einfügevorgangs wird auch mit time(1) gemessen.
Jedem Titel ist ein int (32 Bit) zugeordnet. Alle Hash-basierten Strukturen verwenden CityHash64 als Hash-Funktion. Bei den mit „reserve“ gekennzeichneten Tests wird die Funktion reserve
vorher aufgerufen, um ein erneutes Aufwärmen zu vermeiden.
Beachten Sie, dass tsl::hopscotch_map
, std::unordered_map
, google::dense_hash_map
und spp::sparse_hash_map
std::string
als Schlüssel verwenden, was eine Mindestgröße von 32 Bytes (auf x64) vorschreibt, selbst wenn der Schlüssel nur ein Zeichen lang ist. Andere Strukturen können möglicherweise einstellige Schlüssel mit 1 Byte + 8 Bytes für einen Zeiger speichern (auf x64).
Der Benchmark wurde mit GCC 6.3 kompiliert und lief auf Debian Stretch x64 mit einem Intel i5-5200u und 8 GB RAM. Es wurden die besten 20 Läufe genommen.
Der Code des Benchmarks ist auf Gist zu finden.
Der Datensatz enwiki-20170320-all-titles-in-ns0.gz ist alphabetisch sortiert. Für diesen Benchmark mischen wir den Datensatz zunächst über shuf(1), um einen voreingenommenen sortierten Datensatz zu vermeiden.
Bibliothek | Datenstruktur | Spitzenspeicher (MiB) | Speicher (MiB) | Einfügen (ns/key) | Lesen (ns/key) |
---|---|---|---|---|---|
tsl::htrie_map | HAT-versuch | 405.22 | 402.25 | 643.10 | 250,87 |
tsl::htrie_map max_load_factor=4 | HAT-versuch | 471,85 | 468,50 | 638,66 | 212,90 |
tsl::htrie_map max_load_factor=2 | HAT-versuch | 569,76 | 566,52 | 630,61 | 201.10 |
tsl::htrie_map max_load_factor=1 | HAT-versuch | 713,44 | 709,81 | 645,76 | 190,87 |
Zeder::da | Double-Array-Versuch | 1269,68 | 1254.41 | 1102.93 | 557,20 |
cedar::da ORDERED=false | Double-Array-Versuch | 1269,80 | 1254.41 | 1089,78 | 570.13 |
Zeder::da | Doppelter Array-reduzierter Versuch | 1183.07 | 1167,79 | 1076,68 | 645,79 |
cedar::da ORDERED=false | Doppelter Array-reduzierter Versuch | 1183.14 | 1167,85 | 1065,43 | 641,98 |
Zeder::da | Double-Array-Präfixversuch | 498,69 | 496,54 | 1096,90 | 628.01 |
cedar::da ORDERED=false | Double-Array-Präfixversuch | 498,65 | 496,60 | 1048,40 | 628,94 |
Hatversuch 1 (C) | HAT-versuch | 504.07 | 501,50 | 917,49 | 261,00 |
qp Versuch (C) | QP-Versuch | 941,23 | 938,17 | 1349,25 | 1281,46 |
kritischer Versuch (C) | Kritischer Versuch | 1074,96 | 1071,98 | 2930.42 | 2869,74 |
JudySL (C) | Judy-Array | 631.09 | 628,37 | 884,29 | 803.58 |
JudyHS (C) | Judy-Array | 723,44 | 719,47 | 476,79 | 417.15 |
tsl::array_map | Array-Hash-Tabelle | 823,54 | 678,73 | 603,94 | 138,24 |
tsl::array_map mit Reserve | Array-Hash-Tabelle | 564,26 | 555,91 | 249,52 | 128,28 |
tsl::hopscotch_map | Hash-Tabelle | 1325,83 | 1077,99 | 368,26 | 119,49 |
tsl::hopscotch_map mit Reserve | Hash-Tabelle | 1080,51 | 1077,98 | 240,58 | 119,91 |
google::dense_hash_map | Hash-Tabelle | 2319,40 | 1677.11 | 466,60 | 138,87 |
google::dense_hash_map mit Reserve | Hash-Tabelle | 1592.51 | 1589,99 | 259,56 | 120,40 |
spp::sparse_hash_map | Sparse-Hash-Tabelle | 918,67 | 917.10 | 769,00 | 175,59 |
spp::sparse_hash_map mit Reserve | Sparse-Hash-Tabelle | 913,35 | 910,65 | 427,22 | 159.08 |
std::unordered_map | Hash-Tabelle | 1249.05 | 1246,60 | 590,88 | 173,58 |
std::unordered_map mit Reserve | Hash-Tabelle | 1212.23 | 1209.71 | 350,33 | 178,70 |
Die Schlüssel werden in alphabetischer Reihenfolge eingefügt und gelesen.
Bibliothek | Datenstruktur | Spitzenspeicher (MiB) | Speicher (MiB) | Einfügen (ns/key) | Lesen (ns/key) |
---|---|---|---|---|---|
tsl::htrie_map | HAT-versuch | 396.10 | 393,22 | 255,76 | 68.08 |
tsl::htrie_map max_load_factor=4 | HAT-versuch | 465.02 | 461,80 | 248,88 | 59.23 |
tsl::htrie_map max_load_factor=2 | HAT-versuch | 543,99 | 541.21 | 230.13 | 53,50 |
tsl::htrie_map max_load_factor=1 | HAT-versuch | 692,29 | 689,70 | 243,84 | 49.22 |
Zeder::da | Double-Array-Versuch | 1269,58 | 1254.41 | 278,51 | 54,72 |
cedar::da ORDERED=false | Double-Array-Versuch | 1269,66 | 1254.41 | 264,43 | 56.02 |
Zeder::da | Doppelter Array-reduzierter Versuch | 1183.01 | 1167,78 | 254,60 | 69,18 |
cedar::da ORDERED=false | Doppelter Array-reduzierter Versuch | 1183.03 | 1167,78 | 241,45 | 69,67 |
Zeder::da | Double-Array-Präfixversuch | 621,59 | 619,38 | 246,88 | 57,83 |
cedar::da ORDERED=false | Double-Array-Präfixversuch | 621,59 | 619,38 | 187,98 | 58,56 |
Hatversuch 2 (C) | HAT-versuch | 521,25 | 518,52 | 503.01 | 86,40 |
qp Versuch (C) | QP-Versuch | 940,65 | 937,66 | 392,86 | 190,19 |
kritischer Versuch (C) | Kritischer Versuch | 1074,87 | 1071,98 | 430.04 | 347,60 |
JudySL (C) | Judy-Array | 616,95 | 614,27 | 279.07 | 114,47 |
JudyHS (C) | Judy-Array | 722,29 | 719,47 | 439,66 | 372,25 |
tsl::array_map | Array-Hash-Tabelle | 826,98 | 682,99 | 612.31 | 139.16 |
tsl::array_map mit Reserve | Array-Hash-Tabelle | 565,37 | 555,35 | 246,55 | 126,32 |
tsl::hopscotch_map | Hash-Tabelle | 1331,87 | 1078.02 | 375,19 | 118.08 |
tsl::hopscotch_map mit Reserve | Hash-Tabelle | 1080,51 | 1077,97 | 238,93 | 117,20 |
google::dense_hash_map | Hash-Tabelle | 2325.27 | 1683.07 | 483,95 | 137.09 |
google::dense_hash_map mit Reserve | Hash-Tabelle | 1592.54 | 1589,99 | 257,22 | 113,71 |
spp::sparse_hash_map | Sparse-Hash-Tabelle | 920,96 | 918,70 | 772.03 | 176,64 |
spp::sparse_hash_map mit Reserve | Sparse-Hash-Tabelle | 914,84 | 912,47 | 422,85 | 158,73 |
std::unordered_map | Hash-Tabelle | 1249.09 | 1246,65 | 594,85 | 173,54 |
std::unordered_map mit Reserve | Hash-Tabelle | 1212.21 | 1209.71 | 347,40 | 176,49 |
Der Benchmark besteht darin, alle Wörter aus dem Datensatz „Distinct Strings“ von Dr. Askitis in die Datenstruktur einzufügen, den belegten Speicherplatz zu überprüfen und nach allen Wörtern aus dem Datensatz „Skew String Set 1“ (wo sich ein String befinden kann) zu suchen mehrfach vorhanden) in der Datenstruktur. Beachten Sie, dass die Zeichenfolgen in diesem Datensatz eine recht kurze durchschnittliche und mittlere Schlüssellänge haben (was im Vergleich zum oben verwendeten Wikipedia-Datensatz möglicherweise kein realistischer Anwendungsfall ist). Es ähnelt dem auf der Cedar-Homepage.
Das Benchmark-Protokoll ist das gleiche wie für den Wikipedia-Datensatz.
Bibliothek | Datenstruktur | Spitzenspeicher (MiB) | Speicher (MiB) | Einfügen (ns/key) | Lesen (ns/key) |
---|---|---|---|---|---|
tsl::htrie_map | HAT-versuch | 604,76 | 601,79 | 485,45 | 77,80 |
tsl::htrie_map max_load_factor=4 | HAT-versuch | 768.10 | 764,98 | 491,78 | 75,48 |
tsl::htrie_map max_load_factor=2 | HAT-versuch | 1002.42 | 999,34 | 496,78 | 72,53 |
tsl::htrie_map max_load_factor=1 | HAT-versuch | 1344,98 | 1341,97 | 520,66 | 72,45 |
Zeder::da | Double-Array-Versuch | 1105,45 | 1100.05 | 682,25 | 71,98 |
cedar::da ORDERED=false | Double-Array-Versuch | 1105.47 | 1100.05 | 668,75 | 71,95 |
Zeder::da | Doppelter Array-reduzierter Versuch | 941.16 | 926.04 | 684,38 | 79.11 |
cedar::da ORDERED=false | Doppelter Array-reduzierter Versuch | 941.16 | 925,98 | 672,14 | 79.02 |
Zeder::da | Double-Array-Präfixversuch | 714,58 | 712,59 | 831,71 | 75,83 |
cedar::da ORDERED=false | Double-Array-Präfixversuch | 714,66 | 712.31 | 786,93 | 75,89 |
Hatversuch 3 (C) | HAT-versuch | 786,93 | 784,32 | 743,34 | 93,58 |
qp Versuch (C) | QP-Versuch | 1800.02 | 1797.21 | 987,95 | 428,51 |
kritischer Versuch (C) | Kritischer Versuch | 2210.52 | 2207.64 | 1986.19 | 1109,88 |
JudySL (C) | Judy-Array | 1025,59 | 1023.11 | 535.02 | 202.36 |
JudyHS (C) | Judy-Array | 1002,50 | 999,97 | 456.09 | 148,36 |
tsl::array_map | Array-Hash-Tabelle | 1308.08 | 1031,67 | 545,82 | 46,41 |
tsl::array_map mit Reserve | Array-Hash-Tabelle | 979,44 | 921.363 | 244.19 | 45,74 |
tsl::hopscotch_map | Hash-Tabelle | 2336,39 | 1611.54 | 288,70 | 47.05 |
tsl::hopscotch_map mit Reserve | Hash-Tabelle | 1614.22 | 1611.64 | 220,67 | 46,39 |
google::dense_hash_map | Hash-Tabelle | 3913,64 | 2636.31 | 317,66 | 43,62 |
google::dense_hash_map mit Reserve | Hash-Tabelle | 2638.19 | 2635,68 | 227,58 | 43.09 |
spp::sparse_hash_map | Sparse-Hash-Tabelle | 1419,69 | 1417,61 | 586,26 | 56,00 |
spp::sparse_hash_map mit Reserve | Sparse-Hash-Tabelle | 1424.21 | 1421,69 | 392,76 | 55,73 |
std::unordered_map | Hash-Tabelle | 2112,66 | 2110.19 | 554.02 | 105.05 |
std::unordered_map mit Reserve | Hash-Tabelle | 2053,95 | 2051,67 | 309.06 | 109,89 |
Um die Bibliothek zu verwenden, fügen Sie einfach das Include-Verzeichnis zu Ihrem Include-Pfad hinzu. Es handelt sich um eine reine Header- Bibliothek.
Wenn Sie CMake verwenden, können Sie auch das tsl::hat_trie
exportierte Ziel aus CMakeLists.txt mit target_link_libraries
verwenden.
# Example where the hat-trie project is stored in a third-party directory
add_subdirectory (third-party/hat-trie)
target_link_libraries (your_target PRIVATE tsl::hat_trie)
Der Code sollte mit jedem C++11-Standard-kompatiblen Compiler funktionieren und wurde mit GCC 4.8.4, Clang 3.5.0 und Visual Studio 2015 getestet.
Zum Ausführen der Tests benötigen Sie die Boost-Testbibliothek und CMake.
git clone https://github.com/Tessil/hat-trie.git
cd hat-trie/tests
mkdir build
cd build
cmake ..
cmake --build .
./tsl_hat_trie_tests
Die API finden Sie hier. Wenn std::string_view
verfügbar ist, ändert sich die API geringfügig und ist hier zu finden.
# include < iostream >
# include < string >
# include < tsl/htrie_map.h >
# include < tsl/htrie_set.h >
int main () {
/*
* Map of strings to int having char as character type.
* There is no support for wchar_t, char16_t or char32_t yet,
* but UTF-8 strings will work fine.
*/
tsl::htrie_map< char , int > map = {{ " one " , 1 }, { " two " , 2 }};
map[ " three " ] = 3 ;
map[ " four " ] = 4 ;
map. insert ( " five " , 5 );
map. insert_ks ( " six_with_extra_chars_we_ignore " , 3 , 6 );
map. erase ( " two " );
/*
* Due to the compression on the common prefixes, the letters of the string
* are not always stored contiguously. When we retrieve the key, we have to
* construct it.
*
* To avoid a heap-allocation at each iteration (when SSO doesn't occur),
* we reuse the key_buffer to construct the key.
*/
std::string key_buffer;
for ( auto it = map. begin (); it != map. end (); ++it) {
it. key (key_buffer);
std::cout << " { " << key_buffer << " , " << it. value () << " } " << std::endl;
}
/*
* If you don't care about the allocation.
*/
for ( auto it = map. begin (); it != map. end (); ++it) {
std::cout << " { " << it. key () << " , " << *it << " } " << std::endl;
}
tsl::htrie_map< char , int > map2 = {{ " apple " , 1 }, { " mango " , 2 }, { " apricot " , 3 },
{ " mandarin " , 4 }, { " melon " , 5 }, { " macadamia " , 6 }};
// Prefix search
auto prefix_range = map2. equal_prefix_range ( " ma " );
// {mandarin, 4} {mango, 2} {macadamia, 6}
for ( auto it = prefix_range. first ; it != prefix_range. second ; ++it) {
std::cout << " { " << it. key () << " , " << *it << " } " << std::endl;
}
// Find longest match prefix.
auto longest_prefix = map2. longest_prefix ( " apple juice " );
if (longest_prefix != map2. end ()) {
// {apple, 1}
std::cout << " { " << longest_prefix. key () << " , "
<< *longest_prefix << " } " << std::endl;
}
// Prefix erase
map2. erase_prefix ( " ma " );
// {apricot, 3} {melon, 5} {apple, 1}
for ( auto it = map2. begin (); it != map2. end (); ++it) {
std::cout << " { " << it. key () << " , " << *it << " } " << std::endl;
}
tsl::htrie_set< char > set = { " one " , " two " , " three " };
set. insert ({ " four " , " five " });
// {one} {two} {five} {four} {three}
for ( auto it = set. begin (); it != set. end (); ++it) {
it. key (key_buffer);
std::cout << " { " << key_buffer << " } " << std::endl;
}
}
Die Bibliothek bietet eine effiziente Möglichkeit, eine Karte oder einen Satz zu serialisieren und zu deserialisieren, sodass er in einer Datei gespeichert oder über das Netzwerk gesendet werden kann. Dazu muss der Benutzer ein Funktionsobjekt sowohl für die Serialisierung als auch für die Deserialisierung bereitstellen.
struct serializer {
// Must support the following types for U: std::uint64_t, float and T if a map is used.
template < typename U>
void operator ()( const U& value);
void operator ()( const CharT* value, std:: size_t value_size);
};
struct deserializer {
// Must support the following types for U: std::uint64_t, float and T if a map is used.
template < typename U>
U operator ()();
void operator ()(CharT* value_out, std:: size_t value_size);
};
Beachten Sie, dass die Implementierung die binäre Kompatibilität (Endianness, Float-Binärdarstellung, Größe von int, ...) der Typen, die sie serialisiert/deserialisiert, den bereitgestellten Funktionsobjekten überlässt, wenn Kompatibilität erforderlich ist.
Weitere Details zu den serialize
und deserialize
finden Sie in der API.
# include < cassert >
# include < cstdint >
# include < fstream >
# include < type_traits >
# include < tsl/htrie_map.h >
class serializer {
public:
serializer ( const char * file_name) {
m_ostream. exceptions (m_ostream. badbit | m_ostream. failbit );
m_ostream. open (file_name);
}
template < class T ,
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr >
void operator ()( const T& value) {
m_ostream. write ( reinterpret_cast < const char *>(&value), sizeof (T));
}
void operator ()( const char * value, std:: size_t value_size) {
m_ostream. write (value, value_size);
}
private:
std::ofstream m_ostream;
};
class deserializer {
public:
deserializer ( const char * file_name) {
m_istream. exceptions (m_istream. badbit | m_istream. failbit | m_istream. eofbit );
m_istream. open (file_name);
}
template < class T ,
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr >
T operator ()() {
T value;
m_istream. read ( reinterpret_cast < char *>(&value), sizeof (T));
return value;
}
void operator ()( char * value_out, std:: size_t value_size) {
m_istream. read (value_out, value_size);
}
private:
std::ifstream m_istream;
};
int main () {
const tsl::htrie_map< char , std:: int64_t > map = {{ " one " , 1 }, { " two " , 2 },
{ " three " , 3 }, { " four " , 4 }};
const char * file_name = " htrie_map.data " ;
{
serializer serial (file_name);
map. serialize (serial);
}
{
deserializer dserial (file_name);
auto map_deserialized = tsl::htrie_map< char , std:: int64_t >:: deserialize (dserial);
assert (map == map_deserialized);
}
{
deserializer dserial (file_name);
/* *
* If the serialized and deserialized map are hash compatibles (see conditions in API),
* setting the argument to true speed-up the deserialization process as we don't have
* to recalculate the hash of each key. We also know how much space each bucket needs.
*/
const bool hash_compatible = true ;
auto map_deserialized =
tsl::htrie_map< char , std:: int64_t >:: deserialize (dserial, hash_compatible);
assert (map == map_deserialized);
}
}
Es ist möglich, eine Serialisierungsbibliothek zu verwenden, um einen Teil des Boilerplates zu vermeiden, wenn die zu serialisierenden Typen komplexer sind.
Im folgenden Beispiel wird die Boost-Serialisierung mit dem Boost-zlib-Komprimierungsstream verwendet, um die Größe der resultierenden serialisierten Datei zu reduzieren.
# include < boost/archive/binary_iarchive.hpp >
# include < boost/archive/binary_oarchive.hpp >
# include < boost/iostreams/filter/zlib.hpp >
# include < boost/iostreams/filtering_stream.hpp >
# include < boost/serialization/split_free.hpp >
# include < boost/serialization/utility.hpp >
# include < cassert >
# include < cstdint >
# include < fstream >
# include < tsl/htrie_map.h >
template < typename Archive>
struct serializer {
Archive& ar;
template < typename T>
void operator ()( const T& val) { ar & val; }
template < typename CharT>
void operator ()( const CharT* val, std:: size_t val_size) {
ar. save_binary ( reinterpret_cast < const void *>(val), val_size* sizeof (CharT));
}
};
template < typename Archive>
struct deserializer {
Archive& ar;
template < typename T>
T operator ()() { T val; ar & val; return val; }
template < typename CharT>
void operator ()(CharT* val_out, std:: size_t val_size) {
ar. load_binary ( reinterpret_cast < void *>(val_out), val_size* sizeof (CharT));
}
};
namespace boost { namespace serialization {
template < class Archive , class CharT , class T >
void serialize (Archive & ar, tsl::htrie_map<CharT, T>& map, const unsigned int version) {
split_free (ar, map, version);
}
template < class Archive , class CharT , class T >
void save (Archive & ar, const tsl::htrie_map<CharT, T>& map, const unsigned int version) {
serializer<Archive> serial{ar};
map. serialize (serial);
}
template < class Archive , class CharT , class T >
void load (Archive & ar, tsl::htrie_map<CharT, T>& map, const unsigned int version) {
deserializer<Archive> deserial{ar};
map = tsl::htrie_map<CharT, T>:: deserialize (deserial);
}
}}
int main () {
const tsl::htrie_map< char , std:: int64_t > map = {{ " one " , 1 }, { " two " , 2 },
{ " three " , 3 }, { " four " , 4 }};
const char * file_name = " htrie_map.data " ;
{
std::ofstream ofs;
ofs. exceptions (ofs. badbit | ofs. failbit );
ofs. open (file_name, std::ios::binary);
boost::iostreams::filtering_ostream fo;
fo. push ( boost::iostreams::zlib_compressor ());
fo. push (ofs);
boost::archive::binary_oarchive oa (fo);
oa << map;
}
{
std::ifstream ifs;
ifs. exceptions (ifs. badbit | ifs. failbit | ifs. eofbit );
ifs. open (file_name, std::ios::binary);
boost::iostreams::filtering_istream fi;
fi. push ( boost::iostreams::zlib_decompressor ());
fi. push (ifs);
boost::archive::binary_iarchive ia (fi);
tsl::htrie_map< char , std:: int64_t > map_deserialized;
ia >> map_deserialized;
assert (map == map_deserialized);
}
}
Der Code ist unter der MIT-Lizenz lizenziert. Weitere Informationen finden Sie in der LICENSE-Datei.