将 hashing/encoding 多个值转换为单个整数值的算法
Algorithm for hashing/encoding multiple values into a single integer value
有一种算法可以将多个值“散列”或编码为一个整数,方法是将指数增长的数值分配给各个值。这种方法特别用于 Windows DLL。
一个可能的用例是客户端应用程序从 API.
请求匹配特定状态代码的项目列表
例如,如果我们有以下值:
* open
* assigned
* completed
* closed
...我们为每个分配一个数值:
* open - 1
* assigned - 2
* completed - 4
* closed - 8
等其中每个后续值都是前一个值的 2 倍。
编码
当我们需要传递任何这些值的组合时,我们将相应的数值相加。例如,对于“打开、分配”,它是 3
,对于“分配、完成、关闭”,它是 14
。这涵盖了所有独特的组合。正如我们所见,“编码”部分非常简单。
解码
要解码值,我能想到的唯一方法是 switch..case 语句,就像这样(伪代码):
1 = open
2 = assigned
3 = open + assigned
4 = completed
5 = open + completed
6 = assigned + completed
7 = open + assigned + completed
8 = closed
9 = open + closed
10 = assigned + closed
11 = open + assigned + closed
12 = completed + closed
13 = open + completed + closed
14 = assigned + completed + closed
15 = open + assigned + completed + closed
该算法显然在以下假设下有效:
- 仅当每个值仅使用一次时有效
- 只有双方都知道匹配的数值才有效
问题:
- 什么是更优化的way/algorithm来“解码”值而不是非常复杂的 switch..case 语句?
- 这个算法有名字吗?
注意:问题被标记为 winapi
主要是为了便于发现。算法比较通用
您所描述的正式名称为 bit mask,其中整数中的每一位都指定了一个含义。位被分配为二进制 2 的幂的数值(bit0=20=1,bit1=21=2,bit2=2 2=4, bit3=23=8, 等等).
您可以使用 OR
和 AND
logical bitwise operators 到 set/query 整数中的各个位,例如:
const DWORD State_Open = 1;
const DWORD State_Assigned = 2;
const DWORD State_Completed = 4;
const DWORD State_Closed = 8;
void DoSomething(DWORD aStates)
{
...
if (aStates & State_Open)
// open is present
else
// open is not present
if (aStates & State_Assigned)
// assigned is present
else
// assigned is not present
if (aStates & State_Completed)
// completed is present
else
// completed is not present
if (aStates & State_Closed)
// closed is present
else
// closed is not present
...
}
DWORD lState = State_Open | State_Assigned | State_Completed | State_Closed;
// whatever combination you need ...
DoSomething(lState);
在 Delphi/Pascal 中,最好使用 Set
来处理,它在内部实现为位掩码,例如:
type
State = (State_Open, State_Assigned, State_Completed, State_Closed);
States = Set of State;
procedure DoSomething(aStates: States);
begin
...
if State_Open in aStates then
// open is present
else
// open is not present
if State_Assigned in aStates then
// assigned is present
else
// assigned is not present
if State_Completed in aStates then
// completed is present
else
// completed is not present
if State_Closed in aStates then
// closed is present
else
// closed is not present
...
end;
var
lState: States;
begin
...
lState := [State_Open, State_Assigned, State_Completed, State_Closed];
// whatever combination you need ...
DoSomething(lState);
...
end;
有一种算法可以将多个值“散列”或编码为一个整数,方法是将指数增长的数值分配给各个值。这种方法特别用于 Windows DLL。
一个可能的用例是客户端应用程序从 API.
请求匹配特定状态代码的项目列表例如,如果我们有以下值:
* open
* assigned
* completed
* closed
...我们为每个分配一个数值:
* open - 1
* assigned - 2
* completed - 4
* closed - 8
等其中每个后续值都是前一个值的 2 倍。
编码
当我们需要传递任何这些值的组合时,我们将相应的数值相加。例如,对于“打开、分配”,它是 3
,对于“分配、完成、关闭”,它是 14
。这涵盖了所有独特的组合。正如我们所见,“编码”部分非常简单。
解码
要解码值,我能想到的唯一方法是 switch..case 语句,就像这样(伪代码):
1 = open
2 = assigned
3 = open + assigned
4 = completed
5 = open + completed
6 = assigned + completed
7 = open + assigned + completed
8 = closed
9 = open + closed
10 = assigned + closed
11 = open + assigned + closed
12 = completed + closed
13 = open + completed + closed
14 = assigned + completed + closed
15 = open + assigned + completed + closed
该算法显然在以下假设下有效:
- 仅当每个值仅使用一次时有效
- 只有双方都知道匹配的数值才有效
问题:
- 什么是更优化的way/algorithm来“解码”值而不是非常复杂的 switch..case 语句?
- 这个算法有名字吗?
注意:问题被标记为 winapi
主要是为了便于发现。算法比较通用
您所描述的正式名称为 bit mask,其中整数中的每一位都指定了一个含义。位被分配为二进制 2 的幂的数值(bit0=20=1,bit1=21=2,bit2=2 2=4, bit3=23=8, 等等).
您可以使用 OR
和 AND
logical bitwise operators 到 set/query 整数中的各个位,例如:
const DWORD State_Open = 1;
const DWORD State_Assigned = 2;
const DWORD State_Completed = 4;
const DWORD State_Closed = 8;
void DoSomething(DWORD aStates)
{
...
if (aStates & State_Open)
// open is present
else
// open is not present
if (aStates & State_Assigned)
// assigned is present
else
// assigned is not present
if (aStates & State_Completed)
// completed is present
else
// completed is not present
if (aStates & State_Closed)
// closed is present
else
// closed is not present
...
}
DWORD lState = State_Open | State_Assigned | State_Completed | State_Closed;
// whatever combination you need ...
DoSomething(lState);
在 Delphi/Pascal 中,最好使用 Set
来处理,它在内部实现为位掩码,例如:
type
State = (State_Open, State_Assigned, State_Completed, State_Closed);
States = Set of State;
procedure DoSomething(aStates: States);
begin
...
if State_Open in aStates then
// open is present
else
// open is not present
if State_Assigned in aStates then
// assigned is present
else
// assigned is not present
if State_Completed in aStates then
// completed is present
else
// completed is not present
if State_Closed in aStates then
// closed is present
else
// closed is not present
...
end;
var
lState: States;
begin
...
lState := [State_Open, State_Assigned, State_Completed, State_Closed];
// whatever combination you need ...
DoSomething(lState);
...
end;