50 #ifndef KOKKOS_UNORDERED_MAP_HPP 
   51 #define KOKKOS_UNORDERED_MAP_HPP 
   53 #include <Kokkos_Core.hpp> 
   54 #include <Kokkos_Functional.hpp> 
   56 #include <Kokkos_Bitset.hpp> 
   58 #include <impl/Kokkos_Traits.hpp> 
   59 #include <impl/Kokkos_UnorderedMap_impl.hpp> 
   70 enum { UnorderedMapInvalidIndex = ~0u };
 
   92    , FREED_EXISTING = 1u << 29
 
   93    , LIST_LENGTH_MASK = ~(SUCCESS | EXISTING | FREED_EXISTING)
 
   98   KOKKOS_FORCEINLINE_FUNCTION
 
   99   bool success()
 const { 
return (m_status & SUCCESS); }
 
  102   KOKKOS_FORCEINLINE_FUNCTION
 
  103   bool existing()
 const { 
return (m_status & EXISTING); }
 
  106   KOKKOS_FORCEINLINE_FUNCTION
 
  107   bool failed()
 const { 
return m_index == UnorderedMapInvalidIndex; }
 
  111   KOKKOS_FORCEINLINE_FUNCTION
 
  116   KOKKOS_FORCEINLINE_FUNCTION
 
  120   KOKKOS_FORCEINLINE_FUNCTION
 
  121   uint32_t 
index()
 const { 
return m_index; }
 
  123   KOKKOS_FORCEINLINE_FUNCTION
 
  125     : m_index(UnorderedMapInvalidIndex)
 
  129   KOKKOS_FORCEINLINE_FUNCTION
 
  130   void increment_list_position()
 
  135   KOKKOS_FORCEINLINE_FUNCTION
 
  136   void set_existing(uint32_t i, 
bool arg_freed_existing)
 
  139     m_status = EXISTING | (arg_freed_existing ? FREED_EXISTING : 0u) | 
list_position();
 
  142   KOKKOS_FORCEINLINE_FUNCTION
 
  143   void set_success(uint32_t i)
 
  209 template <   
typename Key
 
  211            , 
typename Device = Kokkos::DefaultExecutionSpace
 
  212            , 
typename Hasher = pod_hash<typename Impl::remove_const<Key>::type>
 
  213            , 
typename EqualTo = pod_equal_to<typename Impl::remove_const<Key>::type>
 
  218   typedef typename ViewTraits<Key,Device,void,void>::host_mirror_space host_mirror_space ;
 
  224   typedef Key declared_key_type;
 
  225   typedef typename Impl::remove_const<declared_key_type>::type key_type;
 
  226   typedef typename Impl::add_const<key_type>::type const_key_type;
 
  229   typedef Value declared_value_type;
 
  230   typedef typename Impl::remove_const<declared_value_type>::type value_type;
 
  231   typedef typename Impl::add_const<value_type>::type const_value_type;
 
  233   typedef Device device_type;
 
  234   typedef typename Device::execution_space execution_space;
 
  235   typedef Hasher hasher_type;
 
  236   typedef EqualTo  equal_to_type;
 
  237   typedef uint32_t size_type;
 
  245   static const bool is_set = std::is_same<void,value_type>::value;
 
  246   static const bool has_const_key = std::is_same<const_key_type,declared_key_type>::value;
 
  247   static const bool has_const_value = is_set || std::is_same<const_value_type,declared_value_type>::value;
 
  249   static const bool is_insertable_map = !has_const_key && (is_set || !has_const_value);
 
  250   static const bool is_modifiable_map = has_const_key && !has_const_value;
 
  251   static const bool is_const_map = has_const_key && has_const_value;
 
  258   typedef Impl::UnorderedMapHistogram<const_map_type> histogram_type;
 
  263   enum { invalid_index = ~static_cast<size_type>(0) };
 
  265   typedef typename Impl::if_c< is_set, int, declared_value_type>::type impl_value_type;
 
  267   typedef typename Impl::if_c<   is_insertable_map
 
  270                              >::type key_type_view;
 
  272   typedef typename Impl::if_c<   is_insertable_map || is_modifiable_map
 
  275                              >::type value_type_view;
 
  277   typedef typename Impl::if_c<   is_insertable_map
 
  280                              >::type size_type_view;
 
  282   typedef typename Impl::if_c<   is_insertable_map
 
  287   enum { modified_idx = 0, erasable_idx = 1, failed_insert_idx = 2 };
 
  288   enum { num_scalars = 3 };
 
  300     , m_available_indexes()
 
  313   UnorderedMap(  size_type capacity_hint, hasher_type hasher = hasher_type(), equal_to_type equal_to = equal_to_type() )
 
  314     : m_bounded_insert(true)
 
  316     , m_equal_to(equal_to)
 
  318     , m_available_indexes(calculate_capacity(capacity_hint))
 
  319     , m_hash_lists(ViewAllocateWithoutInitializing(
"UnorderedMap hash list"), Impl::find_hash_size(capacity()))
 
  320     , m_next_index(ViewAllocateWithoutInitializing(
"UnorderedMap next index"), capacity()+1) 
 
  321     , m_keys(
"UnorderedMap keys",capacity()+1)
 
  322     , m_values(
"UnorderedMap values",(is_set? 1 : capacity()+1))
 
  323     , m_scalars(
"UnorderedMap scalars")
 
  325     if (!is_insertable_map) {
 
  326       throw std::runtime_error(
"Cannot construct a non-insertable (i.e. const key_type) unordered_map");
 
  333   void reset_failed_insert_flag()
 
  335     reset_flag(failed_insert_idx);
 
  338   histogram_type get_histogram()
 
  340     return histogram_type(*
this);
 
  346     m_bounded_insert = 
true;
 
  348     if (capacity() == 0) 
return;
 
  350     m_available_indexes.clear();
 
  355       const key_type tmp = key_type();
 
  359       const impl_value_type tmp = impl_value_type();
 
  377   bool rehash(size_type requested_capacity = 0)
 
  379     const bool bounded_insert = (capacity() == 0) || (size() == 0u);
 
  380     return rehash(requested_capacity, bounded_insert );
 
  383   bool rehash(size_type requested_capacity, 
bool bounded_insert)
 
  385     if(!is_insertable_map) 
return false;
 
  387     const size_type curr_size = size();
 
  388     requested_capacity = (requested_capacity < curr_size) ? curr_size : requested_capacity;
 
  390     insertable_map_type tmp(requested_capacity, m_hasher, m_equal_to);
 
  393       tmp.m_bounded_insert = 
false;
 
  394       Impl::UnorderedMapRehash<insertable_map_type> f(tmp,*
this);
 
  397     tmp.m_bounded_insert = bounded_insert;
 
  413     if( capacity() == 0u ) 
return 0u;
 
  415       m_size = m_available_indexes.count();
 
  416       reset_flag(modified_idx);
 
  428     return get_flag(failed_insert_idx);
 
  431   bool erasable()
 const 
  433     return is_insertable_map ? get_flag(erasable_idx) : false;
 
  438     bool result = !erasable();
 
  439     if (is_insertable_map && result) {
 
  440       execution_space().fence();
 
  441       set_flag(erasable_idx);
 
  442       execution_space().fence();
 
  449     bool result = erasable();
 
  450     if (is_insertable_map && result) {
 
  451       execution_space().fence();
 
  452       Impl::UnorderedMapErase<declared_map_type> f(*
this);
 
  454       execution_space().fence();
 
  455       reset_flag(erasable_idx);
 
  464   KOKKOS_FORCEINLINE_FUNCTION
 
  466   { 
return m_available_indexes.size(); }
 
  478   KOKKOS_INLINE_FUNCTION
 
  480   { 
return m_hash_lists.extent(0); }
 
  494   KOKKOS_INLINE_FUNCTION
 
  499     if ( !is_insertable_map || capacity() == 0u || m_scalars((
int)erasable_idx) ) {
 
  503     if ( !m_scalars((
int)modified_idx) ) {
 
  504       m_scalars((
int)modified_idx) = 
true;
 
  507     int volatile & failed_insert_ref = m_scalars((
int)failed_insert_idx) ;
 
  509     const size_type hash_value = m_hasher(k);
 
  510     const size_type hash_list = hash_value % m_hash_lists.extent(0);
 
  512     size_type * curr_ptr   = & m_hash_lists[ hash_list ];
 
  513     size_type new_index    = invalid_index ;
 
  516     size_type index_hint = 
static_cast<size_type
>( (
static_cast<double>(hash_list) * capacity()) / m_hash_lists.extent(0));
 
  518     size_type find_attempts = 0;
 
  520     enum : 
unsigned { bounded_find_attempts = 32u };
 
  521     const size_type max_attempts = (m_bounded_insert && (bounded_find_attempts < m_available_indexes.max_hint()) ) ?
 
  522                                     bounded_find_attempts :
 
  523                                     m_available_indexes.max_hint();
 
  525     bool not_done = true ;
 
  527 #if defined( __MIC__ ) 
  535       size_type curr = volatile_load(curr_ptr);
 
  537       KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]);
 
  538 #if defined( __MIC__ ) 
  541       while ( curr != invalid_index && ! m_equal_to( volatile_load(&m_keys[curr]), k) ) {
 
  542         result.increment_list_position();
 
  544         curr_ptr = &m_next_index[curr];
 
  545         curr = volatile_load(curr_ptr);
 
  546         KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]);
 
  551       if ( curr != invalid_index ) {
 
  553         const bool free_existing = new_index != invalid_index;
 
  554         if ( free_existing ) {
 
  557           if (!m_available_indexes.reset(new_index) ) {
 
  558             printf(
"Unable to free existing\n");
 
  563         result.set_existing(curr, free_existing);
 
  573         if (new_index == invalid_index) {
 
  577           Kokkos::tie(found, index_hint) = m_available_indexes.find_any_unset_near( index_hint, hash_list );
 
  580           if ( !found && ++find_attempts >= max_attempts ) {
 
  581             failed_insert_ref = 
true;
 
  584           else if (m_available_indexes.set(index_hint) ) {
 
  585             new_index = index_hint;
 
  587             KOKKOS_NONTEMPORAL_PREFETCH_STORE(&m_keys[new_index]);
 
  588             m_keys[new_index] = k ;
 
  591               KOKKOS_NONTEMPORAL_PREFETCH_STORE(&m_values[new_index]);
 
  592               m_values[new_index] = v ;
 
  599         else if (failed_insert_ref) {
 
  605         if ( new_index != invalid_index &&
 
  606              curr ==  atomic_compare_exchange(curr_ptr, static_cast<size_type>(invalid_index), new_index) ) {
 
  608           result.set_success(new_index);
 
  617   KOKKOS_INLINE_FUNCTION
 
  618   bool erase(key_type 
const& k)
 const 
  622     if(is_insertable_map && 0u < capacity() && m_scalars((
int)erasable_idx)) {
 
  624       if ( ! m_scalars((
int)modified_idx) ) {
 
  625         m_scalars((
int)modified_idx) = 
true;
 
  628       size_type 
index = find(k);
 
  629       if (valid_at(index)) {
 
  630         m_available_indexes.reset(index);
 
  645   KOKKOS_INLINE_FUNCTION
 
  646   size_type 
find( 
const key_type & k)
 const 
  648     size_type curr = 0u < capacity() ? m_hash_lists( m_hasher(k) % m_hash_lists.extent(0) ) : invalid_index ;
 
  650     KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]);
 
  651     while (curr != invalid_index && !m_equal_to( m_keys[curr], k) ) {
 
  652       KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]);
 
  653       curr = m_next_index[curr];
 
  663   KOKKOS_INLINE_FUNCTION
 
  666     return valid_at(find(k));
 
  678   KOKKOS_FORCEINLINE_FUNCTION
 
  679   typename Impl::if_c< (is_set || has_const_value), impl_value_type, impl_value_type &>::type
 
  682     return m_values[ is_set ? 0 : (i < capacity() ? i : capacity()) ];
 
  691   KOKKOS_FORCEINLINE_FUNCTION
 
  694     return m_keys[ i < capacity() ? i : capacity() ];
 
  697   KOKKOS_FORCEINLINE_FUNCTION
 
  698   bool valid_at(size_type i)
 const 
  700     return m_available_indexes.test(i);
 
  703   template <
typename SKey, 
typename SValue>
 
  704   UnorderedMap( UnorderedMap<SKey,SValue,Device,Hasher,EqualTo> 
const& src,
 
  705                 typename Impl::enable_if< Impl::UnorderedMapCanAssign<declared_key_type,declared_value_type,SKey,SValue>::value,
int>::type = 0
 
  707     : m_bounded_insert(src.m_bounded_insert)
 
  708     , m_hasher(src.m_hasher)
 
  709     , m_equal_to(src.m_equal_to)
 
  711     , m_available_indexes(src.m_available_indexes)
 
  712     , m_hash_lists(src.m_hash_lists)
 
  713     , m_next_index(src.m_next_index)
 
  715     , m_values(src.m_values)
 
  716     , m_scalars(src.m_scalars)
 
  720   template <
typename SKey, 
typename SValue>
 
  721   typename Impl::enable_if< Impl::UnorderedMapCanAssign<declared_key_type,declared_value_type,SKey,SValue>::value
 
  722                            ,declared_map_type & >::type
 
  723   operator=( UnorderedMap<SKey,SValue,Device,Hasher,EqualTo> 
const& src)
 
  725     m_bounded_insert = src.m_bounded_insert;
 
  726     m_hasher = src.m_hasher;
 
  727     m_equal_to = src.m_equal_to;
 
  729     m_available_indexes = src.m_available_indexes;
 
  730     m_hash_lists = src.m_hash_lists;
 
  731     m_next_index = src.m_next_index;
 
  733     m_values = src.m_values;
 
  734     m_scalars = src.m_scalars;
 
  738   template <
typename SKey, 
typename SValue, 
typename SDevice>
 
  739   typename Impl::enable_if< std::is_same< typename Impl::remove_const<SKey>::type, key_type>::value &&
 
  740                             std::is_same< typename Impl::remove_const<SValue>::type, value_type>::value
 
  742   create_copy_view( UnorderedMap<SKey, SValue, SDevice, Hasher,EqualTo> 
const& src)
 
  744     if (m_hash_lists.data() != src.m_hash_lists.data()) {
 
  746       insertable_map_type tmp;
 
  748       tmp.m_bounded_insert = src.m_bounded_insert;
 
  749       tmp.m_hasher = src.m_hasher;
 
  750       tmp.m_equal_to = src.m_equal_to;
 
  751       tmp.m_size = src.size();
 
  752       tmp.m_available_indexes = bitset_type( src.capacity() );
 
  753       tmp.m_hash_lists        = size_type_view( ViewAllocateWithoutInitializing(
"UnorderedMap hash list"), src.m_hash_lists.extent(0) );
 
  754       tmp.m_next_index        = size_type_view( ViewAllocateWithoutInitializing(
"UnorderedMap next index"), src.m_next_index.extent(0) );
 
  755       tmp.m_keys              = key_type_view( ViewAllocateWithoutInitializing(
"UnorderedMap keys"), src.m_keys.extent(0) );
 
  756       tmp.m_values            = value_type_view( ViewAllocateWithoutInitializing(
"UnorderedMap values"), src.m_values.extent(0) );
 
  757       tmp.m_scalars           = scalars_view(
"UnorderedMap scalars");
 
  761       typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, typename SDevice::memory_space > raw_deep_copy;
 
  763       raw_deep_copy(tmp.m_hash_lists.data(), src.m_hash_lists.data(), 
sizeof(size_type)*src.m_hash_lists.extent(0));
 
  764       raw_deep_copy(tmp.m_next_index.data(), src.m_next_index.data(), 
sizeof(size_type)*src.m_next_index.extent(0));
 
  765       raw_deep_copy(tmp.m_keys.data(), src.m_keys.data(), 
sizeof(key_type)*src.m_keys.extent(0));
 
  767         raw_deep_copy(tmp.m_values.data(), src.m_values.data(), 
sizeof(impl_value_type)*src.m_values.extent(0));
 
  769       raw_deep_copy(tmp.m_scalars.data(), src.m_scalars.data(), 
sizeof(int)*num_scalars );
 
  778   bool modified()
 const 
  780     return get_flag(modified_idx);
 
  783   void set_flag(
int flag)
 const 
  785     typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, Kokkos::HostSpace > raw_deep_copy;
 
  786     const int true_ = 
true;
 
  787     raw_deep_copy(m_scalars.data() + flag, &true_, 
sizeof(int));
 
  790   void reset_flag(
int flag)
 const 
  792     typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, Kokkos::HostSpace > raw_deep_copy;
 
  793     const int false_ = 
false;
 
  794     raw_deep_copy(m_scalars.data() + flag, &false_, 
sizeof(int));
 
  797   bool get_flag(
int flag)
 const 
  799     typedef Kokkos::Impl::DeepCopy< Kokkos::HostSpace, typename device_type::memory_space > raw_deep_copy;
 
  801     raw_deep_copy(&result, m_scalars.data() + flag, 
sizeof(int));
 
  805   static uint32_t calculate_capacity(uint32_t capacity_hint)
 
  808     return capacity_hint ? ((
static_cast<uint32_t
>(7ull*capacity_hint/6u) + 127u)/128u)*128u : 128u;
 
  812   bool              m_bounded_insert;
 
  813   hasher_type       m_hasher;
 
  814   equal_to_type     m_equal_to;
 
  815   mutable size_type m_size;
 
  816   bitset_type       m_available_indexes;
 
  817   size_type_view    m_hash_lists;
 
  818   size_type_view    m_next_index;
 
  819   key_type_view     m_keys;
 
  820   value_type_view   m_values;
 
  821   scalars_view      m_scalars;
 
  823   template <
typename KKey, 
typename VValue, 
typename DDevice, 
typename HHash, 
typename EEqualTo>
 
  824   friend class UnorderedMap;
 
  826   template <
typename UMap>
 
  827   friend struct Impl::UnorderedMapErase;
 
  829   template <
typename UMap>
 
  830   friend struct Impl::UnorderedMapHistogram;
 
  832   template <
typename UMap>
 
  833   friend struct Impl::UnorderedMapPrint;
 
  837 template <  
typename DKey, 
typename DT, 
typename DDevice
 
  838           , 
typename SKey, 
typename ST, 
typename SDevice
 
  839           , 
typename Hasher, 
typename EqualTo >
 
  840 inline void deep_copy(         UnorderedMap<DKey, DT, DDevice, Hasher, EqualTo> & dst
 
  841                        , 
const UnorderedMap<SKey, ST, SDevice, Hasher, EqualTo> & src )
 
  843   dst.create_copy_view(src);
 
  849 #endif //KOKKOS_UNORDERED_MAP_HPP 
KOKKOS_FORCEINLINE_FUNCTION bool success() const 
Did the map successful insert the key/value pair. 
 
A thread safe view to a bitset. 
 
KOKKOS_FORCEINLINE_FUNCTION size_type capacity() const 
The maximum number of entries that the table can hold. 
 
KOKKOS_FORCEINLINE_FUNCTION uint32_t list_position() const 
 
UnorderedMap(size_type capacity_hint, hasher_type hasher=hasher_type(), equal_to_type equal_to=equal_to_type())
Constructor. 
 
KOKKOS_INLINE_FUNCTION insert_result insert(key_type const &k, impl_value_type const &v=impl_value_type()) const 
 
size_type size() const 
The number of entries in the table. 
 
KOKKOS_FORCEINLINE_FUNCTION uint32_t index() const 
Index where the key can be found as long as the insert did not fail. 
 
void deep_copy(const View< DT, DP...> &dst, typename ViewTraits< DT, DP...>::const_value_type &value, typename std::enable_if< std::is_same< typename ViewTraits< DT, DP...>::specialize, void >::value >::type *=0)
Deep copy a value from Host memory into a view. 
 
void clear()
Clear all entries in the table. 
 
View to an array of data. 
 
KOKKOS_INLINE_FUNCTION size_type hash_capacity() const 
The number of hash table "buckets.". 
 
First element of the return value of UnorderedMap::insert(). 
 
KOKKOS_FORCEINLINE_FUNCTION bool freed_existing() const 
 
bool rehash(size_type requested_capacity=0)
Change the capacity of the the map. 
 
KOKKOS_INLINE_FUNCTION bool exists(const key_type &k) const 
Does the key exist in the map. 
 
bool failed_insert() const 
The current number of failed insert() calls. 
 
KOKKOS_FORCEINLINE_FUNCTION Impl::if_c< (is_set||has_const_value), impl_value_type, impl_value_type & >::type value_at(size_type i) const 
Get the value with i as its direct index. 
 
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 find(const key_type &k) const 
Find the given key k, if it exists in the table. 
 
Thread-safe, performance-portable lookup table. 
 
KOKKOS_FORCEINLINE_FUNCTION bool failed() const 
Did the map fail to insert the key due to insufficent capacity. 
 
KOKKOS_FORCEINLINE_FUNCTION bool existing() const 
Was the key already present in the map. 
 
KOKKOS_FORCEINLINE_FUNCTION pair< T1 &, T2 & > tie(T1 &x, T2 &y)
Return a pair of references to the input arguments.