* Copyright (c) Huawei Technologies Co., Ltd. 2026.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#pragma once
#include <memory>
#include <acl/acl.h>
#include "detail/open_addressing/open_addressing_impl.h"
#include "extent.h"
#include "hash_functions.h"
namespace aclco {
static constexpr size_t defaultSetBucketSize = 5;
template <class Key,
class Extent = Extent<size_t>,
class KeyEqual = aclco::EqualTo<Key>,
class ProbingScheme = aclco::DoubleHashing<aclco::xxhash_32<Key>>,
class Storage = Storage<defaultSetBucketSize>>
class StaticSet {
static_assert(sizeof(Key) <= 8, "Container dose not support key type size bigger than 8 bytes.");
using ImplType = OpenAddressingImpl<Key,
Key,
Extent,
KeyEqual,
ProbingScheme,
Storage>;
public:
static constexpr auto bucketSize = ImplType::bucketSize;
using SizeType = typename ImplType::SizeType;
using KeyType = typename ImplType::KeyType;
using ValueType = typename ImplType::ValueType;
StaticSet(StaticSet const&) = delete;
StaticSet& operator=(StaticSet const&) = delete;
StaticSet(StaticSet&&) = default;
StaticSet& operator=(StaticSet &&) = default;
~StaticSet() = default;
* @brief 构造函数:创建指定容量的 static_set 容器
*
* @param capacity set的容量
* @param emptyKey 表示空键的标记值
* @param pred 键比较器,默认为 KeyEqual()
* @param probingScheme 探测策略,默认为 ProbingScheme()
* @param storage 存储策略,默认为 Storage<BucketSize>()
* @param stream ACL流,默认为 nullptr
*
* @note 实际容量会向上取整到BucketSize的倍数
*
* @warning Key类型大小不能超过8字节
*/
constexpr StaticSet(Extent capacity,
Key emptyKey,
KeyEqual const& pred = {},
ProbingScheme const& probingScheme = {},
Storage storage = {},
aclrtStream stream = nullptr);
* @brief 同步插入键到set中
*
* @param keys Device侧指向键数组的指针
* @param keyNum 要插入的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @return 插入失败的键数量
*
* @note 这是一个同步操作,会阻塞直到插入完成
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
*
* @see InsertAsync 用于异步插入操作
*/
SizeType Insert(void *keys, Extent keyNum, aclrtStream stream);
* @brief 异步插入键到set中
*
* @param keys Device侧指向键数组的指针
* @param keyNum 要插入的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
*
* @warning 必须确保在调用此函数后,流被正确同步,否则可能导致数据竞争
*
* @see Insert 用于同步插入操作
*/
void InsertAsync(void *keys, Extent keyNum, aclrtStream stream);
* @brief 同步条件插入键到set中
*
* @tparam StencilT stencil数组的元素类型。stencil数组与keys数组一一对应,每个元素作为对应键的谓词判断输入,由仿函数根据stencil[i]的值决定是否插入keys[i]
* @tparam Predicate 仿函数类型,需提供 operator()(StencilT) const 重载,返回 bool;返回 true 表示执行插入,返回 false 表示跳过。仿函数需使用 COLLECTION_HOST_DEVICE 宏修饰,以确保在Host和Device侧均可调用
*
* @param keys Device侧指向键数组的指针
* @param stencil Device侧指向stencil数组的指针,与keys一一对应,用于谓词判断
* @param keyNum 要插入的键数量,必须与keys和stencil指向的数组实际大小一致
* @param stream ACL流
*
* @return 插入失败的键数量(仅统计pred(stencil[i])为true且插入失败的元素)
*
* @note 这是一个同步操作,会阻塞直到插入完成
* @note 只有pred(stencil[i])为true时,才会尝试插入keys[i]
*
* @warning keyNum 参数必须与 keys 和 stencil 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
* @warning stencil中的元素类型必须与StencilT一致
*
* @see InsertIfAsync 用于异步条件插入操作
*/
template <typename StencilT, typename Predicate>
SizeType InsertIf(void *keys, StencilT *stencil, Extent keyNum, aclrtStream stream);
* @brief 异步条件插入键到set中
*
* @tparam StencilT stencil数组的元素类型。stencil数组与keys数组一一对应,每个元素作为对应键的谓词判断输入,由仿函数根据stencil[i]的值决定是否插入keys[i]
* @tparam Predicate 仿函数类型,需提供 operator()(StencilT) const 重载,返回 bool;返回 true 表示执行插入,返回 false 表示跳过。仿函数需使用 COLLECTION_HOST_DEVICE 宏修饰,以确保在Host和Device侧均可调用
*
* @param keys Device侧指向键数组的指针
* @param stencil Device侧指向stencil数组的指针,与keys一一对应,用于谓词判断
* @param keyNum 要插入的键数量,必须与keys和stencil指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
* @note 只有pred(stencil[i])为true时,才会尝试插入keys[i]
*
* @warning 必须确保在调用此函数后,流被正确同步,否则可能导致数据竞争
*
* @see InsertIf 用于同步条件插入操作
*/
template <typename StencilT, typename Predicate>
void InsertIfAsync(void *keys, StencilT *stencil, Extent keyNum, aclrtStream stream);
* @brief 同步插入并查找键
*
* @param keys Device侧指向键数组的指针
* @param outputFind Device侧指向输出查找结果数组的指针,元素类型为Key。若键已存在则返回已存在的键,若键不存在则返回新插入的键,若键为空键或容量已满则返回空键(emptyKey)
* @param outputInsert Device侧指向输出插入标志数组的指针,元素类型为unsigned char。非0表示新插入成功,0表示键已存在或插入失败
* @param keyNum 要插入并查找的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个同步操作,会阻塞直到插入并查找完成
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
*
* @see InsertAndFindAsync 用于异步插入并查找操作
*/
void InsertAndFind(void* keys, void* outputFind, void* outputInsert, Extent keyNum, aclrtStream stream);
* @brief 异步插入并查找键
*
* @param keys Device侧指向键数组的指针
* @param outputFind Device侧指向输出查找结果数组的指针,元素类型为Key。若键已存在则返回已存在的键,若键不存在则返回新插入的键,若键为空键或容量已满则返回空键(emptyKey)
* @param outputInsert Device侧指向输出插入标志数组的指针,元素类型为unsigned char。非0表示新插入成功,0表示键已存在或插入失败
* @param keyNum 要插入并查找的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
*
* @warning 必须确保在调用此函数后,流被正确同步,否则可能导致数据竞争
*
* @see InsertAndFind 用于同步插入并查找操作
*/
void InsertAndFindAsync(void* keys, void* outputFind, void* outputInsert, Extent keyNum, aclrtStream stream);
* @brief 同步删除指定键
*
* @param keys Device侧指向键数组的指针
* @param keyNum 要删除的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @return 删除失败的键数量(即不存在的键的数量)
*
* @note 这是一个同步操作,会阻塞直到删除完成
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
*
* @see EraseAsync 用于异步删除操作
*/
SizeType Erase(void *keys, Extent keyNum, aclrtStream stream);
* @brief 异步删除指定键
*
* @param keys Device侧指向键数组的指针
* @param keyNum 要删除的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
*
* @warning 必须确保在调用此函数后,流被正确同步,否则可能导致数据竞争
*
* @see Erase 用于同步删除操作
*/
void EraseAsync(void *keys, Extent keyNum, aclrtStream stream);
* @brief 同步清空 static_set 中所有的元素
*
* @param stream ACL流
*
* @note 这是一个同步操作,会阻塞直到清空完成
*
* @see ClearAsync 用于异步清空操作
*/
void Clear(aclrtStream stream);
* @brief 异步清空 static_set 中所有的元素
*
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
*
* @warning 必须确保在调用此函数后,流被正确同步,否则可能导致数据竞争
*
* @see Clear 用于同步清空操作
*/
void ClearAsync(aclrtStream stream) noexcept;
* @brief 同步查找键
*
* @param keys Device侧指向键数组的指针
* @param outputValues Device侧指向输出值数组的指针
* @param keyNum 要查找的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个同步操作,会阻塞直到查找完成
* @note 如果键不存在,返回空键(emptyKey)
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
*
* @see FindAsync 用于异步查找操作
*/
void Find(void *keys, void *outputValues, Extent keyNum, aclrtStream stream);
* @brief 异步查找键
*
* @param keys Device侧指向键数组的指针
* @param outputValues Device侧指向输出值数组的指针
* @param keyNum 要查找的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
* @note 如果键不存在,返回空键(emptyKey)
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
*
* @see Find 用于同步查找操作
*/
void FindAsync(void *keys, void *outputValues, Extent keyNum, aclrtStream stream);
* @brief 同步条件查找键
*
* @tparam StencilT stencil数组的元素类型。stencil数组与keys数组一一对应,每个元素作为对应键的谓词判断输入,由仿函数根据stencil[i]的值决定是否查找keys[i]
* @tparam Predicate 仿函数类型,需提供 operator()(StencilT) const 重载,返回 bool;返回 true 表示执行查找,返回 false 表示跳过。仿函数需使用 COLLECTION_HOST_DEVICE 宏修饰,以确保在Host和Device侧均可调用
*
* @param keys Device侧指向键数组的指针
* @param stencil Device侧指向stencil数组的指针,与keys一一对应,用于谓词判断
* @param outputValues Device侧指向输出值数组的指针
* @param keyNum 要查找的键数量,必须与keys和stencil指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个同步操作,会阻塞直到查找完成
* @note 只有pred(stencil[i])为true时,才会查找keys[i];否则outputValues[i]写入空键(emptyKey)
* @note 如果键不存在,返回空键(emptyKey)
*
* @warning keyNum 参数必须与 keys 和 stencil 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
* @warning stencil中的元素类型必须与StencilT一致
*
* @see FindIfAsync 用于异步条件查找操作
*/
template <typename StencilT, typename Predicate>
void FindIf(void *keys, StencilT *stencil, void *outputValues, Extent keyNum, aclrtStream stream);
* @brief 异步条件查找键
*
* @tparam StencilT stencil数组的元素类型。stencil数组与keys数组一一对应,每个元素作为对应键的谓词判断输入,由仿函数根据stencil[i]的值决定是否查找keys[i]
* @tparam Predicate 仿函数类型,需提供 operator()(StencilT) const 重载,返回 bool;返回 true 表示执行查找,返回 false 表示跳过。仿函数需使用 COLLECTION_HOST_DEVICE 宏修饰,以确保在Host和Device侧均可调用
*
* @param keys Device侧指向键数组的指针
* @param stencil Device侧指向stencil数组的指针,与keys一一对应,用于谓词判断
* @param outputValues Device侧指向输出值数组的指针
* @param keyNum 要查找的键数量,必须与keys和stencil指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
* @note 只有pred(stencil[i])为true时,才会查找keys[i];否则outputValues[i]写入空键(emptyKey)
* @note 如果键不存在,返回空键(emptyKey)
*
* @warning 必须确保在调用此函数后,流被正确同步,否则可能导致数据竞争
* @warning stencil中的元素类型必须与StencilT一致
*
* @see FindIf 用于同步条件查找操作
*/
template <typename StencilT, typename Predicate>
void FindIfAsync(void *keys, StencilT *stencil, void *outputValues, Extent keyNum, aclrtStream stream);
* @brief 同步检查指定键是否存在
*
* @param keys Device侧指向键数组的指针
* @param outputValues Device侧指向输出值数组的指针
* @param keyNum 要查找的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个同步操作,会阻塞直到检查完成
* @note 无返回值,检查结果通过 outputValues 输出(bool类型)
* @note 输出值为 true 表示键存在,false 表示键不存在
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
*
* @see ContainsAsync 用于异步检查操作
*/
void Contains(void *keys, void *outputValues, Extent keyNum, aclrtStream stream);
* @brief 异步检查指定键是否存在
*
* @param keys Device侧指向键数组的指针
* @param outputValues Device侧指向输出值数组的指针
* @param keyNum 要查找的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
* @note 无返回值,检查结果通过 outputValues 输出(bool类型)
* @note 输出值为 true 表示键存在,false 表示键不存在
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
*
* @see Contains 用于同步检查操作
*/
void ContainsAsync(void *keys, void *outputValues, Extent keyNum, aclrtStream stream);
* @brief 同步条件检查指定键是否存在
*
* @tparam StencilT stencil数组的元素类型。stencil数组与keys数组一一对应,每个元素作为对应键的谓词判断输入,由仿函数根据stencil[i]的值决定是否检查keys[i]
* @tparam Predicate 仿函数类型,需提供 operator()(StencilT) const 重载,返回 bool;返回 true 表示执行检查,返回 false 表示跳过。仿函数需使用 COLLECTION_HOST_DEVICE 宏修饰,以确保在Host和Device侧均可调用
*
* @param keys Device侧指向键数组的指针
* @param stencil Device侧指向stencil数组的指针,与keys一一对应,用于谓词判断
* @param outputValues Device侧指向输出值数组的指针
* @param keyNum 要查找的键数量,必须与keys和stencil指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个同步操作,会阻塞直到检查完成
* @note 只有pred(stencil[i])为true时,才会检查keys[i];否则outputValues[i]写入false
* @note 输出值为 true 表示键存在,false 表示键不存在或谓词为false
*
* @warning keyNum 参数必须与 keys 和 stencil 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
* @warning stencil中的元素类型必须与StencilT一致
*
* @see ContainsIfAsync 用于异步条件检查操作
*/
template <typename StencilT, typename Predicate>
void ContainsIf(void *keys, StencilT *stencil, void *outputValues, Extent keyNum, aclrtStream stream);
* @brief 异步条件检查指定键是否存在
*
* @tparam StencilT stencil数组的元素类型。stencil数组与keys数组一一对应,每个元素作为对应键的谓词判断输入,由仿函数根据stencil[i]的值决定是否检查keys[i]
* @tparam Predicate 仿函数类型,需提供 operator()(StencilT) const 重载,返回 bool;返回 true 表示执行检查,返回 false 表示跳过。仿函数需使用 COLLECTION_HOST_DEVICE 宏修饰,以确保在Host和Device侧均可调用
*
* @param keys Device侧指向键数组的指针
* @param stencil Device侧指向stencil数组的指针,与keys一一对应,用于谓词判断
* @param outputValues Device侧指向输出值数组的指针
* @param keyNum 要查找的键数量,必须与keys和stencil指向的数组实际大小一致
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
* @note 只有pred(stencil[i])为true时,才会检查keys[i];否则outputValues[i]写入false
* @note 输出值为 true 表示键存在,false 表示键不存在或谓词为false
*
* @warning 必须确保在调用此函数后,流被正确同步,否则可能导致数据竞争
* @warning stencil中的元素类型必须与StencilT一致
*
* @see ContainsIf 用于同步条件检查操作
*/
template <typename StencilT, typename Predicate>
void ContainsIfAsync(void *keys, StencilT *stencil, void *outputValues, Extent keyNum, aclrtStream stream);
* @brief 同步遍历哈希表中与指定键匹配的槽位,对每个匹配的槽位执行回调函数
*
* @tparam CallbackOp 仿函数类型,要求如下:
* - 提供 COLLECTION_SIMT_DEVICE void operator()(Key) const 重载,接收匹配的槽位作为参数
* - 提供 COLLECTION_SIMT_DEVICE 构造函数接受 __gm__ uint8_t* 参数,用于接收 callbackArgs 指针并在内部 reinterpret_cast 为实际类型
* - operator() 中可使用 AscendC::Simt::AtomicAdd 等设备端原子操作访问 callbackArgs 指向的设备内存
*
* @param keys Device侧指向键数组的指针
* @param keyNum 要遍历的键数量,必须与keys指向的数组实际大小一致
* @param callbackArgs Device侧指向用户自定义数据的指针,以 void* 类型擦除传入kernel,由 CallbackOp 构造函数 reinterpret_cast 为实际类型使用
* @param stream ACL流
*
* @note 这是一个同步操作,会阻塞直到遍历完成
* @note 对于每个key,如果在哈希表中找到匹配的槽位,则调用回调函数;遇到空槽位则停止探测
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 传入的指针中数据类型需要和set中的相对应
* @warning 回调函数中不应修改哈希表的状态,否则可能导致未定义行为
*
* @see ForEachAsync 用于异步遍历操作
*/
template <typename CallbackOp>
void ForEach(void *keys, Extent keyNum, void *callbackArgs, aclrtStream stream);
* @brief 异步遍历哈希表中与指定键匹配的槽位,对每个匹配的槽位执行回调函数
*
* @tparam CallbackOp 仿函数类型,要求如下:
* - 提供 COLLECTION_SIMT_DEVICE void operator()(Key) const 重载,接收匹配的槽位作为参数
* - 提供 COLLECTION_HOST_DEVICE 构造函数接受 __gm__ uint8_t* 参数,用于接收 callbackArgs 指针并在内部 reinterpret_cast 为实际类型
* - operator() 中可使用 AscendC::Simt::AtomicAdd 等设备端原子操作访问 callbackArgs 指向的设备内存
*
* @param keys Device侧指向键数组的指针
* @param keyNum 要遍历的键数量,必须与keys指向的数组实际大小一致
* @param callbackArgs Device侧指向用户自定义数据的指针,以 void* 类型擦除传入kernel,由 CallbackOp 构造函数 reinterpret_cast 为实际类型使用
* @param stream ACL流
*
* @note 这是一个异步操作,不会阻塞调用线程
* @note 对于每个key,如果在哈希表中找到匹配的槽位,则调用回调函数;遇到空槽位则停止探测
*
* @warning 必须确保在调用此函数后,流被正确同步,否则可能导致数据竞争
* @warning 回调函数中不应修改哈希表的状态,否则可能导致未定义行为
*
* @see ForEach 用于同步遍历操作
*/
template <typename CallbackOp>
void ForEachAsync(void *keys, Extent keyNum, void *callbackArgs, aclrtStream stream);
* @brief 同步统计指定键在set中存在的数量
*
* @param keys Device侧指向键数组的指针
* @param keyNum 要查找的键数量,必须与keys指向的数组实际大小一致
* @param stream ACL流
*
* @return 存在的键数量
*
* @note 这是一个同步操作,会阻塞直到统计完成
*
* @warning keyNum 参数必须与 keys 指向的数组实际大小一致,否则可能导致越界访问或数据不完整
* @warning 建议使用 keys.size() 作为 keyNum 参数,确保一致性
* @warning 传入的指针中数据类型需要和set中的相对应
*/
SizeType Count(void *keys, Extent keyNum, aclrtStream stream);
* @brief 获取set的实际容量
*
* @return 实际容量
*
* @note 实际容量会向上取整到BucketSize的倍数
*/
constexpr auto Capacity() const noexcept;
* @brief 获取Device侧set内部数据的指针
*
* @return 指向Device侧set内部数据的指针
*
* @note 该方法返回Device侧set内部存储的原始指针
*
* @warning 返回Device侧的内存指针,不能在host侧直接访问
*/
ValueType* Data() const;
private:
std::unique_ptr<ImplType> impl_;
Key emptyKey_;
};
}
#include "detail/static_set/static_set.inl"