Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added load&dump interface #22

Merged
merged 6 commits into from Aug 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -5,4 +5,5 @@ benchmark/charts.html
build
build_linux
.vagrant
**/.vscode
TAGS
7 changes: 7 additions & 0 deletions CMakeLists.txt
Expand Up @@ -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)

Expand Down Expand Up @@ -110,6 +111,10 @@ if (PHMAP_BUILD_TESTS)
phmap_cc_test(NAME parallel_flat_hash_map_mutex SRCS "tests/parallel_flat_hash_map_mutex_test.cc"
COPTS "-DUNORDERED_MAP_CXX17" DEPS gmock_main)

phmap_cc_test(NAME dump_load SRCS "tests/dump_load_test.cc"
COPTS "-DUNORDERED_MAP_CXX17" DEPS gmock_main)


endif()

if (PHMAP_BUILD_EXAMPLES)
Expand All @@ -130,6 +135,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()
Expand Down
57 changes: 57 additions & 0 deletions examples/dump_load.cc
@@ -0,0 +1,57 @@
#include <iostream>
#include <string>
#include <parallel_hashmap/phmap.h>

using phmap::flat_hash_map;
using phmap::parallel_flat_hash_map;

void dump_load_uint64_uint32() {
flat_hash_map<uint64_t, uint32_t> mp1;
phmap::BinaryOutputArchive ar_out("./dump.data");
// 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(ar_out);
flat_hash_map<uint64_t, uint32_t> mp2;
phmap::BinaryInputArchive ar_in("./dump.data");
mp2.load(ar_in);
// Iterate and print keys and values g|++
for (const auto& n : mp2)
std::cout << n.first << "'s value is: " << n.second << "\n";
}

void dump_load_parallel_flat_hash_map() {
parallel_flat_hash_map<uint64_t, uint32_t> mp1;
phmap::OutputArchiveWrapper<phmap::BinaryOutputArchive> w_out("./");

// Add a new entry
mp1[100] = 99;
mp1[300] = 299;
mp1[101] = 992;
mp1[1300] = 2991;
mp1[1130] = 299;
mp1[2130] = 1299;
// Iterate and print
for (const auto& n : mp1)
std::cout << "key: " << n.first << ", value: " << n.second << "\n";

mp1.dump(w_out);
parallel_flat_hash_map<uint64_t, uint32_t> mp2;
phmap::InputArchiveWrapper<phmap::BinaryInputArchive> w_in("./");

mp2.load(w_in);
for (const auto& n : mp2)
std::cout << "key: " << n.first << ", value: " << n.second << "\n";
}

int main()
{
dump_load_uint64_uint32();
dump_load_parallel_flat_hash_map();
return 0;
}
4 changes: 2 additions & 2 deletions examples/serialize.cc
Expand Up @@ -22,9 +22,9 @@ void showtime(const char *name, std::function<void ()> doit)
doit();
auto t2 = std::chrono::high_resolution_clock::now();
auto elapsed = milliseconds<double>(t2 - t1).count();
printf("%s: %.3fms\n", name, (int)elapsed / 1000.0f);
printf("%s: %.3fs\n", name, (int)elapsed / 1000.0f);
}

int main()
{
using MapType = phmap::flat_hash_map<bitset<42>, int>;
Expand Down
153 changes: 153 additions & 0 deletions parallel_hashmap/phmap.h
Expand Up @@ -45,6 +45,9 @@
#include <utility>
#include <array>
#include <cassert>
#include <iostream>
#include <fstream>
#include <sstream>

#include "phmap_utils.h"
#include "phmap_base.h"
Expand Down Expand Up @@ -1534,6 +1537,117 @@ class raw_hash_set
}
}

template<typename OutputArchive, typename V = value_type>
typename std::enable_if<type_traits_internal::IsArithmeticType<V>::value, bool>::type
dump(OutputArchive& ar) {
typename OutputArchive::Guard guard(&ar);
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) / Group::kWidth * Group::kWidth)) {

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<typename InputArchive, typename V = value_type>
typename std::enable_if<type_traits_internal::IsArithmeticType<V>::value, bool>::type
load(InputArchive& ar) {
typename InputArchive::Guard guard(&ar);
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) / Group::kWidth * Group::kWidth)) {
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;
}

// V will be V for hash_set and std::pair<const K, V> for hash_map
template<typename OutputArchive, typename V = value_type>
typename std::enable_if<! type_traits_internal::IsArithmeticType<V>::value
&& type_traits_internal::IsStringOrArithmeticType<V>::value, bool>::type
dump(OutputArchive& ar) {
typename OutputArchive::Guard guard(&ar);
if (!ar.template dump<size_t>(size_)) {
std::cerr << "Failed to dump size" << std::endl;
return false;
}
if (size_ == 0) {
return true;
}
for (auto it = this->begin(); it != this->end(); ++it) {
if (!ar.template dump<V>(*it)) {
std::cerr << "Failed to dump element" << std::endl;
return false;
}
}
return true;
}

template<typename InputArchive, typename V = value_type>
typename std::enable_if<! type_traits_internal::IsArithmeticType<V>::value
&& type_traits_internal::IsStringOrArithmeticType<V>::value, bool>::type
load(InputArchive& ar) {
typename InputArchive::Guard guard(&ar);
size_t sz = 0;
ar.template load<size_t>(&sz);
for (size_t i = 0; i < sz; i ++) {
V v;
if (!ar.template load<V>(&v)) {
std::cerr << "Failed to load element " << i << std::endl;
return false;
}
this->insert(v);
}
return true;
}

template<typename OutputArchive, typename V = value_type>
typename std::enable_if<!type_traits_internal::IsStringOrArithmeticType<V>::value, bool>::type
dump(OutputArchive&) {
std::cerr << "Does not support this type now!" << std::endl;
return false;
}

template<typename InputArchive, typename V = value_type>
typename std::enable_if<!type_traits_internal::IsStringOrArithmeticType<V>::value, bool>::type
load(InputArchive&) {
std::cerr << "Does not support this type now!" << std::endl;
return false;
}

void rehash(size_t n) {
if (n == 0 && capacity_ == 0) return;
if (n == 0 && size_ == 0) {
Expand Down Expand Up @@ -3139,6 +3253,45 @@ class parallel_hash_set
a.swap(b);
}

template<typename OutputArchiveWrapper>
bool dump(OutputArchiveWrapper& w) {
for (size_t i = 0; i < sets_.size(); ++i) {
auto& inner = sets_[i];
auto ar = w.create_archive(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;
}
}

if (! w.dump_meta(subcnt())) {
std::cerr << "Failed to dump meta!" << std::endl;
return false;
}
return true;
}

template<typename InputArchiveWrapper>
bool load(InputArchiveWrapper& w) {
size_t submap_count = w.load_meta();

if (submap_count != subcnt()) {
std::cerr << "submap count(" << submap_count << ") != N(" << N << ")" << std::endl;
return false;
}

for (size_t i = 0; i < sets_.size(); ++i) {
auto ar = w.create_archive(i);
auto& inner = sets_[i];
if (!inner.set_.load(*ar)) {
std::cerr << "Failed to load submap " << i << std::endl;
return false;
}
}
return true;
}

private:
template <class Container, typename Enabler>
friend struct phmap::container_internal::hashtable_debug_internal::HashtableDebugAccess;
Expand Down
32 changes: 31 additions & 1 deletion parallel_hashmap/phmap_base.h
Expand Up @@ -33,7 +33,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// ---------------------------------------------------------------------------

#include <algorithm>
#include <cassert>
#include <cstddef>
Expand Down Expand Up @@ -71,6 +70,37 @@ 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));
};

template <typename... Ts>
struct VoidTImpl {
using type = void;
Expand Down