6 #ifndef METALL_CONTAINER_EXPERIMENT_JGRAPH_JGRAPH_HPP
7 #define METALL_CONTAINER_EXPERIMENT_JGRAPH_JGRAPH_HPP
10 #include <string_view>
36 template <
typename allocator_type>
40 template <
typename storage_iterator_type>
43 template <
typename adj_list_edge_list_iterator_type,
44 typename storage_pointer_type>
48 template <
typename _allocator_type = std::allocator<std::
byte>>
61 using other_allocator =
62 typename std::allocator_traits<allocator_type>::template rebind_alloc<T>;
65 using other_scoped_allocator =
70 typename std::allocator_traits<
73 using internal_id_type = uint64_t;
74 static constexpr internal_id_type k_max_internal_id =
75 std::numeric_limits<internal_id_type>::max();
77 class vertex_data_type {
81 explicit vertex_data_type(
83 : m_id(id, allocator), m_value(allocator) {}
86 vertex_data_type(
const vertex_data_type &) =
default;
89 vertex_data_type(
const vertex_data_type &other,
const allocator_type &alloc)
90 : m_id(other.m_id, alloc), m_value(other.m_value, alloc) {}
93 vertex_data_type(vertex_data_type &&) noexcept = default;
97 vertex_data_type(vertex_data_type &&other,
99 : m_id(std::move(other.m_id), alloc),
100 m_value(std::move(other.m_value), alloc) {}
103 vertex_data_type &operator=(
const vertex_data_type &) =
default;
106 vertex_data_type &operator=(vertex_data_type &&) noexcept = default;
112 const value_type &value()
const {
return m_value; }
119 using vertex_storage_type =
122 other_scoped_allocator<std::pair<
const internal_id_type,
125 class edge_data_type {
129 explicit edge_data_type(
const id_type &source_id,
131 const internal_id_type &edge_id,
133 : m_source_id(source_id, allocator),
134 m_destination_id(destination_id, allocator),
136 m_value(allocator) {}
139 edge_data_type(
const edge_data_type &) =
default;
143 edge_data_type(
const edge_data_type &other,
const allocator_type &alloc)
144 : m_source_id(other.m_source_id, alloc),
145 m_destination_id(other.m_destination_id, alloc),
146 m_edge_id(other.m_edge_id),
147 m_value(other.m_value, alloc) {}
150 edge_data_type(edge_data_type &&) noexcept = default;
154 edge_data_type(edge_data_type &&other, const
allocator_type &alloc) noexcept
155 : m_source_id(other.m_source_id, alloc),
156 m_destination_id(other.m_destination_id, alloc),
157 m_edge_id(other.m_edge_id),
158 m_value(other.m_value, alloc) {}
161 edge_data_type &operator=(
const edge_data_type &) =
default;
164 edge_data_type &operator=(edge_data_type &&) noexcept = default;
168 const id_type destination_id()
const {
return id_type(m_destination_id); }
176 const value_type &value()
const {
return m_value; }
179 string_type m_source_id;
180 string_type m_destination_id;
181 internal_id_type m_edge_id;
185 using edge_storage_type =
188 other_scoped_allocator<
189 std::pair<const internal_id_type, edge_data_type>>>;
192 using adj_list_edge_list_type =
195 std::hash<internal_id_type>, std::equal_to<>,
196 other_scoped_allocator<std::pair<
197 const internal_id_type, internal_id_type>>>;
201 adj_list_edge_list_type, std::hash<internal_id_type>, std::equal_to<>,
202 other_scoped_allocator<
203 std::pair<const internal_id_type, adj_list_edge_list_type>>>;
207 internal_id_type, string_type, std::hash<internal_id_type>,
209 other_scoped_allocator<std::pair<const internal_id_type, string_type>>>;
224 typename adj_list_edge_list_type::iterator,
225 typename std::pointer_traits<
typename std::allocator_traits<
229 typename adj_list_edge_list_type::const_iterator,
230 typename std::pointer_traits<
typename std::allocator_traits<
231 allocator_type>::pointer>::template rebind<const edge_storage_type>>;
236 : m_vertex_storage(alloc),
237 m_edge_storage(alloc),
239 m_vertex_id_table(alloc) {}
245 return priv_get_vertex_internal_id(vertex_id) != k_max_internal_id;
249 const id_type &destination_vertex_id)
const {
250 const auto src = priv_get_vertex_internal_id(source_vertex_id);
251 if (src == k_max_internal_id)
return 0;
253 const auto dst = priv_get_vertex_internal_id(destination_vertex_id);
254 if (dst == k_max_internal_id)
return 0;
256 const auto &edge_list = m_adj_list.at(src);
257 return edge_list.count(dst);
261 auto internal_id = priv_get_vertex_internal_id(vertex_id);
262 if (internal_id != k_max_internal_id) {
266 internal_id = priv_generate_vertex_internal_id(vertex_id);
268 m_adj_list.emplace(internal_id,
269 adj_list_edge_list_type{m_adj_list.get_allocator()});
271 auto ret = m_vertex_storage.emplace(
273 vertex_data_type{vertex_id, m_vertex_storage.get_allocator()});
278 const id_type &destination_vertex_id,
279 const bool undirected =
false) {
283 const auto src_internal_id = priv_get_vertex_internal_id(source_vertex_id);
284 assert(src_internal_id != k_max_internal_id);
285 const auto dst_internal_id =
286 priv_get_vertex_internal_id(destination_vertex_id);
287 assert(dst_internal_id != k_max_internal_id);
288 const auto edge_id = priv_generate_edge_id();
290 auto itr = m_adj_list.at(src_internal_id).emplace(dst_internal_id, edge_id);
292 m_adj_list.at(dst_internal_id).emplace(src_internal_id, edge_id);
295 m_edge_storage.emplace(
296 edge_id, edge_data_type{source_vertex_id, destination_vertex_id,
297 edge_id, m_edge_storage.get_allocator()});
303 m_vertex_storage.find(priv_get_vertex_internal_id(vertex_id)));
308 m_vertex_storage.find(priv_get_vertex_internal_id(vertex_id)));
312 const id_type &source_vertex_id,
const id_type &destination_vertex_id) {
313 const auto src_internal_id = priv_get_vertex_internal_id(source_vertex_id);
314 const auto dst_internal_id =
315 priv_get_vertex_internal_id(destination_vertex_id);
317 if (src_internal_id == k_max_internal_id ||
318 dst_internal_id == k_max_internal_id) {
322 auto &edge_list = m_adj_list.at(src_internal_id);
323 auto range = edge_list.equal_range(dst_internal_id);
324 return std::make_pair(
edge_iterator{range.first, &m_edge_storage},
334 std::size_t
num_edges()
const {
return m_edge_storage.size(); }
341 const auto internal_id = priv_get_vertex_internal_id(vertex_id);
342 if (internal_id == k_max_internal_id) {
346 return m_adj_list.at(internal_id).size();
366 const auto internal_id = priv_get_vertex_internal_id(vid);
367 if (internal_id == k_max_internal_id) {
370 return edge_iterator{m_adj_list.at(internal_id).begin(), &m_edge_storage};
374 const auto internal_id = priv_get_vertex_internal_id(vid);
375 if (internal_id == k_max_internal_id) {
383 const auto internal_id = priv_get_vertex_internal_id(vid);
384 if (internal_id == k_max_internal_id) {
387 return edge_iterator{m_adj_list.at(internal_id).end(), &m_edge_storage};
391 const auto internal_id = priv_get_vertex_internal_id(vid);
392 if (internal_id == k_max_internal_id) {
400 return m_vertex_storage.get_allocator();
404 internal_id_type priv_get_vertex_internal_id(
405 const std::string_view &vid)
const {
406 auto hash = priv_hash_id(vid.data());
408 for (std::size_t d = 0; d <= m_max_vid_distance; ++d) {
409 const auto vitr = m_vertex_id_table.find(
hash);
410 if (vitr == m_vertex_id_table.end()) {
414 if (vitr->second == vid) {
417 hash = (
hash + 1) % k_max_internal_id;
420 return k_max_internal_id;
423 internal_id_type priv_generate_vertex_internal_id(
424 const std::string_view &vid) {
425 auto hash = priv_hash_id(vid.data());
427 std::size_t distance = 0;
428 while (m_vertex_id_table.count(
hash) > 0) {
429 hash = (
hash + 1) % k_max_internal_id;
432 m_max_vid_distance = std::max(distance, m_max_vid_distance);
434 m_vertex_id_table[
hash] = vid.data();
439 internal_id_type priv_generate_edge_id() {
return ++m_max_edge_id; }
441 static internal_id_type priv_hash_id(
const std::string_view &
id) {
442 return metall::mtlldetail::murmur_hash_64a(
id.data(),
id.length(), 1234);
445 vertex_storage_type m_vertex_storage;
446 edge_storage_type m_edge_storage;
447 adj_list_type m_adj_list;
448 id_table_type m_vertex_id_table;
449 internal_id_type m_max_edge_id{0};
450 std::size_t m_max_vid_distance{0};
455 template <
typename storage_iterator_type>
458 static constexpr
bool is_const_value = std::is_const_v<
459 typename std::iterator_traits<storage_iterator_type>::value_type>;
462 using raw_value_type =
typename std::tuple_element<
464 typename std::iterator_traits<storage_iterator_type>::value_type>::type;
468 std::conditional_t<is_const_value, const raw_value_type, raw_value_type>;
469 using pointer =
typename std::pointer_traits<
typename std::iterator_traits<
470 storage_iterator_type>
::pointer>::template rebind<value_type>;
473 typename std::iterator_traits<storage_iterator_type>::difference_type;
476 : m_current_pos(begin_pos) {}
496 return m_current_pos == other.m_current_pos;
508 storage_iterator_type m_current_pos;
511 template <
typename storage_iterator_type>
514 return lhs.
equal(rhs);
517 template <
typename storage_iterator_type>
520 return !(lhs == rhs);
523 template <
typename adj_list_edge_list_iterator_type,
524 typename storage_pointer_type>
527 static constexpr
bool is_const_value = std::is_const_v<
528 typename std::pointer_traits<storage_pointer_type>::element_type>;
531 using raw_value_type =
typename std::pointer_traits<
532 storage_pointer_type>::element_type::mapped_type;
536 std::conditional_t<is_const_value, const raw_value_type, raw_value_type>;
538 typename std::pointer_traits<storage_pointer_type>::element_type::
539 iterator::pointer>::template rebind<value_type>;
547 storage_pointer_type storage)
548 : m_current_pos(begin_pos), m_storage_pointer(storage) {}
568 return m_current_pos == other.m_current_pos;
572 const auto &edge_id = m_current_pos->second;
573 return &(m_storage_pointer->at(edge_id));
577 const auto &edge_id = m_current_pos->second;
578 return &(m_storage_pointer->at(edge_id));
582 const auto &edge_id = m_current_pos->second;
583 return (m_storage_pointer->at(edge_id));
587 const auto &edge_id = m_current_pos->second;
588 return (m_storage_pointer->at(edge_id));
592 adj_list_edge_list_iterator_type m_current_pos;
593 storage_pointer_type m_storage_pointer;
596 template <
typename adj_list_edge_list_iterator_type,
597 typename storage_pointer_type>
600 storage_pointer_type> &lhs,
602 storage_pointer_type> &rhs) {
603 return lhs.equal(rhs);
606 template <
typename adj_list_edge_list_iterator_type,
607 typename storage_pointer_type>
610 storage_pointer_type> &lhs,
612 storage_pointer_type> &rhs) {
613 return !(lhs == rhs);