added load&dump interface

This commit is contained in:
sunkaicheng
2019-08-13 22:42:37 +08:00
parent c4abc895b4
commit 5e5ade8c6e
5 changed files with 371 additions and 1 deletions
Vendored
+1
View File
@@ -5,4 +5,5 @@ benchmark/charts.html
build
build_linux
.vagrant
**/.vscode
TAGS
+3
View File
@@ -17,6 +17,7 @@ set(CMAKE_SUPPRESS_REGENERATION true) ## suppress ZERO_CHECK project
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
include(helpers)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
add_library(${PROJECT_NAME} INTERFACE)
@@ -130,6 +131,8 @@ if (PHMAP_BUILD_EXAMPLES)
add_executable(ex_two_files examples/f1.cc examples/f2.cc phmap.natvis)
add_executable(ex_insert_bench examples/insert_bench.cc phmap.natvis)
add_executable(ex_knucleotide examples/knucleotide.cc phmap.natvis)
add_executable(ex_dump_load examples/dump_load.cc phmap.natvis)
target_link_libraries(ex_knucleotide Threads::Threads)
target_link_libraries(ex_bench Threads::Threads)
endif()
+138
View File
@@ -0,0 +1,138 @@
#include <iostream>
#include <string>
#include <parallel_hashmap/phmap.h>
using phmap::flat_hash_map;
using phmap::flat_hash_set;
void load_dump_string_string() {
flat_hash_map<std::string, std::string> mp1;
// Add a new entry
mp1["key-1"] = "value-1";
mp1["key-2"] = "value-2";
// Iterate and print keys and values
for (const auto& n : mp1)
std::cout << n.first << "'s value is: " << n.second << "\n";
mp1.dump("./dump.data");
flat_hash_map<std::string, std::string> mp2;
mp2.load("./dump.data");
// Iterate and print keys and values g|++
for (const auto& n : mp2)
std::cout << n.first << "'s value is: " << n.second << "\n";
}
void load_dump_uint64_uint32() {
flat_hash_map<uint64_t, uint32_t> mp1;
// Add a new entry
mp1[100] = 99;
mp1[300] = 299;
// Iterate and print keys and values
for (const auto& n : mp1)
std::cout << n.first << "'s value is: " << n.second << "\n";
mp1.dump("./dump.data");
flat_hash_map<uint64_t, uint32_t> mp2;
mp2.load("./dump.data");
// Iterate and print keys and values g|++
for (const auto& n : mp2)
std::cout << n.first << "'s value is: " << n.second << "\n";
}
void load_dump_string_uint32() {
flat_hash_map<std::string, uint32_t> mp1;
// Add a new entry
mp1["key-1"] = 99;
mp1["key-2"] = 299;
// Iterate and print keys and values
for (const auto& n : mp1)
std::cout << n.first << "'s value is: " << n.second << "\n";
mp1.dump("./dump.data");
flat_hash_map<std::string, uint32_t> mp2;
mp2.load("./dump.data");
// Iterate and print keys and values g|++
for (const auto& n : mp2)
std::cout << n.first << "'s value is: " << n.second << "\n";
}
void load_dump_uint32_string() {
flat_hash_map<uint32_t, std::string> mp1;
// Add a new entry
mp1[100] = "hello";
mp1[299] = "world";
// Iterate and print keys and values
for (const auto& n : mp1)
std::cout << n.first << "'s value is: " << n.second << "\n";
mp1.dump("./dump.data");
flat_hash_map<uint32_t, std::string> mp2;
mp2.load("./dump.data");
// Iterate and print keys and values g|++
for (const auto& n : mp2)
std::cout << n.first << "'s value is: " << n.second << "\n";
}
void load_dump_string() {
flat_hash_set<std::string> st1;
// Add a new entry
st1.insert("hello");
st1.insert("world");
// Iterate and print
for (const auto& n : st1)
std::cout << "value: " << n << "\n";
st1.dump("./dump.data");
flat_hash_set<std::string> st2;
st2.load("./dump.data");
// Iterate and print keys and values g|++
for (const auto& n : st2)
std::cout << "value: " << n << "\n";
}
void load_dump_uint64() {
flat_hash_set<uint64_t> st1;
// Add a new entry
st1.insert(878);
st1.insert(1424);
// Iterate and print
for (const auto& n : st1)
std::cout << "value: " << n << "\n";
st1.dump("./dump.data");
flat_hash_set<uint64_t> st2;
st2.load("./dump.data");
// Iterate and print keys and values g|++
for (const auto& n : st2)
std::cout << "value: " << n << "\n";
}
int main()
{
load_dump_string_string();
load_dump_uint64_uint32();
load_dump_string_uint32();
load_dump_uint32_string();
load_dump_string();
load_dump_uint64();
std::remove("./dump.data");
return 0;
}
+148
View File
@@ -45,6 +45,9 @@
#include <utility>
#include <array>
#include <cassert>
#include <iostream>
#include <fstream>
#include <sstream>
#include "phmap_utils.h"
#include "phmap_base.h"
@@ -1534,6 +1537,151 @@ public:
}
}
template<typename V = value_type>
typename std::enable_if<type_traits_internal::IsArithmeticType<V>::value, bool>::type
dump(const std::string& dump_file) noexcept(
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
(!AllocTraits::propagate_on_container_swap::value ||
IsNoThrowSwappable<allocator_type>())) {
if (size_ == 0) {
std::cout << "Empty set, nothing to dump" << std::endl;
return true;
}
assert(slots_ != nullptr);
std::ofstream ofs(dump_file);
if (!ofs.is_open()) {
std::cout << "Failed to open dump file " << dump_file << std::endl;
return false;
}
ofs.write(reinterpret_cast<char*>(&size_), sizeof(size_));
ofs.write(reinterpret_cast<char*>(&capacity_), sizeof(capacity_));
ofs.write(reinterpret_cast<char*>(ctrl_), capacity_ * sizeof(ctrl_t));
ofs.write(reinterpret_cast<char*>(slots_), capacity_ * sizeof(slot_type));
ofs.close();
return true;
}
template<typename V = value_type>
typename std::enable_if<type_traits_internal::IsArithmeticType<V>::value, bool>::type
load(const std::string& load_file) noexcept(
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
(!AllocTraits::propagate_on_container_swap::value ||
IsNoThrowSwappable<allocator_type>())) {
std::ifstream ifs(load_file);
if (!ifs.is_open()) {
std::cerr << "Failed to open load file " << load_file << std::endl;
return false;
}
// get file size
ifs.seekg(0, std::ios::end);
size_t file_size = ifs.tellg();
ifs.seekg(0, std::ios::beg);
if (file_size <= sizeof(size_) + sizeof(capacity_)) {
std::cerr << "Invalid file format. file size: " << file_size << ", size_: "
<< size_ << ", capacity_: " << capacity_ << ", slot type size: "
<< sizeof(slot_type);
return false;
}
ifs.read(reinterpret_cast<char*>(&size_), sizeof(size_));
ifs.read(reinterpret_cast<char*>(&capacity_), sizeof(capacity_));
if (file_size != sizeof(size_) + sizeof(capacity_) + capacity_ * sizeof(ctrl_t)
+ capacity_ * sizeof(slot_type)) {
std::cerr << "Invalid file format. file size: " << file_size << ", size_: "
<< size_ << ", capacity_: " << capacity_ << ", slot type size: "
<< sizeof(slot_type);
return false;
}
// allocate memory for ctrl_ and slots_
initialize_slots();
ifs.read(reinterpret_cast<char*>(ctrl_), capacity_ * sizeof(ctrl_t));
ifs.read(reinterpret_cast<char*>(slots_), capacity_ * sizeof(slot_type));
ifs.close();
return true;
}
// V will be V for hash_set and std::pair<const K, V> for hash_map
template<typename V = value_type>
typename std::enable_if<! type_traits_internal::IsArithmeticType<V>::value
&& type_traits_internal::IsStringOrArithmeticType<V>::value, bool>::type
dump(const std::string& dump_file) noexcept(
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
(!AllocTraits::propagate_on_container_swap::value ||
IsNoThrowSwappable<allocator_type>())) {
if (size_ == 0) {
std::cout << "Empty set, nothing to dump" << std::endl;
return true;
}
assert(slots_ != nullptr);
std::ofstream ofs(dump_file);
if (!ofs.is_open()) {
std::cout << "Failed to open dump file " << dump_file << std::endl;
return false;
}
ofs.write(reinterpret_cast<char*>(&size_), sizeof(size_));
for (auto it = this->begin(); it != this->end(); ++it) {
type_traits_internal::Archive<V>::dump(*it, &ofs);
}
ofs.close();
return true;
}
template<typename V = value_type>
typename std::enable_if<! type_traits_internal::IsArithmeticType<V>::value
&& type_traits_internal::IsStringOrArithmeticType<V>::value, bool>::type
load(const std::string& load_file = "") noexcept(
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
(!AllocTraits::propagate_on_container_swap::value ||
IsNoThrowSwappable<allocator_type>())) {
std::ifstream ifs(load_file);
if (!ifs.is_open()) {
std::cerr << "Failed to open load file " << load_file << std::endl;
return false;
}
size_t total_count = 0;
ifs.read((char*)&total_count, sizeof(total_count));
for (size_t i = 0; i < total_count; i ++) {
if (ifs.eof()) {
std::cerr << "Data is not enough, total_count: " << total_count
<< ", meet eof at index: " << i << std::endl;
return false;
}
V v;
type_traits_internal::Archive<V>::load(ifs, &v);
this->insert(v);
}
ifs.close();
return true;
}
template<typename V = value_type>
typename std::enable_if<!type_traits_internal::IsStringOrArithmeticType<V>::value, bool>::type
dump(const std::string&) noexcept(
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
(!AllocTraits::propagate_on_container_swap::value ||
IsNoThrowSwappable<allocator_type>())) {
std::cerr << "Does not support this type now!" << std::endl;
std::abort();
return false;
}
template<typename V = value_type>
typename std::enable_if<!type_traits_internal::IsStringOrArithmeticType<V>::value, bool>::type
load(const std::string&) noexcept(
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
(!AllocTraits::propagate_on_container_swap::value ||
IsNoThrowSwappable<allocator_type>())) {
std::cerr << "Does not support this type now!" << std::endl;
std::abort();
return false;
}
void rehash(size_t n) {
if (n == 0 && capacity_ == 0) return;
if (n == 0 && size_ == 0) {
+81 -1
View File
@@ -33,7 +33,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// ---------------------------------------------------------------------------
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -71,6 +70,87 @@ struct EqualTo
namespace type_traits_internal {
template<typename T>
struct PairTrait : public std::false_type {
using first_type = typename std::remove_cv<T>::type;
using second_type = typename std::remove_cv<T>::type;
};
template<typename T1, typename T2>
struct PairTrait<std::pair<T1, T2>>: public std::true_type {
using first_type = typename std::remove_cv<T1>::type;
using second_type = typename std::remove_cv<T2>::type;
};
template<typename V>
struct IsArithmeticType {
static constexpr bool value = std::is_arithmetic<V>::value
|| (PairTrait<V>::value &&
std::is_arithmetic<typename PairTrait<V>::first_type>::value
&& std::is_arithmetic<typename PairTrait<V>::second_type>::value);
};
template<typename V>
struct IsStringOrArithmeticType {
static constexpr bool value = IsArithmeticType<V>::value
|| std::is_same<V, std::string>::value
|| (PairTrait<V>::value
&& (std::is_arithmetic<typename PairTrait<V>::first_type>::value
|| std::is_same<typename PairTrait<V>::first_type, std::string>::value)
&& (std::is_arithmetic<typename PairTrait<V>::second_type>::value
|| std::is_same<typename PairTrait<V>::second_type, std::string>::value));
};
// only support std::is_arithmetic or std::string types
template<typename T>
struct Archive {
template<typename V = T>
static typename std::enable_if<std::is_arithmetic<V>::value, void>::type
dump(const V& v, std::ofstream* ofs) {
ofs->write(reinterpret_cast<char*>(const_cast<V*>(&v)), sizeof(V));
}
template<typename V = T>
static typename std::enable_if<std::is_arithmetic<V>::value, void>::type
load(std::ifstream& ifs, V* v) {
ifs.read(reinterpret_cast<char*>(v), sizeof(V));
}
template<typename V = T>
static typename std::enable_if<std::is_same<std::string, typename std::remove_cv<V>::type>::value, void>::type
dump(const V& v, std::ofstream* ofs) {
uint32_t sz = v.length();
ofs->write(reinterpret_cast<char*>(&sz), sizeof(sz));
ofs->write(const_cast<char*>(v.data()), sz);
}
template<typename V = T>
static typename std::enable_if<std::is_same<std::string, typename std::remove_cv<V>::type>::value, void>::type
load(std::ifstream& ifs, V* v) {
uint32_t sz = 0;
ifs.read(reinterpret_cast<char*>(&sz), sizeof(sz));
const_cast<std::string*>(v)->resize(sz);
ifs.read(const_cast<char*>(v->data()), sz);
}
template<typename V = T>
static typename std::enable_if<PairTrait<V>::value && IsStringOrArithmeticType<V>::value, void>::type
dump(const V& v, std::ofstream* ofs) {
dump<typename PairTrait<V>::first_type>(v.first, ofs);
dump<typename PairTrait<V>::second_type>(v.second, ofs);
}
template<typename V = T>
static typename std::enable_if<PairTrait<V>::value && IsStringOrArithmeticType<V>::value, void>::type
load(std::ifstream& ifs, V* v) {
using first_type = typename PairTrait<V>::first_type;
using second_type = typename PairTrait<V>::second_type;
load<first_type>(ifs, const_cast<first_type*>(&v->first));
load<second_type>(ifs, const_cast<second_type*>(&v->second));
}
};
template <typename... Ts>
struct VoidTImpl {
using type = void;