| #pragma once |
|
|
| #include <cstdint> |
| #include <vector> |
| #include <algorithm> |
|
|
| namespace cubvh { |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| inline uint32_t _hash_city32_step_cpu(uint32_t hash_val, uint32_t key) { |
| hash_val += key * 0x9E3779B9u; |
| hash_val ^= hash_val >> 16; |
| hash_val *= 0x85EBCA6Bu; |
| hash_val ^= hash_val >> 13; |
| hash_val *= 0xC2B2AE35u; |
| hash_val ^= hash_val >> 16; |
| return hash_val; |
| } |
|
|
| struct CityHashCPU { |
| inline static int hash(const int* key, int key_dim, int capacity) { |
| uint32_t h = 0u; |
| for (int i = 0; i < key_dim; ++i) { |
| h = _hash_city32_step_cpu(h, static_cast<uint32_t>(key[i])); |
| } |
| int signed_h = static_cast<int>(h); |
| int slot = signed_h % capacity; |
| if (slot < 0) slot += capacity; |
| return slot; |
| } |
| }; |
|
|
| inline bool _vec_equal_cpu(const int* a, const int* b, int dim) { |
| |
| if (dim == 3) { |
| return a[0] == b[0] && a[1] == b[1] && a[2] == b[2]; |
| } |
| if (dim == 4) { |
| return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]; |
| } |
| for (int i = 0; i < dim; ++i) { |
| if (a[i] != b[i]) return false; |
| } |
| return true; |
| } |
|
|
| inline int _search_hash_table_cpu( |
| const int* table_kvs, |
| const int* coords, |
| const int* query_key, |
| int table_capacity, |
| int num_dims |
| ) { |
| int slot = CityHashCPU::hash(query_key, num_dims, table_capacity); |
| const int begin = slot; |
| int attempts = 0; |
| while (attempts < table_capacity) { |
| const int marker = table_kvs[slot * 2 + 0]; |
| if (marker == -1) { |
| return -1; |
| } |
| const int vec_idx = table_kvs[slot * 2 + 1]; |
| if (vec_idx != -1) { |
| const int* candidate = &coords[vec_idx * num_dims]; |
| if (_vec_equal_cpu(candidate, query_key, num_dims)) { |
| return vec_idx; |
| } |
| } |
| slot = (slot + 1) % table_capacity; |
| if (slot == begin) return -1; |
| ++attempts; |
| } |
| return -1; |
| } |
|
|
| struct HashTableIntCPU { |
| std::vector<int> table_kvs; |
| int capacity = 0; |
| const int* h_coords = nullptr; |
| int num_coords = 0; |
| int num_dims = 3; |
|
|
| inline void set_num_dims(int d) { num_dims = d; } |
| inline int get_num_dims() const { return num_dims; } |
|
|
| void resize(int new_capacity) { |
| capacity = new_capacity; |
| table_kvs.assign(static_cast<size_t>(capacity) * 2, -1); |
| } |
|
|
| void prepare() { |
| if (capacity <= 0) return; |
| std::fill(table_kvs.begin(), table_kvs.end(), -1); |
| } |
|
|
| void insert(const int* h_coords_in, int n_keys) { |
| h_coords = h_coords_in; |
| num_coords = n_keys; |
| if (capacity <= 0 || n_keys <= 0) return; |
|
|
| |
| int* kv = table_kvs.data(); |
| const int D = num_dims; |
| for (int idx = 0; idx < n_keys; ++idx) { |
| const int* key = &h_coords[idx * D]; |
| int slot = CityHashCPU::hash(key, D, capacity); |
| const int begin = slot; |
| int attempts = 0; |
| while (attempts < capacity) { |
| int& marker = kv[slot * 2 + 0]; |
| if (marker == -1) { |
| marker = slot; |
| kv[slot * 2 + 1] = idx; |
| break; |
| } |
| slot = (slot + 1) % capacity; |
| if (slot == begin) break; |
| ++attempts; |
| } |
| } |
| } |
|
|
| void build(const int* h_coords_in, int n_keys) { |
| int desired_capacity = n_keys * 2; |
| if (desired_capacity < 16) desired_capacity = 16; |
| resize(desired_capacity); |
| prepare(); |
| insert(h_coords_in, n_keys); |
| } |
|
|
| void search(const int* h_queries, int n_queries, int* h_out_indices) const { |
| if (capacity <= 0 || n_queries <= 0) return; |
| const int D = num_dims; |
| const int* kv = table_kvs.data(); |
| for (int i = 0; i < n_queries; ++i) { |
| const int* q = &h_queries[i * D]; |
| h_out_indices[i] = _search_hash_table_cpu(kv, h_coords, q, capacity, D); |
| } |
| } |
| }; |
|
|
| } |
|
|
|
|
|
|