query/concurrent_unordered_map.hpp (122 lines of code) (raw):

// Copyright (c) 2017-2018 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef QUERY_CONCURRENT_UNORDERED_MAP_HPP_ #define QUERY_CONCURRENT_UNORDERED_MAP_HPP_ #if defined(SUPPORT_HASH_REDUCTION) && defined(RUN_ON_DEVICE) #include <hash/concurrent_unordered_map.cuh> #include <hash/hash_functions.cuh> #endif #include <thrust/pair.h> #if defined(SUPPORT_HASH_REDUCTION) && defined(RUN_ON_DEVICE) #include <groupby/aggregation_operations.hpp> #endif #include <limits> #include <unordered_map> namespace ares { #ifndef RUN_ON_DEVICE // we duplicate following operators from cudf for host mode only. This is // because including any cudf files requires c++14 however for host mode. // We can remove those operators once all of our dependent c++ compilers // support c++14. template<typename value_type> struct max_op { constexpr static value_type IDENTITY{ std::numeric_limits<value_type>::lowest()}; __host__ __device__ value_type operator()(value_type new_value, value_type old_value) { return (new_value > old_value ? new_value : old_value); } }; template<typename value_type> struct min_op { constexpr static value_type IDENTITY{std::numeric_limits<value_type>::max()}; __host__ __device__ value_type operator()(value_type new_value, value_type old_value) { return (new_value < old_value ? new_value : old_value); } }; template<typename value_type> struct count_op { constexpr static value_type IDENTITY{0}; __host__ __device__ value_type operator()(value_type, value_type old_value) { old_value += value_type{1}; return old_value; } }; template<typename value_type> struct sum_op { constexpr static value_type IDENTITY{0}; __host__ __device__ value_type operator()(value_type new_value, value_type old_value) { return new_value + old_value; } }; #endif // host_concurrent_unordered_map is a wrapper for std::unordered_map to provide // the same interface as cudf's concurrent_unordered_map. This map is not thread // safe. template<typename Key, typename Element, typename Hasher, typename Equality> class host_concurrent_unordered_map { public: using size_type = size_t; using hasher = Hasher; using key_equal = Equality; using key_type = Key; using mapped_type = Element; using value_type = thrust::pair<Key, Element>; using map_t = std::unordered_map<key_type, mapped_type, hasher, key_equal>; using const_iterator = typename map_t::const_iterator; using iterator = typename map_t::iterator; explicit host_concurrent_unordered_map( size_type _capacity, const mapped_type _identity, const key_type _unused_key, const Hasher &hf = hasher(), const Equality &eql = key_equal()) : m_map(_capacity, hf, eql), m_identity(_identity), m_unused_key(_unused_key) {} private: map_t m_map; key_type m_unused_key; mapped_type m_identity; public: __host__ key_type get_unused_key() const { return m_unused_key; } __host__ const_iterator begin() const noexcept { return m_map.begin(); } __host__ size_type capacity() { return m_map.size(); } template<typename aggregation_type, class comparison_type = key_equal, typename hash_value_type = typename Hasher::result_type> __host__ void insert(const value_type &x, aggregation_type op, comparison_type keys_equal){ key_type key = x.first; mapped_type value = x.second; m_map[key] = op(m_map[key], value); } }; #if defined(RUN_ON_DEVICE) && defined(SUPPORT_HASH_REDUCTION) template<typename Key, typename Element, typename Hasher, typename Equality> using hash_map = concurrent_unordered_map<Key, Element, Hasher, Equality>; template <typename hash_map_type> __host_or_device__ typename hash_map_type::value_type* map_value_at(hash_map_type* map, size_t i) { return map->data() + i; } #else template<typename Key, typename Element, typename Hasher, typename Equality> using hash_map = host_concurrent_unordered_map<Key, Element, Hasher, Equality>; template <typename hash_map_type> __host_or_device__ typename hash_map_type::const_iterator map_value_at(hash_map_type* map, size_t i) { return std::next(map->begin(), i); } #endif } // namespace ares #endif // QUERY_CONCURRENT_UNORDERED_MAP_HPP_