Skip to content

Commit

Permalink
(wip) string containers
Browse files Browse the repository at this point in the history
  • Loading branch information
Keita Iwabuchi committed Mar 1, 2024
1 parent 16b09d3 commit 0aa7883
Show file tree
Hide file tree
Showing 11 changed files with 739 additions and 2 deletions.
4 changes: 3 additions & 1 deletion example/container/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
if (Boost_VERSION_STRING VERSION_GREATER_EQUAL "1.75")
add_metall_executable(string_key_store string_key_store.cpp)
endif()
endif()

add_subdirectory(string_container)
1 change: 1 addition & 0 deletions example/container/string_container/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_metall_executable(string_container string_container.cpp)
92 changes: 92 additions & 0 deletions example/container/string_container/string_container.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2024 Lawrence Livermore National Security, LLC and other Metall
// Project Developers. See the top-level COPYRIGHT file for details.
//
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#include <iostream>
#include <string>

#include <metall/metall.hpp>
#include <metall/container/experimental/string_container/deque.hpp>
#include <metall/container/experimental/string_container/map_from_string.hpp>
#include <metall/container/experimental/string_container/map_to_string.hpp>

using namespace metall::container::experimental::string_container;

int main() {
// Create a new datastore
{
metall::manager manager(metall::create_only, "/tmp/datastore");

// -----------------------------------------------------
// Main string table
auto *main_table = manager.construct<string_table<>>(
metall::unique_instance)(manager.get_allocator<>());

// -----------------------------------------------------
// map from string (map<string, int>)
auto *map_from_str_1 =
manager.construct<map_from_string<int>>("map1")(main_table);

// map operations
(*map_from_str_1)["hello"] = 0;
(*map_from_str_1)["world"] = 1;

// another map that shares the same string table
auto *map_from_str_2 =
manager.construct<map_from_string<int>>("map2")(main_table);

(*map_from_str_2)[std::string("hello")] = 10;
(*map_from_str_2)["universe"] = 11;

// -----------------------------------------------------
// map to string (map<int, string>)
auto *map_to_str =
manager.construct<map_to_string<int>>("map3")(main_table);

(*map_to_str)[0] = "hello";
(*map_to_str)[1] = "virtual world";

// -----------------------------------------------------
// Deque
auto *dq = manager.construct<deque<>>("dq")(main_table);
dq->push_back("hello");
dq->resize(2); // 2nd element is empty
}

// open the existing containers
{
metall::manager manager(metall::open_read_only, "/tmp/datastore");

auto *main_table =
manager.find<string_table<>>(metall::unique_instance).first;
auto *map_from_str_1 = manager.find<map_from_string<int>>("map1").first;
auto *map_from_str_2 = manager.find<map_from_string<int>>("map2").first;
auto *map_to_str = manager.find<map_to_string<int>>("map3").first;
auto *dq = manager.find<deque<>>("dq").first;

std::cout << "\nmap_from_str_1" << std::endl;
std::cout << "hello: " << (*map_from_str_1)["hello"] << std::endl;
std::cout << "world: " << (*map_from_str_1)["world"] << std::endl;

std::cout << "\nmap_from_str_2" << std::endl;
for (const auto &[k, v] : *map_from_str_2) {
std::cout << k << ": " << v << std::endl;
}

std::cout << "\nmap_to_str" << std::endl;
for (const auto &[k, v] : *map_to_str) {
std::cout << k << ": " << v << std::endl;
}

std::cout << "\ndeque" << std::endl;
for (std::size_t i = 0; i < dq->size(); ++i) {
std::cout << i << ": " << (*dq)[i] << std::endl;
}

// NOTE: empty string ("") is also stored in the string table
std::cout << "\n#of unique strings: " << main_table->size() << std::endl;
}

return 0;
}
73 changes: 73 additions & 0 deletions include/metall/container/experimental/string_container/deque.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2024 Lawrence Livermore National Security, LLC and other Metall
// Project Developers. See the top-level COPYRIGHT file for details.
//
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#ifndef METALL_CONTAINER_EXPERIMENT_STRING_CONTAINER_DEQUE_HPP
#define METALL_CONTAINER_EXPERIMENT_STRING_CONTAINER_DEQUE_HPP

#include <memory>

#include <metall/container/deque.hpp>

#include <metall/container/experimental/string_container/string_table.hpp>
#include <metall/container/experimental/string_container/string.hpp>

namespace metall::container::experimental::string_container {

/// \brief A deque container that stores string using the string_table.
template <typename StringTable = string_table<>>
class deque {
public:
using allocator_type = typename StringTable::allocator_type;

private:
using string_table_type = StringTable;
using string_type = string<string_table_type>;
using deque_type = metall::container::deque<
string_type, std::scoped_allocator_adaptor<typename std::allocator_traits<
allocator_type>::template rebind_alloc<string_type>>>;

public:
explicit deque(string_table_type *string_table)
: m_string_table(string_table), m_deque(string_table->get_allocator()) {}

string_type &operator[](const std::size_t i) { return m_deque[i]; }

template <typename Str>
void push_back(const Str &str) {
m_deque.emplace_back(metall::to_raw_pointer(m_string_table));
m_deque.back() = str;
}

void pop_back() { m_deque.pop_back(); }

void resize(const std::size_t n) {
m_deque.resize(n, string_type(metall::to_raw_pointer(m_string_table)));
}

void clear() { m_deque.clear(); }

std::size_t size() const { return m_deque.size(); }

bool empty() const { return m_deque.empty(); }

void reserve(const std::size_t n) { m_deque.reserve(n); }

auto begin() { return m_deque.begin(); }
auto end() { return m_deque.end(); }
auto begin() const { return m_deque.begin(); }
auto end() const { return m_deque.end(); }

allocator_type get_allocator() const { return m_deque.get_allocator(); }

private:
using string_table_ptr_type =
typename std::pointer_traits<typename std::allocator_traits<
allocator_type>::pointer>::template rebind<string_table_type>;

string_table_ptr_type m_string_table;
deque_type m_deque;
};
} // namespace metall::container::experimental::string_container
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2024 Lawrence Livermore National Security, LLC and other Metall
// Project Developers. See the top-level COPYRIGHT file for details.
//
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#ifndef METALL_CONTAINER_EXPERIMENT_STRING_CONTAINER_MAP_FROM_STRING_HPP
#define METALL_CONTAINER_EXPERIMENT_STRING_CONTAINER_MAP_FROM_STRING_HPP

#include <memory>

#include <metall/container/scoped_allocator.hpp>
#include <metall/container/map.hpp>

#include <metall/container/experimental/string_container/string_table.hpp>
#include <metall/container/experimental/string_container/string.hpp>

namespace metall::container::experimental::string_container {

/// \brief A map container that string as keys. Internally, it uses
/// string_container::string_table to store the keys.
/// \tparam T Type of the value.
/// \tparam StringTable Type of the string table.
template <class T, typename StringTable = string_table<>>
class map_from_string {
public:
using key_type = string<StringTable>;
using mapped_type = T;
using allocator_type = typename StringTable::allocator_type;

private:
using string_table_type = StringTable;
using key_locator_type = typename string_table_type::locator_type;
using map_type = metall::container::map<
key_type, mapped_type, std::less<key_type>,
std::scoped_allocator_adaptor<
typename std::allocator_traits<allocator_type>::template rebind_alloc<
std::pair<const key_type, mapped_type>>>>;

public:
explicit map_from_string(string_table_type *const string_table)
: m_string_table(string_table), m_map(string_table->get_allocator()) {}

map_from_string(const map_from_string &) = default;
map_from_string(map_from_string &&) noexcept = default;
map_from_string &operator=(const map_from_string &) = default;
map_from_string &operator=(map_from_string &&) noexcept = default;

~map_from_string() noexcept = default;

template <typename K>
mapped_type &operator[](const K &key) {
return m_map[get_key(key)];
}

template <typename K>
const mapped_type &at(const K &key) const {
assert(m_string_table->contains(key) &&
"The key does not exist in the string table");
return m_map.at(get_key(key));
}

template <typename K>
bool contains(const K &key) const {
return m_string_table->contains(key) && m_map.contains(get_key(key));
}

void clear() { m_map.clear(); }

std::size_t size() const { return m_map.size(); }

bool empty() const { return m_map.empty(); }

void reserve(const std::size_t n) { m_map.reserve(n); }

auto begin() { return m_map.begin(); }
auto end() { return m_map.end(); }
auto begin() const { return m_map.begin(); }
auto end() const { return m_map.end(); }

allocator_type get_allocator() const { return m_map.get_allocator(); }

private:
using string_table_ptr_type =
typename std::pointer_traits<typename std::allocator_traits<
allocator_type>::pointer>::template rebind<string_table_type>;

template <typename K>
key_type get_key(const K &key) {
const auto loc = m_string_table->insert(key);
key_type new_key(metall::to_raw_pointer(m_string_table), loc);
return new_key;
}

template <typename K>
key_type get_key(const K &key) const {
const auto loc = m_string_table->to_locator(key);
key_type new_key(metall::to_raw_pointer(m_string_table), loc);
return new_key;
}

string_table_ptr_type m_string_table;
map_type m_map;
};

} // namespace metall::container::experimental::string_container
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2024 Lawrence Livermore National Security, LLC and other Metall
// Project Developers. See the top-level COPYRIGHT file for details.
//
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

#ifndef METALL_CONTAINER_EXPERIMENT_STRING_CONTAINER_MAP_TO_STRING_HPP
#define METALL_CONTAINER_EXPERIMENT_STRING_CONTAINER_MAP_TO_STRING_HPP

#include <memory>

#include <metall/container/scoped_allocator.hpp>
#include <metall/container/map.hpp>

#include <metall/container/experimental/string_container/string_table.hpp>
#include <metall/container/experimental/string_container/string.hpp>

namespace metall::container::experimental::string_container {

/// \brief A map container that uses string as value and Metall as its default
/// allocator. Internally, it uses string_container::string_table to store the
/// strings. The value is immutable.
/// \tparam Key Type of the key.
/// \tparam Allocator Type of the allocator.
template <class Key, typename StringTable = string_table<>>
class map_to_string {
public:
using key_type = Key;
using mapped_type = string<StringTable>;
using allocator_type = typename StringTable::allocator_type;

private:
using string_table_type = StringTable;
using string_type = string<string_table_type>;

public:
using map_type = metall::container::map<
key_type, string_type, std::less<key_type>,
std::scoped_allocator_adaptor<
typename std::allocator_traits<allocator_type>::template rebind_alloc<
std::pair<const key_type, string_type>>>>;

explicit map_to_string(string_table_type *const string_table)
: m_string_table(string_table), m_map(string_table->get_allocator()) {}

map_to_string(const map_to_string &) = default;
map_to_string(map_to_string &&) noexcept = default;
map_to_string &operator=(const map_to_string &) = default;
map_to_string &operator=(map_to_string &&) noexcept = default;

~map_to_string() noexcept = default;

template <typename K>
mapped_type &operator[](const K &key) {
if (m_map.count(key) == 0) {
m_map.emplace(key_type(key),
mapped_type(metall::to_raw_pointer(m_string_table)));
}
return m_map.at(key_type(key));
}

template <typename K>
const mapped_type &at(const K &key) const {
return m_map.at(key_type(key));
}

template <typename K>
mapped_type &at(const K &key) {
return m_map.at(key_type(key));
}

template <typename K>
bool contains(const K &key) const {
return m_map.count(key) > 0;
}

void clear() { m_map.clear(); }

std::size_t size() const { return m_map.size(); }

bool empty() const { return m_map.empty(); }

void reserve(const std::size_t n) { m_map.reserve(n); }

auto begin() { return m_map.begin(); }
auto end() { return m_map.end(); }
auto begin() const { return m_map.begin(); }
auto end() const { return m_map.end(); }

allocator_type get_allocator() const { return m_map.get_allocator(); }

private:
using string_table_ptr_type =
typename std::pointer_traits<typename std::allocator_traits<
allocator_type>::pointer>::template rebind<string_table_type>;

string_table_ptr_type m_string_table;
map_type m_map;
};

} // namespace metall::container::experimental::string_container
#endif
Loading

0 comments on commit 0aa7883

Please sign in to comment.