forked from MassiveAtoms/hashmap-bench
		
	we can test 19 libs now!!!
This commit is contained in:
		
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							@@ -58,6 +58,7 @@
 | 
			
		||||
        "thread": "cpp",
 | 
			
		||||
        "cinttypes": "cpp",
 | 
			
		||||
        "typeinfo": "cpp",
 | 
			
		||||
        "variant": "cpp"
 | 
			
		||||
        "variant": "cpp",
 | 
			
		||||
        "sparse_hash_map": "cpp"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,12 +3,29 @@ project(another_studproject)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_CXX_STANDARD 17)
 | 
			
		||||
set(CMAKE_CXX_FLAGS "-O3 -flto=thin -march=native")
 | 
			
		||||
add_executable(another_studproject 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Process Abseil's CMake build system
 | 
			
		||||
add_subdirectory(./src/includes/3thparty/abseil-cpp
 | 
			
		||||
                ./src/includes/3thparty/tsl
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
add_executable(studproject 
 | 
			
		||||
                ./src/includes/generator.h
 | 
			
		||||
                ./src/generator.cpp
 | 
			
		||||
                ./src/includes/tests.h
 | 
			
		||||
                ./src/includes/aggregate_tests.h
 | 
			
		||||
                ./src/includes/3thparty/emilib/loguru.cpp
 | 
			
		||||
                main.cpp
 | 
			
		||||
                
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(studproject 
 | 
			
		||||
                        absl::hash 
 | 
			
		||||
                        absl::node_hash_map 
 | 
			
		||||
                        absl::flat_hash_map 
 | 
			
		||||
                        pthread 
 | 
			
		||||
                        dl
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										131
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								main.cpp
									
									
									
									
									
								
							@@ -1,53 +1,116 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
// #include <sparsehash/sparse_hash_map>
 | 
			
		||||
 | 
			
		||||
#include "./src/includes/aggregate_tests.h"
 | 
			
		||||
 | 
			
		||||
// // we can use to switch the map implementations to that
 | 
			
		||||
// // we can add some cli handling so we can specify which maps to tests (or all)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// typedef std::unordered_map<int, int> intmap;
 | 
			
		||||
// typedef std::unordered_map<string, string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // google  sparse
 | 
			
		||||
// typedef google::sparse_hash_map<int, int> intmap;
 | 
			
		||||
// typedef google::sparse_hash_map<std::string,std::string> stringmap
 | 
			
		||||
typedef std::unordered_map<int, int> intmap;
 | 
			
		||||
typedef std::unordered_map<string, string> stringmap;
 | 
			
		||||
// we can use ^ to switch the map implementations to that
 | 
			
		||||
// we can add some cli handling so we can specify which maps to tests (or all)
 | 
			
		||||
// typedef google::sparse_hash_map<string,string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // google dense
 | 
			
		||||
// typedef google::dense_hash_map<int, int> intmap;
 | 
			
		||||
// typedef google::dense_hash_map<string,string> stringmap;
 | 
			
		||||
// 
 | 
			
		||||
// // abseil nodehashmap
 | 
			
		||||
typedef absl::node_hash_map<int, int> intmap;
 | 
			
		||||
typedef absl::node_hash_map<string,string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // flat hashmap
 | 
			
		||||
// typedef absl::flat_hash_map<int, int> intmap;
 | 
			
		||||
// typedef absl::flat_hash_map<string,string> stringmap;
 | 
			
		||||
// 
 | 
			
		||||
// // tessil flat hashmap
 | 
			
		||||
// typedef tsl::sparse_map<int, int> intmap;
 | 
			
		||||
// typedef tsl::sparse_map<string,string> stringmap;
 | 
			
		||||
// 
 | 
			
		||||
// // Tessil tsl::array_map
 | 
			
		||||
// typedef tsl::array_map<int, int> intmap;
 | 
			
		||||
// typedef tsl::array_map<string,string> stringmap;
 | 
			
		||||
// 
 | 
			
		||||
// // Tessil tsl::ordered_map
 | 
			
		||||
// typedef tsl::ordered_map<int, int> intmap;
 | 
			
		||||
// typedef tsl::ordered_map<string,string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // Tessil tsl::robin_map
 | 
			
		||||
// typedef tsl::robin_map<int, int> intmap;
 | 
			
		||||
// typedef tsl::robin_map<string,string> stringmap;
 | 
			
		||||
// 
 | 
			
		||||
// // Tessil hopscotch_map
 | 
			
		||||
// typedef tsl::hopscotch_map<int, int> intmap;
 | 
			
		||||
// typedef tsl::hopscotch_map<string,string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // Boost::unordered_map
 | 
			
		||||
// typedef boost::unordered_map<int, int> intmap;
 | 
			
		||||
// typedef boost::unordered_map<string,string> stringmap;
 | 
			
		||||
// 
 | 
			
		||||
// // skarupke's unordered map
 | 
			
		||||
// typedef ska::unordered_map<int, int> intmap;
 | 
			
		||||
// typedef ska::unordered_map<string,string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // skarupke's bytell hash map
 | 
			
		||||
// typedef ska::bytell_hash_map<int, int> intmap;
 | 
			
		||||
// typedef ska::bytell_hash_map<string,string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // skarupke's flat hash map
 | 
			
		||||
// typedef ska::flat_hash_map<int, int> intmap;
 | 
			
		||||
// typedef ska::flat_hash_map<string,string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // greg7mdp's flat hash map
 | 
			
		||||
// typedef phmap::parallel_flat_hash_map<int, int> intmap;
 | 
			
		||||
// typedef phmap::parallel_flat_hash_map<string,string> stringmap;
 | 
			
		||||
//
 | 
			
		||||
// // greg7mdp's  hash map
 | 
			
		||||
// typedef phmap::parallel_node_hash_map<int, int> intmap;
 | 
			
		||||
// typedef phmap::parallel_node_hash_map<string,string> stringmap;
 | 
			
		||||
// // emilib's  hash map
 | 
			
		||||
// typedef emilib::HashMap<int, int> intmap;
 | 
			
		||||
// typedef emilib::HashMap<string,string> stringmap;
 | 
			
		||||
// // martin flat map
 | 
			
		||||
// typedef robin_hood::unordered_flat_map<int, int> intmap;
 | 
			
		||||
// typedef robin_hood::unordered_flat_map<string,string> stringmap;
 | 
			
		||||
// // martin flat map
 | 
			
		||||
// typedef robin_hood::unordered_node_map<int, int> intmap;
 | 
			
		||||
// typedef robin_hood::unordered_node_map<string,string> stringmap;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
    time_point<steady_clock> start_test = steady_clock::now();
 | 
			
		||||
    // string_test(stringmap{}, 1); // process gets killed for sizes >35000
 | 
			
		||||
    int_test_aggregate(intmap{}, 30);
 | 
			
		||||
    string_test_aggregate(stringmap{}, 30);
 | 
			
		||||
    int_test_aggregate(intmap{}, 2);
 | 
			
		||||
    string_test_aggregate(stringmap{}, 2);
 | 
			
		||||
    time_point<steady_clock> end_test = steady_clock::now();
 | 
			
		||||
    std::cout << "\n\n 30 runs for all tests for 1 map: " << duration_cast<seconds>(end_test-start_test).count() << " seconds\n\n";
 | 
			
		||||
    
 | 
			
		||||
    // test takes 52 mins for 10 runs for one hashmap
 | 
			
		||||
    // so it'll take ~3 hours per map if we want 30 runs per test
 | 
			
		||||
    // test takes 2hrs  for 30 runs for one hashmap
 | 
			
		||||
    /* if the other maps have about the same operation times ************
 | 
			
		||||
 | 
			
		||||
    // maps to benchmark:
 | 
			
		||||
    1. Google dense_hash_map
 | 
			
		||||
    2. Google sparse_hash_map
 | 
			
		||||
    // possible maps to bench. priorities are that the interface must be the same/similar to unordered_map
 | 
			
		||||
    // and that we don't have to jump through hoops to get it to work
 | 
			
		||||
    1. Google dense_hash_map [y] https://github.com/sparsehash/sparsehash
 | 
			
		||||
    2. Google sparse_hash_map [y]
 | 
			
		||||
    3. abseil node_hash_map [y]  https://abseil.io/docs/cpp/tools/cmake-installs
 | 
			
		||||
    4. abseil flat_hash_map [y]
 | 
			
		||||
    5. Tessil/sparse-map/ [y]  header only implementation for all tessil
 | 
			
		||||
    6. Tessil/hopscotch-map[y]
 | 
			
		||||
    7. tessil/robin-map[y] [y]
 | 
			
		||||
    8. Boost unordered_map [y] just install boost with your package manager
 | 
			
		||||
    9. skarupke/flat_hash_map [y] header only implementation
 | 
			
		||||
    10. skarupke /bytell_hash_map [y]
 | 
			
		||||
    11. skarupke/unordered_map [y]
 | 
			
		||||
    12. greg7mdp/parallel-hashmap/paralel_flat [y] header only
 | 
			
		||||
    13. greg7mdp/parallel-hashmap/paralel_node [y] 
 | 
			
		||||
    17. emilk/emilib emilib::hashmap [y] header only
 | 
			
		||||
    18. martinus robin_hood::unordered_node_map [y]
 | 
			
		||||
    19. martinus/robin_hood/ flatmap [y]
 | 
			
		||||
    3. folly F14ValueMap
 | 
			
		||||
    4. folly F14NodeMap
 | 
			
		||||
    5. Tessil/ordered-map
 | 
			
		||||
    6. Tessil/array-hash
 | 
			
		||||
    7. Tessil/hopscotch-map
 | 
			
		||||
    8. Tessil/sparse-map/
 | 
			
		||||
    9. abseil node_hash_map
 | 
			
		||||
    10. abseil flat_hash_map
 | 
			
		||||
    11. Glib GHashTable
 | 
			
		||||
    12. Boost unordered_map
 | 
			
		||||
    13. Qt QHash
 | 
			
		||||
    14. skarupke/flat_hash_map
 | 
			
		||||
    15. greg7mdp/sparsepp
 | 
			
		||||
    16. greg7mdp /parallel-hashmap  (phmap::flat_hash_map and phmap::node_hash_map)
 | 
			
		||||
    17. emilk/emilib emilib::hashmap
 | 
			
		||||
    18. martinus robin_hood::unordered_node_map
 | 
			
		||||
    19. martinus/robin-hood-hashing/
 | 
			
		||||
    20. skarupke /flat_hash_map 
 | 
			
		||||
    5. Tessil/ordered-map [n] something is wrong with this one, verrrrry slow
 | 
			
		||||
    6. Tessil/array-hash[n] (not with a small modification of the insert function)
 | 
			
		||||
    */
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										305
									
								
								results.csv
									
									
									
									
									
								
							
							
						
						
									
										305
									
								
								results.csv
									
									
									
									
									
								
							@@ -0,0 +1,305 @@
 | 
			
		||||
 | 
			
		||||
int_insert, 'google::dense_hash_map<int, int>', 26, 34, 64, 40, 40, 50, 40, 44, 51, 45, 77, 47, 51, 57
 | 
			
		||||
int_succ_lookup, 'google::dense_hash_map<int, int>', 10, 18, 30, 20, 18, 22, 21, 23, 24, 23, 27, 24, 25, 26
 | 
			
		||||
int_nosucc_lookup, 'google::dense_hash_map<int, int>', 31, 33, 62, 54, 43, 40, 43, 49, 56, 42, 53, 52, 55, 59
 | 
			
		||||
int_delete, 'google::dense_hash_map<int, int>', 13, 11, 26, 38, 16, 13, 15, 17, 22, 15, 32, 19, 23, 24
 | 
			
		||||
int_insert, 'google::dense_hash_map<int, int>', 19, 53, 38, 36, 40, 36, 40, 43, 51, 41, 44, 48, 52, 59
 | 
			
		||||
int_succ_lookup, 'google::dense_hash_map<int, int>', 7, 19, 20, 17, 18, 20, 21, 22, 24, 23, 24, 24, 27, 26
 | 
			
		||||
int_nosucc_lookup, 'google::dense_hash_map<int, int>', 23, 72, 39, 36, 43, 40, 43, 50, 56, 42, 50, 49, 57, 59
 | 
			
		||||
int_delete, 'google::dense_hash_map<int, int>', 9, 35, 17, 13, 17, 16, 15, 21, 22, 17, 22, 18, 24, 24
 | 
			
		||||
int_insert, 'google::dense_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 146, 155, 159, 175, 178, 161, 167, 179, 195, 185, 191, 202, 205, 231
 | 
			
		||||
int_succ_lookup, 'google::dense_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 87, 98, 110, 106, 110, 117, 113, 112, 121, 117, 119, 119, 129, 128
 | 
			
		||||
int_nosucc_lookup, 'google::dense_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 189, 160, 184, 170, 182, 200, 189, 184, 192, 170, 188, 185, 199, 193
 | 
			
		||||
int_delete, 'google::dense_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 91, 91, 113, 119, 108, 134, 103, 104, 110, 105, 108, 109, 118, 131
 | 
			
		||||
int_insert, 'google::dense_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 213, 154, 148, 169, 185, 162, 170, 175, 192, 180, 186, 197, 206, 214
 | 
			
		||||
int_succ_lookup, 'google::dense_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 122, 91, 98, 103, 109, 101, 107, 107, 114, 114, 120, 123, 127, 141
 | 
			
		||||
int_nosucc_lookup, 'google::dense_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 234, 166, 159, 174, 183, 160, 173, 181, 184, 169, 183, 194, 200, 194
 | 
			
		||||
int_delete, 'google::dense_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 126, 90, 89, 111, 105, 94, 96, 102, 112, 111, 110, 111, 123, 124
 | 
			
		||||
int_insert, 'absl::node_hash_map<int, int>', 101, 116, 91, 90, 101, 99, 107, 106, 114, 114, 123, 161, 138, 130
 | 
			
		||||
int_succ_lookup, 'absl::node_hash_map<int, int>', 24, 87, 40, 40, 52, 48, 49, 49, 58, 59, 61, 68, 61, 73
 | 
			
		||||
int_nosucc_lookup, 'absl::node_hash_map<int, int>', 464, 141, 90, 95, 99, 98, 100, 105, 112, 114, 118, 134, 144, 132
 | 
			
		||||
int_delete, 'absl::node_hash_map<int, int>', 140, 257, 139, 126, 138, 145, 146, 145, 189, 182, 179, 222, 201, 270
 | 
			
		||||
int_insert, 'absl::node_hash_map<int, int>', 73, 110, 83, 90, 103, 99, 101, 105, 116, 118, 120, 130, 142, 134
 | 
			
		||||
int_succ_lookup, 'absl::node_hash_map<int, int>', 19, 64, 38, 40, 52, 47, 50, 51, 62, 61, 61, 61, 61, 70
 | 
			
		||||
int_nosucc_lookup, 'absl::node_hash_map<int, int>', 502, 192, 90, 90, 101, 99, 111, 105, 125, 117, 122, 127, 141, 126
 | 
			
		||||
int_delete, 'absl::node_hash_map<int, int>', 95, 269, 110, 121, 144, 139, 175, 146, 190, 187, 187, 187, 194, 222
 | 
			
		||||
int_insert, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 127, 163, 171, 180, 190, 187, 193, 226, 208, 235, 243, 286, 287, 228
 | 
			
		||||
int_succ_lookup, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 185, 164, 173, 178, 204, 197, 219, 206, 231, 236, 240, 290, 240, 278
 | 
			
		||||
int_nosucc_lookup, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 938, 139, 133, 145, 145, 152, 333, 205, 167, 189, 187, 268, 221, 183
 | 
			
		||||
int_delete, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 244, 223, 191, 190, 208, 211, 326, 303, 250, 253, 252, 292, 259, 289
 | 
			
		||||
int_insert, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 130, 148, 169, 174, 187, 197, 191, 203, 220, 211, 218, 237, 259, 232
 | 
			
		||||
int_succ_lookup, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 106, 142, 169, 178, 194, 199, 199, 199, 248, 236, 239, 247, 243, 286
 | 
			
		||||
int_nosucc_lookup, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 844, 133, 129, 140, 144, 146, 147, 158, 164, 164, 168, 178, 200, 188
 | 
			
		||||
int_delete, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 223, 163, 179, 187, 213, 210, 233, 225, 244, 249, 275, 260, 335, 296
 | 
			
		||||
int_insert, 'absl::flat_hash_map<int, int>', 42, 53, 45, 44, 55, 45, 41, 41, 55, 55, 52, 58, 69, 71
 | 
			
		||||
int_succ_lookup, 'absl::flat_hash_map<int, int>', 25, 58, 53, 31, 68, 29, 25, 24, 35, 34, 35, 35, 34, 52
 | 
			
		||||
int_nosucc_lookup, 'absl::flat_hash_map<int, int>', 334, 76, 54, 59, 73, 58, 50, 56, 67, 64, 63, 69, 79, 83
 | 
			
		||||
int_delete, 'absl::flat_hash_map<int, int>', 101, 61, 58, 51, 60, 48, 33, 35, 51, 46, 47, 48, 47, 69
 | 
			
		||||
int_insert, 'absl::flat_hash_map<int, int>', 43, 29, 76, 40, 51, 38, 38, 45, 86, 52, 52, 57, 69, 70
 | 
			
		||||
int_succ_lookup, 'absl::flat_hash_map<int, int>', 16, 10, 52, 26, 40, 25, 24, 26, 56, 33, 38, 34, 35, 44
 | 
			
		||||
int_nosucc_lookup, 'absl::flat_hash_map<int, int>', 188, 36, 74, 63, 63, 50, 49, 55, 65, 61, 65, 68, 79, 80
 | 
			
		||||
int_delete, 'absl::flat_hash_map<int, int>', 29, 26, 157, 59, 57, 32, 32, 36, 48, 45, 49, 49, 46, 66
 | 
			
		||||
int_insert, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 129, 155, 198, 174, 188, 187, 188, 194, 212, 213, 216, 224, 239, 240
 | 
			
		||||
int_succ_lookup, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 88, 148, 140, 115, 139, 133, 134, 135, 164, 165, 164, 164, 164, 193
 | 
			
		||||
int_nosucc_lookup, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 978, 157, 178, 135, 146, 146, 149, 155, 171, 170, 168, 177, 195, 199
 | 
			
		||||
int_delete, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 193, 141, 139, 100, 130, 132, 130, 134, 162, 158, 159, 161, 162, 196
 | 
			
		||||
int_insert, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 263, 181, 166, 169, 184, 187, 191, 194, 210, 209, 213, 220, 236, 243
 | 
			
		||||
int_succ_lookup, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 173, 136, 115, 115, 135, 135, 138, 136, 164, 164, 165, 169, 165, 193
 | 
			
		||||
int_nosucc_lookup, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 576, 223, 129, 142, 145, 143, 211, 297, 168, 163, 174, 175, 193, 193
 | 
			
		||||
int_delete, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 123, 132, 101, 104, 134, 129, 180, 137, 177, 160, 159, 159, 157, 195
 | 
			
		||||
int_insert, 'absl::flat_hash_map<int, int>', 42, 32, 92, 48, 35, 36, 40, 41, 50, 51, 54, 56, 71, 71
 | 
			
		||||
int_succ_lookup, 'absl::flat_hash_map<int, int>', 19, 20, 68, 26, 24, 24, 26, 25, 34, 35, 38, 35, 36, 46
 | 
			
		||||
int_nosucc_lookup, 'absl::flat_hash_map<int, int>', 312, 40, 58, 57, 52, 48, 52, 50, 63, 62, 65, 71, 77, 78
 | 
			
		||||
int_delete, 'absl::flat_hash_map<int, int>', 55, 28, 177, 37, 30, 29, 35, 30, 46, 52, 45, 54, 45, 71
 | 
			
		||||
int_insert, 'absl::flat_hash_map<int, int>', 27, 31, 30, 37, 36, 39, 37, 41, 50, 52, 54, 58, 71, 71
 | 
			
		||||
int_succ_lookup, 'absl::flat_hash_map<int, int>', 8, 12, 16, 23, 25, 26, 29, 25, 34, 35, 41, 36, 36, 52
 | 
			
		||||
int_nosucc_lookup, 'absl::flat_hash_map<int, int>', 173, 39, 38, 51, 49, 51, 51, 51, 62, 65, 66, 67, 82, 80
 | 
			
		||||
int_delete, 'absl::flat_hash_map<int, int>', 19, 25, 22, 62, 32, 29, 30, 31, 44, 45, 57, 45, 52, 73
 | 
			
		||||
int_insert, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 183, 178, 155, 154, 193, 187, 189, 193, 208, 223, 217, 222, 238, 243
 | 
			
		||||
int_succ_lookup, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 104, 171, 111, 114, 138, 136, 153, 141, 166, 164, 165, 165, 168, 192
 | 
			
		||||
int_nosucc_lookup, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 347, 127, 126, 132, 144, 144, 145, 168, 164, 163, 169, 174, 188, 195
 | 
			
		||||
int_delete, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 102, 101, 94, 96, 133, 134, 131, 137, 159, 155, 159, 161, 158, 188
 | 
			
		||||
int_insert, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 186, 140, 154, 159, 185, 182, 187, 214, 207, 257, 214, 220, 292, 240
 | 
			
		||||
int_succ_lookup, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 150, 101, 112, 114, 136, 137, 138, 138, 156, 219, 164, 165, 200, 195
 | 
			
		||||
int_nosucc_lookup, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 370, 122, 127, 131, 138, 141, 150, 149, 163, 274, 169, 173, 269, 206
 | 
			
		||||
int_delete, 'absl::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 127, 83, 93, 100, 132, 133, 128, 125, 154, 221, 159, 158, 206, 212
 | 
			
		||||
int_insert, 'tsl::sparse_map<int, int>', 67, 88, 108, 81, 94, 97, 118, 118, 142, 142, 143, 151, 159, 171
 | 
			
		||||
int_succ_lookup, 'tsl::sparse_map<int, int>', 20, 35, 36, 32, 36, 42, 50, 50, 59, 68, 68, 72, 76, 80
 | 
			
		||||
int_nosucc_lookup, 'tsl::sparse_map<int, int>', 79, 130, 112, 90, 103, 111, 127, 133, 151, 161, 166, 178, 176, 202
 | 
			
		||||
int_delete, 'tsl::sparse_map<int, int>', 32, 42, 54, 41, 56, 51, 54, 65, 69, 72, 80, 82, 85, 101
 | 
			
		||||
int_insert, 'tsl::sparse_map<int, int>', 65, 103, 107, 98, 90, 155, 128, 137, 127, 155, 140, 175, 153, 159
 | 
			
		||||
int_succ_lookup, 'tsl::sparse_map<int, int>', 20, 29, 71, 33, 36, 120, 49, 53, 56, 70, 66, 73, 72, 76
 | 
			
		||||
int_nosucc_lookup, 'tsl::sparse_map<int, int>', 74, 85, 121, 88, 101, 147, 120, 130, 140, 151, 158, 173, 177, 184
 | 
			
		||||
int_delete, 'tsl::sparse_map<int, int>', 31, 36, 68, 41, 48, 53, 54, 59, 67, 72, 76, 82, 89, 90
 | 
			
		||||
int_insert, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 344, 626, 395, 487, 589, 462, 509, 545, 654, 467, 504, 556, 648, 679
 | 
			
		||||
int_succ_lookup, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 94, 151, 119, 125, 133, 135, 139, 145, 159, 154, 164, 167, 175, 178
 | 
			
		||||
int_nosucc_lookup, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 650, 576, 600, 494, 580, 461, 516, 552, 653, 472, 519, 549, 621, 676
 | 
			
		||||
int_delete, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 325, 380, 376, 313, 360, 285, 322, 344, 400, 310, 336, 365, 395, 426
 | 
			
		||||
int_insert, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 547, 407, 391, 469, 549, 432, 477, 569, 603, 474, 514, 559, 602, 649
 | 
			
		||||
int_succ_lookup, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 71, 103, 115, 122, 130, 136, 137, 162, 150, 158, 161, 166, 169, 178
 | 
			
		||||
int_nosucc_lookup, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 493, 443, 382, 478, 565, 428, 470, 709, 603, 468, 509, 544, 596, 641
 | 
			
		||||
int_delete, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 253, 265, 256, 301, 356, 287, 312, 387, 396, 315, 349, 366, 392, 427
 | 
			
		||||
int_insert, 'tsl::sparse_map<int, int>', 69, 234, 77, 145, 102, 108, 114, 117, 139, 143, 148, 157, 276, 192
 | 
			
		||||
int_succ_lookup, 'tsl::sparse_map<int, int>', 21, 52, 36, 79, 38, 47, 47, 50, 56, 67, 72, 77, 75, 87
 | 
			
		||||
int_nosucc_lookup, 'tsl::sparse_map<int, int>', 90, 135, 85, 127, 103, 113, 125, 135, 152, 154, 164, 178, 187, 183
 | 
			
		||||
int_delete, 'tsl::sparse_map<int, int>', 56, 49, 38, 44, 48, 50, 55, 60, 71, 71, 77, 96, 90, 95
 | 
			
		||||
int_insert, 'tsl::sparse_map<int, int>', 67, 87, 102, 153, 89, 119, 129, 135, 133, 137, 158, 152, 181, 159
 | 
			
		||||
int_succ_lookup, 'tsl::sparse_map<int, int>', 19, 28, 53, 23, 35, 47, 49, 89, 59, 66, 73, 102, 77, 80
 | 
			
		||||
int_nosucc_lookup, 'tsl::sparse_map<int, int>', 72, 89, 92, 85, 97, 115, 119, 184, 151, 148, 172, 180, 290, 178
 | 
			
		||||
int_delete, 'tsl::sparse_map<int, int>', 31, 66, 49, 40, 52, 53, 56, 63, 72, 72, 79, 85, 87, 93
 | 
			
		||||
int_insert, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 323, 451, 559, 481, 558, 464, 513, 561, 640, 486, 527, 576, 675, 708
 | 
			
		||||
int_succ_lookup, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 67, 159, 154, 120, 141, 136, 141, 153, 181, 167, 173, 177, 187, 191
 | 
			
		||||
int_nosucc_lookup, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 614, 628, 449, 501, 560, 479, 518, 568, 962, 478, 537, 577, 661, 714
 | 
			
		||||
int_delete, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 245, 309, 251, 312, 377, 296, 311, 391, 431, 326, 352, 383, 415, 449
 | 
			
		||||
int_insert, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 547, 418, 406, 495, 576, 454, 494, 554, 641, 485, 544, 588, 633, 668
 | 
			
		||||
int_succ_lookup, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 69, 101, 116, 128, 136, 139, 151, 150, 165, 167, 169, 176, 184, 190
 | 
			
		||||
int_nosucc_lookup, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 546, 446, 408, 511, 591, 447, 504, 550, 634, 488, 536, 583, 643, 662
 | 
			
		||||
int_delete, 'tsl::sparse_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 340, 279, 262, 321, 372, 301, 329, 361, 423, 328, 367, 386, 417, 441
 | 
			
		||||
int_insert, 'tsl::robin_map<int, int>', 18, 25, 37, 36, 35, 28, 31, 31, 41, 26, 30, 33, 39, 53
 | 
			
		||||
int_succ_lookup, 'tsl::robin_map<int, int>', 9, 25, 21, 20, 20, 23, 24, 24, 24, 20, 29, 24, 24, 26
 | 
			
		||||
int_nosucc_lookup, 'tsl::robin_map<int, int>', 23, 44, 28, 33, 39, 32, 30, 34, 42, 29, 32, 38, 38, 49
 | 
			
		||||
int_delete, 'tsl::robin_map<int, int>', 21, 51, 24, 24, 31, 22, 30, 27, 35, 23, 26, 29, 34, 68
 | 
			
		||||
int_insert, 'tsl::robin_map<int, int>', 22, 34, 31, 36, 61, 26, 32, 30, 39, 27, 32, 33, 37, 42
 | 
			
		||||
int_succ_lookup, 'tsl::robin_map<int, int>', 11, 24, 27, 22, 24, 24, 37, 24, 24, 24, 25, 25, 25, 28
 | 
			
		||||
int_nosucc_lookup, 'tsl::robin_map<int, int>', 26, 38, 30, 33, 36, 33, 31, 36, 45, 34, 33, 35, 40, 46
 | 
			
		||||
int_delete, 'tsl::robin_map<int, int>', 23, 41, 25, 33, 30, 21, 25, 28, 36, 25, 27, 31, 33, 38
 | 
			
		||||
int_insert, 'tsl::robin_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 199, 145, 149, 172, 182, 166, 174, 176, 238, 173, 218, 193, 206, 209
 | 
			
		||||
int_succ_lookup, 'tsl::robin_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 95, 97, 100, 108, 114, 110, 112, 109, 180, 113, 161, 127, 130, 133
 | 
			
		||||
int_nosucc_lookup, 'tsl::robin_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 174, 128, 119, 133, 149, 126, 136, 140, 250, 132, 211, 159, 165, 174
 | 
			
		||||
int_delete, 'tsl::robin_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 126, 112, 100, 119, 150, 104, 114, 167, 141, 108, 183, 135, 169, 157
 | 
			
		||||
int_insert, 'tsl::robin_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 140, 166, 149, 165, 177, 157, 180, 180, 195, 179, 188, 208, 213, 211
 | 
			
		||||
int_succ_lookup, 'tsl::robin_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 90, 133, 105, 104, 114, 109, 113, 115, 122, 119, 122, 150, 134, 139
 | 
			
		||||
int_nosucc_lookup, 'tsl::robin_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 125, 153, 116, 134, 149, 129, 137, 143, 165, 141, 145, 149, 161, 171
 | 
			
		||||
int_delete, 'tsl::robin_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 105, 116, 95, 117, 157, 109, 118, 127, 149, 117, 127, 165, 148, 159
 | 
			
		||||
int_insert, 'tsl::hopscotch_map<int, int>', 43, 47, 135, 85, 62, 72, 89, 103, 66, 78, 94, 115, 163, 114
 | 
			
		||||
int_succ_lookup, 'tsl::hopscotch_map<int, int>', 11, 12, 69, 24, 20, 23, 29, 30, 22, 25, 28, 33, 42, 40
 | 
			
		||||
int_nosucc_lookup, 'tsl::hopscotch_map<int, int>', 437, 56, 114, 87, 64, 76, 87, 111, 67, 80, 96, 123, 182, 110
 | 
			
		||||
int_delete, 'tsl::hopscotch_map<int, int>', 26, 14, 24, 24, 20, 24, 27, 34, 24, 26, 32, 37, 47, 32
 | 
			
		||||
int_insert, 'tsl::hopscotch_map<int, int>', 56, 76, 89, 77, 62, 168, 97, 178, 67, 80, 93, 114, 164, 70
 | 
			
		||||
int_succ_lookup, 'tsl::hopscotch_map<int, int>', 14, 23, 20, 23, 21, 62, 26, 30, 22, 25, 28, 35, 40, 24
 | 
			
		||||
int_nosucc_lookup, 'tsl::hopscotch_map<int, int>', 232, 103, 76, 84, 64, 122, 91, 122, 65, 81, 95, 121, 172, 73
 | 
			
		||||
int_delete, 'tsl::hopscotch_map<int, int>', 19, 41, 20, 25, 20, 41, 31, 36, 21, 26, 29, 36, 54, 25
 | 
			
		||||
int_insert, 'tsl::hopscotch_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 230, 167, 163, 190, 161, 167, 181, 207, 172, 188, 204, 341, 314, 260
 | 
			
		||||
int_succ_lookup, 'tsl::hopscotch_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 156, 98, 99, 113, 100, 108, 109, 118, 114, 115, 123, 208, 142, 148
 | 
			
		||||
int_nosucc_lookup, 'tsl::hopscotch_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 887, 194, 151, 194, 141, 162, 174, 206, 162, 172, 199, 302, 336, 192
 | 
			
		||||
int_delete, 'tsl::hopscotch_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 143, 90, 90, 104, 100, 100, 107, 113, 101, 113, 117, 217, 136, 112
 | 
			
		||||
int_insert, 'tsl::hopscotch_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 140, 170, 162, 186, 157, 216, 185, 206, 173, 226, 205, 274, 322, 185
 | 
			
		||||
int_succ_lookup, 'tsl::hopscotch_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 74, 98, 98, 109, 103, 116, 112, 114, 112, 136, 123, 181, 145, 119
 | 
			
		||||
int_nosucc_lookup, 'tsl::hopscotch_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 623, 190, 152, 194, 149, 174, 175, 207, 147, 185, 195, 261, 347, 161
 | 
			
		||||
int_delete, 'tsl::hopscotch_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 83, 92, 94, 139, 101, 102, 109, 112, 107, 109, 116, 126, 152, 252
 | 
			
		||||
int_insert, 'boost::unordered::unordered_map<int, int>', 175, 206, 424, 392, 373, 430, 290, 255, 369, 404, 268, 214, 222, 316
 | 
			
		||||
int_succ_lookup, 'boost::unordered::unordered_map<int, int>', 66, 56, 153, 223, 89, 143, 84, 74, 208, 154, 85, 124, 79, 79
 | 
			
		||||
int_nosucc_lookup, 'boost::unordered::unordered_map<int, int>', 263, 164, 248, 286, 201, 348, 309, 204, 384, 257, 259, 275, 223, 233
 | 
			
		||||
int_delete, 'boost::unordered::unordered_map<int, int>', 393, 144, 217, 320, 237, 342, 414, 265, 336, 408, 433, 539, 409, 338
 | 
			
		||||
int_insert, 'boost::unordered::unordered_map<int, int>', 159, 323, 316, 207, 294, 469, 369, 347, 300, 326, 311, 243, 318, 300
 | 
			
		||||
int_succ_lookup, 'boost::unordered::unordered_map<int, int>', 67, 200, 84, 154, 153, 201, 136, 128, 87, 160, 169, 174, 176, 241
 | 
			
		||||
int_nosucc_lookup, 'boost::unordered::unordered_map<int, int>', 155, 367, 212, 211, 287, 304, 398, 219, 274, 343, 338, 447, 255, 363
 | 
			
		||||
int_delete, 'boost::unordered::unordered_map<int, int>', 293, 486, 282, 224, 332, 472, 311, 326, 447, 377, 388, 374, 295, 345
 | 
			
		||||
int_insert, 'boost::unordered::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 446, 614, 504, 317, 415, 347, 787, 761, 534, 390, 502, 428, 509, 712
 | 
			
		||||
int_succ_lookup, 'boost::unordered::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 308, 506, 427, 284, 268, 373, 514, 491, 417, 367, 488, 388, 317, 326
 | 
			
		||||
int_nosucc_lookup, 'boost::unordered::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 445, 405, 398, 370, 294, 464, 562, 326, 516, 502, 324, 528, 624, 564
 | 
			
		||||
int_delete, 'boost::unordered::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 363, 482, 436, 472, 384, 359, 683, 498, 516, 393, 549, 442, 672, 706
 | 
			
		||||
int_insert, 'boost::unordered::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 315, 538, 328, 377, 462, 270, 385, 429, 560, 416, 497, 570, 474, 581
 | 
			
		||||
int_succ_lookup, 'boost::unordered::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 306, 249, 338, 348, 433, 326, 318, 381, 313, 410, 292, 306, 529, 330
 | 
			
		||||
int_nosucc_lookup, 'boost::unordered::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 504, 285, 511, 417, 624, 384, 417, 482, 306, 450, 262, 511, 336, 616
 | 
			
		||||
int_delete, 'boost::unordered::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 459, 495, 417, 348, 393, 748, 346, 409, 478, 434, 439, 590, 443, 659
 | 
			
		||||
int_insert, 'ska::unordered_map<int, int>', 135, 168, 222, 129, 158, 137, 138, 165, 178, 144, 153, 163, 180, 297
 | 
			
		||||
int_succ_lookup, 'ska::unordered_map<int, int>', 41, 79, 60, 33, 38, 35, 36, 39, 43, 40, 43, 44, 45, 98
 | 
			
		||||
int_nosucc_lookup, 'ska::unordered_map<int, int>', 212, 141, 199, 127, 195, 134, 139, 157, 170, 144, 209, 163, 175, 273
 | 
			
		||||
int_delete, 'ska::unordered_map<int, int>', 206, 157, 120, 107, 152, 137, 179, 152, 171, 151, 180, 193, 185, 253
 | 
			
		||||
int_insert, 'ska::unordered_map<int, int>', 94, 203, 115, 130, 286, 169, 145, 156, 186, 150, 214, 167, 179, 202
 | 
			
		||||
int_succ_lookup, 'ska::unordered_map<int, int>', 23, 76, 32, 47, 82, 46, 52, 39, 61, 38, 44, 46, 43, 47
 | 
			
		||||
int_nosucc_lookup, 'ska::unordered_map<int, int>', 78, 185, 109, 169, 231, 131, 173, 155, 219, 147, 262, 181, 173, 184
 | 
			
		||||
int_delete, 'ska::unordered_map<int, int>', 57, 219, 100, 134, 283, 129, 152, 141, 181, 153, 154, 169, 160, 170
 | 
			
		||||
int_insert, 'ska::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 184, 182, 221, 241, 240, 230, 293, 253, 260, 233, 236, 249, 270, 451
 | 
			
		||||
int_succ_lookup, 'ska::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 115, 147, 195, 191, 185, 180, 246, 193, 196, 198, 191, 195, 240, 355
 | 
			
		||||
int_nosucc_lookup, 'ska::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 146, 242, 234, 248, 257, 229, 312, 264, 269, 241, 270, 278, 287, 427
 | 
			
		||||
int_delete, 'ska::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 138, 217, 210, 206, 227, 194, 228, 228, 221, 199, 214, 217, 224, 352
 | 
			
		||||
int_insert, 'ska::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 154, 212, 345, 218, 268, 350, 239, 337, 247, 221, 252, 237, 249, 269
 | 
			
		||||
int_succ_lookup, 'ska::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 132, 165, 294, 192, 187, 241, 185, 310, 196, 216, 201, 196, 206, 236
 | 
			
		||||
int_nosucc_lookup, 'ska::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 258, 199, 335, 218, 224, 309, 252, 356, 239, 217, 225, 231, 248, 329
 | 
			
		||||
int_delete, 'ska::unordered_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 212, 190, 186, 214, 214, 248, 205, 284, 210, 209, 242, 213, 222, 290
 | 
			
		||||
int_insert, 'ska::bytell_hash_map<int, int>', 60, 50, 71, 62, 54, 71, 76, 90, 68, 78, 120, 117, 150, 100
 | 
			
		||||
int_succ_lookup, 'ska::bytell_hash_map<int, int>', 14, 9, 20, 14, 20, 27, 23, 23, 25, 26, 29, 29, 30, 38
 | 
			
		||||
int_nosucc_lookup, 'ska::bytell_hash_map<int, int>', 118, 56, 91, 68, 54, 70, 74, 103, 67, 75, 93, 115, 184, 104
 | 
			
		||||
int_delete, 'ska::bytell_hash_map<int, int>', 27, 19, 36, 27, 26, 35, 29, 41, 33, 37, 40, 51, 67, 39
 | 
			
		||||
int_insert, 'ska::bytell_hash_map<int, int>', 44, 113, 53, 106, 75, 61, 89, 155, 78, 78, 99, 118, 177, 80
 | 
			
		||||
int_succ_lookup, 'ska::bytell_hash_map<int, int>', 8, 40, 21, 20, 29, 21, 24, 45, 26, 28, 28, 30, 44, 28
 | 
			
		||||
int_nosucc_lookup, 'ska::bytell_hash_map<int, int>', 66, 111, 66, 79, 78, 64, 81, 160, 67, 77, 93, 113, 218, 70
 | 
			
		||||
int_delete, 'ska::bytell_hash_map<int, int>', 20, 24, 26, 26, 32, 27, 33, 75, 29, 34, 40, 48, 66, 37
 | 
			
		||||
int_insert, 'ska::bytell_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 170, 191, 176, 198, 185, 190, 213, 222, 197, 205, 216, 240, 367, 210
 | 
			
		||||
int_succ_lookup, 'ska::bytell_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 230, 116, 107, 118, 122, 106, 124, 120, 123, 135, 121, 127, 176, 124
 | 
			
		||||
int_nosucc_lookup, 'ska::bytell_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 267, 192, 212, 195, 137, 161, 201, 207, 142, 159, 196, 368, 372, 162
 | 
			
		||||
int_delete, 'ska::bytell_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 97, 116, 114, 132, 112, 122, 121, 131, 121, 122, 135, 234, 201, 132
 | 
			
		||||
int_insert, 'ska::bytell_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 214, 186, 175, 197, 175, 189, 255, 247, 188, 201, 255, 241, 589, 209
 | 
			
		||||
int_succ_lookup, 'ska::bytell_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 83, 97, 103, 95, 120, 115, 155, 123, 120, 121, 130, 135, 153, 131
 | 
			
		||||
int_nosucc_lookup, 'ska::bytell_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 191, 177, 172, 171, 195, 160, 210, 218, 169, 171, 190, 219, 299, 235
 | 
			
		||||
int_delete, 'ska::bytell_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 218, 104, 109, 102, 115, 121, 131, 134, 126, 128, 135, 142, 152, 157
 | 
			
		||||
int_insert, 'ska::flat_hash_map<int, int>', 60, 30, 84, 41, 51, 41, 46, 48, 54, 57, 49, 52, 66, 70
 | 
			
		||||
int_succ_lookup, 'ska::flat_hash_map<int, int>', 28, 12, 60, 19, 21, 22, 30, 24, 24, 27, 26, 27, 28, 27
 | 
			
		||||
int_nosucc_lookup, 'ska::flat_hash_map<int, int>', 49, 33, 58, 45, 49, 48, 77, 51, 60, 50, 52, 59, 59, 62
 | 
			
		||||
int_delete, 'ska::flat_hash_map<int, int>', 23, 18, 29, 23, 28, 21, 36, 27, 35, 24, 30, 30, 38, 36
 | 
			
		||||
int_insert, 'ska::flat_hash_map<int, int>', 25, 79, 43, 43, 49, 44, 49, 48, 52, 45, 49, 50, 52, 70
 | 
			
		||||
int_succ_lookup, 'ska::flat_hash_map<int, int>', 8, 19, 66, 19, 21, 23, 29, 24, 24, 25, 26, 28, 26, 26
 | 
			
		||||
int_nosucc_lookup, 'ska::flat_hash_map<int, int>', 27, 63, 85, 50, 61, 45, 101, 71, 59, 52, 47, 57, 55, 60
 | 
			
		||||
int_delete, 'ska::flat_hash_map<int, int>', 15, 46, 30, 25, 45, 20, 47, 51, 35, 25, 25, 30, 38, 35
 | 
			
		||||
int_insert, 'ska::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 170, 180, 169, 162, 180, 158, 174, 173, 261, 176, 181, 190, 277, 203
 | 
			
		||||
int_succ_lookup, 'ska::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 187, 109, 114, 101, 109, 102, 106, 109, 121, 113, 115, 122, 170, 129
 | 
			
		||||
int_nosucc_lookup, 'ska::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 211, 135, 161, 138, 152, 147, 123, 146, 158, 136, 139, 145, 171, 170
 | 
			
		||||
int_delete, 'ska::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 135, 129, 127, 121, 144, 128, 109, 119, 143, 118, 148, 138, 145, 147
 | 
			
		||||
int_insert, 'ska::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 137, 149, 144, 163, 176, 158, 251, 171, 188, 179, 184, 186, 203, 203
 | 
			
		||||
int_succ_lookup, 'ska::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 112, 98, 78, 109, 145, 105, 174, 109, 117, 114, 120, 116, 125, 137
 | 
			
		||||
int_nosucc_lookup, 'ska::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 222, 135, 99, 130, 198, 130, 137, 140, 153, 130, 170, 148, 154, 172
 | 
			
		||||
int_delete, 'ska::flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 178, 104, 74, 115, 159, 101, 132, 119, 138, 108, 125, 127, 139, 157
 | 
			
		||||
int_insert, 'phmap::parallel_flat_hash_map<int, int>', 47, 45, 60, 58, 55, 56, 69, 75, 72, 71, 129, 93, 112, 98
 | 
			
		||||
int_succ_lookup, 'phmap::parallel_flat_hash_map<int, int>', 12, 12, 48, 21, 32, 29, 32, 30, 40, 43, 52, 58, 48, 55
 | 
			
		||||
int_nosucc_lookup, 'phmap::parallel_flat_hash_map<int, int>', 158, 54, 66, 64, 59, 60, 67, 74, 78, 76, 86, 123, 128, 93
 | 
			
		||||
int_delete, 'phmap::parallel_flat_hash_map<int, int>', 48, 25, 39, 32, 38, 32, 41, 37, 53, 51, 62, 70, 63, 78
 | 
			
		||||
int_insert, 'phmap::parallel_flat_hash_map<int, int>', 59, 152, 61, 49, 81, 55, 57, 69, 67, 78, 82, 86, 128, 89
 | 
			
		||||
int_succ_lookup, 'phmap::parallel_flat_hash_map<int, int>', 22, 99, 41, 17, 36, 28, 27, 30, 38, 48, 52, 40, 67, 53
 | 
			
		||||
int_nosucc_lookup, 'phmap::parallel_flat_hash_map<int, int>', 197, 98, 123, 60, 61, 60, 69, 79, 72, 104, 88, 95, 207, 117
 | 
			
		||||
int_delete, 'phmap::parallel_flat_hash_map<int, int>', 48, 44, 70, 35, 37, 36, 38, 42, 58, 73, 60, 91, 85, 95
 | 
			
		||||
int_insert, 'phmap::parallel_flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 309, 245, 199, 231, 222, 230, 237, 261, 252, 427, 268, 287, 335, 325
 | 
			
		||||
int_succ_lookup, 'phmap::parallel_flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 139, 147, 120, 131, 156, 160, 147, 164, 174, 271, 170, 179, 178, 205
 | 
			
		||||
int_nosucc_lookup, 'phmap::parallel_flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 957, 200, 166, 172, 183, 179, 171, 194, 200, 364, 200, 261, 284, 236
 | 
			
		||||
int_delete, 'phmap::parallel_flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 259, 117, 116, 117, 135, 133, 135, 183, 165, 265, 169, 183, 208, 197
 | 
			
		||||
int_insert, 'phmap::parallel_flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 281, 247, 200, 236, 225, 224, 246, 247, 247, 266, 267, 392, 330, 277
 | 
			
		||||
int_succ_lookup, 'phmap::parallel_flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 175, 152, 125, 130, 111, 140, 140, 142, 196, 168, 172, 249, 180, 201
 | 
			
		||||
int_nosucc_lookup, 'phmap::parallel_flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 617, 188, 151, 204, 149, 166, 172, 173, 200, 204, 218, 251, 240, 224
 | 
			
		||||
int_delete, 'phmap::parallel_flat_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 123, 131, 113, 123, 104, 128, 179, 122, 162, 174, 212, 178, 230, 201
 | 
			
		||||
int_insert, 'phmap::parallel_node_hash_map<int, int>', 259, 122, 136, 137, 168, 162, 179, 174, 165, 169, 192, 197, 260, 214
 | 
			
		||||
int_succ_lookup, 'phmap::parallel_node_hash_map<int, int>', 32, 40, 51, 56, 82, 70, 69, 70, 71, 79, 75, 98, 84, 90
 | 
			
		||||
int_nosucc_lookup, 'phmap::parallel_node_hash_map<int, int>', 533, 181, 131, 158, 165, 164, 175, 180, 182, 176, 193, 218, 262, 248
 | 
			
		||||
int_delete, 'phmap::parallel_node_hash_map<int, int>', 112, 122, 123, 183, 168, 173, 191, 192, 236, 210, 207, 230, 249, 249
 | 
			
		||||
int_insert, 'phmap::parallel_node_hash_map<int, int>', 91, 140, 114, 141, 144, 141, 306, 183, 156, 284, 182, 379, 243, 205
 | 
			
		||||
int_succ_lookup, 'phmap::parallel_node_hash_map<int, int>', 24, 55, 48, 52, 79, 66, 63, 66, 71, 102, 83, 79, 102, 100
 | 
			
		||||
int_nosucc_lookup, 'phmap::parallel_node_hash_map<int, int>', 389, 392, 123, 147, 143, 150, 178, 182, 177, 201, 183, 210, 796, 211
 | 
			
		||||
int_delete, 'phmap::parallel_node_hash_map<int, int>', 105, 171, 126, 138, 173, 151, 206, 175, 229, 229, 208, 224, 261, 252
 | 
			
		||||
int_insert, 'phmap::parallel_node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 177, 238, 276, 277, 245, 284, 303, 313, 283, 296, 320, 366, 426, 358
 | 
			
		||||
int_succ_lookup, 'phmap::parallel_node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 101, 143, 174, 171, 197, 215, 212, 219, 237, 230, 245, 257, 270, 276
 | 
			
		||||
int_nosucc_lookup, 'phmap::parallel_node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 971, 221, 224, 228, 222, 219, 243, 259, 246, 257, 272, 315, 364, 313
 | 
			
		||||
int_delete, 'phmap::parallel_node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 147, 157, 198, 201, 247, 223, 251, 255, 279, 262, 259, 297, 298, 300
 | 
			
		||||
int_insert, 'phmap::parallel_node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 210, 241, 242, 282, 264, 282, 292, 343, 288, 443, 324, 395, 423, 314
 | 
			
		||||
int_succ_lookup, 'phmap::parallel_node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 148, 142, 173, 208, 202, 240, 207, 217, 244, 388, 241, 267, 267, 282
 | 
			
		||||
int_nosucc_lookup, 'phmap::parallel_node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 1011, 225, 221, 248, 219, 250, 246, 284, 291, 569, 276, 384, 376, 281
 | 
			
		||||
int_delete, 'phmap::parallel_node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 138, 168, 220, 212, 224, 230, 237, 248, 412, 463, 264, 295, 299, 297
 | 
			
		||||
int_insert, 'emilib::HashMap<int, int>', 23, 20, 22, 24, 26, 35, 29, 31, 40, 44, 37, 40, 45, 49
 | 
			
		||||
int_succ_lookup, 'emilib::HashMap<int, int>', 11, 14, 14, 20, 21, 25, 26, 27, 33, 33, 31, 36, 34, 34
 | 
			
		||||
int_nosucc_lookup, 'emilib::HashMap<int, int>', 26, 21, 28, 28, 28, 38, 31, 36, 40, 53, 36, 41, 43, 47
 | 
			
		||||
int_delete, 'emilib::HashMap<int, int>', 9, 8, 11, 15, 14, 18, 16, 19, 21, 26, 21, 23, 29, 26
 | 
			
		||||
int_insert, 'emilib::HashMap<int, int>', 15, 16, 22, 22, 29, 80, 121, 33, 37, 50, 39, 39, 45, 51
 | 
			
		||||
int_succ_lookup, 'emilib::HashMap<int, int>', 9, 12, 13, 19, 24, 28, 46, 28, 33, 34, 32, 31, 43, 36
 | 
			
		||||
int_nosucc_lookup, 'emilib::HashMap<int, int>', 18, 18, 24, 23, 31, 37, 37, 32, 39, 50, 37, 38, 54, 50
 | 
			
		||||
int_delete, 'emilib::HashMap<int, int>', 6, 7, 10, 11, 15, 17, 61, 17, 21, 25, 21, 22, 28, 26
 | 
			
		||||
int_insert, 'emilib::HashMap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 134, 138, 161, 155, 156, 159, 163, 165, 182, 178, 174, 177, 488, 182
 | 
			
		||||
int_succ_lookup, 'emilib::HashMap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 80, 93, 106, 118, 108, 114, 110, 111, 116, 119, 117, 120, 341, 133
 | 
			
		||||
int_nosucc_lookup, 'emilib::HashMap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 169, 120, 121, 142, 124, 125, 129, 129, 130, 141, 138, 151, 179, 147
 | 
			
		||||
int_delete, 'emilib::HashMap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 127, 84, 91, 115, 106, 102, 103, 101, 105, 124, 114, 112, 153, 123
 | 
			
		||||
int_insert, 'emilib::HashMap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 183, 137, 146, 154, 147, 161, 154, 159, 168, 173, 170, 174, 179, 181
 | 
			
		||||
int_succ_lookup, 'emilib::HashMap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 138, 90, 101, 101, 105, 125, 104, 106, 120, 118, 120, 127, 122, 129
 | 
			
		||||
int_nosucc_lookup, 'emilib::HashMap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 208, 111, 121, 111, 123, 137, 121, 122, 135, 134, 138, 139, 144, 142
 | 
			
		||||
int_delete, 'emilib::HashMap<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 94, 79, 94, 87, 95, 105, 101, 100, 153, 115, 111, 114, 115, 124
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<true, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 102, 126, 38, 112, 81, 144, 120, 168, 69, 163, 130, 135, 112, 91
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<true, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 35, 53, 22, 65, 33, 61, 30, 127, 73, 51, 52, 119, 179, 43
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<true, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 266, 366, 38, 911, 40, 84, 93, 167, 67, 103, 82, 113, 114, 83
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<true, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 22, 25, 64, 40, 35, 99, 118, 276, 44, 98, 104, 207, 185, 103
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<true, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 89, 87, 50, 97, 66, 42, 84, 151, 180, 78, 218, 101, 58, 135
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<true, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 40, 63, 49, 30, 29, 34, 35, 104, 79, 38, 88, 74, 37, 85
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<true, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 245, 298, 94, 552, 40, 87, 90, 110, 92, 77, 176, 124, 70, 89
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<true, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 105, 77, 62, 126, 65, 79, 111, 77, 132, 176, 136, 118, 64, 131
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<true, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 495, 480, 352, 848, 246, 185, 347, 315, 176, 174, 240, 353, 150, 180
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<true, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 247, 224, 202, 241, 200, 190, 80, 121, 121, 112, 125, 127, 119, 89
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<true, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 981, 2163, 456, 5086, 252, 204, 179, 314, 184, 185, 216, 367, 131, 115
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<true, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 135, 149, 263, 287, 253, 238, 153, 268, 133, 173, 194, 475, 133, 111
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<true, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 261, 278, 141, 408, 141, 158, 203, 300, 262, 275, 392, 503, 315, 543
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<true, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 124, 84, 93, 73, 98, 108, 109, 119, 114, 216, 136, 195, 265, 305
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<true, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 530, 763, 277, 2340, 128, 158, 202, 341, 256, 544, 355, 541, 377, 315
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<true, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 82, 114, 196, 83, 127, 176, 239, 285, 259, 355, 405, 643, 296, 298
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 58, 147, 92, 239, 73, 172, 123, 237, 151, 151, 192, 187, 72, 230
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 24, 69, 47, 105, 123, 235, 77, 67, 212, 65, 69, 74, 103, 146
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 343, 1310, 71, 1802, 89, 104, 107, 145, 118, 136, 131, 194, 83, 134
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 44, 60, 106, 155, 255, 262, 163, 219, 171, 222, 226, 244, 276, 297
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 146, 76, 42, 197, 122, 96, 163, 172, 85, 227, 150, 180, 108, 173
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 68, 80, 51, 80, 166, 67, 60, 133, 108, 161, 159, 131, 89, 164
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 451, 1078, 99, 1906, 89, 168, 105, 151, 125, 202, 95, 315, 58, 160
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 83, 220, 123, 221, 206, 151, 151, 288, 319, 260, 238, 456, 268, 230
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 188, 229, 240, 326, 312, 271, 325, 465, 264, 203, 312, 422, 258, 395
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 105, 250, 349, 256, 320, 244, 311, 333, 254, 331, 320, 355, 271, 217
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 939, 1950, 232, 4612, 253, 133, 326, 327, 273, 290, 368, 293, 224, 150
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 174, 260, 254, 305, 310, 297, 289, 546, 324, 345, 328, 383, 282, 204
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 317, 336, 242, 295, 196, 216, 298, 412, 401, 256, 455, 296, 202, 284
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 236, 194, 293, 240, 321, 283, 252, 328, 422, 280, 265, 321, 239, 274
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 1039, 1621, 155, 3866, 176, 170, 308, 420, 231, 321, 283, 322, 209, 182
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 294, 265, 183, 409, 445, 274, 433, 364, 316, 397, 410, 328, 333, 322
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 74, 109, 108, 124, 60, 69, 65, 86, 47, 74, 77, 108, 52, 134
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 37, 137, 155, 90, 73, 80, 52, 54, 48, 57, 55, 63, 57, 61
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 324, 936, 89, 2001, 67, 88, 69, 95, 48, 79, 81, 112, 54, 79
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 57, 144, 125, 160, 121, 152, 109, 133, 124, 133, 142, 162, 140, 180
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 45, 89, 74, 74, 46, 166, 88, 128, 102, 147, 224, 229, 243, 72
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 39, 66, 86, 128, 73, 130, 56, 65, 70, 155, 116, 65, 146, 59
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 415, 930, 64, 1715, 68, 94, 100, 183, 117, 79, 156, 160, 160, 59
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<false, 80, int, int, robin_hood::hash<int>, std::equal_to<int> >', 29, 55, 67, 107, 102, 236, 134, 167, 199, 191, 269, 309, 183, 199
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 185, 258, 320, 245, 211, 218, 251, 273, 260, 273, 271, 473, 143, 354
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 120, 284, 314, 179, 290, 253, 253, 223, 226, 299, 317, 366, 189, 360
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 743, 1682, 221, 3335, 251, 144, 132, 287, 201, 254, 559, 333, 173, 206
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 90, 156, 239, 228, 253, 235, 288, 307, 229, 282, 289, 277, 186, 276
 | 
			
		||||
int_insert, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 188, 176, 128, 171, 134, 142, 160, 183, 141, 151, 235, 198, 137, 160
 | 
			
		||||
int_succ_lookup, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 118, 158, 142, 148, 156, 160, 166, 171, 172, 177, 237, 194, 193, 240
 | 
			
		||||
int_nosucc_lookup, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 669, 1179, 96, 2382, 107, 112, 131, 161, 132, 142, 178, 207, 141, 188
 | 
			
		||||
int_delete, 'robin_hood::detail::Table<false, 80, std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, robin_hood::hash<std::__cxx11::basic_string<char> >, std::equal_to<std::__cxx11::basic_string<char> > >', 108, 126, 154, 161, 147, 152, 196, 197, 176, 184, 199, 216, 194, 234
 | 
			
		||||
int_insert, 'absl::node_hash_map<int, int>', 136, 129, 113, 106, 117, 211, 122, 131, 140, 121, 142, 215, 171, 149
 | 
			
		||||
int_succ_lookup, 'absl::node_hash_map<int, int>', 61, 81, 127, 53, 59, 145, 64, 64, 71, 66, 76, 147, 74, 80
 | 
			
		||||
int_nosucc_lookup, 'absl::node_hash_map<int, int>', 801, 170, 269, 109, 115, 205, 118, 122, 131, 120, 133, 225, 156, 140
 | 
			
		||||
int_delete, 'absl::node_hash_map<int, int>', 164, 189, 308, 164, 188, 256, 203, 204, 228, 199, 231, 325, 290, 256
 | 
			
		||||
int_insert, 'absl::node_hash_map<int, int>', 96, 128, 137, 283, 114, 115, 118, 312, 129, 137, 137, 141, 249, 229
 | 
			
		||||
int_succ_lookup, 'absl::node_hash_map<int, int>', 29, 79, 127, 310, 58, 58, 64, 146, 74, 73, 75, 75, 133, 165
 | 
			
		||||
int_nosucc_lookup, 'absl::node_hash_map<int, int>', 411, 137, 160, 263, 115, 117, 118, 292, 130, 131, 134, 142, 257, 231
 | 
			
		||||
int_delete, 'absl::node_hash_map<int, int>', 92, 168, 166, 270, 236, 208, 214, 385, 416, 236, 238, 250, 279, 288
 | 
			
		||||
int_insert, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 140, 157, 297, 183, 189, 202, 205, 211, 386, 333, 258, 281, 315, 378
 | 
			
		||||
int_succ_lookup, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 114, 154, 361, 182, 205, 233, 272, 228, 275, 387, 261, 259, 272, 529
 | 
			
		||||
int_nosucc_lookup, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 846, 367, 210, 186, 180, 204, 216, 282, 463, 496, 252, 274, 296, 399
 | 
			
		||||
int_delete, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 181, 232, 224, 192, 218, 251, 261, 340, 425, 460, 290, 297, 299, 466
 | 
			
		||||
int_insert, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 332, 351, 180, 308, 210, 445, 214, 245, 336, 490, 226, 245, 263, 578
 | 
			
		||||
int_succ_lookup, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 161, 212, 192, 248, 238, 430, 252, 209, 304, 331, 264, 263, 268, 402
 | 
			
		||||
int_nosucc_lookup, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 1630, 385, 182, 393, 208, 425, 209, 210, 369, 464, 234, 251, 284, 606
 | 
			
		||||
int_delete, 'absl::node_hash_map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >', 362, 347, 213, 410, 267, 336, 253, 243, 464, 491, 287, 299, 299, 642
 | 
			
		||||
| 
		
		
			 Can't render this file because it has a wrong number of fields in line 242. 
		
	 | 
							
								
								
									
										1
									
								
								src/includes/3thparty/abseil-cpp
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								src/includes/3thparty/abseil-cpp
									
									
									
									
									
										Submodule
									
								
							 Submodule src/includes/3thparty/abseil-cpp added at 08a7e7bf97
									
								
							
							
								
								
									
										666
									
								
								src/includes/3thparty/emilib/hash_map.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										666
									
								
								src/includes/3thparty/emilib/hash_map.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,666 @@
 | 
			
		||||
// By Emil Ernerfeldt 2014-2017
 | 
			
		||||
// LICENSE:
 | 
			
		||||
//   This software is dual-licensed to the public domain and under the following
 | 
			
		||||
//   license: you are granted a perpetual, irrevocable license to copy, modify,
 | 
			
		||||
//   publish, and distribute this file as you see fit.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "loguru.hpp"
 | 
			
		||||
 | 
			
		||||
namespace emilib {
 | 
			
		||||
 | 
			
		||||
/// like std::equal_to but no need to #include <functional>
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct HashMapEqualTo
 | 
			
		||||
{
 | 
			
		||||
	constexpr bool operator()(const T& lhs, const T& rhs) const
 | 
			
		||||
	{
 | 
			
		||||
		return lhs == rhs;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// A cache-friendly hash table with open addressing, linear probing and power-of-two capacity
 | 
			
		||||
template <typename KeyT, typename ValueT, typename HashT = std::hash<KeyT>, typename EqT = HashMapEqualTo<KeyT>>
 | 
			
		||||
class HashMap
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	using MyType = HashMap<KeyT, ValueT, HashT, EqT>;
 | 
			
		||||
 | 
			
		||||
	using PairT = std::pair<KeyT, ValueT>;
 | 
			
		||||
public:
 | 
			
		||||
	using size_type       = size_t;
 | 
			
		||||
	using value_type      = PairT;
 | 
			
		||||
	using reference       = PairT&;
 | 
			
		||||
	using const_reference = const PairT&;
 | 
			
		||||
 | 
			
		||||
	class iterator
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		using iterator_category = std::forward_iterator_tag;
 | 
			
		||||
		using difference_type   = size_t;
 | 
			
		||||
		using distance_type     = size_t;
 | 
			
		||||
		using value_type        = std::pair<KeyT, ValueT>;
 | 
			
		||||
		using pointer           = value_type*;
 | 
			
		||||
		using reference         = value_type&;
 | 
			
		||||
 | 
			
		||||
		iterator() { }
 | 
			
		||||
 | 
			
		||||
		iterator(MyType* hash_map, size_t bucket) : _map(hash_map), _bucket(bucket)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		iterator& operator++()
 | 
			
		||||
		{
 | 
			
		||||
			this->goto_next_element();
 | 
			
		||||
			return *this;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		iterator operator++(int)
 | 
			
		||||
		{
 | 
			
		||||
			size_t old_index = _bucket;
 | 
			
		||||
			this->goto_next_element();
 | 
			
		||||
			return iterator(_map, old_index);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		reference operator*() const
 | 
			
		||||
		{
 | 
			
		||||
			return _map->_pairs[_bucket];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pointer operator->() const
 | 
			
		||||
		{
 | 
			
		||||
			return _map->_pairs + _bucket;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool operator==(const iterator& rhs) const
 | 
			
		||||
		{
 | 
			
		||||
			DCHECK_EQ_F(_map, rhs._map);
 | 
			
		||||
			return this->_bucket == rhs._bucket;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool operator!=(const iterator& rhs) const
 | 
			
		||||
		{
 | 
			
		||||
			DCHECK_EQ_F(_map, rhs._map);
 | 
			
		||||
			return this->_bucket != rhs._bucket;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void goto_next_element()
 | 
			
		||||
		{
 | 
			
		||||
			DCHECK_LT_F(_bucket, _map->_num_buckets);
 | 
			
		||||
			do {
 | 
			
		||||
				_bucket++;
 | 
			
		||||
			} while (_bucket < _map->_num_buckets && _map->_states[_bucket] != State::FILLED);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	//private:
 | 
			
		||||
	//	friend class MyType;
 | 
			
		||||
	public:
 | 
			
		||||
		MyType* _map;
 | 
			
		||||
		size_t  _bucket;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class const_iterator
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		using iterator_category = std::forward_iterator_tag;
 | 
			
		||||
		using difference_type   = size_t;
 | 
			
		||||
		using distance_type     = size_t;
 | 
			
		||||
		using value_type        = const std::pair<KeyT, ValueT>;
 | 
			
		||||
		using pointer           = value_type*;
 | 
			
		||||
		using reference         = value_type&;
 | 
			
		||||
 | 
			
		||||
		const_iterator() { }
 | 
			
		||||
 | 
			
		||||
		const_iterator(iterator proto) : _map(proto._map), _bucket(proto._bucket)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const_iterator(const MyType* hash_map, size_t bucket) : _map(hash_map), _bucket(bucket)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const_iterator& operator++()
 | 
			
		||||
		{
 | 
			
		||||
			this->goto_next_element();
 | 
			
		||||
			return *this;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const_iterator operator++(int)
 | 
			
		||||
		{
 | 
			
		||||
			size_t old_index = _bucket;
 | 
			
		||||
			this->goto_next_element();
 | 
			
		||||
			return const_iterator(_map, old_index);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		reference operator*() const
 | 
			
		||||
		{
 | 
			
		||||
			return _map->_pairs[_bucket];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pointer operator->() const
 | 
			
		||||
		{
 | 
			
		||||
			return _map->_pairs + _bucket;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool operator==(const const_iterator& rhs) const
 | 
			
		||||
		{
 | 
			
		||||
			DCHECK_EQ_F(_map, rhs._map);
 | 
			
		||||
			return this->_bucket == rhs._bucket;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bool operator!=(const const_iterator& rhs) const
 | 
			
		||||
		{
 | 
			
		||||
			DCHECK_EQ_F(_map, rhs._map);
 | 
			
		||||
			return this->_bucket != rhs._bucket;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void goto_next_element()
 | 
			
		||||
		{
 | 
			
		||||
			DCHECK_LT_F(_bucket, _map->_num_buckets);
 | 
			
		||||
			do {
 | 
			
		||||
				_bucket++;
 | 
			
		||||
			} while (_bucket < _map->_num_buckets && _map->_states[_bucket] != State::FILLED);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	//private:
 | 
			
		||||
	//	friend class MyType;
 | 
			
		||||
	public:
 | 
			
		||||
		const MyType* _map;
 | 
			
		||||
		size_t        _bucket;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	HashMap() = default;
 | 
			
		||||
 | 
			
		||||
	HashMap(const HashMap& other)
 | 
			
		||||
	{
 | 
			
		||||
		reserve(other.size());
 | 
			
		||||
		insert(other.cbegin(), other.cend());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	HashMap(HashMap&& other)
 | 
			
		||||
	{
 | 
			
		||||
		*this = std::move(other);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	HashMap& operator=(const HashMap& other)
 | 
			
		||||
	{
 | 
			
		||||
		clear();
 | 
			
		||||
		reserve(other.size());
 | 
			
		||||
		insert(other.cbegin(), other.cend());
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void operator=(HashMap&& other)
 | 
			
		||||
	{
 | 
			
		||||
		this->swap(other);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~HashMap()
 | 
			
		||||
	{
 | 
			
		||||
		for (size_t bucket=0; bucket<_num_buckets; ++bucket) {
 | 
			
		||||
			if (_states[bucket] == State::FILLED) {
 | 
			
		||||
				_pairs[bucket].~PairT();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		free(_states);
 | 
			
		||||
		free(_pairs);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void swap(HashMap& other)
 | 
			
		||||
	{
 | 
			
		||||
		std::swap(_hasher,           other._hasher);
 | 
			
		||||
		std::swap(_eq,               other._eq);
 | 
			
		||||
		std::swap(_states,           other._states);
 | 
			
		||||
		std::swap(_pairs,            other._pairs);
 | 
			
		||||
		std::swap(_num_buckets,      other._num_buckets);
 | 
			
		||||
		std::swap(_num_filled,       other._num_filled);
 | 
			
		||||
		std::swap(_max_probe_length, other._max_probe_length);
 | 
			
		||||
		std::swap(_mask,             other._mask);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	iterator begin()
 | 
			
		||||
	{
 | 
			
		||||
		size_t bucket = 0;
 | 
			
		||||
		while (bucket<_num_buckets && _states[bucket] != State::FILLED) {
 | 
			
		||||
			++bucket;
 | 
			
		||||
		}
 | 
			
		||||
		return iterator(this, bucket);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const_iterator cbegin() const
 | 
			
		||||
	{
 | 
			
		||||
		size_t bucket = 0;
 | 
			
		||||
		while (bucket<_num_buckets && _states[bucket] != State::FILLED) {
 | 
			
		||||
			++bucket;
 | 
			
		||||
		}
 | 
			
		||||
		return const_iterator(this, bucket);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const_iterator begin() const
 | 
			
		||||
	{
 | 
			
		||||
		return cbegin();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iterator end()
 | 
			
		||||
	{
 | 
			
		||||
		return iterator(this, _num_buckets);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const_iterator cend() const
 | 
			
		||||
	{
 | 
			
		||||
		return const_iterator(this, _num_buckets);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const_iterator end() const
 | 
			
		||||
	{
 | 
			
		||||
		return cend();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t size() const
 | 
			
		||||
	{
 | 
			
		||||
		return _num_filled;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool empty() const
 | 
			
		||||
	{
 | 
			
		||||
		return _num_filled==0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Returns the number of buckets.
 | 
			
		||||
	size_t bucket_count() const
 | 
			
		||||
	{
 | 
			
		||||
		return _num_buckets;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Returns average number of elements per bucket.
 | 
			
		||||
	float load_factor() const
 | 
			
		||||
	{
 | 
			
		||||
		return static_cast<float>(_num_filled) / static_cast<float>(_num_buckets);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	template<typename KeyLike>
 | 
			
		||||
	iterator find(const KeyLike& key)
 | 
			
		||||
	{
 | 
			
		||||
		auto bucket = this->find_filled_bucket(key);
 | 
			
		||||
		if (bucket == (size_t)-1) {
 | 
			
		||||
			return this->end();
 | 
			
		||||
		}
 | 
			
		||||
		return iterator(this, bucket);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename KeyLike>
 | 
			
		||||
	const_iterator find(const KeyLike& key) const
 | 
			
		||||
	{
 | 
			
		||||
		auto bucket = this->find_filled_bucket(key);
 | 
			
		||||
		if (bucket == (size_t)-1)
 | 
			
		||||
		{
 | 
			
		||||
			return this->end();
 | 
			
		||||
		}
 | 
			
		||||
		return const_iterator(this, bucket);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename KeyLike>
 | 
			
		||||
	bool contains(const KeyLike& k) const
 | 
			
		||||
	{
 | 
			
		||||
		return find_filled_bucket(k) != (size_t)-1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template<typename KeyLike>
 | 
			
		||||
	size_t count(const KeyLike& k) const
 | 
			
		||||
	{
 | 
			
		||||
		return find_filled_bucket(k) != (size_t)-1 ? 1 : 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Returns the matching ValueT or nullptr if k isn't found.
 | 
			
		||||
	template<typename KeyLike>
 | 
			
		||||
	ValueT* try_get(const KeyLike& k)
 | 
			
		||||
	{
 | 
			
		||||
		auto bucket = find_filled_bucket(k);
 | 
			
		||||
		if (bucket != (size_t)-1) {
 | 
			
		||||
			return &_pairs[bucket].second;
 | 
			
		||||
		} else {
 | 
			
		||||
			return nullptr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Const version of the above
 | 
			
		||||
	template<typename KeyLike>
 | 
			
		||||
	const ValueT* try_get(const KeyLike& k) const
 | 
			
		||||
	{
 | 
			
		||||
		auto bucket = find_filled_bucket(k);
 | 
			
		||||
		if (bucket != (size_t)-1) {
 | 
			
		||||
			return &_pairs[bucket].second;
 | 
			
		||||
		} else {
 | 
			
		||||
			return nullptr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Convenience function.
 | 
			
		||||
	template<typename KeyLike>
 | 
			
		||||
	const ValueT get_or_return_default(const KeyLike& k) const
 | 
			
		||||
	{
 | 
			
		||||
		const ValueT* ret = try_get(k);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			return *ret;
 | 
			
		||||
		} else {
 | 
			
		||||
			return ValueT();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/// Returns a pair consisting of an iterator to the inserted element
 | 
			
		||||
	/// (or to the element that prevented the insertion)
 | 
			
		||||
	/// and a bool denoting whether the insertion took place.
 | 
			
		||||
	std::pair<iterator, bool> insert(const KeyT& key, const ValueT& value)
 | 
			
		||||
	{
 | 
			
		||||
		check_expand_need();
 | 
			
		||||
 | 
			
		||||
		auto bucket = find_or_allocate(key);
 | 
			
		||||
 | 
			
		||||
		if (_states[bucket] == State::FILLED) {
 | 
			
		||||
			return { iterator(this, bucket), false };
 | 
			
		||||
		} else {
 | 
			
		||||
			_states[bucket] = State::FILLED;
 | 
			
		||||
			new(_pairs + bucket) PairT(key, value);
 | 
			
		||||
			_num_filled++;
 | 
			
		||||
			return { iterator(this, bucket), true };
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT>& p)
 | 
			
		||||
	{
 | 
			
		||||
		return insert(p.first, p.second);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void insert(const_iterator begin, const_iterator end)
 | 
			
		||||
	{
 | 
			
		||||
		// TODO: reserve space exactly once.
 | 
			
		||||
		for (; begin != end; ++begin) {
 | 
			
		||||
			insert(begin->first, begin->second);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Same as above, but contains(key) MUST be false
 | 
			
		||||
	void insert_unique(KeyT&& key, ValueT&& value)
 | 
			
		||||
	{
 | 
			
		||||
		DCHECK_F(!contains(key));
 | 
			
		||||
		check_expand_need();
 | 
			
		||||
		auto bucket = find_empty_bucket(key);
 | 
			
		||||
		_states[bucket] = State::FILLED;
 | 
			
		||||
		new(_pairs + bucket) PairT(std::move(key), std::move(value));
 | 
			
		||||
		_num_filled++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void insert_unique(std::pair<KeyT, ValueT>&& p)
 | 
			
		||||
	{
 | 
			
		||||
		insert_unique(std::move(p.first), std::move(p.second));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void insert_or_assign(const KeyT& key, ValueT&& value)
 | 
			
		||||
	{
 | 
			
		||||
		check_expand_need();
 | 
			
		||||
 | 
			
		||||
		auto bucket = find_or_allocate(key);
 | 
			
		||||
 | 
			
		||||
		// Check if inserting a new value rather than overwriting an old entry
 | 
			
		||||
		if (_states[bucket] == State::FILLED) {
 | 
			
		||||
			_pairs[bucket].second = value;
 | 
			
		||||
		} else {
 | 
			
		||||
			_states[bucket] = State::FILLED;
 | 
			
		||||
			new(_pairs + bucket) PairT(key, value);
 | 
			
		||||
			_num_filled++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Return the old value or ValueT() if it didn't exist.
 | 
			
		||||
	ValueT set_get(const KeyT& key, const ValueT& new_value)
 | 
			
		||||
	{
 | 
			
		||||
		check_expand_need();
 | 
			
		||||
 | 
			
		||||
		auto bucket = find_or_allocate(key);
 | 
			
		||||
 | 
			
		||||
		// Check if inserting a new value rather than overwriting an old entry
 | 
			
		||||
		if (_states[bucket] == State::FILLED) {
 | 
			
		||||
			ValueT old_value = _pairs[bucket].second;
 | 
			
		||||
			_pairs[bucket] = new_value.second;
 | 
			
		||||
			return old_value;
 | 
			
		||||
		} else {
 | 
			
		||||
			_states[bucket] = State::FILLED;
 | 
			
		||||
			new(_pairs + bucket) PairT(key, new_value);
 | 
			
		||||
			_num_filled++;
 | 
			
		||||
			return ValueT();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Like std::map<KeyT,ValueT>::operator[].
 | 
			
		||||
	ValueT& operator[](const KeyT& key)
 | 
			
		||||
	{
 | 
			
		||||
		check_expand_need();
 | 
			
		||||
 | 
			
		||||
		auto bucket = find_or_allocate(key);
 | 
			
		||||
 | 
			
		||||
		/* Check if inserting a new value rather than overwriting an old entry */
 | 
			
		||||
		if (_states[bucket] != State::FILLED) {
 | 
			
		||||
			_states[bucket] = State::FILLED;
 | 
			
		||||
			new(_pairs + bucket) PairT(key, ValueT());
 | 
			
		||||
			_num_filled++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return _pairs[bucket].second;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// -------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
	/// Erase an element from the hash table.
 | 
			
		||||
	/// return false if element was not found
 | 
			
		||||
	bool erase(const KeyT& key)
 | 
			
		||||
	{
 | 
			
		||||
		auto bucket = find_filled_bucket(key);
 | 
			
		||||
		if (bucket != (size_t)-1) {
 | 
			
		||||
			_states[bucket] = State::ACTIVE;
 | 
			
		||||
			_pairs[bucket].~PairT();
 | 
			
		||||
			_num_filled -= 1;
 | 
			
		||||
			return true;
 | 
			
		||||
		} else {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Erase an element using an iterator.
 | 
			
		||||
	/// Returns an iterator to the next element (or end()).
 | 
			
		||||
	iterator erase(iterator it)
 | 
			
		||||
	{
 | 
			
		||||
		DCHECK_EQ_F(it._map, this);
 | 
			
		||||
		DCHECK_LT_F(it._bucket, _num_buckets);
 | 
			
		||||
		_states[it._bucket] = State::ACTIVE;
 | 
			
		||||
		_pairs[it._bucket].~PairT();
 | 
			
		||||
		_num_filled -= 1;
 | 
			
		||||
		return ++it;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Remove all elements, keeping full capacity.
 | 
			
		||||
	void clear()
 | 
			
		||||
	{
 | 
			
		||||
		for (size_t bucket=0; bucket<_num_buckets; ++bucket) {
 | 
			
		||||
			if (_states[bucket] == State::FILLED) {
 | 
			
		||||
				_states[bucket] = State::INACTIVE;
 | 
			
		||||
				_pairs[bucket].~PairT();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		_num_filled = 0;
 | 
			
		||||
		_max_probe_length = -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Make room for this many elements
 | 
			
		||||
	void reserve(size_t num_elems)
 | 
			
		||||
	{
 | 
			
		||||
		size_t required_buckets = num_elems + num_elems/2 + 1;
 | 
			
		||||
		if (required_buckets <= _num_buckets) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		size_t num_buckets = 4;
 | 
			
		||||
		while (num_buckets < required_buckets) { num_buckets *= 2; }
 | 
			
		||||
 | 
			
		||||
		auto new_states = (State*)malloc(num_buckets * sizeof(State));
 | 
			
		||||
		auto new_pairs  = (PairT*)malloc(num_buckets * sizeof(PairT));
 | 
			
		||||
 | 
			
		||||
		if (!new_states || !new_pairs) {
 | 
			
		||||
			free(new_states);
 | 
			
		||||
			free(new_pairs);
 | 
			
		||||
			throw std::bad_alloc();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//auto old_num_filled  = _num_filled;
 | 
			
		||||
		auto old_num_buckets = _num_buckets;
 | 
			
		||||
		auto old_states      = _states;
 | 
			
		||||
		auto old_pairs       = _pairs;
 | 
			
		||||
 | 
			
		||||
		_num_filled  = 0;
 | 
			
		||||
		_num_buckets = num_buckets;
 | 
			
		||||
		_mask        = _num_buckets - 1;
 | 
			
		||||
		_states      = new_states;
 | 
			
		||||
		_pairs       = new_pairs;
 | 
			
		||||
 | 
			
		||||
		std::fill_n(_states, num_buckets, State::INACTIVE);
 | 
			
		||||
 | 
			
		||||
		_max_probe_length = -1;
 | 
			
		||||
 | 
			
		||||
		for (size_t src_bucket=0; src_bucket<old_num_buckets; src_bucket++) {
 | 
			
		||||
			if (old_states[src_bucket] == State::FILLED) {
 | 
			
		||||
				auto& src_pair = old_pairs[src_bucket];
 | 
			
		||||
 | 
			
		||||
				auto dst_bucket = find_empty_bucket(src_pair.first);
 | 
			
		||||
				DCHECK_NE_F(dst_bucket, (size_t)-1);
 | 
			
		||||
				DCHECK_NE_F(_states[dst_bucket], State::FILLED);
 | 
			
		||||
				_states[dst_bucket] = State::FILLED;
 | 
			
		||||
				new(_pairs + dst_bucket) PairT(std::move(src_pair));
 | 
			
		||||
				_num_filled += 1;
 | 
			
		||||
 | 
			
		||||
				src_pair.~PairT();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//DCHECK_EQ_F(old_num_filled, _num_filled);
 | 
			
		||||
 | 
			
		||||
		free(old_states);
 | 
			
		||||
		free(old_pairs);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	// Can we fit another element?
 | 
			
		||||
	void check_expand_need()
 | 
			
		||||
	{
 | 
			
		||||
		reserve(_num_filled + 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Find the bucket with this key, or return (size_t)-1
 | 
			
		||||
	template<typename KeyLike>
 | 
			
		||||
	size_t find_filled_bucket(const KeyLike& key) const
 | 
			
		||||
	{
 | 
			
		||||
		if (empty()) { return (size_t)-1; } // Optimization
 | 
			
		||||
 | 
			
		||||
		auto hash_value = _hasher(key);
 | 
			
		||||
		for (int offset=0; offset<=_max_probe_length; ++offset) {
 | 
			
		||||
			auto bucket = (hash_value + offset) & _mask;
 | 
			
		||||
			if (_states[bucket] == State::FILLED) {
 | 
			
		||||
				if (_eq(_pairs[bucket].first, key)) {
 | 
			
		||||
					return bucket;
 | 
			
		||||
				}
 | 
			
		||||
			} else if (_states[bucket] == State::INACTIVE) {
 | 
			
		||||
				return (size_t)-1; // End of the chain!
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return (size_t)-1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Find the bucket with this key, or return a good empty bucket to place the key in.
 | 
			
		||||
	// In the latter case, the bucket is expected to be filled.
 | 
			
		||||
	size_t find_or_allocate(const KeyT& key)
 | 
			
		||||
	{
 | 
			
		||||
		auto hash_value = _hasher(key);
 | 
			
		||||
		size_t hole = (size_t)-1;
 | 
			
		||||
		int offset=0;
 | 
			
		||||
		for (; offset<=_max_probe_length; ++offset) {
 | 
			
		||||
			auto bucket = (hash_value + offset) & _mask;
 | 
			
		||||
 | 
			
		||||
			if (_states[bucket] == State::FILLED) {
 | 
			
		||||
				if (_eq(_pairs[bucket].first, key)) {
 | 
			
		||||
					return bucket;
 | 
			
		||||
				}
 | 
			
		||||
			} else if (_states[bucket] == State::INACTIVE) {
 | 
			
		||||
				return bucket;
 | 
			
		||||
			} else {
 | 
			
		||||
				// ACTIVE: keep searching
 | 
			
		||||
				if (hole == (size_t)-1) {
 | 
			
		||||
					hole = bucket;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// No key found - but maybe a hole for it
 | 
			
		||||
 | 
			
		||||
		DCHECK_EQ_F(offset, _max_probe_length+1);
 | 
			
		||||
 | 
			
		||||
		if (hole != (size_t)-1) {
 | 
			
		||||
			return hole;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// No hole found within _max_probe_length
 | 
			
		||||
		for (; ; ++offset) {
 | 
			
		||||
			auto bucket = (hash_value + offset) & _mask;
 | 
			
		||||
 | 
			
		||||
			if (_states[bucket] != State::FILLED) {
 | 
			
		||||
				_max_probe_length = offset;
 | 
			
		||||
				return bucket;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// key is not in this map. Find a place to put it.
 | 
			
		||||
	size_t find_empty_bucket(const KeyT& key)
 | 
			
		||||
	{
 | 
			
		||||
		auto hash_value = _hasher(key);
 | 
			
		||||
		for (int offset=0; ; ++offset) {
 | 
			
		||||
			auto bucket = (hash_value + offset) & _mask;
 | 
			
		||||
			if (_states[bucket] != State::FILLED) {
 | 
			
		||||
				if (offset > _max_probe_length) {
 | 
			
		||||
					_max_probe_length = offset;
 | 
			
		||||
				}
 | 
			
		||||
				return bucket;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	enum class State : uint8_t
 | 
			
		||||
	{
 | 
			
		||||
		INACTIVE, // Never been touched
 | 
			
		||||
		ACTIVE,   // Is inside a search-chain, but is empty
 | 
			
		||||
		FILLED    // Is set with key/value
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	HashT   _hasher;
 | 
			
		||||
	EqT     _eq;
 | 
			
		||||
	State*  _states           = nullptr;
 | 
			
		||||
	PairT*  _pairs            = nullptr;
 | 
			
		||||
	size_t  _num_buckets      =  0;
 | 
			
		||||
	size_t  _num_filled       =  0;
 | 
			
		||||
	int     _max_probe_length = -1; // Our longest bucket-brigade is this long. ONLY when we have zero elements is this ever negative (-1).
 | 
			
		||||
	size_t  _mask             = 0;  // _num_buckets minus one
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace emilib
 | 
			
		||||
							
								
								
									
										1787
									
								
								src/includes/3thparty/emilib/loguru.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1787
									
								
								src/includes/3thparty/emilib/loguru.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1324
									
								
								src/includes/3thparty/emilib/loguru.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1324
									
								
								src/includes/3thparty/emilib/loguru.hpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4063
									
								
								src/includes/3thparty/parallel_hashmap/btree.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4063
									
								
								src/includes/3thparty/parallel_hashmap/btree.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										36
									
								
								src/includes/3thparty/parallel_hashmap/conanfile.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/includes/3thparty/parallel_hashmap/conanfile.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
from conans import ConanFile, tools
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
class SparseppConan(ConanFile):
 | 
			
		||||
    name = "parallel_hashmap"
 | 
			
		||||
    version = "1.27"
 | 
			
		||||
    description = "A header-only, very fast and memory-friendly hash map"
 | 
			
		||||
    
 | 
			
		||||
    # Indicates License type of the packaged library
 | 
			
		||||
    license = "https://github.com/greg7mdp/parallel-hashmap/blob/master/LICENSE"
 | 
			
		||||
    
 | 
			
		||||
    # Packages the license for the conanfile.py
 | 
			
		||||
    exports = ["LICENSE"]
 | 
			
		||||
    
 | 
			
		||||
    # Custom attributes for Bincrafters recipe conventions
 | 
			
		||||
    source_subfolder = "source_subfolder"
 | 
			
		||||
    
 | 
			
		||||
    def source(self):
 | 
			
		||||
        source_url = "https://github.com/greg7mdp/parallel-hashmap"
 | 
			
		||||
        tools.get("{0}/archive/{1}.tar.gz".format(source_url, self.version))
 | 
			
		||||
        extracted_dir = self.name + "-" + self.version
 | 
			
		||||
 | 
			
		||||
        #Rename to "source_folder" is a convention to simplify later steps
 | 
			
		||||
        os.rename(extracted_dir, self.source_subfolder)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def package(self):
 | 
			
		||||
        include_folder = os.path.join(self.source_subfolder, "parallel_hashmap")
 | 
			
		||||
        self.copy(pattern="LICENSE")
 | 
			
		||||
        self.copy(pattern="*", dst="include/parallel_hashmap", src=include_folder)
 | 
			
		||||
 | 
			
		||||
    def package_id(self):
 | 
			
		||||
        self.info.header_only()
 | 
			
		||||
							
								
								
									
										195
									
								
								src/includes/3thparty/parallel_hashmap/meminfo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								src/includes/3thparty/parallel_hashmap/meminfo.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,195 @@
 | 
			
		||||
#if !defined(spp_memory_h_guard)
 | 
			
		||||
#define spp_memory_h_guard
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) || defined( __CYGWIN__)
 | 
			
		||||
    #define SPP_WIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef SPP_WIN
 | 
			
		||||
    #include <windows.h>
 | 
			
		||||
    #include <Psapi.h>
 | 
			
		||||
    #undef min
 | 
			
		||||
    #undef max
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
    #include <sys/types.h>
 | 
			
		||||
    #include <sys/sysinfo.h>
 | 
			
		||||
#elif defined(__FreeBSD__)
 | 
			
		||||
    #include <paths.h>
 | 
			
		||||
    #include <fcntl.h>
 | 
			
		||||
    #include <kvm.h>
 | 
			
		||||
    #include <unistd.h>
 | 
			
		||||
    #include <sys/sysctl.h>
 | 
			
		||||
    #include <sys/user.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace spp
 | 
			
		||||
{
 | 
			
		||||
    uint64_t GetSystemMemory();
 | 
			
		||||
    uint64_t GetTotalMemoryUsed();
 | 
			
		||||
    uint64_t GetProcessMemoryUsed();
 | 
			
		||||
    uint64_t GetPhysicalMemory();
 | 
			
		||||
 | 
			
		||||
    uint64_t GetSystemMemory()
 | 
			
		||||
    {
 | 
			
		||||
#ifdef SPP_WIN
 | 
			
		||||
        MEMORYSTATUSEX memInfo;
 | 
			
		||||
        memInfo.dwLength = sizeof(MEMORYSTATUSEX);
 | 
			
		||||
        GlobalMemoryStatusEx(&memInfo);
 | 
			
		||||
        return static_cast<uint64_t>(memInfo.ullTotalPageFile);
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
        struct sysinfo memInfo;
 | 
			
		||||
        sysinfo (&memInfo);
 | 
			
		||||
        auto totalVirtualMem = memInfo.totalram;
 | 
			
		||||
 | 
			
		||||
        totalVirtualMem += memInfo.totalswap;
 | 
			
		||||
        totalVirtualMem *= memInfo.mem_unit;
 | 
			
		||||
        return static_cast<uint64_t>(totalVirtualMem);
 | 
			
		||||
#elif defined(__FreeBSD__)
 | 
			
		||||
        kvm_t *kd;
 | 
			
		||||
        u_int pageCnt;
 | 
			
		||||
        size_t pageCntLen = sizeof(pageCnt);
 | 
			
		||||
        u_int pageSize;
 | 
			
		||||
        struct kvm_swap kswap;
 | 
			
		||||
        uint64_t totalVirtualMem;
 | 
			
		||||
 | 
			
		||||
        pageSize = static_cast<u_int>(getpagesize());
 | 
			
		||||
 | 
			
		||||
        sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0);
 | 
			
		||||
        totalVirtualMem = pageCnt * pageSize;
 | 
			
		||||
 | 
			
		||||
        kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
 | 
			
		||||
        kvm_getswapinfo(kd, &kswap, 1, 0);
 | 
			
		||||
        kvm_close(kd);
 | 
			
		||||
        totalVirtualMem += kswap.ksw_total * pageSize;
 | 
			
		||||
 | 
			
		||||
        return totalVirtualMem;
 | 
			
		||||
#else
 | 
			
		||||
        return 0;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint64_t GetTotalMemoryUsed()
 | 
			
		||||
    {
 | 
			
		||||
#ifdef SPP_WIN
 | 
			
		||||
        MEMORYSTATUSEX memInfo;
 | 
			
		||||
        memInfo.dwLength = sizeof(MEMORYSTATUSEX);
 | 
			
		||||
        GlobalMemoryStatusEx(&memInfo);
 | 
			
		||||
        return static_cast<uint64_t>(memInfo.ullTotalPageFile - memInfo.ullAvailPageFile);
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
        struct sysinfo memInfo;
 | 
			
		||||
        sysinfo(&memInfo);
 | 
			
		||||
        auto virtualMemUsed = memInfo.totalram - memInfo.freeram;
 | 
			
		||||
 | 
			
		||||
        virtualMemUsed += memInfo.totalswap - memInfo.freeswap;
 | 
			
		||||
        virtualMemUsed *= memInfo.mem_unit;
 | 
			
		||||
 | 
			
		||||
        return static_cast<uint64_t>(virtualMemUsed);
 | 
			
		||||
#elif defined(__FreeBSD__)
 | 
			
		||||
        kvm_t *kd;
 | 
			
		||||
        u_int pageSize;
 | 
			
		||||
        u_int pageCnt, freeCnt;
 | 
			
		||||
        size_t pageCntLen = sizeof(pageCnt);
 | 
			
		||||
        size_t freeCntLen = sizeof(freeCnt);
 | 
			
		||||
        struct kvm_swap kswap;
 | 
			
		||||
        uint64_t virtualMemUsed;
 | 
			
		||||
 | 
			
		||||
        pageSize = static_cast<u_int>(getpagesize());
 | 
			
		||||
 | 
			
		||||
        sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0);
 | 
			
		||||
        sysctlbyname("vm.stats.vm.v_free_count", &freeCnt, &freeCntLen, NULL, 0);
 | 
			
		||||
        virtualMemUsed = (pageCnt - freeCnt) * pageSize;
 | 
			
		||||
 | 
			
		||||
        kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
 | 
			
		||||
        kvm_getswapinfo(kd, &kswap, 1, 0);
 | 
			
		||||
        kvm_close(kd);
 | 
			
		||||
        virtualMemUsed += kswap.ksw_used * pageSize;
 | 
			
		||||
 | 
			
		||||
        return virtualMemUsed;
 | 
			
		||||
#else
 | 
			
		||||
        return 0;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint64_t GetProcessMemoryUsed()
 | 
			
		||||
    {
 | 
			
		||||
#ifdef SPP_WIN
 | 
			
		||||
        PROCESS_MEMORY_COUNTERS_EX pmc;
 | 
			
		||||
        GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PPROCESS_MEMORY_COUNTERS>(&pmc), sizeof(pmc));
 | 
			
		||||
        return static_cast<uint64_t>(pmc.PrivateUsage);
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
        auto parseLine = 
 | 
			
		||||
            [](char* line)->int
 | 
			
		||||
            {
 | 
			
		||||
                auto i = strlen(line);
 | 
			
		||||
				
 | 
			
		||||
                while(*line < '0' || *line > '9') 
 | 
			
		||||
                {
 | 
			
		||||
                    line++;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                line[i-3] = '\0';
 | 
			
		||||
                i = atoi(line);
 | 
			
		||||
                return i;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        auto file = fopen("/proc/self/status", "r");
 | 
			
		||||
        auto result = -1;
 | 
			
		||||
        char line[128];
 | 
			
		||||
 | 
			
		||||
        while(fgets(line, 128, file) != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            if(strncmp(line, "VmSize:", 7) == 0)
 | 
			
		||||
            {
 | 
			
		||||
                result = parseLine(line);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fclose(file);
 | 
			
		||||
        return static_cast<uint64_t>(result) * 1024;
 | 
			
		||||
#elif defined(__FreeBSD__)
 | 
			
		||||
        struct kinfo_proc info;
 | 
			
		||||
        size_t infoLen = sizeof(info);
 | 
			
		||||
        int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
 | 
			
		||||
 | 
			
		||||
        sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &infoLen, NULL, 0);
 | 
			
		||||
        return static_cast<uint64_t>(info.ki_rssize * getpagesize());
 | 
			
		||||
#else
 | 
			
		||||
        return 0;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint64_t GetPhysicalMemory()
 | 
			
		||||
    {
 | 
			
		||||
#ifdef SPP_WIN
 | 
			
		||||
        MEMORYSTATUSEX memInfo;
 | 
			
		||||
        memInfo.dwLength = sizeof(MEMORYSTATUSEX);
 | 
			
		||||
        GlobalMemoryStatusEx(&memInfo);
 | 
			
		||||
        return static_cast<uint64_t>(memInfo.ullTotalPhys);
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
        struct sysinfo memInfo;
 | 
			
		||||
        sysinfo(&memInfo);
 | 
			
		||||
 | 
			
		||||
        auto totalPhysMem = memInfo.totalram;
 | 
			
		||||
 | 
			
		||||
        totalPhysMem *= memInfo.mem_unit;
 | 
			
		||||
        return static_cast<uint64_t>(totalPhysMem);
 | 
			
		||||
#elif defined(__FreeBSD__)
 | 
			
		||||
        u_long physMem;
 | 
			
		||||
        size_t physMemLen = sizeof(physMem);
 | 
			
		||||
        int mib[] = { CTL_HW, HW_PHYSMEM };
 | 
			
		||||
 | 
			
		||||
        sysctl(mib, sizeof(mib) / sizeof(*mib), &physMem, &physMemLen, NULL, 0);
 | 
			
		||||
        return physMem;
 | 
			
		||||
#else
 | 
			
		||||
        return 0;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // spp_memory_h_guard
 | 
			
		||||
							
								
								
									
										4382
									
								
								src/includes/3thparty/parallel_hashmap/phmap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4382
									
								
								src/includes/3thparty/parallel_hashmap/phmap.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5167
									
								
								src/includes/3thparty/parallel_hashmap/phmap_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5167
									
								
								src/includes/3thparty/parallel_hashmap/phmap_base.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										663
									
								
								src/includes/3thparty/parallel_hashmap/phmap_bits.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										663
									
								
								src/includes/3thparty/parallel_hashmap/phmap_bits.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,663 @@
 | 
			
		||||
#if !defined(phmap_bits_h_guard_)
 | 
			
		||||
#define phmap_bits_h_guard_
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
//
 | 
			
		||||
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
 | 
			
		||||
// with modifications.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright 2018 The Abseil Authors.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// The following guarantees declaration of the byte swap functions
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
    #include <stdlib.h>  // NOLINT(build/include)
 | 
			
		||||
#elif defined(__APPLE__)
 | 
			
		||||
    // Mac OS X / Darwin features
 | 
			
		||||
    #include <libkern/OSByteOrder.h>
 | 
			
		||||
#elif defined(__FreeBSD__)
 | 
			
		||||
    #include <sys/endian.h>
 | 
			
		||||
#elif defined(__GLIBC__)
 | 
			
		||||
    #include <byteswap.h>  // IWYU pragma: export
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include "phmap_config.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
    #pragma warning(push)  
 | 
			
		||||
    #pragma warning(disable : 4514) // unreferenced inline function has been removed
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// unaligned APIs
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// Portable handling of unaligned loads, stores, and copies.
 | 
			
		||||
// On some platforms, like ARM, the copy functions can be more efficient
 | 
			
		||||
// then a load and a store.
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
 | 
			
		||||
    defined(MEMORY_SANITIZER)
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
    uint16_t __sanitizer_unaligned_load16(const void *p);
 | 
			
		||||
    uint32_t __sanitizer_unaligned_load32(const void *p);
 | 
			
		||||
    uint64_t __sanitizer_unaligned_load64(const void *p);
 | 
			
		||||
    void __sanitizer_unaligned_store16(void *p, uint16_t v);
 | 
			
		||||
    void __sanitizer_unaligned_store32(void *p, uint32_t v);
 | 
			
		||||
    void __sanitizer_unaligned_store64(void *p, uint64_t v);
 | 
			
		||||
}  // extern "C"
 | 
			
		||||
 | 
			
		||||
namespace phmap {
 | 
			
		||||
namespace bits {
 | 
			
		||||
 | 
			
		||||
inline uint16_t UnalignedLoad16(const void *p) {
 | 
			
		||||
  return __sanitizer_unaligned_load16(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint32_t UnalignedLoad32(const void *p) {
 | 
			
		||||
  return __sanitizer_unaligned_load32(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint64_t UnalignedLoad64(const void *p) {
 | 
			
		||||
  return __sanitizer_unaligned_load64(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void UnalignedStore16(void *p, uint16_t v) {
 | 
			
		||||
  __sanitizer_unaligned_store16(p, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void UnalignedStore32(void *p, uint32_t v) {
 | 
			
		||||
  __sanitizer_unaligned_store32(p, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void UnalignedStore64(void *p, uint64_t v) {
 | 
			
		||||
  __sanitizer_unaligned_store64(p, v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace bits
 | 
			
		||||
}  // namespace phmap
 | 
			
		||||
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) (phmap::bits::UnalignedLoad16(_p))
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) (phmap::bits::UnalignedLoad32(_p))
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) (phmap::bits::UnalignedLoad64(_p))
 | 
			
		||||
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) (phmap::bits::UnalignedStore16(_p, _val))
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) (phmap::bits::UnalignedStore32(_p, _val))
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) (phmap::bits::UnalignedStore64(_p, _val))
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
namespace phmap {
 | 
			
		||||
namespace bits {
 | 
			
		||||
 | 
			
		||||
inline uint16_t UnalignedLoad16(const void *p) {
 | 
			
		||||
  uint16_t t;
 | 
			
		||||
  memcpy(&t, p, sizeof t);
 | 
			
		||||
  return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint32_t UnalignedLoad32(const void *p) {
 | 
			
		||||
  uint32_t t;
 | 
			
		||||
  memcpy(&t, p, sizeof t);
 | 
			
		||||
  return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint64_t UnalignedLoad64(const void *p) {
 | 
			
		||||
  uint64_t t;
 | 
			
		||||
  memcpy(&t, p, sizeof t);
 | 
			
		||||
  return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
 | 
			
		||||
 | 
			
		||||
inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
 | 
			
		||||
 | 
			
		||||
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
 | 
			
		||||
 | 
			
		||||
}  // namespace bits
 | 
			
		||||
}  // namespace phmap
 | 
			
		||||
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) (phmap::bits::UnalignedLoad16(_p))
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) (phmap::bits::UnalignedLoad32(_p))
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) (phmap::bits::UnalignedLoad64(_p))
 | 
			
		||||
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) (phmap::bits::UnalignedStore16(_p, _val))
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) (phmap::bits::UnalignedStore32(_p, _val))
 | 
			
		||||
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) (phmap::bits::UnalignedStore64(_p, _val))
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// File: optimization.h
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#if defined(__pnacl__)
 | 
			
		||||
    #define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
 | 
			
		||||
#elif defined(__clang__)
 | 
			
		||||
    // Clang will not tail call given inline volatile assembly.
 | 
			
		||||
    #define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
    // GCC will not tail call given inline volatile assembly.
 | 
			
		||||
    #define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
    #include <intrin.h>
 | 
			
		||||
    // The __nop() intrinsic blocks the optimisation.
 | 
			
		||||
    #define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__)
 | 
			
		||||
    #pragma GCC diagnostic push
 | 
			
		||||
    #pragma GCC diagnostic ignored "-Wpedantic"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PHMAP_HAVE_INTRINSIC_INT128
 | 
			
		||||
    __extension__ typedef unsigned __int128 phmap_uint128;
 | 
			
		||||
    inline uint64_t umul128(uint64_t a, uint64_t b, uint64_t* high) 
 | 
			
		||||
    {
 | 
			
		||||
        auto result = static_cast<phmap_uint128>(a) * static_cast<phmap_uint128>(b);
 | 
			
		||||
        *high = static_cast<uint64_t>(result >> 64);
 | 
			
		||||
        return static_cast<uint64_t>(result);
 | 
			
		||||
    }
 | 
			
		||||
    #define PHMAP_HAS_UMUL128 1
 | 
			
		||||
#elif (defined(_MSC_VER))
 | 
			
		||||
    #if defined(_M_X64)
 | 
			
		||||
        #pragma intrinsic(_umul128)
 | 
			
		||||
        inline uint64_t umul128(uint64_t a, uint64_t b, uint64_t* high) 
 | 
			
		||||
        {
 | 
			
		||||
            return _umul128(a, b, high);
 | 
			
		||||
        }
 | 
			
		||||
        #define PHMAP_HAS_UMUL128 1
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__)
 | 
			
		||||
    #pragma GCC diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__)
 | 
			
		||||
    // Cache line alignment
 | 
			
		||||
    #if defined(__i386__) || defined(__x86_64__)
 | 
			
		||||
        #define PHMAP_CACHELINE_SIZE 64
 | 
			
		||||
    #elif defined(__powerpc64__)
 | 
			
		||||
        #define PHMAP_CACHELINE_SIZE 128
 | 
			
		||||
    #elif defined(__aarch64__)
 | 
			
		||||
        // We would need to read special register ctr_el0 to find out L1 dcache size.
 | 
			
		||||
        // This value is a good estimate based on a real aarch64 machine.
 | 
			
		||||
        #define PHMAP_CACHELINE_SIZE 64
 | 
			
		||||
    #elif defined(__arm__)
 | 
			
		||||
        // Cache line sizes for ARM: These values are not strictly correct since
 | 
			
		||||
        // cache line sizes depend on implementations, not architectures.  There
 | 
			
		||||
        // are even implementations with cache line sizes configurable at boot
 | 
			
		||||
        // time.
 | 
			
		||||
        #if defined(__ARM_ARCH_5T__)
 | 
			
		||||
            #define PHMAP_CACHELINE_SIZE 32
 | 
			
		||||
        #elif defined(__ARM_ARCH_7A__)
 | 
			
		||||
            #define PHMAP_CACHELINE_SIZE 64
 | 
			
		||||
        #endif
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    #ifndef PHMAP_CACHELINE_SIZE
 | 
			
		||||
        // A reasonable default guess.  Note that overestimates tend to waste more
 | 
			
		||||
        // space, while underestimates tend to waste more time.
 | 
			
		||||
        #define PHMAP_CACHELINE_SIZE 64
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    #define PHMAP_CACHELINE_ALIGNED __attribute__((aligned(PHMAP_CACHELINE_SIZE)))
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
    #define PHMAP_CACHELINE_SIZE 64
 | 
			
		||||
    #define PHMAP_CACHELINE_ALIGNED __declspec(align(PHMAP_CACHELINE_SIZE))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_CACHELINE_SIZE 64
 | 
			
		||||
    #define PHMAP_CACHELINE_ALIGNED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_BUILTIN(__builtin_expect) || \
 | 
			
		||||
    (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_PREDICT_FALSE(x) (__builtin_expect(x, 0))
 | 
			
		||||
    #define PHMAP_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_PREDICT_FALSE(x) (x)
 | 
			
		||||
    #define PHMAP_PREDICT_TRUE(x) (x)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// File: bits.h
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
    // We can achieve something similar to attribute((always_inline)) with MSVC by
 | 
			
		||||
    // using the __forceinline keyword, however this is not perfect. MSVC is
 | 
			
		||||
    // much less aggressive about inlining, and even with the __forceinline keyword.
 | 
			
		||||
    #define PHMAP_BASE_INTERNAL_FORCEINLINE __forceinline
 | 
			
		||||
#else
 | 
			
		||||
    // Use default attribute inline.
 | 
			
		||||
    #define PHMAP_BASE_INTERNAL_FORCEINLINE inline PHMAP_ATTRIBUTE_ALWAYS_INLINE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace phmap {
 | 
			
		||||
namespace base_internal {
 | 
			
		||||
 | 
			
		||||
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
 | 
			
		||||
    int zeroes = 60;
 | 
			
		||||
    if (n >> 32) zeroes -= 32, n >>= 32;
 | 
			
		||||
    if (n >> 16) zeroes -= 16, n >>= 16;
 | 
			
		||||
    if (n >> 8) zeroes -= 8, n >>= 8;
 | 
			
		||||
    if (n >> 4) zeroes -= 4, n >>= 4;
 | 
			
		||||
    return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
 | 
			
		||||
#if defined(_MSC_VER) && defined(_M_X64)
 | 
			
		||||
    // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
 | 
			
		||||
    unsigned long result = 0;  // NOLINT(runtime/int)
 | 
			
		||||
    if (_BitScanReverse64(&result, n)) {
 | 
			
		||||
        return (int)(63 - result);
 | 
			
		||||
    }
 | 
			
		||||
    return 64;
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
    // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
 | 
			
		||||
    unsigned long result = 0;  // NOLINT(runtime/int)
 | 
			
		||||
    if ((n >> 32) && _BitScanReverse(&result, (unsigned long)(n >> 32))) {
 | 
			
		||||
        return 31 - result;
 | 
			
		||||
    }
 | 
			
		||||
    if (_BitScanReverse(&result, (unsigned long)n)) {
 | 
			
		||||
        return 63 - result;
 | 
			
		||||
    }
 | 
			
		||||
    return 64;
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
    // Use __builtin_clzll, which uses the following instructions:
 | 
			
		||||
    //  x86: bsr
 | 
			
		||||
    //  ARM64: clz
 | 
			
		||||
    //  PPC: cntlzd
 | 
			
		||||
    static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
 | 
			
		||||
                  "__builtin_clzll does not take 64-bit arg");
 | 
			
		||||
 | 
			
		||||
    // Handle 0 as a special case because __builtin_clzll(0) is undefined.
 | 
			
		||||
    if (n == 0) {
 | 
			
		||||
        return 64;
 | 
			
		||||
    }
 | 
			
		||||
    return __builtin_clzll(n);
 | 
			
		||||
#else
 | 
			
		||||
    return CountLeadingZeros64Slow(n);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
 | 
			
		||||
    int zeroes = 28;
 | 
			
		||||
    if (n >> 16) zeroes -= 16, n >>= 16;
 | 
			
		||||
    if (n >> 8) zeroes -= 8, n >>= 8;
 | 
			
		||||
    if (n >> 4) zeroes -= 4, n >>= 4;
 | 
			
		||||
    return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
    unsigned long result = 0;  // NOLINT(runtime/int)
 | 
			
		||||
    if (_BitScanReverse(&result, n)) {
 | 
			
		||||
        return (int)(31 - result);
 | 
			
		||||
    }
 | 
			
		||||
    return 32;
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
    // Use __builtin_clz, which uses the following instructions:
 | 
			
		||||
    //  x86: bsr
 | 
			
		||||
    //  ARM64: clz
 | 
			
		||||
    //  PPC: cntlzd
 | 
			
		||||
    static_assert(sizeof(int) == sizeof(n),
 | 
			
		||||
                  "__builtin_clz does not take 32-bit arg");
 | 
			
		||||
 | 
			
		||||
    // Handle 0 as a special case because __builtin_clz(0) is undefined.
 | 
			
		||||
    if (n == 0) {
 | 
			
		||||
        return 32;
 | 
			
		||||
    }
 | 
			
		||||
    return __builtin_clz(n);
 | 
			
		||||
#else
 | 
			
		||||
    return CountLeadingZeros32Slow(n);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PHMAP_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
 | 
			
		||||
    int c = 63;
 | 
			
		||||
    n &= ~n + 1;
 | 
			
		||||
    if (n & 0x00000000FFFFFFFF) c -= 32;
 | 
			
		||||
    if (n & 0x0000FFFF0000FFFF) c -= 16;
 | 
			
		||||
    if (n & 0x00FF00FF00FF00FF) c -= 8;
 | 
			
		||||
    if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
 | 
			
		||||
    if (n & 0x3333333333333333) c -= 2;
 | 
			
		||||
    if (n & 0x5555555555555555) c -= 1;
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PHMAP_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
 | 
			
		||||
#if defined(_MSC_VER) && defined(_M_X64)
 | 
			
		||||
    unsigned long result = 0;  // NOLINT(runtime/int)
 | 
			
		||||
    _BitScanForward64(&result, n);
 | 
			
		||||
    return (int)result;
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
    unsigned long result = 0;  // NOLINT(runtime/int)
 | 
			
		||||
    if (static_cast<uint32_t>(n) == 0) {
 | 
			
		||||
        _BitScanForward(&result, (unsigned long)(n >> 32));
 | 
			
		||||
        return result + 32;
 | 
			
		||||
    }
 | 
			
		||||
    _BitScanForward(&result, (unsigned long)n);
 | 
			
		||||
    return result;
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
    static_assert(sizeof(unsigned long long) == sizeof(n),  // NOLINT(runtime/int)
 | 
			
		||||
                  "__builtin_ctzll does not take 64-bit arg");
 | 
			
		||||
    return __builtin_ctzll(n);
 | 
			
		||||
#else
 | 
			
		||||
    return CountTrailingZerosNonZero64Slow(n);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PHMAP_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
 | 
			
		||||
    int c = 31;
 | 
			
		||||
    n &= ~n + 1;
 | 
			
		||||
    if (n & 0x0000FFFF) c -= 16;
 | 
			
		||||
    if (n & 0x00FF00FF) c -= 8;
 | 
			
		||||
    if (n & 0x0F0F0F0F) c -= 4;
 | 
			
		||||
    if (n & 0x33333333) c -= 2;
 | 
			
		||||
    if (n & 0x55555555) c -= 1;
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PHMAP_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
    unsigned long result = 0;  // NOLINT(runtime/int)
 | 
			
		||||
    _BitScanForward(&result, n);
 | 
			
		||||
    return (int)result;
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
    static_assert(sizeof(int) == sizeof(n),
 | 
			
		||||
                  "__builtin_ctz does not take 32-bit arg");
 | 
			
		||||
    return __builtin_ctz(n);
 | 
			
		||||
#else
 | 
			
		||||
    return CountTrailingZerosNonZero32Slow(n);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#undef PHMAP_BASE_INTERNAL_FORCEINLINE
 | 
			
		||||
 | 
			
		||||
}  // namespace base_internal
 | 
			
		||||
}  // namespace phmap
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// File: endian.h
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
namespace phmap {
 | 
			
		||||
 | 
			
		||||
// Use compiler byte-swapping intrinsics if they are available.  32-bit
 | 
			
		||||
// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
 | 
			
		||||
// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
 | 
			
		||||
// For simplicity, we enable them all only for GCC 4.8.0 or later.
 | 
			
		||||
#if defined(__clang__) || \
 | 
			
		||||
    (defined(__GNUC__) && \
 | 
			
		||||
     ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
 | 
			
		||||
 | 
			
		||||
    inline uint64_t gbswap_64(uint64_t host_int) {
 | 
			
		||||
        return __builtin_bswap64(host_int);
 | 
			
		||||
    }
 | 
			
		||||
    inline uint32_t gbswap_32(uint32_t host_int) {
 | 
			
		||||
        return __builtin_bswap32(host_int);
 | 
			
		||||
    }
 | 
			
		||||
    inline uint16_t gbswap_16(uint16_t host_int) {
 | 
			
		||||
        return __builtin_bswap16(host_int);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
 | 
			
		||||
    inline uint64_t gbswap_64(uint64_t host_int) {
 | 
			
		||||
        return _byteswap_uint64(host_int);
 | 
			
		||||
    }
 | 
			
		||||
    inline uint32_t gbswap_32(uint32_t host_int) {
 | 
			
		||||
        return _byteswap_ulong(host_int);
 | 
			
		||||
    }
 | 
			
		||||
    inline uint16_t gbswap_16(uint16_t host_int) {
 | 
			
		||||
        return _byteswap_ushort(host_int);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#elif defined(__APPLE__)
 | 
			
		||||
 | 
			
		||||
    inline uint64_t gbswap_64(uint64_t host_int) { return OSSwapInt16(host_int); }
 | 
			
		||||
    inline uint32_t gbswap_32(uint32_t host_int) { return OSSwapInt32(host_int); }
 | 
			
		||||
    inline uint16_t gbswap_16(uint16_t host_int) { return OSSwapInt64(host_int); }
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
    inline uint64_t gbswap_64(uint64_t host_int) {
 | 
			
		||||
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__)
 | 
			
		||||
        // Adapted from /usr/include/byteswap.h.  Not available on Mac.
 | 
			
		||||
        if (__builtin_constant_p(host_int)) {
 | 
			
		||||
            return __bswap_constant_64(host_int);
 | 
			
		||||
        } else {
 | 
			
		||||
            uint64_t result;
 | 
			
		||||
            __asm__("bswap %0" : "=r"(result) : "0"(host_int));
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
#elif defined(__GLIBC__)
 | 
			
		||||
        return bswap_64(host_int);
 | 
			
		||||
#else
 | 
			
		||||
        return (((host_int & uint64_t{0xFF}) << 56) |
 | 
			
		||||
                ((host_int & uint64_t{0xFF00}) << 40) |
 | 
			
		||||
                ((host_int & uint64_t{0xFF0000}) << 24) |
 | 
			
		||||
                ((host_int & uint64_t{0xFF000000}) << 8) |
 | 
			
		||||
                ((host_int & uint64_t{0xFF00000000}) >> 8) |
 | 
			
		||||
                ((host_int & uint64_t{0xFF0000000000}) >> 24) |
 | 
			
		||||
                ((host_int & uint64_t{0xFF000000000000}) >> 40) |
 | 
			
		||||
                ((host_int & uint64_t{0xFF00000000000000}) >> 56));
 | 
			
		||||
#endif  // bswap_64
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline uint32_t gbswap_32(uint32_t host_int) {
 | 
			
		||||
#if defined(__GLIBC__)
 | 
			
		||||
        return bswap_32(host_int);
 | 
			
		||||
#else
 | 
			
		||||
        return (((host_int & uint32_t{0xFF}) << 24) |
 | 
			
		||||
                ((host_int & uint32_t{0xFF00}) << 8) |
 | 
			
		||||
                ((host_int & uint32_t{0xFF0000}) >> 8) |
 | 
			
		||||
                ((host_int & uint32_t{0xFF000000}) >> 24));
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline uint16_t gbswap_16(uint16_t host_int) {
 | 
			
		||||
#if defined(__GLIBC__)
 | 
			
		||||
        return bswap_16(host_int);
 | 
			
		||||
#else
 | 
			
		||||
        return (((host_int & uint16_t{0xFF}) << 8) |
 | 
			
		||||
                ((host_int & uint16_t{0xFF00}) >> 8));
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#endif  // intrinics available
 | 
			
		||||
 | 
			
		||||
#ifdef PHMAP_IS_LITTLE_ENDIAN
 | 
			
		||||
 | 
			
		||||
    // Definitions for ntohl etc. that don't require us to include
 | 
			
		||||
    // netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
 | 
			
		||||
    // than just #defining them because in debug mode, gcc doesn't
 | 
			
		||||
    // correctly handle the (rather involved) definitions of bswap_32.
 | 
			
		||||
    // gcc guarantees that inline functions are as fast as macros, so
 | 
			
		||||
    // this isn't a performance hit.
 | 
			
		||||
    inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
 | 
			
		||||
    inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
 | 
			
		||||
    inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
 | 
			
		||||
 | 
			
		||||
#elif defined PHMAP_IS_BIG_ENDIAN
 | 
			
		||||
 | 
			
		||||
    // These definitions are simpler on big-endian machines
 | 
			
		||||
    // These are functions instead of macros to avoid self-assignment warnings
 | 
			
		||||
    // on calls such as "i = ghtnol(i);".  This also provides type checking.
 | 
			
		||||
    inline uint16_t ghtons(uint16_t x) { return x; }
 | 
			
		||||
    inline uint32_t ghtonl(uint32_t x) { return x; }
 | 
			
		||||
    inline uint64_t ghtonll(uint64_t x) { return x; }
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
    #error \
 | 
			
		||||
        "Unsupported byte order: Either PHMAP_IS_BIG_ENDIAN or " \
 | 
			
		||||
           "PHMAP_IS_LITTLE_ENDIAN must be defined"
 | 
			
		||||
#endif  // byte order
 | 
			
		||||
 | 
			
		||||
inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
 | 
			
		||||
inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
 | 
			
		||||
inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
 | 
			
		||||
 | 
			
		||||
// Utilities to convert numbers between the current hosts's native byte
 | 
			
		||||
// order and little-endian byte order
 | 
			
		||||
//
 | 
			
		||||
// Load/Store methods are alignment safe
 | 
			
		||||
namespace little_endian {
 | 
			
		||||
// Conversion functions.
 | 
			
		||||
#ifdef PHMAP_IS_LITTLE_ENDIAN
 | 
			
		||||
 | 
			
		||||
    inline uint16_t FromHost16(uint16_t x) { return x; }
 | 
			
		||||
    inline uint16_t ToHost16(uint16_t x) { return x; }
 | 
			
		||||
 | 
			
		||||
    inline uint32_t FromHost32(uint32_t x) { return x; }
 | 
			
		||||
    inline uint32_t ToHost32(uint32_t x) { return x; }
 | 
			
		||||
 | 
			
		||||
    inline uint64_t FromHost64(uint64_t x) { return x; }
 | 
			
		||||
    inline uint64_t ToHost64(uint64_t x) { return x; }
 | 
			
		||||
 | 
			
		||||
    inline constexpr bool IsLittleEndian() { return true; }
 | 
			
		||||
 | 
			
		||||
#elif defined PHMAP_IS_BIG_ENDIAN
 | 
			
		||||
 | 
			
		||||
    inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
 | 
			
		||||
    inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
 | 
			
		||||
 | 
			
		||||
    inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
 | 
			
		||||
    inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
 | 
			
		||||
 | 
			
		||||
    inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
 | 
			
		||||
    inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
 | 
			
		||||
 | 
			
		||||
    inline constexpr bool IsLittleEndian() { return false; }
 | 
			
		||||
 | 
			
		||||
#endif /* ENDIAN */
 | 
			
		||||
 | 
			
		||||
// Functions to do unaligned loads and stores in little-endian order.
 | 
			
		||||
inline uint16_t Load16(const void *p) {
 | 
			
		||||
  return ToHost16(PHMAP_INTERNAL_UNALIGNED_LOAD16(p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Store16(void *p, uint16_t v) {
 | 
			
		||||
  PHMAP_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint32_t Load32(const void *p) {
 | 
			
		||||
  return ToHost32(PHMAP_INTERNAL_UNALIGNED_LOAD32(p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Store32(void *p, uint32_t v) {
 | 
			
		||||
  PHMAP_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint64_t Load64(const void *p) {
 | 
			
		||||
  return ToHost64(PHMAP_INTERNAL_UNALIGNED_LOAD64(p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Store64(void *p, uint64_t v) {
 | 
			
		||||
  PHMAP_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace little_endian
 | 
			
		||||
 | 
			
		||||
// Utilities to convert numbers between the current hosts's native byte
 | 
			
		||||
// order and big-endian byte order (same as network byte order)
 | 
			
		||||
//
 | 
			
		||||
// Load/Store methods are alignment safe
 | 
			
		||||
namespace big_endian {
 | 
			
		||||
#ifdef PHMAP_IS_LITTLE_ENDIAN
 | 
			
		||||
 | 
			
		||||
    inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
 | 
			
		||||
    inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
 | 
			
		||||
 | 
			
		||||
    inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
 | 
			
		||||
    inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
 | 
			
		||||
 | 
			
		||||
    inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
 | 
			
		||||
    inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
 | 
			
		||||
 | 
			
		||||
    inline constexpr bool IsLittleEndian() { return true; }
 | 
			
		||||
 | 
			
		||||
#elif defined PHMAP_IS_BIG_ENDIAN
 | 
			
		||||
 | 
			
		||||
    inline uint16_t FromHost16(uint16_t x) { return x; }
 | 
			
		||||
    inline uint16_t ToHost16(uint16_t x) { return x; }
 | 
			
		||||
 | 
			
		||||
    inline uint32_t FromHost32(uint32_t x) { return x; }
 | 
			
		||||
    inline uint32_t ToHost32(uint32_t x) { return x; }
 | 
			
		||||
 | 
			
		||||
    inline uint64_t FromHost64(uint64_t x) { return x; }
 | 
			
		||||
    inline uint64_t ToHost64(uint64_t x) { return x; }
 | 
			
		||||
 | 
			
		||||
    inline constexpr bool IsLittleEndian() { return false; }
 | 
			
		||||
 | 
			
		||||
#endif /* ENDIAN */
 | 
			
		||||
 | 
			
		||||
// Functions to do unaligned loads and stores in big-endian order.
 | 
			
		||||
inline uint16_t Load16(const void *p) {
 | 
			
		||||
  return ToHost16(PHMAP_INTERNAL_UNALIGNED_LOAD16(p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Store16(void *p, uint16_t v) {
 | 
			
		||||
  PHMAP_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint32_t Load32(const void *p) {
 | 
			
		||||
  return ToHost32(PHMAP_INTERNAL_UNALIGNED_LOAD32(p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Store32(void *p, uint32_t v) {
 | 
			
		||||
  PHMAP_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline uint64_t Load64(const void *p) {
 | 
			
		||||
  return ToHost64(PHMAP_INTERNAL_UNALIGNED_LOAD64(p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void Store64(void *p, uint64_t v) {
 | 
			
		||||
  PHMAP_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace big_endian
 | 
			
		||||
 | 
			
		||||
}  // namespace phmap
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
     #pragma warning(pop)  
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // phmap_bits_h_guard_
 | 
			
		||||
							
								
								
									
										753
									
								
								src/includes/3thparty/parallel_hashmap/phmap_config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										753
									
								
								src/includes/3thparty/parallel_hashmap/phmap_config.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,753 @@
 | 
			
		||||
#if !defined(phmap_config_h_guard_)
 | 
			
		||||
#define phmap_config_h_guard_
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
//
 | 
			
		||||
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
 | 
			
		||||
// with modifications.
 | 
			
		||||
// 
 | 
			
		||||
// Copyright 2018 The Abseil Authors.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#define PHMAP_VERSION_MAJOR 1
 | 
			
		||||
#define PHMAP_VERSION_MINOR 0
 | 
			
		||||
#define PHMAP_VERSION_PATCH 0
 | 
			
		||||
 | 
			
		||||
// Included for the __GLIBC__ macro (or similar macros on other systems).
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
    // Included for __GLIBCXX__, _LIBCPP_VERSION
 | 
			
		||||
    #include <cstddef>
 | 
			
		||||
#endif  // __cplusplus
 | 
			
		||||
 | 
			
		||||
#if defined(__APPLE__)
 | 
			
		||||
    // Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
 | 
			
		||||
    // __IPHONE_8_0.
 | 
			
		||||
    #include <Availability.h>
 | 
			
		||||
    #include <TargetConditionals.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PHMAP_XSTR(x) PHMAP_STR(x)
 | 
			
		||||
#define PHMAP_STR(x) #x
 | 
			
		||||
#define PHMAP_VAR_NAME_VALUE(var) #var "="  PHMAP_STR(var)
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// Some sanity checks
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
//#if defined(__CYGWIN__)
 | 
			
		||||
//    #error "Cygwin is not supported."
 | 
			
		||||
//#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__)
 | 
			
		||||
    #error "phmap requires Visual Studio 2015 Update 2 or higher."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// We support gcc 4.7 and later.
 | 
			
		||||
#if defined(__GNUC__) && !defined(__clang__)
 | 
			
		||||
    #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
 | 
			
		||||
        #error "phmap requires gcc 4.7 or higher."
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
 | 
			
		||||
// This corresponds to Apple Xcode version 4.5.
 | 
			
		||||
#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
 | 
			
		||||
    #error "phmap requires __apple_build_version__ of 4211165 or higher."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Enforce C++11 as the minimum. 
 | 
			
		||||
#if defined(__cplusplus) && !defined(_MSC_VER)
 | 
			
		||||
    #if __cplusplus < 201103L
 | 
			
		||||
        #error "C++ versions less than C++11 are not supported."
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// We have chosen glibc 2.12 as the minimum 
 | 
			
		||||
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
 | 
			
		||||
    #if !__GLIBC_PREREQ(2, 12)
 | 
			
		||||
        #error "Minimum required version of glibc is 2.12."
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_STLPORT_VERSION)
 | 
			
		||||
    #error "STLPort is not supported."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if CHAR_BIT != 8
 | 
			
		||||
    #error "phmap assumes CHAR_BIT == 8."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// phmap currently assumes that an int is 4 bytes. 
 | 
			
		||||
#if INT_MAX < 2147483647
 | 
			
		||||
    #error "phmap assumes that int is at least 4 bytes. "
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// Compiler Feature Checks
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#ifdef __has_builtin
 | 
			
		||||
    #define PHMAP_HAVE_BUILTIN(x) __has_builtin(x)
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_HAVE_BUILTIN(x) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------
 | 
			
		||||
// Checks whether `std::is_trivially_destructible<T>` is supported.
 | 
			
		||||
// ----------------------------------------------------------------
 | 
			
		||||
#ifdef PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
 | 
			
		||||
    #error PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
 | 
			
		||||
#elif defined(_LIBCPP_VERSION) ||                                        \
 | 
			
		||||
    (!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
 | 
			
		||||
     (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) ||        \
 | 
			
		||||
    defined(_MSC_VER)
 | 
			
		||||
    #define PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// --------------------------------------------------------------
 | 
			
		||||
// Checks whether `std::is_trivially_default_constructible<T>` is 
 | 
			
		||||
// supported.
 | 
			
		||||
// --------------------------------------------------------------
 | 
			
		||||
#if defined(PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
 | 
			
		||||
    #error PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
 | 
			
		||||
#elif defined(PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
 | 
			
		||||
    #error PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
 | 
			
		||||
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) ||        \
 | 
			
		||||
    (!defined(__clang__) && defined(__GNUC__) &&                 \
 | 
			
		||||
     (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
 | 
			
		||||
     (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) ||      \
 | 
			
		||||
    (defined(_MSC_VER) && !defined(__NVCC__))
 | 
			
		||||
    #define PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
 | 
			
		||||
    #define PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------------------------------
 | 
			
		||||
// Checks whether C++11's `thread_local` storage duration specifier is
 | 
			
		||||
// supported.
 | 
			
		||||
// -------------------------------------------------------------------
 | 
			
		||||
#ifdef PHMAP_HAVE_THREAD_LOCAL
 | 
			
		||||
    #error PHMAP_HAVE_THREAD_LOCAL cannot be directly set
 | 
			
		||||
#elif defined(__APPLE__)
 | 
			
		||||
    #if __has_feature(cxx_thread_local) && \
 | 
			
		||||
        !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
 | 
			
		||||
        #define PHMAP_HAVE_THREAD_LOCAL 1
 | 
			
		||||
    #endif
 | 
			
		||||
#else  // !defined(__APPLE__)
 | 
			
		||||
    #define PHMAP_HAVE_THREAD_LOCAL 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__ANDROID__) && defined(__clang__)
 | 
			
		||||
 | 
			
		||||
    #if __has_include(<android/ndk-version.h>)
 | 
			
		||||
        #include <android/ndk-version.h>
 | 
			
		||||
    #endif  // __has_include(<android/ndk-version.h>)
 | 
			
		||||
 | 
			
		||||
    #if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
 | 
			
		||||
        defined(__NDK_MINOR__) &&                                               \
 | 
			
		||||
        ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
 | 
			
		||||
        #undef PHMAP_HAVE_TLS
 | 
			
		||||
        #undef PHMAP_HAVE_THREAD_LOCAL
 | 
			
		||||
    #endif
 | 
			
		||||
#endif 
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------
 | 
			
		||||
// Checks whether the __int128 compiler extension for a 128-bit 
 | 
			
		||||
// integral type is supported.
 | 
			
		||||
// ------------------------------------------------------------
 | 
			
		||||
#ifdef PHMAP_HAVE_INTRINSIC_INT128
 | 
			
		||||
    #error PHMAP_HAVE_INTRINSIC_INT128 cannot be directly set
 | 
			
		||||
#elif defined(__SIZEOF_INT128__)
 | 
			
		||||
    #if (defined(__clang__) && !defined(_WIN32) && !defined(__aarch64__)) || \
 | 
			
		||||
        (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) ||                \
 | 
			
		||||
        (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
 | 
			
		||||
        #define PHMAP_HAVE_INTRINSIC_INT128 1
 | 
			
		||||
    #elif defined(__CUDACC__)
 | 
			
		||||
        #if __CUDACC_VER__ >= 70000
 | 
			
		||||
            #define PHMAP_HAVE_INTRINSIC_INT128 1
 | 
			
		||||
        #endif  // __CUDACC_VER__ >= 70000
 | 
			
		||||
    #endif  // defined(__CUDACC__)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------
 | 
			
		||||
// Checks whether the compiler both supports and enables exceptions. 
 | 
			
		||||
// ------------------------------------------------------------------
 | 
			
		||||
#ifdef PHMAP_HAVE_EXCEPTIONS
 | 
			
		||||
    #error PHMAP_HAVE_EXCEPTIONS cannot be directly set.
 | 
			
		||||
#elif defined(__clang__)
 | 
			
		||||
    #if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
 | 
			
		||||
        #define PHMAP_HAVE_EXCEPTIONS 1
 | 
			
		||||
    #endif  // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
 | 
			
		||||
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) &&    \
 | 
			
		||||
    !(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
 | 
			
		||||
    !(defined(_MSC_VER) && !defined(_CPPUNWIND))
 | 
			
		||||
    #define PHMAP_HAVE_EXCEPTIONS 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------
 | 
			
		||||
// Checks whether the platform has an mmap(2) implementation as defined in
 | 
			
		||||
// POSIX.1-2001.
 | 
			
		||||
// -----------------------------------------------------------------------
 | 
			
		||||
#ifdef PHMAP_HAVE_MMAP
 | 
			
		||||
    #error PHMAP_HAVE_MMAP cannot be directly set
 | 
			
		||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) ||   \
 | 
			
		||||
    defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
 | 
			
		||||
    defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
 | 
			
		||||
    defined(__ASYLO__)
 | 
			
		||||
    #define PHMAP_HAVE_MMAP 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------
 | 
			
		||||
// Checks the endianness of the platform.
 | 
			
		||||
// -----------------------------------------------------------------------
 | 
			
		||||
#if defined(PHMAP_IS_BIG_ENDIAN)
 | 
			
		||||
    #error "PHMAP_IS_BIG_ENDIAN cannot be directly set."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(PHMAP_IS_LITTLE_ENDIAN)
 | 
			
		||||
    #error "PHMAP_IS_LITTLE_ENDIAN cannot be directly set."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
 | 
			
		||||
     __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
 | 
			
		||||
    #define PHMAP_IS_LITTLE_ENDIAN 1
 | 
			
		||||
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
 | 
			
		||||
    __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
 | 
			
		||||
    #define PHMAP_IS_BIG_ENDIAN 1
 | 
			
		||||
#elif defined(_WIN32)
 | 
			
		||||
    #define PHMAP_IS_LITTLE_ENDIAN 1
 | 
			
		||||
#else
 | 
			
		||||
    #error "phmap endian detection needs to be set up for your compiler"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
 | 
			
		||||
    defined(__MAC_OS_X_VERSION_MIN_REQUIRED__) &&     \
 | 
			
		||||
    __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400
 | 
			
		||||
    #define PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 1
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
// Checks whether C++17 std::any is available by checking whether <any> exists.
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
#ifdef PHMAP_HAVE_STD_ANY
 | 
			
		||||
    #error "PHMAP_HAVE_STD_ANY cannot be directly set."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __has_include
 | 
			
		||||
    #if __has_include(<any>) && __cplusplus >= 201703L && \
 | 
			
		||||
        !PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
 | 
			
		||||
        #define PHMAP_HAVE_STD_ANY 1
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PHMAP_HAVE_STD_OPTIONAL
 | 
			
		||||
    #error "PHMAP_HAVE_STD_OPTIONAL cannot be directly set."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __has_include
 | 
			
		||||
    #if __has_include(<optional>) && __cplusplus >= 201703L && \
 | 
			
		||||
        !PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
 | 
			
		||||
        #define PHMAP_HAVE_STD_OPTIONAL 1
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PHMAP_HAVE_STD_VARIANT
 | 
			
		||||
    #error "PHMAP_HAVE_STD_VARIANT cannot be directly set."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __has_include
 | 
			
		||||
    #if __has_include(<variant>) && __cplusplus >= 201703L && \
 | 
			
		||||
        !PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
 | 
			
		||||
        #define PHMAP_HAVE_STD_VARIANT 1
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PHMAP_HAVE_STD_STRING_VIEW
 | 
			
		||||
    #error "PHMAP_HAVE_STD_STRING_VIEW cannot be directly set."
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __has_include
 | 
			
		||||
    #if __has_include(<string_view>) && __cplusplus >= 201703L
 | 
			
		||||
        #define PHMAP_HAVE_STD_STRING_VIEW 1
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// #pragma message(PHMAP_VAR_NAME_VALUE(_MSVC_LANG))
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
 | 
			
		||||
    ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703) || __cplusplus >= 201703)
 | 
			
		||||
    // #define PHMAP_HAVE_STD_ANY 1
 | 
			
		||||
    #define PHMAP_HAVE_STD_OPTIONAL 1
 | 
			
		||||
    #define PHMAP_HAVE_STD_VARIANT 1
 | 
			
		||||
    #define PHMAP_HAVE_STD_STRING_VIEW 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703) || __cplusplus >= 201703
 | 
			
		||||
    #define PHMAP_HAVE_SHARED_MUTEX 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef PHMAP_HAVE_STD_STRING_VIEW
 | 
			
		||||
    #define PHMAP_HAVE_STD_STRING_VIEW 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
 | 
			
		||||
// SEH exception from emplace for variant<SomeStruct> when constructing the
 | 
			
		||||
// struct can throw. This defeats some of variant_test and
 | 
			
		||||
// variant_exception_safety_test.
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
 | 
			
		||||
    #define PHMAP_INTERNAL_MSVC_2017_DBG_MODE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// Sanitizer Attributes
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
//
 | 
			
		||||
// Sanitizer-related attributes are not "defined" in this file (and indeed
 | 
			
		||||
// are not defined as such in any file). To utilize the following
 | 
			
		||||
// sanitizer-related attributes within your builds, define the following macros
 | 
			
		||||
// within your build using a `-D` flag, along with the given value for
 | 
			
		||||
// `-fsanitize`:
 | 
			
		||||
//
 | 
			
		||||
//   * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
 | 
			
		||||
//   * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
 | 
			
		||||
//   * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
 | 
			
		||||
//   * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
 | 
			
		||||
//   * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// A function-like feature checking macro that is a wrapper around
 | 
			
		||||
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
 | 
			
		||||
// nonzero constant integer if the attribute is supported or 0 if not.
 | 
			
		||||
//
 | 
			
		||||
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
#ifdef __has_attribute
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE(x) __has_attribute(x)
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE(x) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// A function-like feature checking macro that accepts C++11 style attributes.
 | 
			
		||||
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
 | 
			
		||||
// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
 | 
			
		||||
// find `__has_cpp_attribute`, will evaluate to 0.
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
#if defined(__cplusplus) && defined(__has_cpp_attribute)
 | 
			
		||||
    #define PHMAP_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_HAVE_CPP_ATTRIBUTE(x) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
// Function Attributes
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_PRINTF_ATTRIBUTE(string_index, first_to_check) \
 | 
			
		||||
      __attribute__((__format__(__printf__, string_index, first_to_check)))
 | 
			
		||||
    #define PHMAP_SCANF_ATTRIBUTE(string_index, first_to_check) \
 | 
			
		||||
      __attribute__((__format__(__scanf__, string_index, first_to_check)))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_PRINTF_ATTRIBUTE(string_index, first_to_check)
 | 
			
		||||
    #define PHMAP_SCANF_ATTRIBUTE(string_index, first_to_check)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(always_inline) || \
 | 
			
		||||
    (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_ALWAYS_INLINE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(__INTEL_COMPILER) && (PHMAP_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NOINLINE __attribute__((noinline))
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_NOINLINE 1
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NOINLINE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(disable_tail_calls)
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
 | 
			
		||||
#elif defined(__GNUC__) && !defined(__clang__)
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_TAIL_CALL \
 | 
			
		||||
      __attribute__((optimize("no-optimize-sibling-calls")))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_TAIL_CALL
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (PHMAP_HAVE_ATTRIBUTE(weak) || \
 | 
			
		||||
     (defined(__GNUC__) && !defined(__clang__))) && \
 | 
			
		||||
    !(defined(__llvm__) && defined(_WIN32))
 | 
			
		||||
    #undef PHMAP_ATTRIBUTE_WEAK
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_WEAK __attribute__((weak))
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_WEAK 1
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_WEAK
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_WEAK 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NONNULL(...)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NORETURN __attribute__((noreturn))
 | 
			
		||||
#elif defined(_MSC_VER)
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NORETURN __declspec(noreturn)
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NORETURN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_ADDRESS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_MEMORY
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) && defined(THREAD_SANITIZER)
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_THREAD
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) && \
 | 
			
		||||
    (defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
 | 
			
		||||
      __attribute__((no_sanitize("undefined")))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_UNDEFINED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_CFI
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
 | 
			
		||||
      __attribute__((no_sanitize("safe-stack")))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_NO_SANITIZE_SAFESTACK
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(returns_nonnull) || \
 | 
			
		||||
    (defined(__GNUC__) && \
 | 
			
		||||
     (__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
 | 
			
		||||
     !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_RETURNS_NONNULL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PHMAP_HAVE_ATTRIBUTE_SECTION
 | 
			
		||||
    #error PHMAP_HAVE_ATTRIBUTE_SECTION cannot be directly set
 | 
			
		||||
#elif (PHMAP_HAVE_ATTRIBUTE(section) ||                \
 | 
			
		||||
       (defined(__GNUC__) && !defined(__clang__))) && \
 | 
			
		||||
    !defined(__APPLE__) && PHMAP_HAVE_ATTRIBUTE_WEAK
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_SECTION 1
 | 
			
		||||
    #ifndef PHMAP_ATTRIBUTE_SECTION
 | 
			
		||||
        #define PHMAP_ATTRIBUTE_SECTION(name) \
 | 
			
		||||
          __attribute__((section(#name))) __attribute__((noinline))
 | 
			
		||||
    #endif
 | 
			
		||||
    #ifndef PHMAP_ATTRIBUTE_SECTION_VARIABLE
 | 
			
		||||
        #define PHMAP_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
 | 
			
		||||
    #endif
 | 
			
		||||
    #ifndef PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS
 | 
			
		||||
        #define PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
 | 
			
		||||
          extern char __start_##name[] PHMAP_ATTRIBUTE_WEAK;    \
 | 
			
		||||
          extern char __stop_##name[] PHMAP_ATTRIBUTE_WEAK
 | 
			
		||||
    #endif
 | 
			
		||||
    #ifndef PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS
 | 
			
		||||
        #define PHMAP_INIT_ATTRIBUTE_SECTION_VARS(name)
 | 
			
		||||
        #define PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS(name)
 | 
			
		||||
    #endif
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_SECTION_START(name) \
 | 
			
		||||
      (reinterpret_cast<void *>(__start_##name))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_SECTION_STOP(name) \
 | 
			
		||||
      (reinterpret_cast<void *>(__stop_##name))
 | 
			
		||||
#else  // !PHMAP_HAVE_ATTRIBUTE_SECTION
 | 
			
		||||
    #define PHMAP_HAVE_ATTRIBUTE_SECTION 0
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_SECTION(name)
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_SECTION_VARIABLE(name)
 | 
			
		||||
    #define PHMAP_INIT_ATTRIBUTE_SECTION_VARS(name)
 | 
			
		||||
    #define PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS(name)
 | 
			
		||||
    #define PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS(name)
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
 | 
			
		||||
#endif  // PHMAP_ATTRIBUTE_SECTION
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
 | 
			
		||||
    (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #if defined(__i386__)
 | 
			
		||||
        #define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
 | 
			
		||||
          __attribute__((force_align_arg_pointer))
 | 
			
		||||
        #define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
 | 
			
		||||
    #elif defined(__x86_64__)
 | 
			
		||||
        #define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
 | 
			
		||||
        #define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
 | 
			
		||||
    #else  // !__i386__ && !__x86_64
 | 
			
		||||
        #define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
 | 
			
		||||
        #define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
 | 
			
		||||
    #endif  // __i386__
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
 | 
			
		||||
    #define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(nodiscard)
 | 
			
		||||
    #define PHMAP_MUST_USE_RESULT [[nodiscard]]
 | 
			
		||||
#elif defined(__clang__) && PHMAP_HAVE_ATTRIBUTE(warn_unused_result)
 | 
			
		||||
    #define PHMAP_MUST_USE_RESULT __attribute__((warn_unused_result))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_MUST_USE_RESULT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_HOT __attribute__((hot))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_HOT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_COLD __attribute__((cold))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_COLD
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
    #if PHMAP_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
 | 
			
		||||
        #define PHMAP_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
 | 
			
		||||
    #else
 | 
			
		||||
        #define PHMAP_ATTRIBUTE_REINITIALIZES
 | 
			
		||||
    #endif
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_REINITIALIZES
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #undef PHMAP_ATTRIBUTE_UNUSED
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_UNUSED __attribute__((__unused__))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_UNUSED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_INITIAL_EXEC
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_PACKED __attribute__((__packed__))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_PACKED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ATTRIBUTE_FUNC_ALIGN(bytes)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------
 | 
			
		||||
// Figure out SSE support
 | 
			
		||||
// ----------------------------------------------------------------------
 | 
			
		||||
#ifndef PHMAP_HAVE_SSE2
 | 
			
		||||
    #if defined(__SSE2__) ||  \
 | 
			
		||||
        (defined(_MSC_VER) && \
 | 
			
		||||
         (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
 | 
			
		||||
        #define PHMAP_HAVE_SSE2 1
 | 
			
		||||
    #else
 | 
			
		||||
        #define PHMAP_HAVE_SSE2 0
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef PHMAP_HAVE_SSSE3
 | 
			
		||||
    #ifdef __SSSE3__
 | 
			
		||||
        #define PHMAP_HAVE_SSSE3 1
 | 
			
		||||
    #else
 | 
			
		||||
        #define PHMAP_HAVE_SSSE3 0
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_SSSE3 && !PHMAP_HAVE_SSE2
 | 
			
		||||
    #error "Bad configuration!"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_SSE2
 | 
			
		||||
    #include <emmintrin.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if PHMAP_HAVE_SSSE3
 | 
			
		||||
    #include <tmmintrin.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------
 | 
			
		||||
// constexpr if
 | 
			
		||||
// ----------------------------------------------------------------------
 | 
			
		||||
#if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703)
 | 
			
		||||
    #define PHMAP_IF_CONSTEXPR(expr) if constexpr ((expr))
 | 
			
		||||
#else 
 | 
			
		||||
    #define PHMAP_IF_CONSTEXPR(expr) if ((expr))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------
 | 
			
		||||
// base/macros.h
 | 
			
		||||
// ----------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// PHMAP_ARRAYSIZE()
 | 
			
		||||
//
 | 
			
		||||
// Returns the number of elements in an array as a compile-time constant, which
 | 
			
		||||
// can be used in defining new arrays. If you use this macro on a pointer by
 | 
			
		||||
// mistake, you will get a compile-time error.
 | 
			
		||||
#define PHMAP_ARRAYSIZE(array) \
 | 
			
		||||
  (sizeof(::phmap::macros_internal::ArraySizeHelper(array)))
 | 
			
		||||
 | 
			
		||||
namespace phmap {
 | 
			
		||||
namespace macros_internal {
 | 
			
		||||
    // Note: this internal template function declaration is used by PHMAP_ARRAYSIZE.
 | 
			
		||||
    // The function doesn't need a definition, as we only use its type.
 | 
			
		||||
    template <typename T, size_t N>
 | 
			
		||||
    auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
 | 
			
		||||
}  // namespace macros_internal
 | 
			
		||||
}  // namespace phmap
 | 
			
		||||
 | 
			
		||||
// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
 | 
			
		||||
#if defined(__clang__) && defined(__has_warning)
 | 
			
		||||
    #if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
 | 
			
		||||
        #define PHMAP_FALLTHROUGH_INTENDED [[clang::fallthrough]]
 | 
			
		||||
    #endif
 | 
			
		||||
#elif defined(__GNUC__) && __GNUC__ >= 7
 | 
			
		||||
    #define PHMAP_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef PHMAP_FALLTHROUGH_INTENDED
 | 
			
		||||
    #define PHMAP_FALLTHROUGH_INTENDED \
 | 
			
		||||
      do {  } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// PHMAP_DEPRECATED()
 | 
			
		||||
//
 | 
			
		||||
// Marks a deprecated class, struct, enum, function, method and variable
 | 
			
		||||
// declarations. The macro argument is used as a custom diagnostic message (e.g.
 | 
			
		||||
// suggestion of a better alternative).
 | 
			
		||||
//
 | 
			
		||||
// Example:
 | 
			
		||||
//
 | 
			
		||||
//   class PHMAP_DEPRECATED("Use Bar instead") Foo {...};
 | 
			
		||||
//   PHMAP_DEPRECATED("Use Baz instead") void Bar() {...}
 | 
			
		||||
//
 | 
			
		||||
// Every usage of a deprecated entity will trigger a warning when compiled with
 | 
			
		||||
// clang's `-Wdeprecated-declarations` option. This option is turned off by
 | 
			
		||||
// default, but the warnings will be reported by clang-tidy.
 | 
			
		||||
#if defined(__clang__) && __cplusplus >= 201103L
 | 
			
		||||
    #define PHMAP_DEPRECATED(message) __attribute__((deprecated(message)))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef PHMAP_DEPRECATED
 | 
			
		||||
    #define PHMAP_DEPRECATED(message)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// PHMAP_BAD_CALL_IF()
 | 
			
		||||
//
 | 
			
		||||
// Used on a function overload to trap bad calls: any call that matches the
 | 
			
		||||
// overload will cause a compile-time error. This macro uses a clang-specific
 | 
			
		||||
// "enable_if" attribute, as described at
 | 
			
		||||
// http://clang.llvm.org/docs/AttributeReference.html#enable-if
 | 
			
		||||
//
 | 
			
		||||
// Overloads which use this macro should be bracketed by
 | 
			
		||||
// `#ifdef PHMAP_BAD_CALL_IF`.
 | 
			
		||||
//
 | 
			
		||||
// Example:
 | 
			
		||||
//
 | 
			
		||||
//   int isdigit(int c);
 | 
			
		||||
//   #ifdef PHMAP_BAD_CALL_IF
 | 
			
		||||
//   int isdigit(int c)
 | 
			
		||||
//     PHMAP_BAD_CALL_IF(c <= -1 || c > 255,
 | 
			
		||||
//                       "'c' must have the value of an unsigned char or EOF");
 | 
			
		||||
//   #endif // PHMAP_BAD_CALL_IF
 | 
			
		||||
 | 
			
		||||
#if defined(__clang__)
 | 
			
		||||
    #if __has_attribute(enable_if)
 | 
			
		||||
        #define PHMAP_BAD_CALL_IF(expr, msg) \
 | 
			
		||||
            __attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
 | 
			
		||||
    #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// PHMAP_ASSERT()
 | 
			
		||||
//
 | 
			
		||||
// In C++11, `assert` can't be used portably within constexpr functions.
 | 
			
		||||
// PHMAP_ASSERT functions as a runtime assert but works in C++11 constexpr
 | 
			
		||||
// functions.  Example:
 | 
			
		||||
//
 | 
			
		||||
// constexpr double Divide(double a, double b) {
 | 
			
		||||
//   return PHMAP_ASSERT(b != 0), a / b;
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// This macro is inspired by
 | 
			
		||||
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
 | 
			
		||||
#if defined(NDEBUG)
 | 
			
		||||
    #define PHMAP_ASSERT(expr) (false ? (void)(expr) : (void)0)
 | 
			
		||||
#else
 | 
			
		||||
    #define PHMAP_ASSERT(expr)              \
 | 
			
		||||
      (PHMAP_PREDICT_TRUE((expr)) ? (void)0 \
 | 
			
		||||
                                 : [] { assert(false && #expr); }())  // NOLINT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef PHMAP_HAVE_EXCEPTIONS
 | 
			
		||||
    #define PHMAP_INTERNAL_TRY try
 | 
			
		||||
    #define PHMAP_INTERNAL_CATCH_ANY catch (...)
 | 
			
		||||
    #define PHMAP_INTERNAL_RETHROW do { throw; } while (false)
 | 
			
		||||
#else  // PHMAP_HAVE_EXCEPTIONS
 | 
			
		||||
    #define PHMAP_INTERNAL_TRY if (true)
 | 
			
		||||
    #define PHMAP_INTERNAL_CATCH_ANY else if (false)
 | 
			
		||||
    #define PHMAP_INTERNAL_RETHROW do {} while (false)
 | 
			
		||||
#endif  // PHMAP_HAVE_EXCEPTIONS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // phmap_config_h_guard_
 | 
			
		||||
							
								
								
									
										227
									
								
								src/includes/3thparty/parallel_hashmap/phmap_dump.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								src/includes/3thparty/parallel_hashmap/phmap_dump.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
#if !defined(phmap_dump_h_guard_)
 | 
			
		||||
#define phmap_dump_h_guard_
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
 | 
			
		||||
//
 | 
			
		||||
//       providing dump/load/mmap_load
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include "phmap.h"
 | 
			
		||||
namespace phmap
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace type_traits_internal {
 | 
			
		||||
 | 
			
		||||
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20150801
 | 
			
		||||
    template<typename T> struct IsTriviallyCopyable : public std::integral_constant<bool, __has_trivial_copy(T)> {};
 | 
			
		||||
#else
 | 
			
		||||
    template<typename T> struct IsTriviallyCopyable : public std::is_trivially_copyable<T> {};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
template <class T1, class T2>
 | 
			
		||||
struct IsTriviallyCopyable<std::pair<T1, T2>> {
 | 
			
		||||
    static constexpr bool value = IsTriviallyCopyable<T1>::value && IsTriviallyCopyable<T2>::value;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace container_internal {
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// dump/load for raw_hash_set
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
template <class Policy, class Hash, class Eq, class Alloc>
 | 
			
		||||
template<typename OutputArchive>
 | 
			
		||||
bool raw_hash_set<Policy, Hash, Eq, Alloc>::dump(OutputArchive& ar) {
 | 
			
		||||
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
 | 
			
		||||
                    "value_type should be trivially copyable");
 | 
			
		||||
 | 
			
		||||
    if (!ar.dump(size_)) {
 | 
			
		||||
        std::cerr << "Failed to dump size_" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (size_ == 0) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (!ar.dump(capacity_)) {
 | 
			
		||||
        std::cerr << "Failed to dump capacity_" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (!ar.dump(reinterpret_cast<char*>(ctrl_),
 | 
			
		||||
        sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1))) {
 | 
			
		||||
 | 
			
		||||
        std::cerr << "Failed to dump ctrl_" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (!ar.dump(reinterpret_cast<char*>(slots_),
 | 
			
		||||
                    sizeof(slot_type) * capacity_)) {
 | 
			
		||||
        std::cerr << "Failed to dump slot_" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Policy, class Hash, class Eq, class Alloc>
 | 
			
		||||
template<typename InputArchive>
 | 
			
		||||
bool raw_hash_set<Policy, Hash, Eq, Alloc>::load(InputArchive& ar) {
 | 
			
		||||
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
 | 
			
		||||
                    "value_type should be trivially copyable");
 | 
			
		||||
    raw_hash_set<Policy, Hash, Eq, Alloc>().swap(*this); // clear any existing content
 | 
			
		||||
    if (!ar.load(&size_)) {
 | 
			
		||||
        std::cerr << "Failed to load size_" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (size_ == 0) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (!ar.load(&capacity_)) {
 | 
			
		||||
        std::cerr << "Failed to load capacity_" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // allocate memory for ctrl_ and slots_
 | 
			
		||||
    initialize_slots();
 | 
			
		||||
    if (!ar.load(reinterpret_cast<char*>(ctrl_),
 | 
			
		||||
        sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1))) {
 | 
			
		||||
        std::cerr << "Failed to load ctrl" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (!ar.load(reinterpret_cast<char*>(slots_),
 | 
			
		||||
                    sizeof(slot_type) * capacity_)) {
 | 
			
		||||
        std::cerr << "Failed to load slot" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// dump/load for parallel_hash_set
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
template <size_t N,
 | 
			
		||||
          template <class, class, class, class> class RefSet,
 | 
			
		||||
          class Mtx_,
 | 
			
		||||
          class Policy, class Hash, class Eq, class Alloc>
 | 
			
		||||
template<typename OutputArchive>
 | 
			
		||||
bool parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>::dump(OutputArchive& ar) {
 | 
			
		||||
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
 | 
			
		||||
                    "value_type should be trivially copyable");
 | 
			
		||||
 | 
			
		||||
    if (! ar.dump(subcnt())) {
 | 
			
		||||
        std::cerr << "Failed to dump meta!" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    for (size_t i = 0; i < sets_.size(); ++i) {
 | 
			
		||||
        auto& inner = sets_[i];
 | 
			
		||||
        typename Lockable::UniqueLock m(const_cast<Inner&>(inner));
 | 
			
		||||
        if (!inner.set_.dump(ar)) {
 | 
			
		||||
            std::cerr << "Failed to dump submap " << i << std::endl;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <size_t N,
 | 
			
		||||
          template <class, class, class, class> class RefSet,
 | 
			
		||||
          class Mtx_,
 | 
			
		||||
          class Policy, class Hash, class Eq, class Alloc>
 | 
			
		||||
template<typename InputArchive>
 | 
			
		||||
bool parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>::load(InputArchive& ar) {
 | 
			
		||||
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
 | 
			
		||||
                    "value_type should be trivially copyable");
 | 
			
		||||
 | 
			
		||||
    size_t submap_count = 0;
 | 
			
		||||
    if (!ar.load(&submap_count)) {
 | 
			
		||||
        std::cerr << "Failed to load submap count!" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (submap_count != subcnt()) {
 | 
			
		||||
        std::cerr << "submap count(" << submap_count << ") != N(" << N << ")" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < submap_count; ++i) {            
 | 
			
		||||
        auto& inner = sets_[i];
 | 
			
		||||
        typename Lockable::UniqueLock m(const_cast<Inner&>(inner));
 | 
			
		||||
        if (!inner.set_.load(ar)) {
 | 
			
		||||
            std::cerr << "Failed to load submap " << i << std::endl;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
} // namespace container_internal
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// BinaryArchive
 | 
			
		||||
//       File is closed when archive object is destroyed
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
// ------------------------------------------------------------------------
 | 
			
		||||
class BinaryOutputArchive {
 | 
			
		||||
public:
 | 
			
		||||
    BinaryOutputArchive(const char *file_path) {
 | 
			
		||||
        ofs_.open(file_path, std::ios_base::binary);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool dump(const char *p, size_t sz) {
 | 
			
		||||
        ofs_.write(p, sz);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename V>
 | 
			
		||||
    typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type
 | 
			
		||||
    dump(const V& v) {
 | 
			
		||||
        ofs_.write(reinterpret_cast<const char *>(&v), sizeof(V));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::ofstream ofs_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BinaryInputArchive {
 | 
			
		||||
public:
 | 
			
		||||
    BinaryInputArchive(const char * file_path) {
 | 
			
		||||
        ifs_.open(file_path, std::ios_base::binary);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool load(char* p, size_t sz) {
 | 
			
		||||
        ifs_.read(p, sz);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename V>
 | 
			
		||||
    typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type
 | 
			
		||||
    load(V* v) {
 | 
			
		||||
        ifs_.read(reinterpret_cast<char *>(v), sizeof(V));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::ifstream ifs_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace phmap
 | 
			
		||||
 | 
			
		||||
#endif // phmap_dump_h_guard_
 | 
			
		||||
							
								
								
									
										154
									
								
								src/includes/3thparty/parallel_hashmap/phmap_fwd_decl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/includes/3thparty/parallel_hashmap/phmap_fwd_decl.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
			
		||||
#if !defined(phmap_fwd_decl_h_guard_)
 | 
			
		||||
#define phmap_fwd_decl_h_guard_
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
    #pragma warning(push)  
 | 
			
		||||
    #pragma warning(disable : 4514) // unreferenced inline function has been removed
 | 
			
		||||
    #pragma warning(disable : 4710) // function not inlined
 | 
			
		||||
    #pragma warning(disable : 4711) // selected for automatic inline expansion
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#if defined(PHMAP_USE_ABSL_HASH)
 | 
			
		||||
    namespace absl { template <class T> struct Hash; };
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace phmap {
 | 
			
		||||
 | 
			
		||||
#if defined(PHMAP_USE_ABSL_HASH)
 | 
			
		||||
    template <class T> using Hash = absl::Hash<T>;
 | 
			
		||||
#else
 | 
			
		||||
    template <class T> struct Hash;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    template <class T> struct EqualTo;
 | 
			
		||||
    template <class T> struct Less;
 | 
			
		||||
    template <class T> using Allocator      = typename std::allocator<T>;
 | 
			
		||||
    template<class T1, class T2> using Pair = typename std::pair<T1, T2>;
 | 
			
		||||
 | 
			
		||||
    class NullMutex;
 | 
			
		||||
 | 
			
		||||
    namespace container_internal {
 | 
			
		||||
 | 
			
		||||
        // The hash of an object of type T is computed by using phmap::Hash.
 | 
			
		||||
        template <class T, class E = void>
 | 
			
		||||
        struct HashEq 
 | 
			
		||||
        {
 | 
			
		||||
            using Hash = phmap::Hash<T>;
 | 
			
		||||
            using Eq   = phmap::EqualTo<T>;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        template <class T>
 | 
			
		||||
        using hash_default_hash = typename container_internal::HashEq<T>::Hash;
 | 
			
		||||
 | 
			
		||||
        template <class T>
 | 
			
		||||
        using hash_default_eq = typename container_internal::HashEq<T>::Eq;
 | 
			
		||||
 | 
			
		||||
        // type alias for std::allocator so we can forward declare without including other headers
 | 
			
		||||
        template <class T>  
 | 
			
		||||
        using Allocator = typename phmap::Allocator<T>;
 | 
			
		||||
 | 
			
		||||
        // type alias for std::pair so we can forward declare without including other headers
 | 
			
		||||
        template<class T1, class T2> 
 | 
			
		||||
        using Pair = typename phmap::Pair<T1, T2>;
 | 
			
		||||
 | 
			
		||||
    }  // namespace container_internal
 | 
			
		||||
 | 
			
		||||
    // ------------- forward declarations for hash containers ----------------------------------
 | 
			
		||||
    template <class T, 
 | 
			
		||||
              class Hash  = phmap::container_internal::hash_default_hash<T>,
 | 
			
		||||
              class Eq    = phmap::container_internal::hash_default_eq<T>,
 | 
			
		||||
              class Alloc = phmap::container_internal::Allocator<T>>  // alias for std::allocator
 | 
			
		||||
        class flat_hash_set;
 | 
			
		||||
 | 
			
		||||
    template <class K, class V,
 | 
			
		||||
              class Hash  = phmap::container_internal::hash_default_hash<K>,
 | 
			
		||||
              class Eq    = phmap::container_internal::hash_default_eq<K>,
 | 
			
		||||
              class Alloc = phmap::container_internal::Allocator<
 | 
			
		||||
                            phmap::container_internal::Pair<const K, V>>> // alias for std::allocator
 | 
			
		||||
        class flat_hash_map;
 | 
			
		||||
    
 | 
			
		||||
    template <class T, 
 | 
			
		||||
              class Hash  = phmap::container_internal::hash_default_hash<T>,
 | 
			
		||||
              class Eq    = phmap::container_internal::hash_default_eq<T>,
 | 
			
		||||
              class Alloc = phmap::container_internal::Allocator<T>> // alias for std::allocator
 | 
			
		||||
        class node_hash_set;
 | 
			
		||||
 | 
			
		||||
    template <class Key, class Value,
 | 
			
		||||
              class Hash  = phmap::container_internal::hash_default_hash<Key>,
 | 
			
		||||
              class Eq    = phmap::container_internal::hash_default_eq<Key>,
 | 
			
		||||
              class Alloc = phmap::container_internal::Allocator<
 | 
			
		||||
                            phmap::container_internal::Pair<const Key, Value>>> // alias for std::allocator
 | 
			
		||||
        class node_hash_map;
 | 
			
		||||
 | 
			
		||||
    template <class T,
 | 
			
		||||
              class Hash  = phmap::container_internal::hash_default_hash<T>,
 | 
			
		||||
              class Eq    = phmap::container_internal::hash_default_eq<T>,
 | 
			
		||||
              class Alloc = phmap::container_internal::Allocator<T>, // alias for std::allocator
 | 
			
		||||
              size_t N    = 4,                  // 2**N submaps
 | 
			
		||||
              class Mutex = phmap::NullMutex>   // use std::mutex to enable internal locks
 | 
			
		||||
        class parallel_flat_hash_set;
 | 
			
		||||
 | 
			
		||||
    template <class K, class V,
 | 
			
		||||
              class Hash  = phmap::container_internal::hash_default_hash<K>,
 | 
			
		||||
              class Eq    = phmap::container_internal::hash_default_eq<K>,
 | 
			
		||||
              class Alloc = phmap::container_internal::Allocator<
 | 
			
		||||
                            phmap::container_internal::Pair<const K, V>>, // alias for std::allocator
 | 
			
		||||
              size_t N    = 4,                  // 2**N submaps
 | 
			
		||||
              class Mutex = phmap::NullMutex>   // use std::mutex to enable internal locks
 | 
			
		||||
        class parallel_flat_hash_map;
 | 
			
		||||
 | 
			
		||||
    template <class T, 
 | 
			
		||||
              class Hash  = phmap::container_internal::hash_default_hash<T>,
 | 
			
		||||
              class Eq    = phmap::container_internal::hash_default_eq<T>,
 | 
			
		||||
              class Alloc = phmap::container_internal::Allocator<T>, // alias for std::allocator
 | 
			
		||||
              size_t N    = 4,                  // 2**N submaps
 | 
			
		||||
              class Mutex = phmap::NullMutex>   // use std::mutex to enable internal locks
 | 
			
		||||
        class parallel_node_hash_set;
 | 
			
		||||
 | 
			
		||||
    template <class Key, class Value,
 | 
			
		||||
              class Hash  = phmap::container_internal::hash_default_hash<Key>,
 | 
			
		||||
              class Eq    = phmap::container_internal::hash_default_eq<Key>,
 | 
			
		||||
              class Alloc = phmap::container_internal::Allocator<
 | 
			
		||||
                            phmap::container_internal::Pair<const Key, Value>>, // alias for std::allocator
 | 
			
		||||
              size_t N    = 4,                  // 2**N submaps
 | 
			
		||||
              class Mutex = phmap::NullMutex>   // use std::mutex to enable internal locks
 | 
			
		||||
        class parallel_node_hash_map;
 | 
			
		||||
 | 
			
		||||
    // ------------- forward declarations for btree containers ----------------------------------
 | 
			
		||||
    template <typename Key, typename Compare = phmap::Less<Key>,
 | 
			
		||||
              typename Alloc = phmap::Allocator<Key>>
 | 
			
		||||
        class btree_set;
 | 
			
		||||
 | 
			
		||||
    template <typename Key, typename Compare = phmap::Less<Key>,
 | 
			
		||||
              typename Alloc = phmap::Allocator<Key>>
 | 
			
		||||
        class btree_multiset;
 | 
			
		||||
 | 
			
		||||
    template <typename Key, typename Value, typename Compare = phmap::Less<Key>,
 | 
			
		||||
              typename Alloc = phmap::Allocator<phmap::container_internal::Pair<const Key, Value>>>
 | 
			
		||||
        class btree_map;
 | 
			
		||||
    
 | 
			
		||||
    template <typename Key, typename Value, typename Compare = phmap::Less<Key>,
 | 
			
		||||
              typename Alloc = phmap::Allocator<phmap::container_internal::Pair<const Key, Value>>>
 | 
			
		||||
        class btree_multimap;
 | 
			
		||||
 | 
			
		||||
}  // namespace phmap
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
     #pragma warning(pop)  
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // phmap_fwd_decl_h_guard_
 | 
			
		||||
							
								
								
									
										370
									
								
								src/includes/3thparty/parallel_hashmap/phmap_utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										370
									
								
								src/includes/3thparty/parallel_hashmap/phmap_utils.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,370 @@
 | 
			
		||||
#if !defined(phmap_utils_h_guard_)
 | 
			
		||||
#define phmap_utils_h_guard_
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
 | 
			
		||||
//
 | 
			
		||||
//       minimal header providing phmap::HashState
 | 
			
		||||
//
 | 
			
		||||
//       use as:  phmap::HashState().combine(0, _first_name, _last_name, _age);
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
    #pragma warning(push)  
 | 
			
		||||
    #pragma warning(disable : 4514) // unreferenced inline function has been removed
 | 
			
		||||
    #pragma warning(disable : 4710) // function not inlined
 | 
			
		||||
    #pragma warning(disable : 4711) // selected for automatic inline expansion
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include "phmap_bits.h"
 | 
			
		||||
 | 
			
		||||
namespace phmap
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------
 | 
			
		||||
// ---------------------------------------------------------------
 | 
			
		||||
template<int n> 
 | 
			
		||||
struct phmap_mix
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(size_t) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<>
 | 
			
		||||
struct phmap_mix<4>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(size_t a) const
 | 
			
		||||
    {
 | 
			
		||||
        static constexpr uint64_t kmul = 0xcc9e2d51UL;
 | 
			
		||||
        // static constexpr uint64_t kmul = 0x3B9ACB93UL; // [greg] my own random prime
 | 
			
		||||
        uint64_t l = a * kmul;
 | 
			
		||||
        return static_cast<size_t>(l ^ (l >> 32));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if defined(PHMAP_HAS_UMUL128)
 | 
			
		||||
    template<>
 | 
			
		||||
    struct phmap_mix<8>
 | 
			
		||||
    {
 | 
			
		||||
        // Very fast mixing (similar to Abseil)
 | 
			
		||||
        inline size_t operator()(size_t a) const
 | 
			
		||||
        {
 | 
			
		||||
            static constexpr uint64_t k = 0xde5fb9d2630458e9ULL;
 | 
			
		||||
            // static constexpr uint64_t k = 0x7C9D0BF0567102A5ULL; // [greg] my own random prime
 | 
			
		||||
            uint64_t h;
 | 
			
		||||
            uint64_t l = umul128(a, k, &h);
 | 
			
		||||
            return static_cast<size_t>(h + l);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
#else
 | 
			
		||||
    template<>
 | 
			
		||||
    struct phmap_mix<8>
 | 
			
		||||
    {
 | 
			
		||||
        inline size_t operator()(size_t a) const
 | 
			
		||||
        {
 | 
			
		||||
            a = (~a) + (a << 21); // a = (a << 21) - a - 1;
 | 
			
		||||
            a = a ^ (a >> 24);
 | 
			
		||||
            a = (a + (a << 3)) + (a << 8); // a * 265
 | 
			
		||||
            a = a ^ (a >> 14);
 | 
			
		||||
            a = (a + (a << 2)) + (a << 4); // a * 21
 | 
			
		||||
            a = a ^ (a >> 28);
 | 
			
		||||
            a = a + (a << 31);
 | 
			
		||||
            return static_cast<size_t>(a);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// --------------------------------------------
 | 
			
		||||
template<int n> 
 | 
			
		||||
struct fold_if_needed
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(uint64_t) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<>
 | 
			
		||||
struct fold_if_needed<4>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(uint64_t a) const
 | 
			
		||||
    {
 | 
			
		||||
        return static_cast<size_t>(a ^ (a >> 32));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<>
 | 
			
		||||
struct fold_if_needed<8>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(uint64_t a) const
 | 
			
		||||
    {
 | 
			
		||||
        return static_cast<size_t>(a);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------
 | 
			
		||||
// see if class T has a hash_value() friend method
 | 
			
		||||
// ---------------------------------------------------------------
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct has_hash_value
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    typedef std::true_type yes;
 | 
			
		||||
    typedef std::false_type no;
 | 
			
		||||
 | 
			
		||||
    template<typename U> static auto test(int) -> decltype(hash_value(std::declval<U&>()) == 1, yes());
 | 
			
		||||
 | 
			
		||||
    template<typename> static no test(...);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static constexpr bool value = std::is_same<decltype(test<T>(0)), yes>::value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if defined(PHMAP_USE_ABSL_HASH) && !defined(phmap_fwd_decl_h_guard_)
 | 
			
		||||
    namespace absl { template <class T> struct Hash; };
 | 
			
		||||
    template <class T> using Hash = absl::Hash<T>;
 | 
			
		||||
#else
 | 
			
		||||
// ---------------------------------------------------------------
 | 
			
		||||
//               phmap::Hash
 | 
			
		||||
// ---------------------------------------------------------------
 | 
			
		||||
template <class T>
 | 
			
		||||
struct Hash
 | 
			
		||||
{
 | 
			
		||||
    template <class U, typename std::enable_if<has_hash_value<U>::value, int>::type = 0>
 | 
			
		||||
    size_t _hash(const T& val) const
 | 
			
		||||
    {
 | 
			
		||||
        return hash_value(val);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
    template <class U, typename std::enable_if<!has_hash_value<U>::value, int>::type = 0>
 | 
			
		||||
    size_t _hash(const T& val) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::hash<T>()(val);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
    inline size_t operator()(const T& val) const
 | 
			
		||||
    {
 | 
			
		||||
        return _hash<T>(val);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
struct Hash<T *>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(const T *val) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return static_cast<size_t>(reinterpret_cast<const uintptr_t>(val)); 
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<class ArgumentType, class ResultType>
 | 
			
		||||
struct phmap_unary_function
 | 
			
		||||
{
 | 
			
		||||
    typedef ArgumentType argument_type;
 | 
			
		||||
    typedef ResultType result_type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<bool> : public phmap_unary_function<bool, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(bool val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<char> : public phmap_unary_function<char, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(char val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<signed char> : public phmap_unary_function<signed char, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(signed char val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<unsigned char> : public phmap_unary_function<unsigned char, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(unsigned char val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<wchar_t> : public phmap_unary_function<wchar_t, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(wchar_t val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<int16_t> : public phmap_unary_function<int16_t, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(int16_t val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<uint16_t> : public phmap_unary_function<uint16_t, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(uint16_t val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<int32_t> : public phmap_unary_function<int32_t, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(int32_t val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<uint32_t> : public phmap_unary_function<uint32_t, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(uint32_t val) const noexcept
 | 
			
		||||
    { return static_cast<size_t>(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<int64_t> : public phmap_unary_function<int64_t, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(int64_t val) const noexcept
 | 
			
		||||
    { return fold_if_needed<sizeof(size_t)>()(static_cast<uint64_t>(val)); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<uint64_t> : public phmap_unary_function<uint64_t, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(uint64_t val) const noexcept
 | 
			
		||||
    { return fold_if_needed<sizeof(size_t)>()(val); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<float> : public phmap_unary_function<float, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(float val) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        // -0.0 and 0.0 should return same hash
 | 
			
		||||
        uint32_t *as_int = reinterpret_cast<uint32_t *>(&val);
 | 
			
		||||
        return (val == 0) ? static_cast<size_t>(0) : 
 | 
			
		||||
                            static_cast<size_t>(*as_int);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct Hash<double> : public phmap_unary_function<double, size_t>
 | 
			
		||||
{
 | 
			
		||||
    inline size_t operator()(double val) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        // -0.0 and 0.0 should return same hash
 | 
			
		||||
        uint64_t *as_int = reinterpret_cast<uint64_t *>(&val);
 | 
			
		||||
        return (val == 0) ? static_cast<size_t>(0) : 
 | 
			
		||||
                            fold_if_needed<sizeof(size_t)>()(*as_int);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
template <class H, int sz> struct Combiner
 | 
			
		||||
{
 | 
			
		||||
    H operator()(H seed, size_t value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class H> struct Combiner<H, 4>
 | 
			
		||||
{
 | 
			
		||||
    H operator()(H seed, size_t value)
 | 
			
		||||
    {
 | 
			
		||||
        return seed ^ (value + 0x9e3779b9 + (seed << 6) + (seed >> 2));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class H> struct Combiner<H, 8>
 | 
			
		||||
{
 | 
			
		||||
    H operator()(H seed, size_t value)
 | 
			
		||||
    {
 | 
			
		||||
        return seed ^ (value + size_t(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// define HashState to combine member hashes... see example below
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
template <typename H>
 | 
			
		||||
class HashStateBase {
 | 
			
		||||
public:
 | 
			
		||||
    template <typename T, typename... Ts>
 | 
			
		||||
    static H combine(H state, const T& value, const Ts&... values);
 | 
			
		||||
 | 
			
		||||
    static H combine(H state) { return state; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename H>
 | 
			
		||||
template <typename T, typename... Ts>
 | 
			
		||||
H HashStateBase<H>::combine(H seed, const T& v, const Ts&... vs)
 | 
			
		||||
{
 | 
			
		||||
    return HashStateBase<H>::combine(Combiner<H, sizeof(H)>()(
 | 
			
		||||
                                         seed, phmap::Hash<T>()(v)), 
 | 
			
		||||
                                     vs...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using HashState = HashStateBase<size_t>;
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#if !defined(PHMAP_USE_ABSL_HASH)
 | 
			
		||||
 | 
			
		||||
// define Hash for std::pair
 | 
			
		||||
// -------------------------
 | 
			
		||||
template<class T1, class T2> 
 | 
			
		||||
struct Hash<std::pair<T1, T2>> {
 | 
			
		||||
    size_t operator()(std::pair<T1, T2> const& p) const noexcept {
 | 
			
		||||
        return phmap::HashState().combine(phmap::Hash<T1>()(p.first), p.second);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// define Hash for std::tuple
 | 
			
		||||
// --------------------------
 | 
			
		||||
template<class... T> 
 | 
			
		||||
struct Hash<std::tuple<T...>> {
 | 
			
		||||
    size_t operator()(std::tuple<T...> const& t) const noexcept {
 | 
			
		||||
        return _hash_helper(t);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template<size_t I = 0, class ...P>
 | 
			
		||||
        typename std::enable_if<I == sizeof...(P), size_t>::type
 | 
			
		||||
        _hash_helper(const std::tuple<P...> &) const noexcept { return 0; }
 | 
			
		||||
 | 
			
		||||
    template<size_t I = 0, class ...P>
 | 
			
		||||
    typename std::enable_if<I < sizeof...(P), size_t>::type
 | 
			
		||||
    _hash_helper(const std::tuple<P...> &t) const noexcept {
 | 
			
		||||
        const auto &el = std::get<I>(t);
 | 
			
		||||
        using el_type = typename std::remove_cv<typename std::remove_reference<decltype(el)>::type>::type;
 | 
			
		||||
        return Combiner<size_t, sizeof(size_t)>()(
 | 
			
		||||
            phmap::Hash<el_type>()(el),  _hash_helper<I + 1>(t));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}  // namespace phmap
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
     #pragma warning(pop)  
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // phmap_utils_h_guard_
 | 
			
		||||
							
								
								
									
										2184
									
								
								src/includes/3thparty/robinhood/robin_hood.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2184
									
								
								src/includes/3thparty/robinhood/robin_hood.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1
									
								
								src/includes/3thparty/skarupke
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								src/includes/3thparty/skarupke
									
									
									
									
									
										Submodule
									
								
							 Submodule src/includes/3thparty/skarupke added at 2c4687431f
									
								
							
							
								
								
									
										295
									
								
								src/includes/3thparty/tsl/array_growth_policy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								src/includes/3thparty/tsl/array_growth_policy.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,295 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_ARRAY_GROWTH_POLICY_H
 | 
			
		||||
#define TSL_ARRAY_GROWTH_POLICY_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <ratio>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
namespace ah {
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by a factor of GrowthFactor keeping the bucket count to a power of two. It allows
 | 
			
		||||
 * the table to use a mask operation instead of a modulo operation to map a hash to a bucket.
 | 
			
		||||
 * 
 | 
			
		||||
 * GrowthFactor must be a power of two >= 2.
 | 
			
		||||
 */
 | 
			
		||||
template<std::size_t GrowthFactor>
 | 
			
		||||
class power_of_two_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    /**
 | 
			
		||||
     * Called on the hash table creation and on rehash. The number of buckets for the table is passed in parameter.
 | 
			
		||||
     * This number is a minimum, the policy may update this value with a higher value if needed (but not lower).
 | 
			
		||||
     *
 | 
			
		||||
     * If 0 is given, min_bucket_count_in_out must still be 0 after the policy creation and
 | 
			
		||||
     * bucket_for_hash must always return 0 in this case.
 | 
			
		||||
     */
 | 
			
		||||
    explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        if(min_bucket_count_in_out > max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            min_bucket_count_in_out = round_up_to_power_of_two(min_bucket_count_in_out);
 | 
			
		||||
            m_mask = min_bucket_count_in_out - 1;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_mask = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the bucket [0, bucket_count()) to which the hash belongs. 
 | 
			
		||||
     * If bucket_count() is 0, it must always return 0.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return hash & m_mask;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of buckets that should be used on next growth.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if((m_mask + 1) > max_bucket_count() / GrowthFactor) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return (m_mask + 1) * GrowthFactor;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the maximum number of buckets supported by the policy.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        // Largest power of two.
 | 
			
		||||
        return (std::numeric_limits<std::size_t>::max() / 2) + 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Reset the growth policy as if it was created with a bucket count of 0.
 | 
			
		||||
     * After a clear, the policy must always return 0 when bucket_for_hash is called.
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_mask = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static std::size_t round_up_to_power_of_two(std::size_t value) {
 | 
			
		||||
        if(is_power_of_two(value)) {
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(value == 0) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        --value;
 | 
			
		||||
        for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) {
 | 
			
		||||
            value |= value >> i;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return value + 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    static constexpr bool is_power_of_two(std::size_t value) {
 | 
			
		||||
        return value != 0 && (value & (value - 1)) == 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
protected:
 | 
			
		||||
    static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2, "GrowthFactor must be a power of two >= 2.");
 | 
			
		||||
    
 | 
			
		||||
    std::size_t m_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo to map a hash
 | 
			
		||||
 * to a bucket. Slower but it can be useful if you want a slower growth.
 | 
			
		||||
 */
 | 
			
		||||
template<class GrowthFactor = std::ratio<3, 2>>
 | 
			
		||||
class mod_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        if(min_bucket_count_in_out > max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            m_mod = min_bucket_count_in_out;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_mod = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return hash % m_mod;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if(m_mod == max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        const double next_bucket_count = std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
 | 
			
		||||
        if(!std::isnormal(next_bucket_count)) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(next_bucket_count > double(max_bucket_count())) {
 | 
			
		||||
            return max_bucket_count();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return std::size_t(next_bucket_count);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        return MAX_BUCKET_COUNT;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_mod = 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR = 1.0 * GrowthFactor::num / GrowthFactor::den;
 | 
			
		||||
    static const std::size_t MAX_BUCKET_COUNT = 
 | 
			
		||||
            std::size_t(double(
 | 
			
		||||
                    std::numeric_limits<std::size_t>::max() / REHASH_SIZE_MULTIPLICATION_FACTOR
 | 
			
		||||
            ));
 | 
			
		||||
            
 | 
			
		||||
    static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1, "Growth factor should be >= 1.1.");
 | 
			
		||||
    
 | 
			
		||||
    std::size_t m_mod;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
static constexpr const std::array<std::size_t, 40> PRIMES = {{
 | 
			
		||||
    1ul, 5ul, 17ul, 29ul, 37ul, 53ul, 67ul, 79ul, 97ul, 131ul, 193ul, 257ul, 389ul, 521ul, 769ul, 1031ul, 
 | 
			
		||||
    1543ul, 2053ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 
 | 
			
		||||
    1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 
 | 
			
		||||
    402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
template<unsigned int IPrime>
 | 
			
		||||
static constexpr std::size_t mod(std::size_t hash) { return hash % PRIMES[IPrime]; }
 | 
			
		||||
 | 
			
		||||
// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for faster modulo as the
 | 
			
		||||
// compiler can optimize the modulo code better with a constant known at the compilation.
 | 
			
		||||
static constexpr const std::array<std::size_t(*)(std::size_t), 40> MOD_PRIME = {{ 
 | 
			
		||||
    &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>, &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, 
 | 
			
		||||
    &mod<11>, &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>, &mod<18>, &mod<19>, &mod<20>, 
 | 
			
		||||
    &mod<21>, &mod<22>, &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, &mod<29>, &mod<30>, 
 | 
			
		||||
    &mod<31>, &mod<32>, &mod<33>, &mod<34>, &mod<35>, &mod<36>, &mod<37> , &mod<38>, &mod<39>
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by using prime numbers as bucket count. Slower than tsl::ah::power_of_two_growth_policy in  
 | 
			
		||||
 * general but will probably distribute the values around better in the buckets with a poor hash function.
 | 
			
		||||
 * 
 | 
			
		||||
 * To allow the compiler to optimize the modulo operation, a lookup table is used with constant primes numbers.
 | 
			
		||||
 * 
 | 
			
		||||
 * With a switch the code would look like:
 | 
			
		||||
 * \code
 | 
			
		||||
 * switch(iprime) { // iprime is the current prime of the hash table
 | 
			
		||||
 *     case 0: hash % 5ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     case 1: hash % 17ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     case 2: hash % 29ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     ...
 | 
			
		||||
 * }    
 | 
			
		||||
 * \endcode
 | 
			
		||||
 * 
 | 
			
		||||
 * Due to the constant variable in the modulo the compiler is able to optimize the operation
 | 
			
		||||
 * by a series of multiplications, substractions and shifts. 
 | 
			
		||||
 * 
 | 
			
		||||
 * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) * 5' in a 64 bits environement.
 | 
			
		||||
 */
 | 
			
		||||
class prime_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    explicit prime_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        auto it_prime = std::lower_bound(detail::PRIMES.begin(), 
 | 
			
		||||
                                         detail::PRIMES.end(), min_bucket_count_in_out);
 | 
			
		||||
        if(it_prime == detail::PRIMES.end()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        m_iprime = static_cast<unsigned int>(std::distance(detail::PRIMES.begin(), it_prime));
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            min_bucket_count_in_out = *it_prime;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            min_bucket_count_in_out = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return detail::MOD_PRIME[m_iprime](hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if(m_iprime + 1 >= detail::PRIMES.size()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return detail::PRIMES[m_iprime + 1];
 | 
			
		||||
    }   
 | 
			
		||||
    
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        return detail::PRIMES.back();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_iprime = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    unsigned int m_iprime;
 | 
			
		||||
    
 | 
			
		||||
    static_assert(std::numeric_limits<decltype(m_iprime)>::max() >= detail::PRIMES.size(), 
 | 
			
		||||
                  "The type of m_iprime is not big enough.");
 | 
			
		||||
}; 
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1772
									
								
								src/includes/3thparty/tsl/array_hash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1772
									
								
								src/includes/3thparty/tsl/array_hash.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										863
									
								
								src/includes/3thparty/tsl/array_map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										863
									
								
								src/includes/3thparty/tsl/array_map.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,863 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_ARRAY_MAP_H
 | 
			
		||||
#define TSL_ARRAY_MAP_H
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "array_hash.h"
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of a cache-conscious string hash map.
 | 
			
		||||
 * 
 | 
			
		||||
 * The map stores the strings as `const CharT*`. If `StoreNullTerminator` is true,
 | 
			
		||||
 * the strings are stored with the a null-terminator (the `key()` method of the iterators
 | 
			
		||||
 * will return a pointer to this null-terminated string). Otherwise the null character
 | 
			
		||||
 * is not stored (which allow an economy of 1 byte per string).
 | 
			
		||||
 * 
 | 
			
		||||
 * The value `T` must be either nothrow move-constructible, copy-constuctible or both.
 | 
			
		||||
 * 
 | 
			
		||||
 * The size of a key string is limited to `std::numeric_limits<KeySizeT>::max() - 1`. 
 | 
			
		||||
 * That is 65 535 characters by default, but can be raised with the `KeySizeT` template parameter. 
 | 
			
		||||
 * See `max_key_size()` for an easy access to this limit.
 | 
			
		||||
 * 
 | 
			
		||||
 * The number of elements in the map is limited to `std::numeric_limits<IndexSizeT>::max()`.
 | 
			
		||||
 * That is 4 294 967 296 elements, but can be raised with the `IndexSizeT` template parameter. 
 | 
			
		||||
 * See `max_size()` for an easy access to this limit.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=: always invalidate the iterators.
 | 
			
		||||
 *  - insert, emplace, operator[]: always invalidate the iterators.
 | 
			
		||||
 *  - erase: always invalidate the iterators.
 | 
			
		||||
 *  - shrink_to_fit: always invalidate the iterators.
 | 
			
		||||
 */    
 | 
			
		||||
template<class CharT,
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = tsl::ah::str_hash<CharT>,
 | 
			
		||||
         class KeyEqual = tsl::ah::str_equal<CharT>,
 | 
			
		||||
         bool StoreNullTerminator = true,
 | 
			
		||||
         class KeySizeT = std::uint16_t,
 | 
			
		||||
         class IndexSizeT = std::uint32_t,
 | 
			
		||||
         class GrowthPolicy = tsl::ah::power_of_two_growth_policy<2>>
 | 
			
		||||
class array_map {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using is_iterator = tsl::detail_array_hash::is_iterator<U>;
 | 
			
		||||
 | 
			
		||||
    using ht = tsl::detail_array_hash::array_hash<CharT, T, Hash, KeyEqual, StoreNullTerminator, 
 | 
			
		||||
                                                  KeySizeT, IndexSizeT, GrowthPolicy>;
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    using char_type = typename ht::char_type;
 | 
			
		||||
    using mapped_type = T;
 | 
			
		||||
    using key_size_type = typename ht::key_size_type;
 | 
			
		||||
    using index_size_type = typename ht::index_size_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
 
 | 
			
		||||
public:
 | 
			
		||||
    array_map(): array_map(ht::DEFAULT_INIT_BUCKET_COUNT) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit array_map(size_type bucket_count,
 | 
			
		||||
                       const Hash& hash = Hash()): m_ht(bucket_count, hash, ht::DEFAULT_MAX_LOAD_FACTOR) 
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt, typename std::enable_if<is_iterator<InputIt>::value>::type* = nullptr>
 | 
			
		||||
    array_map(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
              const Hash& hash = Hash()): array_map(bucket_count, hash)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    array_map(std::initializer_list<std::pair<std::basic_string_view<CharT>, T>> init,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
              const Hash& hash = Hash()): array_map(bucket_count, hash)
 | 
			
		||||
    {
 | 
			
		||||
        insert(init);
 | 
			
		||||
    }
 | 
			
		||||
#else    
 | 
			
		||||
    array_map(std::initializer_list<std::pair<const CharT*, T>> init,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
              const Hash& hash = Hash()): array_map(bucket_count, hash)
 | 
			
		||||
    {
 | 
			
		||||
        insert(init);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    array_map& operator=(std::initializer_list<std::pair<std::basic_string_view<CharT>, T>> ilist) {
 | 
			
		||||
        clear();
 | 
			
		||||
        
 | 
			
		||||
        reserve(ilist.size());
 | 
			
		||||
        insert(ilist);
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    array_map& operator=(std::initializer_list<std::pair<const CharT*, T>> ilist) {
 | 
			
		||||
        clear();
 | 
			
		||||
        
 | 
			
		||||
        reserve(ilist.size());
 | 
			
		||||
        insert(ilist);
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
#endif     
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    size_type max_key_size() const noexcept { return m_ht.max_key_size(); }
 | 
			
		||||
    void shrink_to_fit() { m_ht.shrink_to_fit(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    std::pair<iterator, bool> insert(const std::basic_string_view<CharT>& key, const T& value) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size(), value); 
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    std::pair<iterator, bool> insert(const CharT* key, const T& value) {
 | 
			
		||||
        return m_ht.emplace(key, std::char_traits<CharT>::length(key), value);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const std::basic_string<CharT>& key, const T& value) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size(), value); 
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    std::pair<iterator, bool> insert_ks(const CharT* key, size_type key_size, const T& value) {
 | 
			
		||||
        return m_ht.emplace(key, key_size, value);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
   
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    std::pair<iterator, bool> insert(const std::basic_string_view<CharT>& key, T&& value) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size(), std::move(value));
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    std::pair<iterator, bool> insert(const CharT* key, T&& value) {
 | 
			
		||||
        return m_ht.emplace(key, std::char_traits<CharT>::length(key), std::move(value));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const std::basic_string<CharT>& key, T&& value) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size(), std::move(value));
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    std::pair<iterator, bool> insert_ks(const CharT* key, size_type key_size, T&& value) {
 | 
			
		||||
        return m_ht.emplace(key, key_size, std::move(value));
 | 
			
		||||
    }
 | 
			
		||||
       
 | 
			
		||||
       
 | 
			
		||||
       
 | 
			
		||||
    template<class InputIt, typename std::enable_if<is_iterator<InputIt>::value>::type* = nullptr>
 | 
			
		||||
    void insert(InputIt first, InputIt last) {
 | 
			
		||||
        if(std::is_base_of<std::forward_iterator_tag, 
 | 
			
		||||
                           typename std::iterator_traits<InputIt>::iterator_category>::value) 
 | 
			
		||||
        {
 | 
			
		||||
            const auto nb_elements_insert = std::distance(first, last);
 | 
			
		||||
            const std::size_t nb_free_buckets = std::size_t(float(bucket_count())*max_load_factor()) - size();
 | 
			
		||||
            
 | 
			
		||||
            if(nb_elements_insert > 0 && nb_free_buckets < std::size_t(nb_elements_insert)) {
 | 
			
		||||
                reserve(size() + std::size_t(nb_elements_insert));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(auto it = first; it != last; ++it) {
 | 
			
		||||
            insert_pair(*it);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    void insert(std::initializer_list<std::pair<std::basic_string_view<CharT>, T>> ilist) {
 | 
			
		||||
        insert(ilist.begin(), ilist.end());
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    void insert(std::initializer_list<std::pair<const CharT*, T>> ilist) {
 | 
			
		||||
        insert(ilist.begin(), ilist.end());
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(const std::basic_string_view<CharT>& key, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(key.data(), key.size(), std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(const CharT* key, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(key, std::char_traits<CharT>::length(key), std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(const std::basic_string<CharT>& key, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(key.data(), key.size(), std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
#endif 
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign_ks(const CharT* key, size_type key_size, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(key, key_size, std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(const std::basic_string_view<CharT>& key, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size(), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(const CharT* key, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace(key, std::char_traits<CharT>::length(key), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(const std::basic_string<CharT>& key, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size(), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace_ks(const CharT* key, size_type key_size, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace(key, key_size, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Erase has an amortized O(1) runtime complexity, but even if it removes the key immediatly,
 | 
			
		||||
     * it doesn't do the same for the associated value T.
 | 
			
		||||
     * 
 | 
			
		||||
     * T will only be removed when the ratio between the size of the map and 
 | 
			
		||||
     * the size of the map + the number of deleted values still stored is low enough.
 | 
			
		||||
     * 
 | 
			
		||||
     * To force the deletion you can call shrink_to_fit.
 | 
			
		||||
     */
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const_iterator pos)
 | 
			
		||||
     */
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const_iterator pos)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const std::basic_string_view<CharT>& key) {
 | 
			
		||||
        return m_ht.erase(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#else    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const_iterator pos)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const CharT* key) {
 | 
			
		||||
        return m_ht.erase(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const_iterator pos)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const std::basic_string<CharT>& key) {
 | 
			
		||||
        return m_ht.erase(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const_iterator pos)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase_ks(const CharT* key, size_type key_size) {
 | 
			
		||||
        return m_ht.erase(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.erase(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#else    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const CharT* key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.erase(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const std::basic_string<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.erase(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const_iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.erase(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(array_map& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW    
 | 
			
		||||
    T& at(const std::basic_string_view<CharT>& key) { 
 | 
			
		||||
        return m_ht.at(key.data(), key.size()); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const T& at(const std::basic_string_view<CharT>& key) const { 
 | 
			
		||||
        return m_ht.at(key.data(), key.size()); 
 | 
			
		||||
    }
 | 
			
		||||
#else    
 | 
			
		||||
    T& at(const CharT* key) { 
 | 
			
		||||
        return m_ht.at(key, std::char_traits<CharT>::length(key)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const T& at(const CharT* key) const { 
 | 
			
		||||
        return m_ht.at(key, std::char_traits<CharT>::length(key)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    T& at(const std::basic_string<CharT>& key) { 
 | 
			
		||||
        return m_ht.at(key.data(), key.size()); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const T& at(const std::basic_string<CharT>& key) const { 
 | 
			
		||||
        return m_ht.at(key.data(), key.size()); 
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    T& at_ks(const CharT* key, size_type key_size) { 
 | 
			
		||||
        return m_ht.at(key, key_size); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const T& at_ks(const CharT* key, size_type key_size) const { 
 | 
			
		||||
        return m_ht.at(key, key_size); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.at(key.data(), key.size(), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const T& at(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.at(key.data(), key.size(), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
#else    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const CharT* key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.at(key, std::char_traits<CharT>::length(key), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const T& at(const CharT* key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.at(key, std::char_traits<CharT>::length(key), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const std::basic_string<CharT>& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.at(key.data(), key.size(), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const T& at(const std::basic_string<CharT>& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.at(key.data(), key.size(), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
#endif  
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    T& at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.at(key, key_size, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const T& at_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.at(key, key_size, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    T& operator[](const std::basic_string_view<CharT>& key) { return m_ht.access_operator(key.data(), key.size()); }
 | 
			
		||||
#else
 | 
			
		||||
    T& operator[](const CharT* key) { return m_ht.access_operator(key, std::char_traits<CharT>::length(key)); }
 | 
			
		||||
    T& operator[](const std::basic_string<CharT>& key) { return m_ht.access_operator(key.data(), key.size()); }
 | 
			
		||||
#endif    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    size_type count(const std::basic_string_view<CharT>& key) const { 
 | 
			
		||||
        return m_ht.count(key.data(), key.size()); 
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    size_type count(const CharT* key) const { 
 | 
			
		||||
        return m_ht.count(key, std::char_traits<CharT>::length(key)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    size_type count(const std::basic_string<CharT>& key) const { 
 | 
			
		||||
        return m_ht.count(key.data(), key.size()); 
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    size_type count_ks(const CharT* key, size_type key_size) const { 
 | 
			
		||||
        return m_ht.count(key, key_size); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key.data(), key.size(), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const CharT* key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, std::char_traits<CharT>::length(key), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const std::basic_string<CharT>& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key.data(), key.size(), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, key_size, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    iterator find(const std::basic_string_view<CharT>& key) {
 | 
			
		||||
        return m_ht.find(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const std::basic_string_view<CharT>& key) const {
 | 
			
		||||
        return m_ht.find(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    iterator find(const CharT* key) {
 | 
			
		||||
        return m_ht.find(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const CharT* key) const {
 | 
			
		||||
        return m_ht.find(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const std::basic_string<CharT>& key) {
 | 
			
		||||
        return m_ht.find(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const std::basic_string<CharT>& key) const {
 | 
			
		||||
        return m_ht.find(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    iterator find_ks(const CharT* key, size_type key_size) {
 | 
			
		||||
        return m_ht.find(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find_ks(const CharT* key, size_type key_size) const {
 | 
			
		||||
        return m_ht.find(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.find(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.find(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const CharT* key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.find(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const CharT* key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.find(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const std::basic_string<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.find(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const std::basic_string<CharT>& key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.find(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.find(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.find(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const std::basic_string_view<CharT>& key) {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const std::basic_string_view<CharT>& key) const {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const CharT* key) {
 | 
			
		||||
        return m_ht.equal_range(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const CharT* key) const {
 | 
			
		||||
        return m_ht.equal_range(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const std::basic_string<CharT>& key) {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const std::basic_string<CharT>& key) const {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range_ks(const CharT* key, size_type key_size) {
 | 
			
		||||
        return m_ht.equal_range(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range_ks(const CharT* key, size_type key_size) const {
 | 
			
		||||
        return m_ht.equal_range(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const CharT* key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.equal_range(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const CharT* key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.equal_range(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const std::basic_string<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const std::basic_string<CharT>& key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.equal_range(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.equal_range(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count) { m_ht.rehash(count); }
 | 
			
		||||
    void reserve(size_type count) { m_ht.reserve(count); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the `const_iterator it` as an `iterator`.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator it) noexcept { return m_ht.mutable_iterator(it); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Serialize the map through the `serializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `serializer` parameter must be a function object that supports the following calls:
 | 
			
		||||
     *  - `template<typename U> void operator()(const U& value);` where the types `std::uint64_t`, `float` and `T` must be supported for U.
 | 
			
		||||
     *  - `void operator()(const CharT* value, std::size_t value_size);`
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, ...) of the types it serializes
 | 
			
		||||
     * in the hands of the `Serializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Serializer>
 | 
			
		||||
    void serialize(Serializer& serializer) const {
 | 
			
		||||
        m_ht.serialize(serializer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deserialize a previouly serialized map through the `deserializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `deserializer` parameter must be a function object that supports the following calls:
 | 
			
		||||
     *  - `template<typename U> U operator()();` where the types `std::uint64_t`, `float` and `T` must be supported for U.
 | 
			
		||||
     *  - `void operator()(CharT* value_out, std::size_t value_size);`
 | 
			
		||||
     * 
 | 
			
		||||
     * If the deserialized hash map type is hash compatible with the serialized map, the deserialization process can be
 | 
			
		||||
     * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash (take care of the 32-bits vs 64 bits), 
 | 
			
		||||
     * KeyEqual, GrowthPolicy, StoreNullTerminator, KeySizeT and IndexSizeT must behave the same than the ones used on the 
 | 
			
		||||
     * serialized map. Otherwise the behaviour is undefined with `hash_compatible` sets to true.
 | 
			
		||||
     * 
 | 
			
		||||
     * The behaviour is undefined if the type `CharT` and `T` of the `array_map` are not the same as the
 | 
			
		||||
     * types used during serialization.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, size of int, ...) of the types it 
 | 
			
		||||
     * deserializes in the hands of the `Deserializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Deserializer>
 | 
			
		||||
    static array_map deserialize(Deserializer& deserializer, bool hash_compatible = false) {
 | 
			
		||||
        array_map map(0);
 | 
			
		||||
        map.m_ht.deserialize(deserializer, hash_compatible);
 | 
			
		||||
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const array_map& lhs, const array_map& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(auto it = lhs.cbegin(); it != lhs.cend(); ++it) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find_ks(it.key(), it.key_size());
 | 
			
		||||
            if(it_element_rhs == rhs.cend() || it.value() != it_element_rhs.value()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const array_map& lhs, const array_map& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(array_map& lhs, array_map& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    template<class U, class V>
 | 
			
		||||
    void insert_pair(const std::pair<U, V>& value) {
 | 
			
		||||
        insert(value.first, value.second);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class U, class V>
 | 
			
		||||
    void insert_pair(std::pair<U, V>&& value) {
 | 
			
		||||
        insert(value.first, std::move(value.second));
 | 
			
		||||
    }    
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    static const size_type MAX_KEY_SIZE = ht::MAX_KEY_SIZE;
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as 
 | 
			
		||||
 * `tsl::array_map<CharT, T, Hash, KeyEqual, StoreNullTerminator, KeySizeT, IndexSizeT, tsl::ah::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class CharT,
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = tsl::ah::str_hash<CharT>,
 | 
			
		||||
         class KeyEqual = tsl::ah::str_equal<CharT>,
 | 
			
		||||
         bool StoreNullTerminator = true,
 | 
			
		||||
         class KeySizeT = std::uint16_t,
 | 
			
		||||
         class IndexSizeT = std::uint32_t>         
 | 
			
		||||
using array_pg_map = array_map<CharT, T, Hash, KeyEqual, StoreNullTerminator, 
 | 
			
		||||
                               KeySizeT, IndexSizeT, tsl::ah::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} //end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										664
									
								
								src/includes/3thparty/tsl/array_set.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										664
									
								
								src/includes/3thparty/tsl/array_set.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,664 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_ARRAY_SET_H
 | 
			
		||||
#define TSL_ARRAY_SET_H
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "array_hash.h"
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of a cache-conscious string hash set.
 | 
			
		||||
 * 
 | 
			
		||||
 * The set stores the strings as `const CharT*`. If `StoreNullTerminator` is true,
 | 
			
		||||
 * the strings are stored with the a null-terminator (the `key()` method of the iterators
 | 
			
		||||
 * will return a pointer to this null-terminated string). Otherwise the null character
 | 
			
		||||
 * is not stored (which allow an economy of 1 byte per string).
 | 
			
		||||
 * 
 | 
			
		||||
 * The size of a key string is limited to `std::numeric_limits<KeySizeT>::max() - 1`. 
 | 
			
		||||
 * That is 65 535 characters by default, but can be raised with the `KeySizeT` template parameter. 
 | 
			
		||||
 * See `max_key_size()` for an easy access to this limit.
 | 
			
		||||
 * 
 | 
			
		||||
 * The number of elements in the set is limited to `std::numeric_limits<IndexSizeT>::max()`.
 | 
			
		||||
 * That is 4 294 967 296 elements, but can be raised with the `IndexSizeT` template parameter. 
 | 
			
		||||
 * See `max_size()` for an easy access to this limit.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=: always invalidate the iterators.
 | 
			
		||||
 *  - insert, emplace, operator[]: always invalidate the iterators.
 | 
			
		||||
 *  - erase: always invalidate the iterators.
 | 
			
		||||
 *  - shrink_to_fit: always invalidate the iterators.
 | 
			
		||||
 */  
 | 
			
		||||
template<class CharT,
 | 
			
		||||
         class Hash = tsl::ah::str_hash<CharT>,
 | 
			
		||||
         class KeyEqual = tsl::ah::str_equal<CharT>,
 | 
			
		||||
         bool StoreNullTerminator = true,
 | 
			
		||||
         class KeySizeT = std::uint16_t,
 | 
			
		||||
         class IndexSizeT = std::uint32_t,
 | 
			
		||||
         class GrowthPolicy = tsl::ah::power_of_two_growth_policy<2>>
 | 
			
		||||
class array_set {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using is_iterator = tsl::detail_array_hash::is_iterator<U>;
 | 
			
		||||
    
 | 
			
		||||
    using ht = tsl::detail_array_hash::array_hash<CharT, void, Hash, KeyEqual, StoreNullTerminator, 
 | 
			
		||||
                                                  KeySizeT, IndexSizeT, GrowthPolicy>;
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    using char_type = typename ht::char_type;
 | 
			
		||||
    using key_size_type = typename ht::key_size_type;
 | 
			
		||||
    using index_size_type = typename ht::index_size_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
 
 | 
			
		||||
    array_set(): array_set(ht::DEFAULT_INIT_BUCKET_COUNT) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit array_set(size_type bucket_count,
 | 
			
		||||
                       const Hash& hash = Hash()): m_ht(bucket_count, hash, ht::DEFAULT_MAX_LOAD_FACTOR) 
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt, typename std::enable_if<is_iterator<InputIt>::value>::type* = nullptr>
 | 
			
		||||
    array_set(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
              const Hash& hash = Hash()): array_set(bucket_count, hash)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    array_set(std::initializer_list<std::basic_string_view<CharT>> init,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
              const Hash& hash = Hash()): array_set(bucket_count, hash)
 | 
			
		||||
    {
 | 
			
		||||
        insert(init);
 | 
			
		||||
    }
 | 
			
		||||
#else    
 | 
			
		||||
    array_set(std::initializer_list<const CharT*> init,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
              const Hash& hash = Hash()): array_set(bucket_count, hash)
 | 
			
		||||
    {
 | 
			
		||||
        insert(init);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    array_set& operator=(std::initializer_list<std::basic_string_view<CharT>> ilist) {
 | 
			
		||||
        clear();
 | 
			
		||||
        
 | 
			
		||||
        reserve(ilist.size());
 | 
			
		||||
        insert(ilist);
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    array_set& operator=(std::initializer_list<const CharT*> ilist) {
 | 
			
		||||
        clear();
 | 
			
		||||
        
 | 
			
		||||
        reserve(ilist.size());
 | 
			
		||||
        insert(ilist);
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    size_type max_key_size() const noexcept { return m_ht.max_key_size(); }
 | 
			
		||||
    void shrink_to_fit() { m_ht.shrink_to_fit(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
        
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    std::pair<iterator, bool> insert(const std::basic_string_view<CharT>& key) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size()); 
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    std::pair<iterator, bool> insert(const CharT* key) {
 | 
			
		||||
        return m_ht.emplace(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const std::basic_string<CharT>& key) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size()); 
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    std::pair<iterator, bool> insert_ks(const CharT* key, size_type key_size) {
 | 
			
		||||
        return m_ht.emplace(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt, typename std::enable_if<is_iterator<InputIt>::value>::type* = nullptr>
 | 
			
		||||
    void insert(InputIt first, InputIt last) {
 | 
			
		||||
        if(std::is_base_of<std::forward_iterator_tag, 
 | 
			
		||||
                           typename std::iterator_traits<InputIt>::iterator_category>::value) 
 | 
			
		||||
        {
 | 
			
		||||
            const auto nb_elements_insert = std::distance(first, last);
 | 
			
		||||
            const std::size_t nb_free_buckets = std::size_t(float(bucket_count())*max_load_factor()) - size();
 | 
			
		||||
            
 | 
			
		||||
            if(nb_elements_insert > 0 && nb_free_buckets < std::size_t(nb_elements_insert)) {
 | 
			
		||||
                reserve(size() + std::size_t(nb_elements_insert));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(auto it = first; it != last; ++it) {
 | 
			
		||||
            insert(*it);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    void insert(std::initializer_list<std::basic_string_view<CharT>> ilist) {
 | 
			
		||||
        insert(ilist.begin(), ilist.end());
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    void insert(std::initializer_list<const CharT*> ilist) {
 | 
			
		||||
        insert(ilist.begin(), ilist.end());
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc emplace_ks(const CharT* key, size_type key_size)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, bool> emplace(const std::basic_string_view<CharT>& key) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc emplace_ks(const CharT* key, size_type key_size)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, bool> emplace(const CharT* key) {
 | 
			
		||||
        return m_ht.emplace(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc emplace_ks(const CharT* key, size_type key_size)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, bool> emplace(const std::basic_string<CharT>& key) {
 | 
			
		||||
        return m_ht.emplace(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    /**
 | 
			
		||||
     * No difference compared to the insert method. Mainly here for coherence with array_map.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, bool> emplace_ks(const CharT* key, size_type key_size) {
 | 
			
		||||
        return m_ht.emplace(key, key_size);
 | 
			
		||||
    } 
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    size_type erase(const std::basic_string_view<CharT>& key) {
 | 
			
		||||
        return m_ht.erase(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#else    
 | 
			
		||||
    size_type erase(const CharT* key) {
 | 
			
		||||
        return m_ht.erase(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    size_type erase(const std::basic_string<CharT>& key) {
 | 
			
		||||
        return m_ht.erase(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    size_type erase_ks(const CharT* key, size_type key_size) {
 | 
			
		||||
        return m_ht.erase(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.erase(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#else    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const CharT* key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.erase(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase(const std::basic_string<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.erase(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type erase_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.erase(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(array_set& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    size_type count(const std::basic_string_view<CharT>& key) const { return m_ht.count(key.data(), key.size()); }
 | 
			
		||||
#else
 | 
			
		||||
    size_type count(const CharT* key) const { return m_ht.count(key, std::char_traits<CharT>::length(key)); }
 | 
			
		||||
    size_type count(const std::basic_string<CharT>& key) const { return m_ht.count(key.data(), key.size()); }
 | 
			
		||||
#endif
 | 
			
		||||
    size_type count_ks(const CharT* key, size_type key_size) const { return m_ht.count(key, key_size); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key.data(), key.size(), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const CharT* key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, std::char_traits<CharT>::length(key), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const std::basic_string<CharT>& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key.data(), key.size(), precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, key_size, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    iterator find(const std::basic_string_view<CharT>& key) {
 | 
			
		||||
        return m_ht.find(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const std::basic_string_view<CharT>& key) const {
 | 
			
		||||
        return m_ht.find(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    iterator find(const CharT* key) {
 | 
			
		||||
        return m_ht.find(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const CharT* key) const {
 | 
			
		||||
        return m_ht.find(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const std::basic_string<CharT>& key) {
 | 
			
		||||
        return m_ht.find(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const std::basic_string<CharT>& key) const {
 | 
			
		||||
        return m_ht.find(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    iterator find_ks(const CharT* key, size_type key_size) {
 | 
			
		||||
        return m_ht.find(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find_ks(const CharT* key, size_type key_size) const {
 | 
			
		||||
        return m_ht.find(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.find(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.find(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const CharT* key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.find(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const CharT* key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.find(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const std::basic_string<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.find(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const std::basic_string<CharT>& key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.find(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.find(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.find(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const std::basic_string_view<CharT>& key) {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const std::basic_string_view<CharT>& key) const {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const CharT* key) {
 | 
			
		||||
        return m_ht.equal_range(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const CharT* key) const {
 | 
			
		||||
        return m_ht.equal_range(key, std::char_traits<CharT>::length(key));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const std::basic_string<CharT>& key) {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const std::basic_string<CharT>& key) const {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size());
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range_ks(const CharT* key, size_type key_size) {
 | 
			
		||||
        return m_ht.equal_range(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range_ks(const CharT* key, size_type key_size) const {
 | 
			
		||||
        return m_ht.equal_range(key, key_size);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
#ifdef TSL_AH_HAS_STRING_VIEW 
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const std::basic_string_view<CharT>& key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const CharT* key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.equal_range(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const CharT* key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.equal_range(key, std::char_traits<CharT>::length(key), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const std::basic_string<CharT>& key, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const std::basic_string<CharT>& key, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.equal_range(key.data(), key.size(), precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
#endif    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) {
 | 
			
		||||
        return m_ht.equal_range(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range_ks(const CharT* key, size_type key_size, std::size_t precalculated_hash) const {
 | 
			
		||||
        return m_ht.equal_range(key, key_size, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count) { m_ht.rehash(count); }
 | 
			
		||||
    void reserve(size_type count) { m_ht.reserve(count); } 
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }   
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the `const_iterator it` as an `iterator`.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator it) noexcept { return m_ht.mutable_iterator(it); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Serialize the set through the `serializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `serializer` parameter must be a function object that supports the following calls:
 | 
			
		||||
     *  - `template<typename U> void operator()(const U& value);` where the types `std::uint64_t` and `float` must be supported for U.
 | 
			
		||||
     *  - `void operator()(const CharT* value, std::size_t value_size);`
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, ...) of the types it serializes
 | 
			
		||||
     * in the hands of the `Serializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Serializer>
 | 
			
		||||
    void serialize(Serializer& serializer) const {
 | 
			
		||||
        m_ht.serialize(serializer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deserialize a previouly serialized set through the `deserializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `deserializer` parameter must be a function object that supports the following calls:
 | 
			
		||||
     *  - `template<typename U> U operator()();` where the types `std::uint64_t` and `float` must be supported for U.
 | 
			
		||||
     *  - `void operator()(CharT* value_out, std::size_t value_size);`
 | 
			
		||||
     * 
 | 
			
		||||
     * If the deserialized hash set type is hash compatible with the serialized set, the deserialization process can be
 | 
			
		||||
     * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash (take care of the 32-bits vs 64 bits), 
 | 
			
		||||
     * KeyEqual, GrowthPolicy, StoreNullTerminator, KeySizeT and IndexSizeT must behave the same than the ones used on the 
 | 
			
		||||
     * serialized set. Otherwise the behaviour is undefined with `hash_compatible` sets to true.
 | 
			
		||||
     * 
 | 
			
		||||
     * The behaviour is undefined if the type `CharT` of the `array_set` is not the same as the
 | 
			
		||||
     * type used during serialization.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, size of int, ...) of the types it 
 | 
			
		||||
     * deserializes in the hands of the `Deserializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Deserializer>
 | 
			
		||||
    static array_set deserialize(Deserializer& deserializer, bool hash_compatible = false) {
 | 
			
		||||
        array_set set(0);
 | 
			
		||||
        set.m_ht.deserialize(deserializer, hash_compatible);
 | 
			
		||||
 | 
			
		||||
        return set;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const array_set& lhs, const array_set& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(auto it = lhs.cbegin(); it != lhs.cend(); ++it) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find_ks(it.key(), it.key_size());
 | 
			
		||||
            if(it_element_rhs == rhs.cend()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const array_set& lhs, const array_set& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(array_set& lhs, array_set& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    static const size_type MAX_KEY_SIZE = ht::MAX_KEY_SIZE;
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as 
 | 
			
		||||
 * `tsl::array_set<CharT, Hash, KeyEqual, StoreNullTerminator, KeySizeT, IndexSizeT, tsl::ah::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class CharT,
 | 
			
		||||
         class Hash = tsl::ah::str_hash<CharT>,
 | 
			
		||||
         class KeyEqual = tsl::ah::str_equal<CharT>,
 | 
			
		||||
         bool StoreNullTerminator = true,
 | 
			
		||||
         class KeySizeT = std::uint16_t,
 | 
			
		||||
         class IndexSizeT = std::uint32_t>         
 | 
			
		||||
using array_pg_set = array_set<CharT, Hash, KeyEqual, StoreNullTerminator, 
 | 
			
		||||
                               KeySizeT, IndexSizeT, tsl::ah::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} //end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										706
									
								
								src/includes/3thparty/tsl/bhopscotch_map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										706
									
								
								src/includes/3thparty/tsl/bhopscotch_map.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,706 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_BHOPSCOTCH_MAP_H
 | 
			
		||||
#define TSL_BHOPSCOTCH_MAP_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "hopscotch_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Similar to tsl::hopscotch_map but instead of using a list for overflowing elements it uses
 | 
			
		||||
 * a binary search tree. It thus needs an additional template parameter Compare. Compare should
 | 
			
		||||
 * be arithmetically coherent with KeyEqual.
 | 
			
		||||
 * 
 | 
			
		||||
 * The binary search tree allows the map to have a worst-case scenario of O(log n) for search 
 | 
			
		||||
 * and delete, even if the hash function maps all the elements to the same bucket. 
 | 
			
		||||
 * For insert, the amortized worst case is O(log n), but the worst case is O(n) in case of rehash.
 | 
			
		||||
 * 
 | 
			
		||||
 * This makes the map resistant to DoS attacks (but doesn't preclude you to have a good hash function,
 | 
			
		||||
 * as an element in the bucket array is faster to retrieve than in the tree).
 | 
			
		||||
 * 
 | 
			
		||||
 * @copydoc hopscotch_map
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Compare = std::less<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<const Key, T>>,
 | 
			
		||||
         unsigned int NeighborhoodSize = 62,
 | 
			
		||||
         bool StoreHash = false,
 | 
			
		||||
         class GrowthPolicy = tsl::hh::power_of_two_growth_policy<2>>
 | 
			
		||||
class bhopscotch_map {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_hopscotch_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const std::pair<const Key, T>& key_value) const {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(std::pair<const Key, T>& key_value) {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
    };  
 | 
			
		||||
    
 | 
			
		||||
    class ValueSelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using value_type = T;
 | 
			
		||||
        
 | 
			
		||||
        const value_type& operator()(const std::pair<const Key, T>& key_value) const {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        value_type& operator()(std::pair<const Key, T>& key_value) {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    // TODO Not optimal as we have to use std::pair<const Key, T> as ValueType which forbid 
 | 
			
		||||
    // us to move the key in the bucket array, we have to use copy. Optimize.
 | 
			
		||||
    using overflow_container_type = std::map<Key, T, Compare, Allocator>;
 | 
			
		||||
    using ht = detail_hopscotch_hash::hopscotch_hash<std::pair<const Key, T>, KeySelect, ValueSelect,
 | 
			
		||||
                                                     Hash, KeyEqual, 
 | 
			
		||||
                                                     Allocator, NeighborhoodSize, 
 | 
			
		||||
                                                     StoreHash, GrowthPolicy,
 | 
			
		||||
                                                     overflow_container_type>;
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using mapped_type = T;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using key_compare = Compare;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    bhopscotch_map() : bhopscotch_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit bhopscotch_map(size_type bucket_count, 
 | 
			
		||||
                        const Hash& hash = Hash(),
 | 
			
		||||
                        const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                        const Allocator& alloc = Allocator(),
 | 
			
		||||
                        const Compare& comp = Compare()) : 
 | 
			
		||||
                        m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR, comp)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bhopscotch_map(size_type bucket_count,
 | 
			
		||||
                  const Allocator& alloc) : bhopscotch_map(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bhopscotch_map(size_type bucket_count,
 | 
			
		||||
                  const Hash& hash,
 | 
			
		||||
                  const Allocator& alloc) : bhopscotch_map(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit bhopscotch_map(const Allocator& alloc) : bhopscotch_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    bhopscotch_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                const Hash& hash = Hash(),
 | 
			
		||||
                const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                const Allocator& alloc = Allocator()) : bhopscotch_map(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    bhopscotch_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc) : bhopscotch_map(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    bhopscotch_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc) : bhopscotch_map(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bhopscotch_map(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                    const Hash& hash = Hash(),
 | 
			
		||||
                    const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                    const Allocator& alloc = Allocator()) : 
 | 
			
		||||
                    bhopscotch_map(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bhopscotch_map(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count,
 | 
			
		||||
                    const Allocator& alloc) : 
 | 
			
		||||
                    bhopscotch_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bhopscotch_map(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count,
 | 
			
		||||
                    const Hash& hash,
 | 
			
		||||
                    const Allocator& alloc) : 
 | 
			
		||||
                    bhopscotch_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    bhopscotch_map& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { 
 | 
			
		||||
        return m_ht.insert(value); 
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    std::pair<iterator, bool> insert(P&& value) { 
 | 
			
		||||
        return m_ht.insert(std::forward<P>(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { 
 | 
			
		||||
        return m_ht.insert(std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) { 
 | 
			
		||||
        return m_ht.insert(hint, value); 
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    iterator insert(const_iterator hint, P&& value) { 
 | 
			
		||||
        return m_ht.insert(hint, std::forward<P>(value));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert(hint, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { 
 | 
			
		||||
        m_ht.insert(first, last); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { 
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end()); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(k, std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(std::move(k), std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, k, std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, std::move(k), std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { 
 | 
			
		||||
        return m_ht.emplace(std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args) { 
 | 
			
		||||
        return m_ht.try_emplace(k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(hint, k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(hint, std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { return m_ht.erase(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(bhopscotch_map& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key) { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const T& at(const Key& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key) { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    T& operator[](const Key& key) { return m_ht[key]; }    
 | 
			
		||||
    T& operator[](Key&& key) { return m_ht[std::move(key)]; }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */     
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    bool contains(const Key& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    bool contains(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc contains(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count_) { m_ht.rehash(count_); }
 | 
			
		||||
    void reserve(size_type count_) { m_ht.reserve(count_); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    key_compare key_comp() const { return m_ht.key_comp(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a const_iterator to an iterator.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    size_type overflow_size() const noexcept { return m_ht.overflow_size(); }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const bhopscotch_map& lhs, const bhopscotch_map& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(const auto& element_lhs : lhs) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find(element_lhs.first);
 | 
			
		||||
            if(it_element_rhs == rhs.cend() || element_lhs.second != it_element_rhs->second) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const bhopscotch_map& lhs, const bhopscotch_map& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(bhopscotch_map& lhs, bhopscotch_map& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as `tsl::bhopscotch_map<Key, T, Hash, KeyEqual, Compare, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Compare = std::less<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<const Key, T>>,
 | 
			
		||||
         unsigned int NeighborhoodSize = 62,
 | 
			
		||||
         bool StoreHash = false>
 | 
			
		||||
using bhopscotch_pg_map = bhopscotch_map<Key, T, Hash, KeyEqual, Compare, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										560
									
								
								src/includes/3thparty/tsl/bhopscotch_set.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										560
									
								
								src/includes/3thparty/tsl/bhopscotch_set.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,560 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_BHOPSCOTCH_SET_H
 | 
			
		||||
#define TSL_BHOPSCOTCH_SET_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "hopscotch_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Similar to tsl::hopscotch_set but instead of using a list for overflowing elements it uses
 | 
			
		||||
 * a binary search tree. It thus needs an additional template parameter Compare. Compare should
 | 
			
		||||
 * be arithmetically coherent with KeyEqual.
 | 
			
		||||
 * 
 | 
			
		||||
 * The binary search tree allows the set to have a worst-case scenario of O(log n) for search 
 | 
			
		||||
 * and delete, even if the hash function maps all the elements to the same bucket. 
 | 
			
		||||
 * For insert, the amortized worst case is O(log n), but the worst case is O(n) in case of rehash.
 | 
			
		||||
 * 
 | 
			
		||||
 * This makes the set resistant to DoS attacks (but doesn't preclude you to have a good hash function,
 | 
			
		||||
 * as an element in the bucket array is faster to retrieve than in the tree).
 | 
			
		||||
 * 
 | 
			
		||||
 * @copydoc hopscotch_set
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Compare = std::less<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>,
 | 
			
		||||
         unsigned int NeighborhoodSize = 62,
 | 
			
		||||
         bool StoreHash = false,
 | 
			
		||||
         class GrowthPolicy = tsl::hh::power_of_two_growth_policy<2>>
 | 
			
		||||
class bhopscotch_set {
 | 
			
		||||
private:    
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_hopscotch_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const Key& key) const {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(Key& key) {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    using overflow_container_type = std::set<Key, Compare, Allocator>;
 | 
			
		||||
    using ht = tsl::detail_hopscotch_hash::hopscotch_hash<Key, KeySelect, void,
 | 
			
		||||
                                                     Hash, KeyEqual, 
 | 
			
		||||
                                                     Allocator, NeighborhoodSize, 
 | 
			
		||||
                                                     StoreHash, GrowthPolicy,
 | 
			
		||||
                                                     overflow_container_type>;
 | 
			
		||||
            
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using key_compare = Compare;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    bhopscotch_set() : bhopscotch_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit bhopscotch_set(size_type bucket_count, 
 | 
			
		||||
                        const Hash& hash = Hash(),
 | 
			
		||||
                        const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                        const Allocator& alloc = Allocator(),
 | 
			
		||||
                        const Compare& comp = Compare()) : 
 | 
			
		||||
                        m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR, comp)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bhopscotch_set(size_type bucket_count,
 | 
			
		||||
                  const Allocator& alloc) : bhopscotch_set(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bhopscotch_set(size_type bucket_count,
 | 
			
		||||
                  const Hash& hash,
 | 
			
		||||
                  const Allocator& alloc) : bhopscotch_set(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit bhopscotch_set(const Allocator& alloc) : bhopscotch_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    bhopscotch_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                const Hash& hash = Hash(),
 | 
			
		||||
                const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                const Allocator& alloc = Allocator()) : bhopscotch_set(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    bhopscotch_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc) : bhopscotch_set(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    bhopscotch_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc) : bhopscotch_set(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bhopscotch_set(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                    const Hash& hash = Hash(),
 | 
			
		||||
                    const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                    const Allocator& alloc = Allocator()) : 
 | 
			
		||||
                    bhopscotch_set(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bhopscotch_set(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count,
 | 
			
		||||
                    const Allocator& alloc) : 
 | 
			
		||||
                    bhopscotch_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bhopscotch_set(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count,
 | 
			
		||||
                    const Hash& hash,
 | 
			
		||||
                    const Allocator& alloc) : 
 | 
			
		||||
                    bhopscotch_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    bhopscotch_set& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { return m_ht.insert(value); }
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { return m_ht.insert(std::move(value)); }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) { return m_ht.insert(hint, value); }
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { return m_ht.insert(hint, std::move(value)); }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { m_ht.insert(first, last); }
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { m_ht.insert(ilist.begin(), ilist.end()); }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { return m_ht.emplace(std::forward<Args>(args)...); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { return m_ht.erase(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(bhopscotch_set& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
        
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    bool contains(const Key& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    bool contains(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc contains(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent 
 | 
			
		||||
     * and Compare::is_transparent exist. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, class CP = Compare, 
 | 
			
		||||
             typename std::enable_if<has_is_transparent<KE>::value && has_is_transparent<CP>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count_) { m_ht.rehash(count_); }
 | 
			
		||||
    void reserve(size_type count_) { m_ht.reserve(count_); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    key_compare key_comp() const { return m_ht.key_comp(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a const_iterator to an iterator.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    size_type overflow_size() const noexcept { return m_ht.overflow_size(); }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const bhopscotch_set& lhs, const bhopscotch_set& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(const auto& element_lhs : lhs) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find(element_lhs);
 | 
			
		||||
            if(it_element_rhs == rhs.cend()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const bhopscotch_set& lhs, const bhopscotch_set& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(bhopscotch_set& lhs, bhopscotch_set& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;    
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as `tsl::bhopscotch_set<Key, Hash, KeyEqual, Compare, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Compare = std::less<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>,
 | 
			
		||||
         unsigned int NeighborhoodSize = 62,
 | 
			
		||||
         bool StoreHash = false>
 | 
			
		||||
using bhopscotch_pg_set = bhopscotch_set<Key, Hash, KeyEqual, Compare, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif 
 | 
			
		||||
							
								
								
									
										295
									
								
								src/includes/3thparty/tsl/hopscotch_growth_policy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								src/includes/3thparty/tsl/hopscotch_growth_policy.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,295 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2018 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_HOPSCOTCH_GROWTH_POLICY_H
 | 
			
		||||
#define TSL_HOPSCOTCH_GROWTH_POLICY_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <ratio>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
namespace hh {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by a factor of GrowthFactor keeping the bucket count to a power of two. It allows
 | 
			
		||||
 * the table to use a mask operation instead of a modulo operation to map a hash to a bucket.
 | 
			
		||||
 * 
 | 
			
		||||
 * GrowthFactor must be a power of two >= 2.
 | 
			
		||||
 */
 | 
			
		||||
template<std::size_t GrowthFactor>
 | 
			
		||||
class power_of_two_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    /**
 | 
			
		||||
     * Called on the hash table creation and on rehash. The number of buckets for the table is passed in parameter.
 | 
			
		||||
     * This number is a minimum, the policy may update this value with a higher value if needed (but not lower).
 | 
			
		||||
     *
 | 
			
		||||
     * If 0 is given, min_bucket_count_in_out must still be 0 after the policy creation and
 | 
			
		||||
     * bucket_for_hash must always return 0 in this case.
 | 
			
		||||
     */
 | 
			
		||||
    explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        if(min_bucket_count_in_out > max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            min_bucket_count_in_out = round_up_to_power_of_two(min_bucket_count_in_out);
 | 
			
		||||
            m_mask = min_bucket_count_in_out - 1;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_mask = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the bucket [0, bucket_count()) to which the hash belongs. 
 | 
			
		||||
     * If bucket_count() is 0, it must always return 0.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return hash & m_mask;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the bucket count to use when the bucket array grows on rehash.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if((m_mask + 1) > max_bucket_count() / GrowthFactor) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return (m_mask + 1) * GrowthFactor;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the maximum number of buckets supported by the policy.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        // Largest power of two.
 | 
			
		||||
        return (std::numeric_limits<std::size_t>::max() / 2) + 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Reset the growth policy as if it was created with a bucket count of 0.
 | 
			
		||||
     * After a clear, the policy must always return 0 when bucket_for_hash is called.
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_mask = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static std::size_t round_up_to_power_of_two(std::size_t value) {
 | 
			
		||||
        if(is_power_of_two(value)) {
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(value == 0) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        --value;
 | 
			
		||||
        for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) {
 | 
			
		||||
            value |= value >> i;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return value + 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    static constexpr bool is_power_of_two(std::size_t value) {
 | 
			
		||||
        return value != 0 && (value & (value - 1)) == 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2, "GrowthFactor must be a power of two >= 2.");
 | 
			
		||||
    
 | 
			
		||||
    std::size_t m_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo to map a hash
 | 
			
		||||
 * to a bucket. Slower but it can be useful if you want a slower growth.
 | 
			
		||||
 */
 | 
			
		||||
template<class GrowthFactor = std::ratio<3, 2>>
 | 
			
		||||
class mod_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        if(min_bucket_count_in_out > max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            m_mod = min_bucket_count_in_out;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_mod = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return hash % m_mod;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if(m_mod == max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        const double next_bucket_count = std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
 | 
			
		||||
        if(!std::isnormal(next_bucket_count)) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(next_bucket_count > double(max_bucket_count())) {
 | 
			
		||||
            return max_bucket_count();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return std::size_t(next_bucket_count);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        return MAX_BUCKET_COUNT;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_mod = 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR = 1.0 * GrowthFactor::num / GrowthFactor::den;
 | 
			
		||||
    static const std::size_t MAX_BUCKET_COUNT = 
 | 
			
		||||
            std::size_t(double(
 | 
			
		||||
                    std::numeric_limits<std::size_t>::max() / REHASH_SIZE_MULTIPLICATION_FACTOR
 | 
			
		||||
            ));
 | 
			
		||||
            
 | 
			
		||||
    static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1, "Growth factor should be >= 1.1.");
 | 
			
		||||
    
 | 
			
		||||
    std::size_t m_mod;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
static constexpr const std::array<std::size_t, 40> PRIMES = {{
 | 
			
		||||
    1ul, 5ul, 17ul, 29ul, 37ul, 53ul, 67ul, 79ul, 97ul, 131ul, 193ul, 257ul, 389ul, 521ul, 769ul, 1031ul, 
 | 
			
		||||
    1543ul, 2053ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 
 | 
			
		||||
    1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 
 | 
			
		||||
    402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
template<unsigned int IPrime>
 | 
			
		||||
static constexpr std::size_t mod(std::size_t hash) { return hash % PRIMES[IPrime]; }
 | 
			
		||||
 | 
			
		||||
// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for faster modulo as the
 | 
			
		||||
// compiler can optimize the modulo code better with a constant known at the compilation.
 | 
			
		||||
static constexpr const std::array<std::size_t(*)(std::size_t), 40> MOD_PRIME = {{ 
 | 
			
		||||
    &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>, &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, 
 | 
			
		||||
    &mod<11>, &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>, &mod<18>, &mod<19>, &mod<20>, 
 | 
			
		||||
    &mod<21>, &mod<22>, &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, &mod<29>, &mod<30>, 
 | 
			
		||||
    &mod<31>, &mod<32>, &mod<33>, &mod<34>, &mod<35>, &mod<36>, &mod<37> , &mod<38>, &mod<39>
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by using prime numbers as bucket count. Slower than tsl::hh::power_of_two_growth_policy in  
 | 
			
		||||
 * general but will probably distribute the values around better in the buckets with a poor hash function.
 | 
			
		||||
 * 
 | 
			
		||||
 * To allow the compiler to optimize the modulo operation, a lookup table is used with constant primes numbers.
 | 
			
		||||
 * 
 | 
			
		||||
 * With a switch the code would look like:
 | 
			
		||||
 * \code
 | 
			
		||||
 * switch(iprime) { // iprime is the current prime of the hash table
 | 
			
		||||
 *     case 0: hash % 5ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     case 1: hash % 17ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     case 2: hash % 29ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     ...
 | 
			
		||||
 * }    
 | 
			
		||||
 * \endcode
 | 
			
		||||
 * 
 | 
			
		||||
 * Due to the constant variable in the modulo the compiler is able to optimize the operation
 | 
			
		||||
 * by a series of multiplications, substractions and shifts. 
 | 
			
		||||
 * 
 | 
			
		||||
 * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) * 5' in a 64 bits environement.
 | 
			
		||||
 */
 | 
			
		||||
class prime_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    explicit prime_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        auto it_prime = std::lower_bound(detail::PRIMES.begin(), 
 | 
			
		||||
                                         detail::PRIMES.end(), min_bucket_count_in_out);
 | 
			
		||||
        if(it_prime == detail::PRIMES.end()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        m_iprime = static_cast<unsigned int>(std::distance(detail::PRIMES.begin(), it_prime));
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            min_bucket_count_in_out = *it_prime;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            min_bucket_count_in_out = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return detail::MOD_PRIME[m_iprime](hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if(m_iprime + 1 >= detail::PRIMES.size()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return detail::PRIMES[m_iprime + 1];
 | 
			
		||||
    }   
 | 
			
		||||
    
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        return detail::PRIMES.back();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_iprime = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    unsigned int m_iprime;
 | 
			
		||||
    
 | 
			
		||||
    static_assert(std::numeric_limits<decltype(m_iprime)>::max() >= detail::PRIMES.size(), 
 | 
			
		||||
                  "The type of m_iprime is not big enough.");
 | 
			
		||||
}; 
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1822
									
								
								src/includes/3thparty/tsl/hopscotch_hash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1822
									
								
								src/includes/3thparty/tsl/hopscotch_hash.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										710
									
								
								src/includes/3thparty/tsl/hopscotch_map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										710
									
								
								src/includes/3thparty/tsl/hopscotch_map.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,710 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_HOPSCOTCH_MAP_H
 | 
			
		||||
#define TSL_HOPSCOTCH_MAP_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "hopscotch_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of a hash map using the hopscotch hashing algorithm.
 | 
			
		||||
 * 
 | 
			
		||||
 * The Key and the value T must be either nothrow move-constructible, copy-constuctible or both.
 | 
			
		||||
 * 
 | 
			
		||||
 * The size of the neighborhood (NeighborhoodSize) must be > 0 and <= 62 if StoreHash is false.
 | 
			
		||||
 * When StoreHash is true, 32-bits of the hash will be stored alongside the neighborhood limiting
 | 
			
		||||
 * the NeighborhoodSize to <= 30. There is no memory usage difference between 
 | 
			
		||||
 * 'NeighborhoodSize 62; StoreHash false' and 'NeighborhoodSize 30; StoreHash true'.
 | 
			
		||||
 * 
 | 
			
		||||
 * Storing the hash may improve performance on insert during the rehash process if the hash takes time
 | 
			
		||||
 * to compute. It may also improve read performance if the KeyEqual function takes time (or incurs a cache-miss).
 | 
			
		||||
 * If used with simple Hash and KeyEqual it may slow things down.
 | 
			
		||||
 * 
 | 
			
		||||
 * StoreHash can only be set if the GrowthPolicy is set to tsl::power_of_two_growth_policy.
 | 
			
		||||
 * 
 | 
			
		||||
 * GrowthPolicy defines how the map grows and consequently how a hash value is mapped to a bucket. 
 | 
			
		||||
 * By default the map uses tsl::power_of_two_growth_policy. This policy keeps the number of buckets 
 | 
			
		||||
 * to a power of two and uses a mask to map the hash to a bucket instead of the slow modulo.
 | 
			
		||||
 * You may define your own growth policy, check tsl::power_of_two_growth_policy for the interface.
 | 
			
		||||
 * 
 | 
			
		||||
 * If the destructors of Key or T throw an exception, behaviour of the class is undefined.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=, reserve, rehash: always invalidate the iterators.
 | 
			
		||||
 *  - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators 
 | 
			
		||||
 *    if a displacement is needed to resolve a collision (which mean that most of the time, 
 | 
			
		||||
 *    insert will invalidate the iterators). Or if there is a rehash.
 | 
			
		||||
 *  - erase: iterator on the erased element is the only one which become invalid.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<Key, T>>,
 | 
			
		||||
         unsigned int NeighborhoodSize = 62,
 | 
			
		||||
         bool StoreHash = false,
 | 
			
		||||
         class GrowthPolicy = tsl::hh::power_of_two_growth_policy<2>>
 | 
			
		||||
class hopscotch_map {
 | 
			
		||||
private:    
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_hopscotch_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const std::pair<Key, T>& key_value) const {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(std::pair<Key, T>& key_value) {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
    };  
 | 
			
		||||
    
 | 
			
		||||
    class ValueSelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using value_type = T;
 | 
			
		||||
        
 | 
			
		||||
        const value_type& operator()(const std::pair<Key, T>& key_value) const {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        value_type& operator()(std::pair<Key, T>& key_value) {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    using overflow_container_type = std::list<std::pair<Key, T>, Allocator>;
 | 
			
		||||
    using ht = detail_hopscotch_hash::hopscotch_hash<std::pair<Key, T>, KeySelect, ValueSelect,
 | 
			
		||||
                                                     Hash, KeyEqual, 
 | 
			
		||||
                                                     Allocator, NeighborhoodSize, 
 | 
			
		||||
                                                     StoreHash, GrowthPolicy,
 | 
			
		||||
                                                     overflow_container_type>;
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using mapped_type = T;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    hopscotch_map() : hopscotch_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit hopscotch_map(size_type bucket_count, 
 | 
			
		||||
                        const Hash& hash = Hash(),
 | 
			
		||||
                        const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                        const Allocator& alloc = Allocator()) : 
 | 
			
		||||
                        m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    hopscotch_map(size_type bucket_count,
 | 
			
		||||
                  const Allocator& alloc) : hopscotch_map(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    hopscotch_map(size_type bucket_count,
 | 
			
		||||
                  const Hash& hash,
 | 
			
		||||
                  const Allocator& alloc) : hopscotch_map(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit hopscotch_map(const Allocator& alloc) : hopscotch_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    hopscotch_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                const Hash& hash = Hash(),
 | 
			
		||||
                const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                const Allocator& alloc = Allocator()) : hopscotch_map(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    hopscotch_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc) : hopscotch_map(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    hopscotch_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc) : hopscotch_map(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hopscotch_map(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                    const Hash& hash = Hash(),
 | 
			
		||||
                    const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                    const Allocator& alloc = Allocator()) : 
 | 
			
		||||
                    hopscotch_map(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hopscotch_map(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count,
 | 
			
		||||
                    const Allocator& alloc) : 
 | 
			
		||||
                    hopscotch_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hopscotch_map(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count,
 | 
			
		||||
                    const Hash& hash,
 | 
			
		||||
                    const Allocator& alloc) : 
 | 
			
		||||
                    hopscotch_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    hopscotch_map& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { 
 | 
			
		||||
        return m_ht.insert(value); 
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    std::pair<iterator, bool> insert(P&& value) { 
 | 
			
		||||
        return m_ht.insert(std::forward<P>(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { 
 | 
			
		||||
        return m_ht.insert(std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) { 
 | 
			
		||||
        return m_ht.insert(hint, value); 
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    iterator insert(const_iterator hint, P&& value) { 
 | 
			
		||||
        return m_ht.insert(hint, std::forward<P>(value));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert(hint, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { 
 | 
			
		||||
        m_ht.insert(first, last); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { 
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end()); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(k, std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(std::move(k), std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, k, std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, std::move(k), std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { 
 | 
			
		||||
        return m_ht.emplace(std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args) { 
 | 
			
		||||
        return m_ht.try_emplace(k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(hint, k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(hint, std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(hopscotch_map& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key) { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    const T& at(const Key& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key) { return m_ht.at(key); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    T& operator[](const Key& key) { return m_ht[key]; }    
 | 
			
		||||
    T& operator[](Key&& key) { return m_ht[std::move(key)]; }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */     
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    bool contains(const Key& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    bool contains(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc contains(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count_) { m_ht.rehash(count_); }
 | 
			
		||||
    void reserve(size_type count_) { m_ht.reserve(count_); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a const_iterator to an iterator.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    size_type overflow_size() const noexcept { return m_ht.overflow_size(); }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const hopscotch_map& lhs, const hopscotch_map& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(const auto& element_lhs : lhs) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find(element_lhs.first);
 | 
			
		||||
            if(it_element_rhs == rhs.cend() || element_lhs.second != it_element_rhs->second) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const hopscotch_map& lhs, const hopscotch_map& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(hopscotch_map& lhs, hopscotch_map& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as `tsl::hopscotch_map<Key, T, Hash, KeyEqual, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<Key, T>>,
 | 
			
		||||
         unsigned int NeighborhoodSize = 62,
 | 
			
		||||
         bool StoreHash = false>
 | 
			
		||||
using hopscotch_pg_map = hopscotch_map<Key, T, Hash, KeyEqual, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										556
									
								
								src/includes/3thparty/tsl/hopscotch_set.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										556
									
								
								src/includes/3thparty/tsl/hopscotch_set.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,556 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_HOPSCOTCH_SET_H
 | 
			
		||||
#define TSL_HOPSCOTCH_SET_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "hopscotch_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of a hash set using the hopscotch hashing algorithm.
 | 
			
		||||
 * 
 | 
			
		||||
 * The Key must be either nothrow move-constructible, copy-constuctible or both.
 | 
			
		||||
 * 
 | 
			
		||||
 * The size of the neighborhood (NeighborhoodSize) must be > 0 and <= 62 if StoreHash is false.
 | 
			
		||||
 * When StoreHash is true, 32-bits of the hash will be stored alongside the neighborhood limiting
 | 
			
		||||
 * the NeighborhoodSize to <= 30. There is no memory usage difference between 
 | 
			
		||||
 * 'NeighborhoodSize 62; StoreHash false' and 'NeighborhoodSize 30; StoreHash true'.
 | 
			
		||||
 * 
 | 
			
		||||
 * Storing the hash may improve performance on insert during the rehash process if the hash takes time
 | 
			
		||||
 * to compute. It may also improve read performance if the KeyEqual function takes time (or incurs a cache-miss).
 | 
			
		||||
 * If used with simple Hash and KeyEqual it may slow things down.
 | 
			
		||||
 * 
 | 
			
		||||
 * StoreHash can only be set if the GrowthPolicy is set to tsl::power_of_two_growth_policy.
 | 
			
		||||
 * 
 | 
			
		||||
 * GrowthPolicy defines how the set grows and consequently how a hash value is mapped to a bucket. 
 | 
			
		||||
 * By default the set uses tsl::power_of_two_growth_policy. This policy keeps the number of buckets 
 | 
			
		||||
 * to a power of two and uses a mask to set the hash to a bucket instead of the slow modulo.
 | 
			
		||||
 * You may define your own growth policy, check tsl::power_of_two_growth_policy for the interface.
 | 
			
		||||
 * 
 | 
			
		||||
 * If the destructor of Key throws an exception, behaviour of the class is undefined.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=, reserve, rehash: always invalidate the iterators.
 | 
			
		||||
 *  - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators 
 | 
			
		||||
 *    if a displacement is needed to resolve a collision (which mean that most of the time, 
 | 
			
		||||
 *    insert will invalidate the iterators). Or if there is a rehash.
 | 
			
		||||
 *  - erase: iterator on the erased element is the only one which become invalid.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>,
 | 
			
		||||
         unsigned int NeighborhoodSize = 62,
 | 
			
		||||
         bool StoreHash = false,
 | 
			
		||||
         class GrowthPolicy = tsl::hh::power_of_two_growth_policy<2>>
 | 
			
		||||
class hopscotch_set {
 | 
			
		||||
private:    
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_hopscotch_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const Key& key) const {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(Key& key) {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    using overflow_container_type = std::list<Key, Allocator>;
 | 
			
		||||
    using ht = detail_hopscotch_hash::hopscotch_hash<Key, KeySelect, void,
 | 
			
		||||
                                                     Hash, KeyEqual, 
 | 
			
		||||
                                                     Allocator, NeighborhoodSize, 
 | 
			
		||||
                                                     StoreHash, GrowthPolicy,
 | 
			
		||||
                                                     overflow_container_type>;
 | 
			
		||||
            
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    hopscotch_set() : hopscotch_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit hopscotch_set(size_type bucket_count, 
 | 
			
		||||
                        const Hash& hash = Hash(),
 | 
			
		||||
                        const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                        const Allocator& alloc = Allocator()) : 
 | 
			
		||||
                        m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    hopscotch_set(size_type bucket_count,
 | 
			
		||||
                  const Allocator& alloc) : hopscotch_set(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    hopscotch_set(size_type bucket_count,
 | 
			
		||||
                  const Hash& hash,
 | 
			
		||||
                  const Allocator& alloc) : hopscotch_set(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit hopscotch_set(const Allocator& alloc) : hopscotch_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    hopscotch_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                const Hash& hash = Hash(),
 | 
			
		||||
                const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                const Allocator& alloc = Allocator()) : hopscotch_set(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    hopscotch_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc) : hopscotch_set(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    hopscotch_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc) : hopscotch_set(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hopscotch_set(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                    const Hash& hash = Hash(),
 | 
			
		||||
                    const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                    const Allocator& alloc = Allocator()) : 
 | 
			
		||||
                    hopscotch_set(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hopscotch_set(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count,
 | 
			
		||||
                    const Allocator& alloc) : 
 | 
			
		||||
                    hopscotch_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hopscotch_set(std::initializer_list<value_type> init,
 | 
			
		||||
                    size_type bucket_count,
 | 
			
		||||
                    const Hash& hash,
 | 
			
		||||
                    const Allocator& alloc) : 
 | 
			
		||||
                    hopscotch_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    hopscotch_set& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { return m_ht.insert(value); }
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { return m_ht.insert(std::move(value)); }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) { return m_ht.insert(hint, value); }
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { return m_ht.insert(hint, std::move(value)); }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { m_ht.insert(first, last); }
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { m_ht.insert(ilist.begin(), ilist.end()); }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { return m_ht.emplace(std::forward<Args>(args)...); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(hopscotch_set& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    bool contains(const Key& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    bool contains(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc contains(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count_) { m_ht.rehash(count_); }
 | 
			
		||||
    void reserve(size_type count_) { m_ht.reserve(count_); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a const_iterator to an iterator.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    size_type overflow_size() const noexcept { return m_ht.overflow_size(); }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const hopscotch_set& lhs, const hopscotch_set& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(const auto& element_lhs : lhs) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find(element_lhs);
 | 
			
		||||
            if(it_element_rhs == rhs.cend()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const hopscotch_set& lhs, const hopscotch_set& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(hopscotch_set& lhs, hopscotch_set& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;    
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as `tsl::hopscotch_set<Key, Hash, KeyEqual, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>,
 | 
			
		||||
         unsigned int NeighborhoodSize = 62,
 | 
			
		||||
         bool StoreHash = false>
 | 
			
		||||
using hopscotch_pg_set = hopscotch_set<Key, Hash, KeyEqual, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1614
									
								
								src/includes/3thparty/tsl/ordered_hash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1614
									
								
								src/includes/3thparty/tsl/ordered_hash.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										833
									
								
								src/includes/3thparty/tsl/ordered_map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										833
									
								
								src/includes/3thparty/tsl/ordered_map.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,833 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_ORDERED_MAP_H
 | 
			
		||||
#define TSL_ORDERED_MAP_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "ordered_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of an hash map using open adressing with robin hood with backshift delete to resolve collisions.
 | 
			
		||||
 * 
 | 
			
		||||
 * The particularity of this hash map is that it remembers the order in which the elements were added and
 | 
			
		||||
 * provide a way to access the structure which stores these values through the 'values_container()' method. 
 | 
			
		||||
 * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but
 | 
			
		||||
 * a std::vector may be used. In this case the map provides a 'data()' method which give a direct access 
 | 
			
		||||
 * to the memory used to store the values (which can be usefull to communicate with C API's).
 | 
			
		||||
 * 
 | 
			
		||||
 * The Key and T must be copy constructible and/or move constructible. To use `unordered_erase` they both
 | 
			
		||||
 * must be swappable.
 | 
			
		||||
 * 
 | 
			
		||||
 * The behaviour of the hash map is undefinded if the destructor of Key or T throws an exception.
 | 
			
		||||
 * 
 | 
			
		||||
 * By default the maximum size of a map is limited to 2^32 - 1 values, if needed this can be changed through
 | 
			
		||||
 * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each
 | 
			
		||||
 * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()).
 | 
			
		||||
 *  - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer 
 | 
			
		||||
 *                                               and if size() < capacity(), only end(). 
 | 
			
		||||
 *                                               Otherwise all the iterators are invalidated if an insert occurs.
 | 
			
		||||
 *  - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of 
 | 
			
		||||
 *                            the erased element and all the ones after the erased element (including end()). 
 | 
			
		||||
 *                            Otherwise all the iterators are invalidated if an erase occurs.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<Key, T>>,
 | 
			
		||||
         class ValueTypeContainer = std::deque<std::pair<Key, T>, Allocator>,
 | 
			
		||||
         class IndexType = std::uint_least32_t>
 | 
			
		||||
class ordered_map {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const std::pair<Key, T>& key_value) const noexcept {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(std::pair<Key, T>& key_value) noexcept {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
    };  
 | 
			
		||||
    
 | 
			
		||||
    class ValueSelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using value_type = T;
 | 
			
		||||
        
 | 
			
		||||
        const value_type& operator()(const std::pair<Key, T>& key_value) const noexcept {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        value_type& operator()(std::pair<Key, T>& key_value) noexcept {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    using ht = detail_ordered_hash::ordered_hash<std::pair<Key, T>, KeySelect, ValueSelect,
 | 
			
		||||
                                                 Hash, KeyEqual, Allocator, ValueTypeContainer, IndexType>;
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using mapped_type = T;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
    using reverse_iterator = typename ht::reverse_iterator;
 | 
			
		||||
    using const_reverse_iterator = typename ht::const_reverse_iterator;
 | 
			
		||||
    
 | 
			
		||||
    using values_container_type = typename ht::values_container_type;
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    ordered_map(): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit ordered_map(size_type bucket_count, 
 | 
			
		||||
                         const Hash& hash = Hash(),
 | 
			
		||||
                         const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                         const Allocator& alloc = Allocator()): 
 | 
			
		||||
                     m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    ordered_map(size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc): ordered_map(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    ordered_map(size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc): ordered_map(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit ordered_map(const Allocator& alloc): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    ordered_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                const Hash& hash = Hash(),
 | 
			
		||||
                const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                const Allocator& alloc = Allocator()): ordered_map(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    ordered_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc): ordered_map(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    ordered_map(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc): ordered_map(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ordered_map(std::initializer_list<value_type> init,
 | 
			
		||||
                size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                const Hash& hash = Hash(),
 | 
			
		||||
                const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                const Allocator& alloc = Allocator()): 
 | 
			
		||||
            ordered_map(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ordered_map(std::initializer_list<value_type> init,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc): 
 | 
			
		||||
            ordered_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ordered_map(std::initializer_list<value_type> init,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc): 
 | 
			
		||||
            ordered_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    ordered_map& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    reverse_iterator rbegin() noexcept { return m_ht.rbegin(); }
 | 
			
		||||
    const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); }
 | 
			
		||||
    const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    reverse_iterator rend() noexcept { return m_ht.rend(); }
 | 
			
		||||
    const_reverse_iterator rend() const noexcept { return m_ht.rend(); }
 | 
			
		||||
    const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { return m_ht.insert(value); }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    std::pair<iterator, bool> insert(P&& value) { return m_ht.emplace(std::forward<P>(value)); }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { return m_ht.insert(std::move(value)); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) {
 | 
			
		||||
        return m_ht.insert_hint(hint, value);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    iterator insert(const_iterator hint, P&& value) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<P>(value));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, std::move(value));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { m_ht.insert(first, last); }
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { m_ht.insert(ilist.begin(), ilist.end()); }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(k, std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(std::move(k), std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, k, std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, std::move(k), std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { return m_ht.emplace(std::forward<Args>(args)...); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template <class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args) { 
 | 
			
		||||
        return m_ht.try_emplace(k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace_hint(hint, k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace_hint(hint, std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * When erasing an element, the insert order will be preserved and no holes will be present in the container
 | 
			
		||||
     * returned by 'values_container()'. 
 | 
			
		||||
     * 
 | 
			
		||||
     * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1)
 | 
			
		||||
     * average complexity.
 | 
			
		||||
     */
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     */
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     */    
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const key_type& key, std::size_t precalculated_hash)
 | 
			
		||||
     * 
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(ordered_map& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key) { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    const T& at(const Key& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key) { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>     
 | 
			
		||||
    const T& at(const K& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    T& operator[](const Key& key) { return m_ht[key]; }    
 | 
			
		||||
    T& operator[](Key&& key) { return m_ht[std::move(key)]; }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>     
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */     
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>     
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>     
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count) { m_ht.rehash(count); }
 | 
			
		||||
    void reserve(size_type count) { m_ht.reserve(count); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a const_iterator to an iterator.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Requires index <= size().
 | 
			
		||||
     * 
 | 
			
		||||
     * Return an iterator to the element at index. Return end() if index == size().
 | 
			
		||||
     */
 | 
			
		||||
    iterator nth(size_type index) { return m_ht.nth(index); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc nth(size_type index)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator nth(size_type index) const { return m_ht.nth(index); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return const_reference to the first element. Requires the container to not be empty.
 | 
			
		||||
     */
 | 
			
		||||
    const_reference front() const { return m_ht.front(); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return const_reference to the last element. Requires the container to not be empty.
 | 
			
		||||
     */
 | 
			
		||||
    const_reference back() const { return m_ht.back(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'.
 | 
			
		||||
     */
 | 
			
		||||
    template<class U = values_container_type, typename std::enable_if<tsl::detail_ordered_hash::is_vector<U>::value>::type* = nullptr>    
 | 
			
		||||
    const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); }
 | 
			
		||||
        
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the container in which the values are stored. The values are in the same order as the insertion order
 | 
			
		||||
     * and are contiguous in the structure, no holes (size() == values_container().size()).
 | 
			
		||||
     */
 | 
			
		||||
    const values_container_type& values_container() const noexcept { return m_ht.values_container(); }
 | 
			
		||||
 | 
			
		||||
    template<class U = values_container_type, typename std::enable_if<tsl::detail_ordered_hash::is_vector<U>::value>::type* = nullptr>    
 | 
			
		||||
    size_type capacity() const noexcept { return m_ht.capacity(); }
 | 
			
		||||
    
 | 
			
		||||
    void shrink_to_fit() { m_ht.shrink_to_fit(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Insert the value before pos shifting all the elements on the right of pos (including pos) one position 
 | 
			
		||||
     * to the right.
 | 
			
		||||
     * 
 | 
			
		||||
     * Amortized linear time-complexity in the distance between pos and end().
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, bool> insert_at_position(const_iterator pos, const value_type& value) { 
 | 
			
		||||
        return m_ht.insert_at_position(pos, value); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc insert_at_position(const_iterator pos, const value_type& value)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, bool> insert_at_position(const_iterator pos, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert_at_position(pos, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc insert_at_position(const_iterator pos, const value_type& value)
 | 
			
		||||
     * 
 | 
			
		||||
     * Same as insert_at_position(pos, value_type(std::forward<Args>(args)...), mainly
 | 
			
		||||
     * here for coherence.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace_at_position(const_iterator pos, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_at_position(pos, std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
       
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc insert_at_position(const_iterator pos, const value_type& value)
 | 
			
		||||
     */       
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace_at_position(const_iterator pos, const key_type& k, Args&&... args) { 
 | 
			
		||||
        return m_ht.try_emplace_at_position(pos, k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc insert_at_position(const_iterator pos, const value_type& value)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace_at_position(const_iterator pos, key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace_at_position(pos, std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void pop_back() { m_ht.pop_back(); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order.
 | 
			
		||||
     * 
 | 
			
		||||
     * If an erasure occurs, the last element of the map will take the place of the erased element.
 | 
			
		||||
     */
 | 
			
		||||
    iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(iterator pos)
 | 
			
		||||
     */
 | 
			
		||||
    iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(iterator pos)
 | 
			
		||||
     */    
 | 
			
		||||
    size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.unordered_erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type unordered_erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.unordered_erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Serialize the map through the `serializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `serializer` parameter must be a function object that supports the following call:
 | 
			
		||||
     *  - `template<typename U> void operator()(const U& value);` where the types `std::uint64_t`, `float` and `std::pair<Key, T>` must be supported for U.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, ...) of the types it serializes
 | 
			
		||||
     * in the hands of the `Serializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Serializer>
 | 
			
		||||
    void serialize(Serializer& serializer) const {
 | 
			
		||||
        m_ht.serialize(serializer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deserialize a previouly serialized map through the `deserializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `deserializer` parameter must be a function object that supports the following calls:
 | 
			
		||||
     *  - `template<typename U> U operator()();` where the types `std::uint64_t`, `float` and `std::pair<Key, T>` must be supported for U.
 | 
			
		||||
     * 
 | 
			
		||||
     * If the deserialized hash map type is hash compatible with the serialized map, the deserialization process can be
 | 
			
		||||
     * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way 
 | 
			
		||||
     * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used
 | 
			
		||||
     * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with 
 | 
			
		||||
     * `hash_compatible` sets to true.
 | 
			
		||||
     * 
 | 
			
		||||
     * The behaviour is undefined if the type `Key` and `T` of the `ordered_map` are not the same as the
 | 
			
		||||
     * types used during serialization.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, size of int, ...) of the types it 
 | 
			
		||||
     * deserializes in the hands of the `Deserializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Deserializer>
 | 
			
		||||
    static ordered_map deserialize(Deserializer& deserializer, bool hash_compatible = false) {
 | 
			
		||||
        ordered_map map(0);
 | 
			
		||||
        map.m_ht.deserialize(deserializer, hash_compatible);
 | 
			
		||||
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht == rhs.m_ht; }
 | 
			
		||||
    friend bool operator!=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht != rhs.m_ht; }
 | 
			
		||||
    friend bool operator<(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht < rhs.m_ht; }
 | 
			
		||||
    friend bool operator<=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht <= rhs.m_ht; }
 | 
			
		||||
    friend bool operator>(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht > rhs.m_ht; }
 | 
			
		||||
    friend bool operator>=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht >= rhs.m_ht; }
 | 
			
		||||
    
 | 
			
		||||
    friend void swap(ordered_map& lhs, ordered_map& rhs) { lhs.swap(rhs); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										688
									
								
								src/includes/3thparty/tsl/ordered_set.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										688
									
								
								src/includes/3thparty/tsl/ordered_set.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,688 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_ORDERED_SET_H
 | 
			
		||||
#define TSL_ORDERED_SET_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "ordered_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of an hash set using open adressing with robin hood with backshift delete to resolve collisions.
 | 
			
		||||
 * 
 | 
			
		||||
 * The particularity of this hash set is that it remembers the order in which the elements were added and
 | 
			
		||||
 * provide a way to access the structure which stores these values through the 'values_container()' method. 
 | 
			
		||||
 * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but
 | 
			
		||||
 * a std::vector may be used. In this case the set provides a 'data()' method which give a direct access 
 | 
			
		||||
 * to the memory used to store the values (which can be usefull to communicate with C API's).
 | 
			
		||||
 * 
 | 
			
		||||
 * The Key must be copy constructible and/or move constructible. To use `unordered_erase` it also must be swappable.
 | 
			
		||||
 * 
 | 
			
		||||
 * The behaviour of the hash set is undefinded if the destructor of Key throws an exception.
 | 
			
		||||
 * 
 | 
			
		||||
 * By default the maximum size of a set is limited to 2^32 - 1 values, if needed this can be changed through
 | 
			
		||||
 * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each
 | 
			
		||||
 * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()).
 | 
			
		||||
 *  - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer 
 | 
			
		||||
 *                                               and if size() < capacity(), only end(). 
 | 
			
		||||
 *                                               Otherwise all the iterators are invalidated if an insert occurs.
 | 
			
		||||
 *  - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of 
 | 
			
		||||
 *                            the erased element and all the ones after the erased element (including end()). 
 | 
			
		||||
 *                            Otherwise all the iterators are invalidated if an erase occurs.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>,
 | 
			
		||||
         class ValueTypeContainer = std::deque<Key, Allocator>,
 | 
			
		||||
         class IndexType = std::uint_least32_t>
 | 
			
		||||
class ordered_set {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const Key& key) const noexcept {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(Key& key) noexcept {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    using ht = detail_ordered_hash::ordered_hash<Key, KeySelect, void,
 | 
			
		||||
                                                 Hash, KeyEqual, Allocator, ValueTypeContainer, IndexType>;
 | 
			
		||||
            
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
    using reverse_iterator = typename ht::reverse_iterator;
 | 
			
		||||
    using const_reverse_iterator = typename ht::const_reverse_iterator;
 | 
			
		||||
    
 | 
			
		||||
    using values_container_type = typename ht::values_container_type;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    ordered_set(): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit ordered_set(size_type bucket_count, 
 | 
			
		||||
                         const Hash& hash = Hash(),
 | 
			
		||||
                         const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                         const Allocator& alloc = Allocator()): 
 | 
			
		||||
                        m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    ordered_set(size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc): ordered_set(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    ordered_set(size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc): ordered_set(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit ordered_set(const Allocator& alloc): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    ordered_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                const Hash& hash = Hash(),
 | 
			
		||||
                const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                const Allocator& alloc = Allocator()): ordered_set(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    ordered_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc): ordered_set(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    ordered_set(InputIt first, InputIt last,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc): ordered_set(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ordered_set(std::initializer_list<value_type> init,
 | 
			
		||||
                size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
                const Hash& hash = Hash(),
 | 
			
		||||
                const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                const Allocator& alloc = Allocator()): 
 | 
			
		||||
            ordered_set(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ordered_set(std::initializer_list<value_type> init,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Allocator& alloc): 
 | 
			
		||||
            ordered_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ordered_set(std::initializer_list<value_type> init,
 | 
			
		||||
                size_type bucket_count,
 | 
			
		||||
                const Hash& hash,
 | 
			
		||||
                const Allocator& alloc): 
 | 
			
		||||
            ordered_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    ordered_set& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    reverse_iterator rbegin() noexcept { return m_ht.rbegin(); }
 | 
			
		||||
    const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); }
 | 
			
		||||
    const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    reverse_iterator rend() noexcept { return m_ht.rend(); }
 | 
			
		||||
    const_reverse_iterator rend() const noexcept { return m_ht.rend(); }
 | 
			
		||||
    const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { return m_ht.insert(value); }
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { return m_ht.insert(std::move(value)); }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) {
 | 
			
		||||
        return m_ht.insert_hint(hint, value); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { m_ht.insert(first, last); }
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { m_ht.insert(ilist.begin(), ilist.end()); }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { return m_ht.emplace(std::forward<Args>(args)...); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * When erasing an element, the insert order will be preserved and no holes will be present in the container
 | 
			
		||||
     * returned by 'values_container()'. 
 | 
			
		||||
     * 
 | 
			
		||||
     * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1)
 | 
			
		||||
     * average complexity.
 | 
			
		||||
     */    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     */    
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     */    
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const key_type& key, std::size_t precalculated_hash)
 | 
			
		||||
     * 
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(ordered_set& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */     
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>     
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>     
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count) { m_ht.rehash(count); }
 | 
			
		||||
    void reserve(size_type count) { m_ht.reserve(count); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a const_iterator to an iterator.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Requires index <= size().
 | 
			
		||||
     * 
 | 
			
		||||
     * Return an iterator to the element at index. Return end() if index == size().
 | 
			
		||||
     */
 | 
			
		||||
    iterator nth(size_type index) { return m_ht.nth(index); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc nth(size_type index)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator nth(size_type index) const { return m_ht.nth(index); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return const_reference to the first element. Requires the container to not be empty.
 | 
			
		||||
     */
 | 
			
		||||
    const_reference front() const { return m_ht.front(); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return const_reference to the last element. Requires the container to not be empty.
 | 
			
		||||
     */
 | 
			
		||||
    const_reference back() const { return m_ht.back(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'.
 | 
			
		||||
     */ 
 | 
			
		||||
    template<class U = values_container_type, typename std::enable_if<tsl::detail_ordered_hash::is_vector<U>::value>::type* = nullptr>    
 | 
			
		||||
    const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the container in which the values are stored. The values are in the same order as the insertion order
 | 
			
		||||
     * and are contiguous in the structure, no holes (size() == values_container().size()).
 | 
			
		||||
     */        
 | 
			
		||||
    const values_container_type& values_container() const noexcept { return m_ht.values_container(); }
 | 
			
		||||
 | 
			
		||||
    template<class U = values_container_type, typename std::enable_if<tsl::detail_ordered_hash::is_vector<U>::value>::type* = nullptr>    
 | 
			
		||||
    size_type capacity() const noexcept { return m_ht.capacity(); }
 | 
			
		||||
    
 | 
			
		||||
    void shrink_to_fit() { m_ht.shrink_to_fit(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Insert the value before pos shifting all the elements on the right of pos (including pos) one position 
 | 
			
		||||
     * to the right.
 | 
			
		||||
     * 
 | 
			
		||||
     * Amortized linear time-complexity in the distance between pos and end().
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, bool> insert_at_position(const_iterator pos, const value_type& value) { 
 | 
			
		||||
        return m_ht.insert_at_position(pos, value); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc insert_at_position(const_iterator pos, const value_type& value)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, bool> insert_at_position(const_iterator pos, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert_at_position(pos, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc insert_at_position(const_iterator pos, const value_type& value)
 | 
			
		||||
     * 
 | 
			
		||||
     * Same as insert_at_position(pos, value_type(std::forward<Args>(args)...), mainly
 | 
			
		||||
     * here for coherence.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace_at_position(const_iterator pos, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_at_position(pos, std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void pop_back() { m_ht.pop_back(); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order.
 | 
			
		||||
     * 
 | 
			
		||||
     * If an erasure occurs, the last element of the map will take the place of the erased element.
 | 
			
		||||
     */    
 | 
			
		||||
    iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(iterator pos)
 | 
			
		||||
     */    
 | 
			
		||||
    iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(iterator pos)
 | 
			
		||||
     */    
 | 
			
		||||
    size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.unordered_erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(iterator pos)
 | 
			
		||||
     * 
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc unordered_erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type unordered_erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.unordered_erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Serialize the set through the `serializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `serializer` parameter must be a function object that supports the following call:
 | 
			
		||||
     *  - `void operator()(const U& value);` where the types `std::uint64_t`, `float` and `Key` must be supported for U.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, ...) of the types it serializes
 | 
			
		||||
     * in the hands of the `Serializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Serializer>
 | 
			
		||||
    void serialize(Serializer& serializer) const {
 | 
			
		||||
        m_ht.serialize(serializer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deserialize a previouly serialized set through the `deserializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `deserializer` parameter must be a function object that supports the following calls:
 | 
			
		||||
     *  - `template<typename U> U operator()();` where the types `std::uint64_t`, `float` and `Key` must be supported for U.
 | 
			
		||||
     * 
 | 
			
		||||
     * If the deserialized hash set type is hash compatible with the serialized set, the deserialization process can be
 | 
			
		||||
     * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way 
 | 
			
		||||
     * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used
 | 
			
		||||
     * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with 
 | 
			
		||||
     * `hash_compatible` sets to true.
 | 
			
		||||
     *
 | 
			
		||||
     * The behaviour is undefined if the type `Key` of the `ordered_set` is not the same as the
 | 
			
		||||
     * type used during serialization.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, size of int, ...) of the types it 
 | 
			
		||||
     * deserializes in the hands of the `Deserializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Deserializer>
 | 
			
		||||
    static ordered_set deserialize(Deserializer& deserializer, bool hash_compatible = false) {
 | 
			
		||||
        ordered_set set(0);
 | 
			
		||||
        set.m_ht.deserialize(deserializer, hash_compatible);
 | 
			
		||||
 | 
			
		||||
        return set;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht == rhs.m_ht; }
 | 
			
		||||
    friend bool operator!=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht != rhs.m_ht; }
 | 
			
		||||
    friend bool operator<(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht < rhs.m_ht; }
 | 
			
		||||
    friend bool operator<=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht <= rhs.m_ht; }
 | 
			
		||||
    friend bool operator>(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht > rhs.m_ht; }
 | 
			
		||||
    friend bool operator>=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht >= rhs.m_ht; }
 | 
			
		||||
    
 | 
			
		||||
    friend void swap(ordered_set& lhs, ordered_set& rhs) { lhs.swap(rhs); }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;    
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										348
									
								
								src/includes/3thparty/tsl/robin_growth_policy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								src/includes/3thparty/tsl/robin_growth_policy.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,348 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_ROBIN_GROWTH_POLICY_H
 | 
			
		||||
#define TSL_ROBIN_GROWTH_POLICY_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <ratio>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef TSL_DEBUG
 | 
			
		||||
#    define tsl_rh_assert(expr) assert(expr)
 | 
			
		||||
#else
 | 
			
		||||
#    define tsl_rh_assert(expr) (static_cast<void>(0))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * If exceptions are enabled, throw the exception passed in parameter, otherwise call std::terminate.
 | 
			
		||||
 */
 | 
			
		||||
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (defined (_MSC_VER) && defined (_CPPUNWIND))) && !defined(TSL_NO_EXCEPTIONS)
 | 
			
		||||
#    define TSL_RH_THROW_OR_TERMINATE(ex, msg) throw ex(msg)
 | 
			
		||||
#else
 | 
			
		||||
#    define TSL_RH_NO_EXCEPTIONS
 | 
			
		||||
#    ifdef NDEBUG
 | 
			
		||||
#        define TSL_RH_THROW_OR_TERMINATE(ex, msg) std::terminate()
 | 
			
		||||
#    else
 | 
			
		||||
#        include <iostream>
 | 
			
		||||
#        define TSL_RH_THROW_OR_TERMINATE(ex, msg) do { std::cerr << msg << std::endl; std::terminate(); } while(0)
 | 
			
		||||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if defined(__GNUC__) || defined(__clang__)
 | 
			
		||||
#    define TSL_RH_LIKELY(exp) (__builtin_expect(!!(exp), true))
 | 
			
		||||
#else
 | 
			
		||||
#    define TSL_RH_LIKELY(exp) (exp)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
namespace rh {
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by a factor of GrowthFactor keeping the bucket count to a power of two. It allows
 | 
			
		||||
 * the table to use a mask operation instead of a modulo operation to map a hash to a bucket.
 | 
			
		||||
 * 
 | 
			
		||||
 * GrowthFactor must be a power of two >= 2.
 | 
			
		||||
 */
 | 
			
		||||
template<std::size_t GrowthFactor>
 | 
			
		||||
class power_of_two_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    /**
 | 
			
		||||
     * Called on the hash table creation and on rehash. The number of buckets for the table is passed in parameter.
 | 
			
		||||
     * This number is a minimum, the policy may update this value with a higher value if needed (but not lower).
 | 
			
		||||
     *
 | 
			
		||||
     * If 0 is given, min_bucket_count_in_out must still be 0 after the policy creation and
 | 
			
		||||
     * bucket_for_hash must always return 0 in this case.
 | 
			
		||||
     */
 | 
			
		||||
    explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        if(min_bucket_count_in_out > max_bucket_count()) {
 | 
			
		||||
            TSL_RH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            min_bucket_count_in_out = round_up_to_power_of_two(min_bucket_count_in_out);
 | 
			
		||||
            m_mask = min_bucket_count_in_out - 1;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_mask = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the bucket [0, bucket_count()) to which the hash belongs. 
 | 
			
		||||
     * If bucket_count() is 0, it must always return 0.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return hash & m_mask;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of buckets that should be used on next growth.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if((m_mask + 1) > max_bucket_count() / GrowthFactor) {
 | 
			
		||||
            TSL_RH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return (m_mask + 1) * GrowthFactor;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the maximum number of buckets supported by the policy.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        // Largest power of two.
 | 
			
		||||
        return (std::numeric_limits<std::size_t>::max() / 2) + 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Reset the growth policy as if it was created with a bucket count of 0.
 | 
			
		||||
     * After a clear, the policy must always return 0 when bucket_for_hash is called.
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_mask = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static std::size_t round_up_to_power_of_two(std::size_t value) {
 | 
			
		||||
        if(is_power_of_two(value)) {
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(value == 0) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        --value;
 | 
			
		||||
        for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) {
 | 
			
		||||
            value |= value >> i;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return value + 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    static constexpr bool is_power_of_two(std::size_t value) {
 | 
			
		||||
        return value != 0 && (value & (value - 1)) == 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
protected:
 | 
			
		||||
    static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2, "GrowthFactor must be a power of two >= 2.");
 | 
			
		||||
    
 | 
			
		||||
    std::size_t m_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo to map a hash
 | 
			
		||||
 * to a bucket. Slower but it can be useful if you want a slower growth.
 | 
			
		||||
 */
 | 
			
		||||
template<class GrowthFactor = std::ratio<3, 2>>
 | 
			
		||||
class mod_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        if(min_bucket_count_in_out > max_bucket_count()) {
 | 
			
		||||
            TSL_RH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            m_mod = min_bucket_count_in_out;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_mod = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return hash % m_mod;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if(m_mod == max_bucket_count()) {
 | 
			
		||||
            TSL_RH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        const double next_bucket_count = std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
 | 
			
		||||
        if(!std::isnormal(next_bucket_count)) {
 | 
			
		||||
            TSL_RH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(next_bucket_count > double(max_bucket_count())) {
 | 
			
		||||
            return max_bucket_count();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return std::size_t(next_bucket_count);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        return MAX_BUCKET_COUNT;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_mod = 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR = 1.0 * GrowthFactor::num / GrowthFactor::den;
 | 
			
		||||
    static const std::size_t MAX_BUCKET_COUNT = 
 | 
			
		||||
            std::size_t(double(
 | 
			
		||||
                    std::numeric_limits<std::size_t>::max() / REHASH_SIZE_MULTIPLICATION_FACTOR
 | 
			
		||||
            ));
 | 
			
		||||
            
 | 
			
		||||
    static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1, "Growth factor should be >= 1.1.");
 | 
			
		||||
    
 | 
			
		||||
    std::size_t m_mod;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
#if SIZE_MAX >= ULLONG_MAX
 | 
			
		||||
#define TSL_RH_NB_PRIMES 51
 | 
			
		||||
#elif SIZE_MAX >= ULONG_MAX
 | 
			
		||||
#define TSL_RH_NB_PRIMES 40
 | 
			
		||||
#else
 | 
			
		||||
#define TSL_RH_NB_PRIMES 23
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static constexpr const std::array<std::size_t, TSL_RH_NB_PRIMES> PRIMES = {{
 | 
			
		||||
    1u, 5u, 17u, 29u, 37u, 53u, 67u, 79u, 97u, 131u, 193u, 257u, 389u, 521u, 769u, 1031u, 
 | 
			
		||||
    1543u, 2053u, 3079u, 6151u, 12289u, 24593u, 49157u,
 | 
			
		||||
#if SIZE_MAX >= ULONG_MAX
 | 
			
		||||
    98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 
 | 
			
		||||
    25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 
 | 
			
		||||
    3221225473ul, 4294967291ul,
 | 
			
		||||
#endif
 | 
			
		||||
#if SIZE_MAX >= ULLONG_MAX
 | 
			
		||||
    6442450939ull, 12884901893ull, 25769803751ull, 51539607551ull, 103079215111ull, 206158430209ull, 
 | 
			
		||||
    412316860441ull, 824633720831ull, 1649267441651ull, 3298534883309ull, 6597069766657ull,
 | 
			
		||||
#endif
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
template<unsigned int IPrime>
 | 
			
		||||
static constexpr std::size_t mod(std::size_t hash) { return hash % PRIMES[IPrime]; }
 | 
			
		||||
 | 
			
		||||
// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for faster modulo as the
 | 
			
		||||
// compiler can optimize the modulo code better with a constant known at the compilation.
 | 
			
		||||
static constexpr const std::array<std::size_t(*)(std::size_t), TSL_RH_NB_PRIMES> MOD_PRIME = {{ 
 | 
			
		||||
    &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>, &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, 
 | 
			
		||||
    &mod<11>, &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>, &mod<18>, &mod<19>, &mod<20>, 
 | 
			
		||||
    &mod<21>, &mod<22>,  
 | 
			
		||||
#if SIZE_MAX >= ULONG_MAX
 | 
			
		||||
    &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, &mod<29>, &mod<30>, &mod<31>, &mod<32>, 
 | 
			
		||||
    &mod<33>, &mod<34>, &mod<35>, &mod<36>, &mod<37> , &mod<38>, &mod<39>,
 | 
			
		||||
#endif
 | 
			
		||||
#if SIZE_MAX >= ULLONG_MAX
 | 
			
		||||
    &mod<40>, &mod<41>, &mod<42>, &mod<43>, &mod<44>, &mod<45>, &mod<46>, &mod<47>, &mod<48>, &mod<49>, 
 | 
			
		||||
    &mod<50>,
 | 
			
		||||
#endif
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by using prime numbers as bucket count. Slower than tsl::rh::power_of_two_growth_policy in  
 | 
			
		||||
 * general but will probably distribute the values around better in the buckets with a poor hash function.
 | 
			
		||||
 * 
 | 
			
		||||
 * To allow the compiler to optimize the modulo operation, a lookup table is used with constant primes numbers.
 | 
			
		||||
 * 
 | 
			
		||||
 * With a switch the code would look like:
 | 
			
		||||
 * \code
 | 
			
		||||
 * switch(iprime) { // iprime is the current prime of the hash table
 | 
			
		||||
 *     case 0: hash % 5ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     case 1: hash % 17ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     case 2: hash % 29ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     ...
 | 
			
		||||
 * }    
 | 
			
		||||
 * \endcode
 | 
			
		||||
 * 
 | 
			
		||||
 * Due to the constant variable in the modulo the compiler is able to optimize the operation
 | 
			
		||||
 * by a series of multiplications, substractions and shifts. 
 | 
			
		||||
 * 
 | 
			
		||||
 * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) * 5' in a 64 bits environement.
 | 
			
		||||
 */
 | 
			
		||||
class prime_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    explicit prime_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        auto it_prime = std::lower_bound(detail::PRIMES.begin(), 
 | 
			
		||||
                                         detail::PRIMES.end(), min_bucket_count_in_out);
 | 
			
		||||
        if(it_prime == detail::PRIMES.end()) {
 | 
			
		||||
            TSL_RH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        m_iprime = static_cast<unsigned int>(std::distance(detail::PRIMES.begin(), it_prime));
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            min_bucket_count_in_out = *it_prime;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            min_bucket_count_in_out = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return detail::MOD_PRIME[m_iprime](hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if(m_iprime + 1 >= detail::PRIMES.size()) {
 | 
			
		||||
            TSL_RH_THROW_OR_TERMINATE(std::length_error, "The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return detail::PRIMES[m_iprime + 1];
 | 
			
		||||
    }   
 | 
			
		||||
    
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        return detail::PRIMES.back();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_iprime = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    unsigned int m_iprime;
 | 
			
		||||
    
 | 
			
		||||
    static_assert(std::numeric_limits<decltype(m_iprime)>::max() >= detail::PRIMES.size(), 
 | 
			
		||||
                  "The type of m_iprime is not big enough.");
 | 
			
		||||
}; 
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1441
									
								
								src/includes/3thparty/tsl/robin_hash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1441
									
								
								src/includes/3thparty/tsl/robin_hash.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										715
									
								
								src/includes/3thparty/tsl/robin_map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										715
									
								
								src/includes/3thparty/tsl/robin_map.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,715 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_ROBIN_MAP_H
 | 
			
		||||
#define TSL_ROBIN_MAP_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "robin_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of a hash map using open-adressing and the robin hood hashing algorithm with backward shift deletion.
 | 
			
		||||
 * 
 | 
			
		||||
 * For operations modifying the hash map (insert, erase, rehash, ...), the strong exception guarantee 
 | 
			
		||||
 * is only guaranteed when the expression `std::is_nothrow_swappable<std::pair<Key, T>>::value &&
 | 
			
		||||
 * std::is_nothrow_move_constructible<std::pair<Key, T>>::value` is true, otherwise if an exception
 | 
			
		||||
 * is thrown during the swap or the move, the hash map may end up in a undefined state. Per the standard
 | 
			
		||||
 * a `Key` or `T` with a noexcept copy constructor and no move constructor also satisfies the 
 | 
			
		||||
 * `std::is_nothrow_move_constructible<std::pair<Key, T>>::value` criterion (and will thus guarantee the 
 | 
			
		||||
 * strong exception for the map).
 | 
			
		||||
 * 
 | 
			
		||||
 * When `StoreHash` is true, 32 bits of the hash are stored alongside the values. It can improve 
 | 
			
		||||
 * the performance during lookups if the `KeyEqual` function takes time (if it engenders a cache-miss for example) 
 | 
			
		||||
 * as we then compare the stored hashes before comparing the keys. When `tsl::rh::power_of_two_growth_policy` is used
 | 
			
		||||
 * as `GrowthPolicy`, it may also speed-up the rehash process as we can avoid to recalculate the hash. 
 | 
			
		||||
 * When it is detected that storing the hash will not incur any memory penality due to alignement (i.e. 
 | 
			
		||||
 * `sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, true>) == 
 | 
			
		||||
 * sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, false>)`) and `tsl::rh::power_of_two_growth_policy` is
 | 
			
		||||
 * used, the hash will be stored even if `StoreHash` is false so that we can speed-up the rehash (but it will
 | 
			
		||||
 * not be used on lookups unless `StoreHash` is true).
 | 
			
		||||
 * 
 | 
			
		||||
 * `GrowthPolicy` defines how the map grows and consequently how a hash value is mapped to a bucket. 
 | 
			
		||||
 * By default the map uses `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of buckets 
 | 
			
		||||
 * to a power of two and uses a mask to map the hash to a bucket instead of the slow modulo.
 | 
			
		||||
 * Other growth policies are available and you may define your own growth policy, 
 | 
			
		||||
 * check `tsl::rh::power_of_two_growth_policy` for the interface.
 | 
			
		||||
 * 
 | 
			
		||||
 * `std::pair<Key, T>` must be swappable.
 | 
			
		||||
 * 
 | 
			
		||||
 * `Key` and `T` must be copy and/or move constructible.
 | 
			
		||||
 * 
 | 
			
		||||
 * If the destructor of `Key` or `T` throws an exception, the behaviour of the class is undefined.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=, reserve, rehash: always invalidate the iterators.
 | 
			
		||||
 *  - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators.
 | 
			
		||||
 *  - erase: always invalidate the iterators.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<Key, T>>,
 | 
			
		||||
         bool StoreHash = false,
 | 
			
		||||
         class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>>
 | 
			
		||||
class robin_map {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_robin_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const std::pair<Key, T>& key_value) const noexcept {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(std::pair<Key, T>& key_value) noexcept {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
    };  
 | 
			
		||||
    
 | 
			
		||||
    class ValueSelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using value_type = T;
 | 
			
		||||
        
 | 
			
		||||
        const value_type& operator()(const std::pair<Key, T>& key_value) const noexcept {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        value_type& operator()(std::pair<Key, T>& key_value) noexcept {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    using ht = detail_robin_hash::robin_hash<std::pair<Key, T>, KeySelect, ValueSelect,
 | 
			
		||||
                                             Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>;  
 | 
			
		||||
                                             
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using mapped_type = T;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    robin_map(): robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit robin_map(size_type bucket_count, 
 | 
			
		||||
                       const Hash& hash = Hash(),
 | 
			
		||||
                       const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                       const Allocator& alloc = Allocator()): 
 | 
			
		||||
                m_ht(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    robin_map(size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): robin_map(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    robin_map(size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): robin_map(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit robin_map(const Allocator& alloc): robin_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    robin_map(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
              const Hash& hash = Hash(),
 | 
			
		||||
              const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
              const Allocator& alloc = Allocator()): robin_map(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    robin_map(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): robin_map(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    robin_map(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): robin_map(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    robin_map(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
              const Hash& hash = Hash(),
 | 
			
		||||
              const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
              const Allocator& alloc = Allocator()): 
 | 
			
		||||
          robin_map(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    robin_map(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): 
 | 
			
		||||
          robin_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    robin_map(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): 
 | 
			
		||||
          robin_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    robin_map& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { 
 | 
			
		||||
        return m_ht.insert(value); 
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    std::pair<iterator, bool> insert(P&& value) { 
 | 
			
		||||
        return m_ht.emplace(std::forward<P>(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { 
 | 
			
		||||
        return m_ht.insert(std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, value); 
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    iterator insert(const_iterator hint, P&& value) { 
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<P>(value));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { 
 | 
			
		||||
        m_ht.insert(first, last); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { 
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end()); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(k, std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(std::move(k), std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, k, std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, std::move(k), std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { 
 | 
			
		||||
        return m_ht.emplace(std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args) { 
 | 
			
		||||
        return m_ht.try_emplace(k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace_hint(hint, k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace_hint(hint, std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(robin_map& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key) { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    const T& at(const Key& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key) { return m_ht.at(key); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    T& operator[](const Key& key) { return m_ht[key]; }    
 | 
			
		||||
    T& operator[](Key&& key) { return m_ht[std::move(key)]; }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */     
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    bool contains(const Key& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    bool contains(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc contains(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    
 | 
			
		||||
    float min_load_factor() const { return m_ht.min_load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the `min_load_factor` to `ml`. When the `load_factor` of the map goes
 | 
			
		||||
     * below `min_load_factor` after some erase operations, the map will be
 | 
			
		||||
     * shrunk when an insertion occurs. The erase method itself never shrinks
 | 
			
		||||
     * the map.
 | 
			
		||||
     * 
 | 
			
		||||
     * The default value of `min_load_factor` is 0.0f, the map never shrinks by default.
 | 
			
		||||
     */
 | 
			
		||||
    void min_load_factor(float ml) { m_ht.min_load_factor(ml); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count) { m_ht.rehash(count); }
 | 
			
		||||
    void reserve(size_type count) { m_ht.reserve(count); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a const_iterator to an iterator.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const robin_map& lhs, const robin_map& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(const auto& element_lhs: lhs) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find(element_lhs.first);
 | 
			
		||||
            if(it_element_rhs == rhs.cend() || element_lhs.second != it_element_rhs->second) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const robin_map& lhs, const robin_map& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(robin_map& lhs, robin_map& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as `tsl::robin_map<Key, T, Hash, KeyEqual, Allocator, StoreHash, tsl::rh::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<Key, T>>,
 | 
			
		||||
         bool StoreHash = false>
 | 
			
		||||
using robin_pg_map = robin_map<Key, T, Hash, KeyEqual, Allocator, StoreHash, tsl::rh::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										582
									
								
								src/includes/3thparty/tsl/robin_set.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										582
									
								
								src/includes/3thparty/tsl/robin_set.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,582 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_ROBIN_SET_H
 | 
			
		||||
#define TSL_ROBIN_SET_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "robin_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of a hash set using open-adressing and the robin hood hashing algorithm with backward shift deletion.
 | 
			
		||||
 * 
 | 
			
		||||
 * For operations modifying the hash set (insert, erase, rehash, ...), the strong exception guarantee 
 | 
			
		||||
 * is only guaranteed when the expression `std::is_nothrow_swappable<Key>::value &&
 | 
			
		||||
 * std::is_nothrow_move_constructible<Key>::value` is true, otherwise if an exception
 | 
			
		||||
 * is thrown during the swap or the move, the hash set may end up in a undefined state. Per the standard
 | 
			
		||||
 * a `Key` with a noexcept copy constructor and no move constructor also satisfies the 
 | 
			
		||||
 * `std::is_nothrow_move_constructible<Key>::value` criterion (and will thus guarantee the 
 | 
			
		||||
 * strong exception for the set).
 | 
			
		||||
 * 
 | 
			
		||||
 * When `StoreHash` is true, 32 bits of the hash are stored alongside the values. It can improve 
 | 
			
		||||
 * the performance during lookups if the `KeyEqual` function takes time (or engenders a cache-miss for example) 
 | 
			
		||||
 * as we then compare the stored hashes before comparing the keys. When `tsl::rh::power_of_two_growth_policy` is used
 | 
			
		||||
 * as `GrowthPolicy`, it may also speed-up the rehash process as we can avoid to recalculate the hash. 
 | 
			
		||||
 * When it is detected that storing the hash will not incur any memory penality due to alignement (i.e. 
 | 
			
		||||
 * `sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, true>) == 
 | 
			
		||||
 * sizeof(tsl::detail_robin_hash::bucket_entry<ValueType, false>)`) and `tsl::rh::power_of_two_growth_policy` is
 | 
			
		||||
 * used, the hash will be stored even if `StoreHash` is false so that we can speed-up the rehash (but it will
 | 
			
		||||
 * not be used on lookups unless `StoreHash` is true).
 | 
			
		||||
 * 
 | 
			
		||||
 * `GrowthPolicy` defines how the set grows and consequently how a hash value is mapped to a bucket. 
 | 
			
		||||
 * By default the set uses `tsl::rh::power_of_two_growth_policy`. This policy keeps the number of buckets 
 | 
			
		||||
 * to a power of two and uses a mask to set the hash to a bucket instead of the slow modulo.
 | 
			
		||||
 * Other growth policies are available and you may define your own growth policy, 
 | 
			
		||||
 * check `tsl::rh::power_of_two_growth_policy` for the interface.
 | 
			
		||||
 * 
 | 
			
		||||
 * `Key` must be swappable.
 | 
			
		||||
 * 
 | 
			
		||||
 * `Key` must be copy and/or move constructible.
 | 
			
		||||
 * 
 | 
			
		||||
 * If the destructor of `Key` throws an exception, the behaviour of the class is undefined.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=, reserve, rehash: always invalidate the iterators.
 | 
			
		||||
 *  - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators.
 | 
			
		||||
 *  - erase: always invalidate the iterators.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>,
 | 
			
		||||
         bool StoreHash = false,
 | 
			
		||||
         class GrowthPolicy = tsl::rh::power_of_two_growth_policy<2>>
 | 
			
		||||
class robin_set {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_robin_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const Key& key) const noexcept {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(Key& key) noexcept {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    using ht = detail_robin_hash::robin_hash<Key, KeySelect, void,
 | 
			
		||||
                                             Hash, KeyEqual, Allocator, StoreHash, GrowthPolicy>;
 | 
			
		||||
            
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    robin_set(): robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit robin_set(size_type bucket_count, 
 | 
			
		||||
                       const Hash& hash = Hash(),
 | 
			
		||||
                       const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                       const Allocator& alloc = Allocator()): 
 | 
			
		||||
                    m_ht(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    robin_set(size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): robin_set(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    robin_set(size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): robin_set(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit robin_set(const Allocator& alloc): robin_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    robin_set(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
              const Hash& hash = Hash(),
 | 
			
		||||
              const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
              const Allocator& alloc = Allocator()): robin_set(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    robin_set(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): robin_set(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    robin_set(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): robin_set(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    robin_set(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
 | 
			
		||||
              const Hash& hash = Hash(),
 | 
			
		||||
              const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
              const Allocator& alloc = Allocator()): 
 | 
			
		||||
          robin_set(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    robin_set(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): 
 | 
			
		||||
          robin_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    robin_set(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): 
 | 
			
		||||
          robin_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    robin_set& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { 
 | 
			
		||||
        return m_ht.insert(value); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { 
 | 
			
		||||
        return m_ht.insert(std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, value); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { 
 | 
			
		||||
        m_ht.insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { 
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end()); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { 
 | 
			
		||||
        return m_ht.emplace(std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the std::unordered_map interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(robin_set& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    bool contains(const Key& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    bool contains(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc contains(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    
 | 
			
		||||
    float min_load_factor() const { return m_ht.min_load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the `min_load_factor` to `ml`. When the `load_factor` of the set goes
 | 
			
		||||
     * below `min_load_factor` after some erase operations, the set will be
 | 
			
		||||
     * shrunk when an insertion occurs. The erase method itself never shrinks
 | 
			
		||||
     * the set.
 | 
			
		||||
     * 
 | 
			
		||||
     * The default value of `min_load_factor` is 0.0f, the set never shrinks by default.
 | 
			
		||||
     */
 | 
			
		||||
    void min_load_factor(float ml) { m_ht.min_load_factor(ml); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count) { m_ht.rehash(count); }
 | 
			
		||||
    void reserve(size_type count) { m_ht.reserve(count); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a const_iterator to an iterator.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const robin_set& lhs, const robin_set& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(const auto& element_lhs: lhs) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find(element_lhs);
 | 
			
		||||
            if(it_element_rhs == rhs.cend()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const robin_set& lhs, const robin_set& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(robin_set& lhs, robin_set& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;    
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as `tsl::robin_set<Key, Hash, KeyEqual, Allocator, StoreHash, tsl::rh::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>,
 | 
			
		||||
         bool StoreHash = false>
 | 
			
		||||
using robin_pg_set = robin_set<Key, Hash, KeyEqual, Allocator, StoreHash, tsl::rh::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										295
									
								
								src/includes/3thparty/tsl/sparse_growth_policy.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								src/includes/3thparty/tsl/sparse_growth_policy.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,295 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_SPARSE_GROWTH_POLICY_H
 | 
			
		||||
#define TSL_SPARSE_GROWTH_POLICY_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <ratio>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
namespace sh {
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by a factor of GrowthFactor keeping the bucket count to a power of two. It allows
 | 
			
		||||
 * the table to use a mask operation instead of a modulo operation to map a hash to a bucket.
 | 
			
		||||
 * 
 | 
			
		||||
 * GrowthFactor must be a power of two >= 2.
 | 
			
		||||
 */
 | 
			
		||||
template<std::size_t GrowthFactor>
 | 
			
		||||
class power_of_two_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    /**
 | 
			
		||||
     * Called on the hash table creation and on rehash. The number of buckets for the table is passed in parameter.
 | 
			
		||||
     * This number is a minimum, the policy may update this value with a higher value if needed (but not lower).
 | 
			
		||||
     *
 | 
			
		||||
     * If 0 is given, min_bucket_count_in_out must still be 0 after the policy creation and
 | 
			
		||||
     * bucket_for_hash must always return 0 in this case.
 | 
			
		||||
     */
 | 
			
		||||
    explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        if(min_bucket_count_in_out > max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            min_bucket_count_in_out = round_up_to_power_of_two(min_bucket_count_in_out);
 | 
			
		||||
            m_mask = min_bucket_count_in_out - 1;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_mask = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the bucket [0, bucket_count()) to which the hash belongs. 
 | 
			
		||||
     * If bucket_count() is 0, it must always return 0.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return hash & m_mask;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the number of buckets that should be used on next growth.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if((m_mask + 1) > max_bucket_count() / GrowthFactor) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return (m_mask + 1) * GrowthFactor;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Return the maximum number of buckets supported by the policy.
 | 
			
		||||
     */
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        // Largest power of two.
 | 
			
		||||
        return (std::numeric_limits<std::size_t>::max() / 2) + 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Reset the growth policy as if it was created with a bucket count of 0.
 | 
			
		||||
     * After a clear, the policy must always return 0 when bucket_for_hash is called.
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_mask = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static std::size_t round_up_to_power_of_two(std::size_t value) {
 | 
			
		||||
        if(is_power_of_two(value)) {
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(value == 0) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        --value;
 | 
			
		||||
        for(std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) {
 | 
			
		||||
            value |= value >> i;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return value + 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    static constexpr bool is_power_of_two(std::size_t value) {
 | 
			
		||||
        return value != 0 && (value & (value - 1)) == 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
protected:
 | 
			
		||||
    static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2, "GrowthFactor must be a power of two >= 2.");
 | 
			
		||||
    
 | 
			
		||||
    std::size_t m_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo to map a hash
 | 
			
		||||
 * to a bucket. Slower but it can be useful if you want a slower growth.
 | 
			
		||||
 */
 | 
			
		||||
template<class GrowthFactor = std::ratio<3, 2>>
 | 
			
		||||
class mod_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        if(min_bucket_count_in_out > max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            m_mod = min_bucket_count_in_out;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_mod = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return hash % m_mod;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if(m_mod == max_bucket_count()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        const double next_bucket_count = std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
 | 
			
		||||
        if(!std::isnormal(next_bucket_count)) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if(next_bucket_count > double(max_bucket_count())) {
 | 
			
		||||
            return max_bucket_count();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return std::size_t(next_bucket_count);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        return MAX_BUCKET_COUNT;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_mod = 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR = 1.0 * GrowthFactor::num / GrowthFactor::den;
 | 
			
		||||
    static const std::size_t MAX_BUCKET_COUNT = 
 | 
			
		||||
            std::size_t(double(
 | 
			
		||||
                    std::numeric_limits<std::size_t>::max() / REHASH_SIZE_MULTIPLICATION_FACTOR
 | 
			
		||||
            ));
 | 
			
		||||
            
 | 
			
		||||
    static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1, "Growth factor should be >= 1.1.");
 | 
			
		||||
    
 | 
			
		||||
    std::size_t m_mod;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
static constexpr const std::array<std::size_t, 40> PRIMES = {{
 | 
			
		||||
    1ul, 5ul, 17ul, 29ul, 37ul, 53ul, 67ul, 79ul, 97ul, 131ul, 193ul, 257ul, 389ul, 521ul, 769ul, 1031ul, 
 | 
			
		||||
    1543ul, 2053ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 
 | 
			
		||||
    1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 
 | 
			
		||||
    402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
template<unsigned int IPrime>
 | 
			
		||||
static constexpr std::size_t mod(std::size_t hash) { return hash % PRIMES[IPrime]; }
 | 
			
		||||
 | 
			
		||||
// MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for faster modulo as the
 | 
			
		||||
// compiler can optimize the modulo code better with a constant known at the compilation.
 | 
			
		||||
static constexpr const std::array<std::size_t(*)(std::size_t), 40> MOD_PRIME = {{ 
 | 
			
		||||
    &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>, &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, 
 | 
			
		||||
    &mod<11>, &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>, &mod<18>, &mod<19>, &mod<20>, 
 | 
			
		||||
    &mod<21>, &mod<22>, &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>, &mod<29>, &mod<30>, 
 | 
			
		||||
    &mod<31>, &mod<32>, &mod<33>, &mod<34>, &mod<35>, &mod<36>, &mod<37> , &mod<38>, &mod<39>
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Grow the hash table by using prime numbers as bucket count. Slower than tsl::sh::power_of_two_growth_policy in  
 | 
			
		||||
 * general but will probably distribute the values around better in the buckets with a poor hash function.
 | 
			
		||||
 * 
 | 
			
		||||
 * To allow the compiler to optimize the modulo operation, a lookup table is used with constant primes numbers.
 | 
			
		||||
 * 
 | 
			
		||||
 * With a switch the code would look like:
 | 
			
		||||
 * \code
 | 
			
		||||
 * switch(iprime) { // iprime is the current prime of the hash table
 | 
			
		||||
 *     case 0: hash % 5ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     case 1: hash % 17ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     case 2: hash % 29ul;
 | 
			
		||||
 *             break;
 | 
			
		||||
 *     ...
 | 
			
		||||
 * }    
 | 
			
		||||
 * \endcode
 | 
			
		||||
 * 
 | 
			
		||||
 * Due to the constant variable in the modulo the compiler is able to optimize the operation
 | 
			
		||||
 * by a series of multiplications, substractions and shifts. 
 | 
			
		||||
 * 
 | 
			
		||||
 * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34) * 5' in a 64 bits environement.
 | 
			
		||||
 */
 | 
			
		||||
class prime_growth_policy {
 | 
			
		||||
public:
 | 
			
		||||
    explicit prime_growth_policy(std::size_t& min_bucket_count_in_out) {
 | 
			
		||||
        auto it_prime = std::lower_bound(detail::PRIMES.begin(), 
 | 
			
		||||
                                         detail::PRIMES.end(), min_bucket_count_in_out);
 | 
			
		||||
        if(it_prime == detail::PRIMES.end()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        m_iprime = static_cast<unsigned int>(std::distance(detail::PRIMES.begin(), it_prime));
 | 
			
		||||
        if(min_bucket_count_in_out > 0) {
 | 
			
		||||
            min_bucket_count_in_out = *it_prime;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            min_bucket_count_in_out = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t bucket_for_hash(std::size_t hash) const noexcept {
 | 
			
		||||
        return detail::MOD_PRIME[m_iprime](hash);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::size_t next_bucket_count() const {
 | 
			
		||||
        if(m_iprime + 1 >= detail::PRIMES.size()) {
 | 
			
		||||
            throw std::length_error("The hash table exceeds its maxmimum size.");
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return detail::PRIMES[m_iprime + 1];
 | 
			
		||||
    }   
 | 
			
		||||
    
 | 
			
		||||
    std::size_t max_bucket_count() const {
 | 
			
		||||
        return detail::PRIMES.back();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void clear() noexcept {
 | 
			
		||||
        m_iprime = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    unsigned int m_iprime;
 | 
			
		||||
    
 | 
			
		||||
    static_assert(std::numeric_limits<decltype(m_iprime)>::max() >= detail::PRIMES.size(), 
 | 
			
		||||
                  "The type of m_iprime is not big enough.");
 | 
			
		||||
}; 
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										2127
									
								
								src/includes/3thparty/tsl/sparse_hash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2127
									
								
								src/includes/3thparty/tsl/sparse_hash.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										749
									
								
								src/includes/3thparty/tsl/sparse_map.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										749
									
								
								src/includes/3thparty/tsl/sparse_map.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,749 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_SPARSE_MAP_H
 | 
			
		||||
#define TSL_SPARSE_MAP_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "sparse_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of a sparse hash map using open-addressing with quadratic probing.
 | 
			
		||||
 * The goal on the hash map is to be the most memory efficient possible, even at low load factor,
 | 
			
		||||
 * while keeping reasonable performances.
 | 
			
		||||
 * 
 | 
			
		||||
 * `GrowthPolicy` defines how the map grows and consequently how a hash value is mapped to a bucket. 
 | 
			
		||||
 * By default the map uses `tsl::sh::power_of_two_growth_policy`. This policy keeps the number of buckets 
 | 
			
		||||
 * to a power of two and uses a mask to map the hash to a bucket instead of the slow modulo.
 | 
			
		||||
 * Other growth policies are available and you may define your own growth policy, 
 | 
			
		||||
 * check `tsl::sh::power_of_two_growth_policy` for the interface.
 | 
			
		||||
 * 
 | 
			
		||||
 * `ExceptionSafety` defines the exception guarantee provided by the class. By default only the basic
 | 
			
		||||
 * exception safety is guaranteed which mean that all resources used by the hash map will be freed (no memory leaks) 
 | 
			
		||||
 * but the hash map may end-up in an undefined state if an exception is thrown (undefined here means that some elements  
 | 
			
		||||
 * may be missing). This can ONLY happen on rehash (either on insert or if `rehash` is called explicitly) and will
 | 
			
		||||
 * occur if the Allocator can't allocate memory (`std::bad_alloc`) or if the copy constructor (when a nothrow 
 | 
			
		||||
 * move constructor is not available) throws an exception. This can be avoided by calling `reserve` beforehand.
 | 
			
		||||
 * This basic guarantee is similar to the one of `google::sparse_hash_map` and `spp::sparse_hash_map`.
 | 
			
		||||
 * It is possible to ask for the strong exception guarantee with `tsl::sh::exception_safety::strong`, the drawback
 | 
			
		||||
 * is that the map will be slower on rehashes and will also need more memory on rehashes.
 | 
			
		||||
 * 
 | 
			
		||||
 * `Sparsity` defines how much the hash set will compromise between insertion speed and memory usage. A high
 | 
			
		||||
 * sparsity means less memory usage but longer insertion times, and vice-versa for low sparsity. The default 
 | 
			
		||||
 * `tsl::sh::sparsity::medium` sparsity offers a good compromise. It doesn't change the lookup speed.
 | 
			
		||||
 * 
 | 
			
		||||
 * `Key` and `T` must be nothrow move constructible and/or copy constructible.
 | 
			
		||||
 * 
 | 
			
		||||
 * If the destructor of `Key` or `T` throws an exception, the behaviour of the class is undefined.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=, reserve, rehash: always invalidate the iterators.
 | 
			
		||||
 *  - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators.
 | 
			
		||||
 *  - erase: always invalidate the iterators.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<Key, T>>,
 | 
			
		||||
         class GrowthPolicy = tsl::sh::power_of_two_growth_policy<2>,
 | 
			
		||||
         tsl::sh::exception_safety ExceptionSafety = tsl::sh::exception_safety::basic,
 | 
			
		||||
         tsl::sh::sparsity Sparsity = tsl::sh::sparsity::medium>
 | 
			
		||||
class sparse_map {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_sparse_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const std::pair<Key, T>& key_value) const noexcept {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(std::pair<Key, T>& key_value) noexcept {
 | 
			
		||||
            return key_value.first;
 | 
			
		||||
        }
 | 
			
		||||
    };  
 | 
			
		||||
    
 | 
			
		||||
    class ValueSelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using value_type = T;
 | 
			
		||||
        
 | 
			
		||||
        const value_type& operator()(const std::pair<Key, T>& key_value) const noexcept {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        value_type& operator()(std::pair<Key, T>& key_value) noexcept {
 | 
			
		||||
            return key_value.second;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    using ht = detail_sparse_hash::sparse_hash<std::pair<Key, T>, KeySelect, ValueSelect,
 | 
			
		||||
                                               Hash, KeyEqual, Allocator, GrowthPolicy,
 | 
			
		||||
                                               ExceptionSafety, Sparsity,
 | 
			
		||||
                                               tsl::sh::probing::quadratic>;  
 | 
			
		||||
                                             
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using mapped_type = T;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    sparse_map(): sparse_map(ht::DEFAULT_INIT_BUCKET_COUNT) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit sparse_map(size_type bucket_count, 
 | 
			
		||||
                        const Hash& hash = Hash(),
 | 
			
		||||
                        const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                        const Allocator& alloc = Allocator()): 
 | 
			
		||||
                    m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    sparse_map(size_type bucket_count,
 | 
			
		||||
               const Allocator& alloc): sparse_map(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    sparse_map(size_type bucket_count,
 | 
			
		||||
               const Hash& hash,
 | 
			
		||||
               const Allocator& alloc): sparse_map(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit sparse_map(const Allocator& alloc): sparse_map(ht::DEFAULT_INIT_BUCKET_COUNT, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    sparse_map(InputIt first, InputIt last,
 | 
			
		||||
               size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
               const Hash& hash = Hash(),
 | 
			
		||||
               const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
               const Allocator& alloc = Allocator()): sparse_map(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    sparse_map(InputIt first, InputIt last,
 | 
			
		||||
               size_type bucket_count,
 | 
			
		||||
               const Allocator& alloc): sparse_map(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    sparse_map(InputIt first, InputIt last,
 | 
			
		||||
               size_type bucket_count,
 | 
			
		||||
               const Hash& hash,
 | 
			
		||||
               const Allocator& alloc): sparse_map(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sparse_map(std::initializer_list<value_type> init,
 | 
			
		||||
               size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
               const Hash& hash = Hash(),
 | 
			
		||||
               const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
               const Allocator& alloc = Allocator()): 
 | 
			
		||||
          sparse_map(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sparse_map(std::initializer_list<value_type> init,
 | 
			
		||||
               size_type bucket_count,
 | 
			
		||||
               const Allocator& alloc): 
 | 
			
		||||
          sparse_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sparse_map(std::initializer_list<value_type> init,
 | 
			
		||||
               size_type bucket_count,
 | 
			
		||||
               const Hash& hash,
 | 
			
		||||
               const Allocator& alloc): 
 | 
			
		||||
          sparse_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    sparse_map& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { 
 | 
			
		||||
        return m_ht.insert(value); 
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    std::pair<iterator, bool> insert(P&& value) { 
 | 
			
		||||
        return m_ht.emplace(std::forward<P>(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { 
 | 
			
		||||
        return m_ht.insert(std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, value); 
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
 | 
			
		||||
    iterator insert(const_iterator hint, P&& value) { 
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<P>(value));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { 
 | 
			
		||||
        m_ht.insert(first, last); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { 
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end()); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(k, std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<class M>
 | 
			
		||||
    std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj) { 
 | 
			
		||||
        return m_ht.insert_or_assign(std::move(k), std::forward<M>(obj)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, k, std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class M>
 | 
			
		||||
    iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
 | 
			
		||||
        return m_ht.insert_or_assign(hint, std::move(k), std::forward<M>(obj));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to `insert(value_type(std::forward<Args>(args)...));`.
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the `std::unordered_map` interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { 
 | 
			
		||||
        return m_ht.emplace(std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to `insert(hint, value_type(std::forward<Args>(args)...));`.
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the `std::unordered_map` interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args) { 
 | 
			
		||||
        return m_ht.try_emplace(k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace(std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace_hint(hint, k, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
 | 
			
		||||
        return m_ht.try_emplace_hint(hint, std::move(k), std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */  
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(sparse_map& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key) { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    const T& at(const Key& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key) { return m_ht.at(key); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key) const { return m_ht.at(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc at(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    T& operator[](const Key& key) { return m_ht[key]; }    
 | 
			
		||||
    T& operator[](Key&& key) { return m_ht[std::move(key)]; }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.count(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */     
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.find(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    bool contains(const Key& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    bool contains(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc contains(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count) { m_ht.rehash(count); }
 | 
			
		||||
    void reserve(size_type count) { m_ht.reserve(count); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a `const_iterator` to an `iterator`.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Serialize the map through the `serializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `serializer` parameter must be a function object that supports the following call:
 | 
			
		||||
     *  - `template<typename U> void operator()(const U& value);` where the types `std::uint64_t`, `float` and `std::pair<Key, T>` must be supported for U.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, ...) of the types it serializes
 | 
			
		||||
     * in the hands of the `Serializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Serializer>
 | 
			
		||||
    void serialize(Serializer& serializer) const {
 | 
			
		||||
        m_ht.serialize(serializer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deserialize a previouly serialized map through the `deserializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `deserializer` parameter must be a function object that supports the following calls:
 | 
			
		||||
     *  - `template<typename U> U operator()();` where the types `std::uint64_t`, `float` and `std::pair<Key, T>` must be supported for U.
 | 
			
		||||
     * 
 | 
			
		||||
     * If the deserialized hash map type is hash compatible with the serialized map, the deserialization process can be
 | 
			
		||||
     * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash, KeyEqual and GrowthPolicy must behave the 
 | 
			
		||||
     * same way than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used
 | 
			
		||||
     * to serialize the map. If these criteria are not met, the behaviour is undefined with `hash_compatible` sets to true.
 | 
			
		||||
     * 
 | 
			
		||||
     * The behaviour is undefined if the type `Key` and `T` of the `sparse_map` are not the same as the
 | 
			
		||||
     * types used during serialization.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, size of int, ...) of the types it 
 | 
			
		||||
     * deserializes in the hands of the `Deserializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Deserializer>
 | 
			
		||||
    static sparse_map deserialize(Deserializer& deserializer, bool hash_compatible = false) {
 | 
			
		||||
        sparse_map map(0);
 | 
			
		||||
        map.m_ht.deserialize(deserializer, hash_compatible);
 | 
			
		||||
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const sparse_map& lhs, const sparse_map& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(const auto& element_lhs: lhs) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find(element_lhs.first);
 | 
			
		||||
            if(it_element_rhs == rhs.cend() || element_lhs.second != it_element_rhs->second) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const sparse_map& lhs, const sparse_map& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(sparse_map& lhs, sparse_map& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as `tsl::sparse_map<Key, T, Hash, KeyEqual, Allocator, tsl::sh::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class T, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<std::pair<Key, T>>>
 | 
			
		||||
using sparse_pg_map = sparse_map<Key, T, Hash, KeyEqual, Allocator, tsl::sh::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										612
									
								
								src/includes/3thparty/tsl/sparse_set.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										612
									
								
								src/includes/3thparty/tsl/sparse_set.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,612 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MIT License
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2017 Tessil
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * 
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef TSL_SPARSE_SET_H
 | 
			
		||||
#define TSL_SPARSE_SET_H 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include "sparse_hash.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace tsl {
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
/**
 | 
			
		||||
 * Implementation of a sparse hash set using open-addressing with quadratic probing.
 | 
			
		||||
 * The goal on the hash set is to be the most memory efficient possible, even at low load factor,
 | 
			
		||||
 * while keeping reasonable performances.
 | 
			
		||||
 * 
 | 
			
		||||
 * `GrowthPolicy` defines how the set grows and consequently how a hash value is mapped to a bucket. 
 | 
			
		||||
 * By default the set uses `tsl::sh::power_of_two_growth_policy`. This policy keeps the number of buckets 
 | 
			
		||||
 * to a power of two and uses a mask to map the hash to a bucket instead of the slow modulo.
 | 
			
		||||
 * Other growth policies are available and you may define your own growth policy, 
 | 
			
		||||
 * check `tsl::sh::power_of_two_growth_policy` for the interface.
 | 
			
		||||
 * 
 | 
			
		||||
 * `ExceptionSafety` defines the exception guarantee provided by the class. By default only the basic
 | 
			
		||||
 * exception safety is guaranteed which mean that all resources used by the hash set will be freed (no memory leaks) 
 | 
			
		||||
 * but the hash set may end-up in an undefined state if an exception is thrown (undefined here means that some elements  
 | 
			
		||||
 * may be missing). This can ONLY happen on rehash (either on insert or if `rehash` is called explicitly) and will
 | 
			
		||||
 * occur if the Allocator can't allocate memory (`std::bad_alloc`) or if the copy constructor (when a nothrow 
 | 
			
		||||
 * move constructor is not available) throws an exception. This can be avoided by calling `reserve` beforehand.
 | 
			
		||||
 * This basic guarantee is similar to the one of `google::sparse_hash_map` and `spp::sparse_hash_map`.
 | 
			
		||||
 * It is possible to ask for the strong exception guarantee with `tsl::sh::exception_safety::strong`, the drawback
 | 
			
		||||
 * is that the set will be slower on rehashes and will also need more memory on rehashes.
 | 
			
		||||
 * 
 | 
			
		||||
 * `Sparsity` defines how much the hash set will compromise between insertion speed and memory usage. A high
 | 
			
		||||
 * sparsity means less memory usage but longer insertion times, and vice-versa for low sparsity. The default 
 | 
			
		||||
 * `tsl::sh::sparsity::medium` sparsity offers a good compromise. It doesn't change the lookup speed.
 | 
			
		||||
 * 
 | 
			
		||||
 * `Key` must be nothrow move constructible and/or copy constructible.
 | 
			
		||||
 * 
 | 
			
		||||
 * If the destructor of `Key` throws an exception, the behaviour of the class is undefined.
 | 
			
		||||
 * 
 | 
			
		||||
 * Iterators invalidation:
 | 
			
		||||
 *  - clear, operator=, reserve, rehash: always invalidate the iterators.
 | 
			
		||||
 *  - insert, emplace, emplace_hint: if there is an effective insert, invalidate the iterators.
 | 
			
		||||
 *  - erase: always invalidate the iterators.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>,
 | 
			
		||||
         class GrowthPolicy = tsl::sh::power_of_two_growth_policy<2>,
 | 
			
		||||
         tsl::sh::exception_safety ExceptionSafety = tsl::sh::exception_safety::basic,
 | 
			
		||||
         tsl::sh::sparsity Sparsity = tsl::sh::sparsity::medium>
 | 
			
		||||
class sparse_set {
 | 
			
		||||
private:
 | 
			
		||||
    template<typename U>
 | 
			
		||||
    using has_is_transparent = tsl::detail_sparse_hash::has_is_transparent<U>;
 | 
			
		||||
    
 | 
			
		||||
    class KeySelect {
 | 
			
		||||
    public:
 | 
			
		||||
        using key_type = Key;
 | 
			
		||||
        
 | 
			
		||||
        const key_type& operator()(const Key& key) const noexcept {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        key_type& operator()(Key& key) noexcept {
 | 
			
		||||
            return key;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    using ht = detail_sparse_hash::sparse_hash<Key, KeySelect, void, Hash, KeyEqual, Allocator, GrowthPolicy, 
 | 
			
		||||
                                               ExceptionSafety, Sparsity,
 | 
			
		||||
                                               tsl::sh::probing::quadratic>;
 | 
			
		||||
            
 | 
			
		||||
public:
 | 
			
		||||
    using key_type = typename ht::key_type;
 | 
			
		||||
    using value_type = typename ht::value_type;
 | 
			
		||||
    using size_type = typename ht::size_type;
 | 
			
		||||
    using difference_type = typename ht::difference_type;
 | 
			
		||||
    using hasher = typename ht::hasher;
 | 
			
		||||
    using key_equal = typename ht::key_equal;
 | 
			
		||||
    using allocator_type = typename ht::allocator_type;
 | 
			
		||||
    using reference = typename ht::reference;
 | 
			
		||||
    using const_reference = typename ht::const_reference;
 | 
			
		||||
    using pointer = typename ht::pointer;
 | 
			
		||||
    using const_pointer = typename ht::const_pointer;
 | 
			
		||||
    using iterator = typename ht::iterator;
 | 
			
		||||
    using const_iterator = typename ht::const_iterator;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Constructors
 | 
			
		||||
     */
 | 
			
		||||
    sparse_set(): sparse_set(ht::DEFAULT_INIT_BUCKET_COUNT) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit sparse_set(size_type bucket_count, 
 | 
			
		||||
                       const Hash& hash = Hash(),
 | 
			
		||||
                       const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
                       const Allocator& alloc = Allocator()): 
 | 
			
		||||
                    m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    sparse_set(size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): sparse_set(bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    sparse_set(size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): sparse_set(bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    explicit sparse_set(const Allocator& alloc): sparse_set(ht::DEFAULT_INIT_BUCKET_COUNT, alloc) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    sparse_set(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
              const Hash& hash = Hash(),
 | 
			
		||||
              const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
              const Allocator& alloc = Allocator()): sparse_set(bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
        insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    sparse_set(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): sparse_set(first, last, bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    sparse_set(InputIt first, InputIt last,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): sparse_set(first, last, bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sparse_set(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count = ht::DEFAULT_INIT_BUCKET_COUNT,
 | 
			
		||||
              const Hash& hash = Hash(),
 | 
			
		||||
              const KeyEqual& equal = KeyEqual(),
 | 
			
		||||
              const Allocator& alloc = Allocator()): 
 | 
			
		||||
          sparse_set(init.begin(), init.end(), bucket_count, hash, equal, alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sparse_set(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Allocator& alloc): 
 | 
			
		||||
          sparse_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sparse_set(std::initializer_list<value_type> init,
 | 
			
		||||
              size_type bucket_count,
 | 
			
		||||
              const Hash& hash,
 | 
			
		||||
              const Allocator& alloc): 
 | 
			
		||||
          sparse_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    sparse_set& operator=(std::initializer_list<value_type> ilist) {
 | 
			
		||||
        m_ht.clear();
 | 
			
		||||
        
 | 
			
		||||
        m_ht.reserve(ilist.size());
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end());
 | 
			
		||||
        
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    allocator_type get_allocator() const { return m_ht.get_allocator(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Iterators
 | 
			
		||||
     */
 | 
			
		||||
    iterator begin() noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator begin() const noexcept { return m_ht.begin(); }
 | 
			
		||||
    const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
 | 
			
		||||
    
 | 
			
		||||
    iterator end() noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator end() const noexcept { return m_ht.end(); }
 | 
			
		||||
    const_iterator cend() const noexcept { return m_ht.cend(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Capacity
 | 
			
		||||
     */
 | 
			
		||||
    bool empty() const noexcept { return m_ht.empty(); }
 | 
			
		||||
    size_type size() const noexcept { return m_ht.size(); }
 | 
			
		||||
    size_type max_size() const noexcept { return m_ht.max_size(); }
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Modifiers
 | 
			
		||||
     */
 | 
			
		||||
    void clear() noexcept { m_ht.clear(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(const value_type& value) { 
 | 
			
		||||
        return m_ht.insert(value); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, bool> insert(value_type&& value) { 
 | 
			
		||||
        return m_ht.insert(std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, const value_type& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, value); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    iterator insert(const_iterator hint, value_type&& value) { 
 | 
			
		||||
        return m_ht.insert_hint(hint, std::move(value)); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template<class InputIt>
 | 
			
		||||
    void insert(InputIt first, InputIt last) { 
 | 
			
		||||
        m_ht.insert(first, last);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void insert(std::initializer_list<value_type> ilist) { 
 | 
			
		||||
        m_ht.insert(ilist.begin(), ilist.end()); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to `insert(value_type(std::forward<Args>(args)...));`.
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the `std::unordered_map` interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    std::pair<iterator, bool> emplace(Args&&... args) { 
 | 
			
		||||
        return m_ht.emplace(std::forward<Args>(args)...); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
 | 
			
		||||
     * The method is equivalent to `insert(hint, value_type(std::forward<Args>(args)...));`.
 | 
			
		||||
     * 
 | 
			
		||||
     * Mainly here for compatibility with the `std::unordered_map` interface.
 | 
			
		||||
     */
 | 
			
		||||
    template<class... Args>
 | 
			
		||||
    iterator emplace_hint(const_iterator hint, Args&&... args) {
 | 
			
		||||
        return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator erase(iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator pos) { return m_ht.erase(pos); }
 | 
			
		||||
    iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
 | 
			
		||||
    size_type erase(const key_type& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    size_type erase(const key_type& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key) { return m_ht.erase(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc erase(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type erase(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.erase(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    void swap(sparse_set& other) { other.m_ht.swap(m_ht); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Lookup
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    size_type count(const Key& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key) const { return m_ht.count(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc count(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    iterator find(const Key& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    const_iterator find(const Key& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    const_iterator find(const Key& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key) { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key) const { return m_ht.find(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc find(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    const_iterator find(const K& key, std::size_t precalculated_hash) const { return m_ht.find(key, precalculated_hash); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    bool contains(const Key& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    bool contains(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists. 
 | 
			
		||||
     * If so, K must be hashable and comparable to Key.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key) const { return m_ht.contains(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc contains(const K& key) const
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    bool contains(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.contains(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
 | 
			
		||||
     */
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * This overload only participates in the overload resolution if the typedef `KeyEqual::is_transparent` exists. 
 | 
			
		||||
     * If so, `K` must be hashable and comparable to `Key`.
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     * 
 | 
			
		||||
     * Use the hash value `precalculated_hash` instead of hashing the key. The hash value should be the same
 | 
			
		||||
     * as `hash_function()(key)`, otherwise the behaviour is undefined. Useful to speed-up the lookup 
 | 
			
		||||
     * if you already have the hash.
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key)
 | 
			
		||||
     */
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
 | 
			
		||||
     */    
 | 
			
		||||
    template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr> 
 | 
			
		||||
    std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const { 
 | 
			
		||||
        return m_ht.equal_range(key, precalculated_hash); 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Bucket interface 
 | 
			
		||||
     */
 | 
			
		||||
    size_type bucket_count() const { return m_ht.bucket_count(); }
 | 
			
		||||
    size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     *  Hash policy 
 | 
			
		||||
     */
 | 
			
		||||
    float load_factor() const { return m_ht.load_factor(); }
 | 
			
		||||
    float max_load_factor() const { return m_ht.max_load_factor(); }
 | 
			
		||||
    void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
 | 
			
		||||
    
 | 
			
		||||
    void rehash(size_type count) { m_ht.rehash(count); }
 | 
			
		||||
    void reserve(size_type count) { m_ht.reserve(count); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Observers
 | 
			
		||||
     */
 | 
			
		||||
    hasher hash_function() const { return m_ht.hash_function(); }
 | 
			
		||||
    key_equal key_eq() const { return m_ht.key_eq(); }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    /*
 | 
			
		||||
     * Other
 | 
			
		||||
     */
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert a `const_iterator` to an `iterator`.
 | 
			
		||||
     */
 | 
			
		||||
    iterator mutable_iterator(const_iterator pos) {
 | 
			
		||||
        return m_ht.mutable_iterator(pos);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Serialize the set through the `serializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `serializer` parameter must be a function object that supports the following call:
 | 
			
		||||
     *  - `void operator()(const U& value);` where the types `std::uint64_t`, `float` and `Key` must be supported for U.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, ...) of the types it serializes
 | 
			
		||||
     * in the hands of the `Serializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Serializer>
 | 
			
		||||
    void serialize(Serializer& serializer) const {
 | 
			
		||||
        m_ht.serialize(serializer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deserialize a previouly serialized set through the `deserializer` parameter.
 | 
			
		||||
     * 
 | 
			
		||||
     * The `deserializer` parameter must be a function object that supports the following calls:
 | 
			
		||||
     *  - `template<typename U> U operator()();` where the types `std::uint64_t`, `float` and `Key` must be supported for U.
 | 
			
		||||
     * 
 | 
			
		||||
     * If the deserialized hash set type is hash compatible with the serialized set, the deserialization process can be
 | 
			
		||||
     * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash, KeyEqual and GrowthPolicy must behave the 
 | 
			
		||||
     * same way than the ones used on the serialized set. The `std::size_t` must also be of the same size as the one on the platform used
 | 
			
		||||
     * to serialize the set. If these criteria are not met, the behaviour is undefined with `hash_compatible` sets to true.
 | 
			
		||||
     * 
 | 
			
		||||
     * The behaviour is undefined if the type `Key` of the `sparse_set` is not the same as the
 | 
			
		||||
     * type used during serialization.
 | 
			
		||||
     * 
 | 
			
		||||
     * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, size of int, ...) of the types it 
 | 
			
		||||
     * deserializes in the hands of the `Deserializer` function object if compatibilty is required.
 | 
			
		||||
     */
 | 
			
		||||
    template<class Deserializer>
 | 
			
		||||
    static sparse_set deserialize(Deserializer& deserializer, bool hash_compatible = false) {
 | 
			
		||||
        sparse_set set(0);
 | 
			
		||||
        set.m_ht.deserialize(deserializer, hash_compatible);
 | 
			
		||||
 | 
			
		||||
        return set;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    friend bool operator==(const sparse_set& lhs, const sparse_set& rhs) {
 | 
			
		||||
        if(lhs.size() != rhs.size()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        for(const auto& element_lhs: lhs) {
 | 
			
		||||
            const auto it_element_rhs = rhs.find(element_lhs);
 | 
			
		||||
            if(it_element_rhs == rhs.cend()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend bool operator!=(const sparse_set& lhs, const sparse_set& rhs) {
 | 
			
		||||
        return !operator==(lhs, rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(sparse_set& lhs, sparse_set& rhs) {
 | 
			
		||||
        lhs.swap(rhs);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    ht m_ht;    
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Same as `tsl::sparse_set<Key, Hash, KeyEqual, Allocator, tsl::sh::prime_growth_policy>`.
 | 
			
		||||
 */
 | 
			
		||||
template<class Key, 
 | 
			
		||||
         class Hash = std::hash<Key>,
 | 
			
		||||
         class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
         class Allocator = std::allocator<Key>>
 | 
			
		||||
using sparse_pg_set = sparse_set<Key, Hash, KeyEqual, Allocator, tsl::sh::prime_growth_policy>;
 | 
			
		||||
 | 
			
		||||
} // end namespace tsl
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -5,13 +5,14 @@
 | 
			
		||||
#include <ostream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
vector<int> sizes = {
 | 
			
		||||
    50000, 100000, 150000, 200000, 250000, 300000, 350000, 400000, 500000, 
 | 
			
		||||
    600000, 700000, 800000, 900000, 1000000,
 | 
			
		||||
    2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000,
 | 
			
		||||
    15000000, 20000000, 25000000, 30000000, 35000000, 40000000, 45000000, 50000000
 | 
			
		||||
    // 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000,
 | 
			
		||||
    // 15000000, 20000000, 25000000, 30000000, 35000000, 40000000, 45000000, 50000000
 | 
			
		||||
};
 | 
			
		||||
// to print type info
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										179
									
								
								src/includes/prepare.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								src/includes/prepare.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
			
		||||
 | 
			
		||||
#ifndef PREPARE_H
 | 
			
		||||
#define PREPARE_H
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// hashmaps and hash
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <sparsehash/sparse_hash_map>
 | 
			
		||||
#include <sparsehash/dense_hash_map>
 | 
			
		||||
#include "./3thparty/abseil-cpp/absl/container/node_hash_map.h"
 | 
			
		||||
#include "./3thparty/abseil-cpp/absl/container/flat_hash_map.h"
 | 
			
		||||
#include "./3thparty/abseil-cpp/absl/hash/hash.h"
 | 
			
		||||
#include "./3thparty/tsl/sparse_map.h"
 | 
			
		||||
#include "./3thparty/tsl/array_map.h"
 | 
			
		||||
#include "./3thparty/tsl/ordered_map.h"
 | 
			
		||||
#include "./3thparty/tsl/robin_map.h"
 | 
			
		||||
#include "./3thparty/tsl/hopscotch_map.h"
 | 
			
		||||
#include <boost/unordered_map.hpp>
 | 
			
		||||
#include "./3thparty/skarupke/bytell_hash_map.hpp"
 | 
			
		||||
#include "./3thparty/skarupke/flat_hash_map.hpp"
 | 
			
		||||
#include "./3thparty/skarupke/unordered_map.hpp"
 | 
			
		||||
#include "./3thparty/parallel_hashmap/phmap.h"
 | 
			
		||||
#include "./3thparty/emilib/hash_map.hpp"
 | 
			
		||||
#include "3thparty/robinhood/robin_hood.h"
 | 
			
		||||
 | 
			
		||||
using std::string;
 | 
			
		||||
using absl::Hash; 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// since my testing is based on this hashmap, this one doesn't need no prep
 | 
			
		||||
void prepare(std::unordered_map<int, int>& map,int  size){
 | 
			
		||||
    map.reserve(size);  
 | 
			
		||||
}
 | 
			
		||||
void prepare(std::unordered_map<string, string>& map,int  size){
 | 
			
		||||
    map.reserve(size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// goooooogle
 | 
			
		||||
void prepare(google::sparse_hash_map<int, int>& map, int size){
 | 
			
		||||
    map.set_deleted_key(0); 
 | 
			
		||||
}
 | 
			
		||||
void prepare(google::sparse_hash_map<string, string>& map, int size){
 | 
			
		||||
    map.set_deleted_key("");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void prepare(google::dense_hash_map<int, int>& map, int size){
 | 
			
		||||
    map.set_empty_key(0);
 | 
			
		||||
    map.set_deleted_key(-1);
 | 
			
		||||
}
 | 
			
		||||
void prepare(google::dense_hash_map<string, string>& map, int size){
 | 
			
		||||
    map.set_deleted_key("a");
 | 
			
		||||
    map.set_empty_key("");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//absl
 | 
			
		||||
void prepare(absl::node_hash_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);  
 | 
			
		||||
}
 | 
			
		||||
void prepare(absl::node_hash_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void prepare(absl::flat_hash_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
void prepare(absl::flat_hash_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tessil
 | 
			
		||||
void prepare(tsl::sparse_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(tsl::sparse_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void prepare(tsl::array_map<int, int>& map, int size){
 | 
			
		||||
    // map.reserve(size);
 | 
			
		||||
}
 | 
			
		||||
void prepare(tsl::array_map<string, string>& map, int size){
 | 
			
		||||
    // map.reserve(size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void prepare(tsl::ordered_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(tsl::ordered_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void prepare(tsl::robin_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(tsl::robin_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void prepare(tsl::hopscotch_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(tsl::hopscotch_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// booooooost
 | 
			
		||||
void prepare(boost::unordered_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(boost::unordered_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// skarupke's maps
 | 
			
		||||
void prepare(ska::bytell_hash_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(ska::bytell_hash_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void prepare(ska::flat_hash_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(ska::flat_hash_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void prepare(ska::unordered_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(ska::unordered_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
// Gregory Popovitch' paralel hashmaps
 | 
			
		||||
void prepare(phmap::parallel_flat_hash_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(phmap::parallel_flat_hash_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void prepare(phmap::parallel_node_hash_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(phmap::parallel_node_hash_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// emilib (Emil Ernerfeld library)
 | 
			
		||||
void prepare(emilib::HashMap<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(emilib::HashMap<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
// martin robinhood
 | 
			
		||||
void prepare(robin_hood::unordered_flat_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(robin_hood::unordered_flat_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void prepare(robin_hood::unordered_node_map<int, int>& map, int size){
 | 
			
		||||
    map.reserve(size);   
 | 
			
		||||
}
 | 
			
		||||
void prepare(robin_hood::unordered_node_map<string, string>& map, int size){
 | 
			
		||||
    map.reserve(size); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* TESTS_H */
 | 
			
		||||
@@ -7,35 +7,20 @@
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
 | 
			
		||||
// maps
 | 
			
		||||
// #include <sparsehash/sparse_hash_map>
 | 
			
		||||
 | 
			
		||||
// own
 | 
			
		||||
#include "./generator.h"
 | 
			
		||||
#include "./prepare.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
using namespace std::chrono;
 | 
			
		||||
using std::vector;
 | 
			
		||||
using std::string;
 | 
			
		||||
using std::cout;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// since my testing is based on this function, this one doesn't need no prep
 | 
			
		||||
void prepare(std::unordered_map<int, int>& map,int  size){
 | 
			
		||||
    map.reserve(size);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
void prepare(std::unordered_map<string, string>& map,int  size){
 | 
			
		||||
    map.reserve(size);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// void prepare(google::sparse_hash_map<int, int>& map, int size){
 | 
			
		||||
//     map.set_deleted_key(0);
 | 
			
		||||
//     return;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
vector<int> int_test(T testmap, int size){
 | 
			
		||||
vector<int> int_test(T map, int size){
 | 
			
		||||
    vector<int> results; // insert, lookup, unsuccesful lookup, delete times
 | 
			
		||||
    vector<int> sample_keys; // get a sample of keys to lookup and later delete
 | 
			
		||||
 | 
			
		||||
@@ -47,7 +32,7 @@ vector<int> int_test(T testmap, int size){
 | 
			
		||||
    vector<int> insert_keys(10000);
 | 
			
		||||
    std::generate(insert_keys.begin(), insert_keys.end(), gen_int);
 | 
			
		||||
 | 
			
		||||
    // T testmap {};
 | 
			
		||||
    T testmap{};
 | 
			
		||||
    prepare(testmap, size); // do special actions, such as setting the tombstone marker for other, more exotic hashmaps
 | 
			
		||||
 | 
			
		||||
    { // seperate scope, so all_keys gets destroyed. for good measure, empty it too
 | 
			
		||||
@@ -120,8 +105,6 @@ vector<int> int_test(T testmap, int size){
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
vector<int> string_test(T map, int size){
 | 
			
		||||
    vector<int> results; // insert, lookup, unsuccesful lookup, delete times
 | 
			
		||||
@@ -135,7 +118,8 @@ vector<int> string_test(T map, int size){
 | 
			
		||||
    vector<string> insert_keys(10000);
 | 
			
		||||
    std::generate(insert_keys.begin(), insert_keys.end(), gen_string);
 | 
			
		||||
 | 
			
		||||
    T testmap {};
 | 
			
		||||
 | 
			
		||||
    T testmap{};
 | 
			
		||||
    prepare(testmap, size); // do special actions, such as setting the tombstone marker for other, more exotic hashmaps
 | 
			
		||||
 | 
			
		||||
    { // seperate scope, so all_keys gets destroyed. for good measure, empty it too
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user