高效实现 64 位和 32 位无符号整数之间的双向映射

Efficient implementation of bidirectional map between 64bit and 32bit unsigned integers

本文关键字:之间 映射 无符号整数 实现 位和 高效      更新时间:2023-10-16

想象一下我们有2台机器命名:Alice和Bob。Alice 支持 64 位无符号整数的操作,而 Bob 仅支持 32 位无符号整数的操作。

Bob 向 Alice 发送创建任务的请求。对于每个任务,Alice 分配唯一的 ID,该 ID 是随机的,但是唯一的 64 位无符号整数。Bob 最多可以创建 2^32 个任务。

我需要为 Bob 添加一项功能,以便能够按 ID 删除任务。因此,我需要设置一个代理,当消息从 Alice 发送到 Bob 时,它将用 32 位 uint 替换 64 位单元,并在消息向相反方向发送时从 32 位 uint 恢复 64 位 uint。

问题是我需要使转换非常高效,我只有~10MB的RAM来执行此操作。
是否有任何容器已经解决了这个问题?

更新

社区要求澄清,澄清的唯一方法是描述现实世界的情况。

因此,我正在研究作为AOSP一部分的OpenGL转换器库。总之,出于加速原因,它允许将Android系统的渲染(例如在VM内运行)移动到主机系统。
它是通过将所有OpenGL命令(来回)从目标(Android)流式传输到主机(即Win8 64位)来完成的。

OpenGL 对象表示为类型为GLuintunsigned int的句柄。因此,对象的大小和允许的值取决于系统是 32 位还是 64 位。

由于大多数Android系统是32位的,而大多数主机系统是64位的,因此出现了问题:在从Android创建OpenGL对象的请求中,主机可以创建具有不能表示为32位值的值的句柄。但是,出于显而易见的原因,Android不能请求超过2^32 - 1的对象。

我想到的唯一解决方案是设置将 64 位句柄映射到 32 位的代理,反之亦然。

产生问题的具体代码段:https://android.googlesource.com/platform/sdk/+/master/emulator/opengl/host/libs/Translator/include/GLcommon/GLutils.h 第 47 行。

更新 2

在进一步探索这个问题之后,我发现这不是 GLuint 的问题(如 @KillianDS 所述)。然而,它仍然是OpenGL的问题。

有些函数返回指针,而不是 GLuint 句柄。 例如 eglCreateContext。 我需要找到一种方法在 64 位主机和 32 位目标之间交换指针。

更新 3

最后,我发现这种具体的崩溃与 32 位和 64 位机器之间的句柄转换无关。这是转换器的目标部分中的一个错误,它用错误的参数调用了错误的函数(glVertexAttribPointerData)。

根据最新核心OpenGL规范中的table 2.2,OpenGL中的uint应该始终是32位的宽度(ES的规范大致相同)。据我所知,所有 OpenGL 名称/句柄都是uint的(您在问题中也说)。因此,主机和目标上的它都应该是 32 位。

请注意,正是因为unsigned int的实际位宽可能因平台而异,OpenGL有自己的类型,应符合规范。

更新

如果其余句柄实际上只是上下文和其他窗口系统调用,我会保持简单,因为我们不是在谈论频繁的操作,也不是大量的句柄。每个 GPU 的每个 OpenGL 应用程序通常不会执行此类操作超过一次,在任何移动电话上都可能是 1 次。我认为最简单的解决方案是使用数组。伪代码

class context_creator
{
std::array<EGLContext, 1000> context_map; //8KB
public:
context_creator() : context_map{} {}
uint32_t allocate(...) {
for(unsigned i = 0; i < context_map.size(); i++) {
if(!context_map[i]) {
context_map[i] = eglCreateContext(...);
return i;
}
}
}
void deallocate(uint32_t handle) {
eglDeleteContext(context_map[handle]);
context_map[handle] = 0;
}
//Has to be called in every function where a context is a parameter.
EGLContext translate(uint32_t handle) const {
return context_map[handle];
}
}

请注意,如果0是上下文的有效名称,这将不起作用。我真的不知道WGL,但可能不是。这样做的好处是,虽然分配不是有史以来最快的算法,但翻译是O(1)的,这是最有可能最常调用的算法。

当然,存在差异:

  • 您可以使用更动态的容器(例如vector) 而不是固定大小。
  • 您可以使用哈希表(如std::map),并且每次调用只需生成一个唯一的索引。这会消耗更多内存,因为您还必须存储索引(它在数组中是imlicit),但如果0是有效的上下文名称,则可以解决问题。

OpenGL 中的 uint 应该是 4 个字节,即宽度始终为 32 位,因此目标和主机上的句柄/名称都应该是 32 位