Kokkos Core Kernels Package Version of the Day
Loading...
Searching...
No Matches
Kokkos_UnorderedMap.hpp
Go to the documentation of this file.
1//@HEADER
2// ************************************************************************
3//
4// Kokkos v. 4.0
5// Copyright (2022) National Technology & Engineering
6// Solutions of Sandia, LLC (NTESS).
7//
8// Under the terms of Contract DE-NA0003525 with NTESS,
9// the U.S. Government retains certain rights in this software.
10//
11// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12// See https://kokkos.org/LICENSE for license information.
13// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14//
15//@HEADER
16
22
23#ifndef KOKKOS_UNORDERED_MAP_HPP
24#define KOKKOS_UNORDERED_MAP_HPP
25#ifndef KOKKOS_IMPL_PUBLIC_INCLUDE
26#define KOKKOS_IMPL_PUBLIC_INCLUDE
27#define KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_UNORDEREDMAP
28#endif
29
30#include <Kokkos_Core.hpp>
31#include <Kokkos_Functional.hpp>
32
33#include <Kokkos_Bitset.hpp>
34
35#include <impl/Kokkos_Traits.hpp>
36#include <impl/Kokkos_UnorderedMap_impl.hpp>
37
38#include <iostream>
39
40#include <cstdint>
41
42namespace Kokkos {
43
44enum : unsigned { UnorderedMapInvalidIndex = ~0u };
45
59
61 private:
62 enum Status : uint32_t {
63 SUCCESS = 1u << 31,
64 EXISTING = 1u << 30,
65 FREED_EXISTING = 1u << 29,
66 LIST_LENGTH_MASK = ~(SUCCESS | EXISTING | FREED_EXISTING)
67 };
68
69 public:
71 KOKKOS_FORCEINLINE_FUNCTION
72 bool success() const { return (m_status & SUCCESS); }
73
75 KOKKOS_FORCEINLINE_FUNCTION
76 bool existing() const { return (m_status & EXISTING); }
77
79 KOKKOS_FORCEINLINE_FUNCTION
80 bool failed() const { return m_index == UnorderedMapInvalidIndex; }
81
84 KOKKOS_FORCEINLINE_FUNCTION
85 bool freed_existing() const { return (m_status & FREED_EXISTING); }
86
89 KOKKOS_FORCEINLINE_FUNCTION
90 uint32_t list_position() const { return (m_status & LIST_LENGTH_MASK); }
91
93 KOKKOS_FORCEINLINE_FUNCTION
94 uint32_t index() const { return m_index; }
95
96 KOKKOS_FORCEINLINE_FUNCTION
97 UnorderedMapInsertResult() : m_index(UnorderedMapInvalidIndex), m_status(0) {}
98
99 KOKKOS_FORCEINLINE_FUNCTION
100 void increment_list_position() {
101 m_status += (list_position() < LIST_LENGTH_MASK) ? 1u : 0u;
102 }
103
104 KOKKOS_FORCEINLINE_FUNCTION
105 void set_existing(uint32_t i, bool arg_freed_existing) {
106 m_index = i;
107 m_status =
108 EXISTING | (arg_freed_existing ? FREED_EXISTING : 0u) | list_position();
109 }
110
111 KOKKOS_FORCEINLINE_FUNCTION
112 void set_success(uint32_t i) {
113 m_index = i;
114 m_status = SUCCESS | list_position();
115 }
116
117 private:
118 uint32_t m_index;
119 uint32_t m_status;
120};
121
177template <typename Key, typename Value,
178 typename Device = Kokkos::DefaultExecutionSpace,
179 typename Hasher = pod_hash<std::remove_const_t<Key>>,
180 typename EqualTo = pod_equal_to<std::remove_const_t<Key>>>
182 private:
183 using host_mirror_space =
184 typename ViewTraits<Key, Device, void, void>::host_mirror_space;
185
186 public:
188
189
190 // key_types
191 using declared_key_type = Key;
192 using key_type = std::remove_const_t<declared_key_type>;
193 using const_key_type = std::add_const_t<key_type>;
194
195 // value_types
196 using declared_value_type = Value;
197 using value_type = std::remove_const_t<declared_value_type>;
198 using const_value_type = std::add_const_t<value_type>;
199
200 using device_type = Device;
201 using execution_space = typename Device::execution_space;
202 using hasher_type = Hasher;
203 using equal_to_type = EqualTo;
204 using size_type = uint32_t;
205
206 // map_types
207 using declared_map_type =
208 UnorderedMap<declared_key_type, declared_value_type, device_type,
209 hasher_type, equal_to_type>;
210 using insertable_map_type = UnorderedMap<key_type, value_type, device_type,
211 hasher_type, equal_to_type>;
212 using modifiable_map_type =
213 UnorderedMap<const_key_type, value_type, device_type, hasher_type,
214 equal_to_type>;
215 using const_map_type = UnorderedMap<const_key_type, const_value_type,
216 device_type, hasher_type, equal_to_type>;
217
218 static const bool is_set = std::is_void<value_type>::value;
219 static const bool has_const_key =
220 std::is_same<const_key_type, declared_key_type>::value;
221 static const bool has_const_value =
222 is_set || std::is_same<const_value_type, declared_value_type>::value;
223
224 static const bool is_insertable_map =
225 !has_const_key && (is_set || !has_const_value);
226 static const bool is_modifiable_map = has_const_key && !has_const_value;
227 static const bool is_const_map = has_const_key && has_const_value;
228
230
231 using HostMirror =
233
234 using histogram_type = Impl::UnorderedMapHistogram<const_map_type>;
235
237
238 private:
239 enum : size_type { invalid_index = ~static_cast<size_type>(0) };
240
241 using impl_value_type = std::conditional_t<is_set, int, declared_value_type>;
242
243 using key_type_view = std::conditional_t<
244 is_insertable_map, View<key_type *, device_type>,
246
247 using value_type_view = std::conditional_t<
248 is_insertable_map || is_modifiable_map,
251
252 using size_type_view = std::conditional_t<
253 is_insertable_map, View<size_type *, device_type>,
255
256 using bitset_type = std::conditional_t<is_insertable_map, Bitset<Device>,
258
259 enum { modified_idx = 0, erasable_idx = 1, failed_insert_idx = 2 };
260 enum { num_scalars = 3 };
262
263 public:
265
266
273 UnorderedMap(size_type capacity_hint = 0, hasher_type hasher = hasher_type(),
274 equal_to_type equal_to = equal_to_type())
275 : m_bounded_insert(true),
276 m_hasher(hasher),
277 m_equal_to(equal_to),
278 m_size(),
279 m_available_indexes(calculate_capacity(capacity_hint)),
280 m_hash_lists(view_alloc(WithoutInitializing, "UnorderedMap hash list"),
281 Impl::find_hash_size(capacity())),
282 m_next_index(view_alloc(WithoutInitializing, "UnorderedMap next index"),
283 capacity() + 1) // +1 so that the *_at functions can
284 // always return a valid reference
285 ,
286 m_keys("UnorderedMap keys", capacity()),
287 m_values("UnorderedMap values", (is_set ? 0 : capacity())),
288 m_scalars("UnorderedMap scalars") {
289 if (!is_insertable_map) {
290 Kokkos::Impl::throw_runtime_exception(
291 "Cannot construct a non-insertable (i.e. const key_type) "
292 "unordered_map");
293 }
294
295 Kokkos::deep_copy(m_hash_lists, invalid_index);
296 Kokkos::deep_copy(m_next_index, invalid_index);
297 }
298
299 void reset_failed_insert_flag() { reset_flag(failed_insert_idx); }
300
301 histogram_type get_histogram() { return histogram_type(*this); }
302
304 void clear() {
305 m_bounded_insert = true;
306
307 if (capacity() == 0) return;
308
309 m_available_indexes.clear();
310
311 Kokkos::deep_copy(m_hash_lists, invalid_index);
312 Kokkos::deep_copy(m_next_index, invalid_index);
313 {
314 const key_type tmp = key_type();
315 Kokkos::deep_copy(m_keys, tmp);
316 }
317 Kokkos::deep_copy(m_scalars, 0);
318 m_size = 0;
319 }
320
321 KOKKOS_INLINE_FUNCTION constexpr bool is_allocated() const {
322 return (m_keys.is_allocated() && (is_set || m_values.is_allocated()) &&
323 m_scalars.is_allocated());
324 }
325
336 bool rehash(size_type requested_capacity = 0) {
337 const bool bounded_insert = (capacity() == 0) || (size() == 0u);
338 return rehash(requested_capacity, bounded_insert);
339 }
340
341 bool rehash(size_type requested_capacity, bool bounded_insert) {
342 if (!is_insertable_map) return false;
343
344 const size_type curr_size = size();
345 requested_capacity =
346 (requested_capacity < curr_size) ? curr_size : requested_capacity;
347
348 insertable_map_type tmp(requested_capacity, m_hasher, m_equal_to);
349
350 if (curr_size) {
351 tmp.m_bounded_insert = false;
352 Impl::UnorderedMapRehash<insertable_map_type> f(tmp, *this);
353 f.apply();
354 }
355 tmp.m_bounded_insert = bounded_insert;
356
357 *this = tmp;
358
359 return true;
360 }
361
369 size_type size() const {
370 if (capacity() == 0u) return 0u;
371 if (modified()) {
372 m_size = m_available_indexes.count();
373 reset_flag(modified_idx);
374 }
375 return m_size;
376 }
377
383 bool failed_insert() const { return get_flag(failed_insert_idx); }
384
385 bool erasable() const {
386 return is_insertable_map ? get_flag(erasable_idx) : false;
387 }
388
389 bool begin_erase() {
390 bool result = !erasable();
391 if (is_insertable_map && result) {
392 execution_space().fence(
393 "Kokkos::UnorderedMap::begin_erase: fence before setting erasable "
394 "flag");
395 set_flag(erasable_idx);
396 }
397 return result;
398 }
399
400 bool end_erase() {
401 bool result = erasable();
402 if (is_insertable_map && result) {
403 execution_space().fence(
404 "Kokkos::UnorderedMap::end_erase: fence before erasing");
405 Impl::UnorderedMapErase<declared_map_type> f(*this);
406 f.apply();
407 execution_space().fence(
408 "Kokkos::UnorderedMap::end_erase: fence after erasing");
409 reset_flag(erasable_idx);
410 }
411 return result;
412 }
413
418 KOKKOS_FORCEINLINE_FUNCTION
419 size_type capacity() const { return m_available_indexes.size(); }
420
431 KOKKOS_INLINE_FUNCTION
432 size_type hash_capacity() const { return m_hash_lists.extent(0); }
433
434 //---------------------------------------------------------------------------
435 //---------------------------------------------------------------------------
436
445 KOKKOS_INLINE_FUNCTION
446 insert_result insert(key_type const &k,
447 impl_value_type const &v = impl_value_type()) const {
448 insert_result result;
449
450 if (!is_insertable_map || capacity() == 0u ||
451 m_scalars((int)erasable_idx)) {
452 return result;
453 }
454
455 if (!m_scalars((int)modified_idx)) {
456 m_scalars((int)modified_idx) = true;
457 }
458
459 int volatile &failed_insert_ref = m_scalars((int)failed_insert_idx);
460
461 const size_type hash_value = m_hasher(k);
462 const size_type hash_list = hash_value % m_hash_lists.extent(0);
463
464 size_type *curr_ptr = &m_hash_lists[hash_list];
465 size_type new_index = invalid_index;
466
467 // Force integer multiply to long
468 size_type index_hint = static_cast<size_type>(
469 (static_cast<double>(hash_list) * capacity()) / m_hash_lists.extent(0));
470
471 size_type find_attempts = 0;
472
473 enum : unsigned { bounded_find_attempts = 32u };
474 const size_type max_attempts =
475 (m_bounded_insert &&
476 (bounded_find_attempts < m_available_indexes.max_hint()))
477 ? bounded_find_attempts
478 : m_available_indexes.max_hint();
479
480 bool not_done = true;
481
482#if defined(__MIC__)
483#pragma noprefetch
484#endif
485 while (not_done) {
486 // Continue searching the unordered list for this key,
487 // list will only be appended during insert phase.
488 // Need volatile_load as other threads may be appending.
489
490 // FIXME_SYCL replacement for memory_fence
491#ifdef KOKKOS_ENABLE_SYCL
492 size_type curr = Kokkos::atomic_load(curr_ptr);
493#else
494 size_type curr = volatile_load(curr_ptr);
495#endif
496
497 KOKKOS_NONTEMPORAL_PREFETCH_LOAD(
498 &m_keys[curr != invalid_index ? curr : 0]);
499#if defined(__MIC__)
500#pragma noprefetch
501#endif
502 while (curr != invalid_index && !m_equal_to(
503#ifdef KOKKOS_ENABLE_SYCL
504 Kokkos::atomic_load(&m_keys[curr])
505#else
506 volatile_load(&m_keys[curr])
507#endif
508 ,
509 k)) {
510 result.increment_list_position();
511 index_hint = curr;
512 curr_ptr = &m_next_index[curr];
513#ifdef KOKKOS_ENABLE_SYCL
514 curr = Kokkos::atomic_load(curr_ptr);
515#else
516 curr = volatile_load(curr_ptr);
517#endif
518 KOKKOS_NONTEMPORAL_PREFETCH_LOAD(
519 &m_keys[curr != invalid_index ? curr : 0]);
520 }
521
522 //------------------------------------------------------------
523 // If key already present then return that index.
524 if (curr != invalid_index) {
525 const bool free_existing = new_index != invalid_index;
526 if (free_existing) {
527 // Previously claimed an unused entry that was not inserted.
528 // Release this unused entry immediately.
529 if (!m_available_indexes.reset(new_index)) {
530 KOKKOS_IMPL_DO_NOT_USE_PRINTF("Unable to free existing\n");
531 }
532 }
533
534 result.set_existing(curr, free_existing);
535 not_done = false;
536 }
537 //------------------------------------------------------------
538 // Key is not currently in the map.
539 // If the thread has claimed an entry try to insert now.
540 else {
541 //------------------------------------------------------------
542 // If have not already claimed an unused entry then do so now.
543 if (new_index == invalid_index) {
544 bool found = false;
545 // use the hash_list as the flag for the search direction
546 Kokkos::tie(found, index_hint) =
547 m_available_indexes.find_any_unset_near(index_hint, hash_list);
548
549 // found and index and this thread set it
550 if (!found && ++find_attempts >= max_attempts) {
551 failed_insert_ref = true;
552 not_done = false;
553 } else if (m_available_indexes.set(index_hint)) {
554 new_index = index_hint;
555 // Set key and value
556 KOKKOS_NONTEMPORAL_PREFETCH_STORE(&m_keys[new_index]);
557// FIXME_SYCL replacement for memory_fence
558#ifdef KOKKOS_ENABLE_SYCL
559 Kokkos::atomic_store(&m_keys[new_index], k);
560#else
561 m_keys[new_index] = k;
562#endif
563
564 if (!is_set) {
565 KOKKOS_NONTEMPORAL_PREFETCH_STORE(&m_values[new_index]);
566#ifdef KOKKOS_ENABLE_SYCL
567 Kokkos::atomic_store(&m_values[new_index], v);
568#else
569 m_values[new_index] = v;
570#endif
571 }
572
573#ifndef KOKKOS_ENABLE_SYCL
574 // Do not proceed until key and value are updated in global memory
575 memory_fence();
576#endif
577 }
578 } else if (failed_insert_ref) {
579 not_done = false;
580 }
581
582 // Attempt to append claimed entry into the list.
583 // Another thread may also be trying to append the same list so protect
584 // with atomic.
585 if (new_index != invalid_index &&
586 curr == atomic_compare_exchange(
587 curr_ptr, static_cast<size_type>(invalid_index),
588 new_index)) {
589 // Succeeded in appending
590 result.set_success(new_index);
591 not_done = false;
592 }
593 }
594 } // while ( not_done )
595
596 return result;
597 }
598
599 KOKKOS_INLINE_FUNCTION
600 bool erase(key_type const &k) const {
601 bool result = false;
602
603 if (is_insertable_map && 0u < capacity() && m_scalars((int)erasable_idx)) {
604 if (!m_scalars((int)modified_idx)) {
605 m_scalars((int)modified_idx) = true;
606 }
607
608 size_type index = find(k);
609 if (valid_at(index)) {
610 m_available_indexes.reset(index);
611 result = true;
612 }
613 }
614
615 return result;
616 }
617
625 KOKKOS_INLINE_FUNCTION
626 size_type find(const key_type &k) const {
627 size_type curr = 0u < capacity()
628 ? m_hash_lists(m_hasher(k) % m_hash_lists.extent(0))
629 : invalid_index;
630
631 KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]);
632 while (curr != invalid_index && !m_equal_to(m_keys[curr], k)) {
633 KOKKOS_NONTEMPORAL_PREFETCH_LOAD(
634 &m_keys[curr != invalid_index ? curr : 0]);
635 curr = m_next_index[curr];
636 }
637
638 return curr;
639 }
640
645 KOKKOS_INLINE_FUNCTION
646 bool exists(const key_type &k) const { return valid_at(find(k)); }
647
656 template <typename Dummy = value_type>
657 KOKKOS_FORCEINLINE_FUNCTION std::enable_if_t<
658 !std::is_void<Dummy>::value, // !is_set
659 std::conditional_t<has_const_value, impl_value_type, impl_value_type &>>
660 value_at(size_type i) const {
661 KOKKOS_EXPECTS(i < capacity());
662 return m_values[i];
663 }
664
671 KOKKOS_FORCEINLINE_FUNCTION
672 key_type key_at(size_type i) const {
673 KOKKOS_EXPECTS(i < capacity());
674 return m_keys[i];
675 }
676
677 KOKKOS_FORCEINLINE_FUNCTION
678 bool valid_at(size_type i) const { return m_available_indexes.test(i); }
679
680 template <typename SKey, typename SValue>
681 UnorderedMap(
682 UnorderedMap<SKey, SValue, Device, Hasher, EqualTo> const &src,
683 std::enable_if_t<
684 Impl::UnorderedMapCanAssign<declared_key_type, declared_value_type,
685 SKey, SValue>::value,
686 int> = 0)
687 : m_bounded_insert(src.m_bounded_insert),
688 m_hasher(src.m_hasher),
689 m_equal_to(src.m_equal_to),
690 m_size(src.m_size),
691 m_available_indexes(src.m_available_indexes),
692 m_hash_lists(src.m_hash_lists),
693 m_next_index(src.m_next_index),
694 m_keys(src.m_keys),
695 m_values(src.m_values),
696 m_scalars(src.m_scalars) {}
697
698 template <typename SKey, typename SValue>
699 std::enable_if_t<
700 Impl::UnorderedMapCanAssign<declared_key_type, declared_value_type, SKey,
701 SValue>::value,
702 declared_map_type &>
703 operator=(UnorderedMap<SKey, SValue, Device, Hasher, EqualTo> const &src) {
704 m_bounded_insert = src.m_bounded_insert;
705 m_hasher = src.m_hasher;
706 m_equal_to = src.m_equal_to;
707 m_size = src.m_size;
708 m_available_indexes = src.m_available_indexes;
709 m_hash_lists = src.m_hash_lists;
710 m_next_index = src.m_next_index;
711 m_keys = src.m_keys;
712 m_values = src.m_values;
713 m_scalars = src.m_scalars;
714 return *this;
715 }
716
717 template <typename SKey, typename SValue, typename SDevice>
718 std::enable_if_t<std::is_same<std::remove_const_t<SKey>, key_type>::value &&
719 std::is_same<std::remove_const_t<SValue>, value_type>::value>
720 create_copy_view(
721 UnorderedMap<SKey, SValue, SDevice, Hasher, EqualTo> const &src) {
722 if (m_hash_lists.data() != src.m_hash_lists.data()) {
723 insertable_map_type tmp;
724
725 tmp.m_bounded_insert = src.m_bounded_insert;
726 tmp.m_hasher = src.m_hasher;
727 tmp.m_equal_to = src.m_equal_to;
728 tmp.m_size = src.size();
729 tmp.m_available_indexes = bitset_type(src.capacity());
730 tmp.m_hash_lists = size_type_view(
731 view_alloc(WithoutInitializing, "UnorderedMap hash list"),
732 src.m_hash_lists.extent(0));
733 tmp.m_next_index = size_type_view(
734 view_alloc(WithoutInitializing, "UnorderedMap next index"),
735 src.m_next_index.extent(0));
736 tmp.m_keys =
737 key_type_view(view_alloc(WithoutInitializing, "UnorderedMap keys"),
738 src.m_keys.extent(0));
739 tmp.m_values = value_type_view(
740 view_alloc(WithoutInitializing, "UnorderedMap values"),
741 src.m_values.extent(0));
742 tmp.m_scalars = scalars_view("UnorderedMap scalars");
743
744 Kokkos::deep_copy(tmp.m_available_indexes, src.m_available_indexes);
745
746 using raw_deep_copy =
747 Kokkos::Impl::DeepCopy<typename device_type::memory_space,
748 typename SDevice::memory_space>;
749
750 raw_deep_copy(tmp.m_hash_lists.data(), src.m_hash_lists.data(),
751 sizeof(size_type) * src.m_hash_lists.extent(0));
752 raw_deep_copy(tmp.m_next_index.data(), src.m_next_index.data(),
753 sizeof(size_type) * src.m_next_index.extent(0));
754 raw_deep_copy(tmp.m_keys.data(), src.m_keys.data(),
755 sizeof(key_type) * src.m_keys.extent(0));
756 if (!is_set) {
757 raw_deep_copy(tmp.m_values.data(), src.m_values.data(),
758 sizeof(impl_value_type) * src.m_values.extent(0));
759 }
760 raw_deep_copy(tmp.m_scalars.data(), src.m_scalars.data(),
761 sizeof(int) * num_scalars);
762
763 Kokkos::fence(
764 "Kokkos::UnorderedMap::create_copy_view: fence after copy to tmp");
765
766 *this = tmp;
767 }
768 }
769
771 private: // private member functions
772 bool modified() const { return get_flag(modified_idx); }
773
774 void set_flag(int flag) const {
775 using raw_deep_copy =
776 Kokkos::Impl::DeepCopy<typename device_type::memory_space,
778 const int true_ = true;
779 raw_deep_copy(m_scalars.data() + flag, &true_, sizeof(int));
780 Kokkos::fence(
781 "Kokkos::UnorderedMap::set_flag: fence after copying flag from "
782 "HostSpace");
783 }
784
785 void reset_flag(int flag) const {
786 using raw_deep_copy =
787 Kokkos::Impl::DeepCopy<typename device_type::memory_space,
789 const int false_ = false;
790 raw_deep_copy(m_scalars.data() + flag, &false_, sizeof(int));
791 Kokkos::fence(
792 "Kokkos::UnorderedMap::reset_flag: fence after copying flag from "
793 "HostSpace");
794 }
795
796 bool get_flag(int flag) const {
797 using raw_deep_copy =
798 Kokkos::Impl::DeepCopy<Kokkos::HostSpace,
799 typename device_type::memory_space>;
800 int result = false;
801 raw_deep_copy(&result, m_scalars.data() + flag, sizeof(int));
802 Kokkos::fence(
803 "Kokkos::UnorderedMap::get_flag: fence after copy to return value in "
804 "HostSpace");
805 return result;
806 }
807
808 static uint32_t calculate_capacity(uint32_t capacity_hint) {
809 // increase by 16% and round to nears multiple of 128
810 return capacity_hint
811 ? ((static_cast<uint32_t>(7ull * capacity_hint / 6u) + 127u) /
812 128u) *
813 128u
814 : 128u;
815 }
816
817 private: // private members
818 bool m_bounded_insert;
819 hasher_type m_hasher;
820 equal_to_type m_equal_to;
821 mutable size_type m_size;
822 bitset_type m_available_indexes;
823 size_type_view m_hash_lists;
824 size_type_view m_next_index;
825 key_type_view m_keys;
826 value_type_view m_values;
827 scalars_view m_scalars;
828
829 template <typename KKey, typename VValue, typename DDevice, typename HHash,
830 typename EEqualTo>
831 friend class UnorderedMap;
832
833 template <typename UMap>
834 friend struct Impl::UnorderedMapErase;
835
836 template <typename UMap>
837 friend struct Impl::UnorderedMapHistogram;
838
839 template <typename UMap>
840 friend struct Impl::UnorderedMapPrint;
841};
842
843// Specialization of deep_copy for two UnorderedMap objects.
844template <typename DKey, typename DT, typename DDevice, typename SKey,
845 typename ST, typename SDevice, typename Hasher, typename EqualTo>
846inline void deep_copy(
847 UnorderedMap<DKey, DT, DDevice, Hasher, EqualTo> &dst,
848 const UnorderedMap<SKey, ST, SDevice, Hasher, EqualTo> &src) {
849 dst.create_copy_view(src);
850}
851
852} // namespace Kokkos
853
854#ifdef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_UNORDEREDMAP
855#undef KOKKOS_IMPL_PUBLIC_INCLUDE
856#undef KOKKOS_IMPL_PUBLIC_INCLUDE_NOTDEFINED_UNORDEREDMAP
857#endif
858#endif // KOKKOS_UNORDERED_MAP_HPP
KOKKOS_FORCEINLINE_FUNCTION pair< T1 &, T2 & > tie(T1 &x, T2 &y)
Return a pair of references to the input arguments.
Memory management for host memory.
First element of the return value of UnorderedMap::insert().
KOKKOS_FORCEINLINE_FUNCTION bool failed() const
Did the map fail to insert the key due to insufficient capacity.
KOKKOS_FORCEINLINE_FUNCTION bool success() const
Did the map successful insert the key/value pair.
KOKKOS_FORCEINLINE_FUNCTION bool freed_existing() const
KOKKOS_FORCEINLINE_FUNCTION bool existing() const
Was the key already present in the map.
KOKKOS_FORCEINLINE_FUNCTION uint32_t list_position() const
KOKKOS_FORCEINLINE_FUNCTION uint32_t index() const
Index where the key can be found as long as the insert did not fail.
Thread-safe, performance-portable lookup table.
bool failed_insert() const
The current number of failed insert() calls.
KOKKOS_FORCEINLINE_FUNCTION key_type key_at(size_type i) const
Get the key with i as its direct index.
KOKKOS_INLINE_FUNCTION size_type hash_capacity() const
The number of hash table "buckets.".
KOKKOS_INLINE_FUNCTION bool exists(const key_type &k) const
Does the key exist in the map.
KOKKOS_INLINE_FUNCTION size_type find(const key_type &k) const
Find the given key k, if it exists in the table.
UnorderedMap(size_type capacity_hint=0, hasher_type hasher=hasher_type(), equal_to_type equal_to=equal_to_type())
Constructor.
KOKKOS_FORCEINLINE_FUNCTION std::enable_if_t< !std::is_void< Dummy >::value, std::conditional_t< has_const_value, impl_value_type, impl_value_type & > > value_at(size_type i) const
Get the value with i as its direct index.
void clear()
Clear all entries in the table.
KOKKOS_FORCEINLINE_FUNCTION size_type capacity() const
The maximum number of entries that the table can hold.
size_type size() const
The number of entries in the table.
bool rehash(size_type requested_capacity=0)
Change the capacity of the the map.
KOKKOS_INLINE_FUNCTION insert_result insert(key_type const &k, impl_value_type const &v=impl_value_type()) const
View to an array of data.