高效处理大量位掩码标志

问题描述 投票:0回答:1

我的函数采用文件系统路径和位掩码,描述要对 FS 对象执行的所需检查。

它存在吗? 是:文件、文件夹、符号链接?空的,隐藏的?可读(R),可写? 符号链接:到文件,到文件夹?

这 11 个标志提供了大量的组合,所以我提供方便的标志,如

SymLinkToAReadableFile
等。这不仅方便,还避免了一些潜在的混淆:
SymLinkToFile | R
可能意味着可读的符号链接(不是很有用),名称“
SymLinkToAReadableFile
”毫无疑问。

为了减少所需的处理,我会定义

RWHiddenFolder = Folder | R | W | Hidden
,所有与
Folder
相关的东西都是一样的:
Folder | ..
,同样适用于
File
SymLink

这使得检查用户没有混合

File
Folder
(这没有意义)很容易:
(flag & Folder) && (flag & File)
->错误。

但这使得

RWHiddenFolder | RWEmptyFile
RWHiddenFile | RWEmptyFolder
File | Folder | R | W | Empty | Hidden
相同:

  • 无法判断用户实际传递了什么!
  • 因此无法建立准确的错误信息
  • 如果我让我的功能容忍并在
    SymLink
    存在的情况下忽略
    Folder
    ,则无法判断用户是否想要
    Empty
    Hidden
    (或两者)
    Folder

对每个可能的组合产生一点影响的天真的“解决方案”显然解决了所有这些问题,但是已经建立了一个密集的

if/else
分支森林,只是为了确保提供的标志组合有意义,更不用说在之后进行实际检查了那..

在复杂的处理和方便/清晰的界面(对于用户)之间是否存在良好的权衡?

c++ c computer-science
1个回答
0
投票

我想出了一个合理的解决方案(我不得不!)。 在这里分享给任何有同样问题的人。


对于那些喜欢行动而不是讲课的人(比如我):sample(忽略众多常量定义)


显然

enum
无法做到这一点,简单的位域/集合也无法做到这一点:与
OR
组合失去了标志的身份(
ReadableFile == Readable | File
)。

但是二元运算使得操作非常有效(阅读“紧凑”)(检查,提取标志,..)

所以想法是携带

mask
并分开
id

constexpr static auto nFlags = 96u; // total amount of flags

struct argFlag {
  string n; // reflection
  bitset<nFlags> id; 
  bitset<16> mask; // plain bitmask 
  
  // id == position of true bit
  argFlag(const string& s, const int i, const uint32_t m = 0 ) 
  : n(s), mask(m)   { id.set(i); } 

  // Cumulate id & mask bits, preserve reflection
  argFlag operator| (const argFlag& b)
  { argFlag r{ (n.empty()? ""s : n+" | ") + b.n, 0 }; 
    r.id = id | b.id; r.mask = mask | b.mask; return /* move */r; }
  
  // operator<< (has atom Id ? Meaning flag = .. | Atom | .. )
  bool operator<< (const argFlag& b)
  { .. }

}

现在您可以制作提供给用户的基本标志列表,这些是“原子”标志:每个标志在

true
中都有1个
id
位。

现在当用户通过标志

Symlink2Folder | HiddenFile

  • 你可以使用
    id
  • 将它分解成它的构建原子(这里是2个)
  • 您不能将其与
    Symlink2HiddenFolder | File
    混淆(相同的
    mask
    ,但不同的
    id
    位):可以实现准确的错误消息。
  • mask
    成员设置了所有正确的位 (
    Symlink | Folder | Hidden | File
    )。用于廉价的逻辑检查。

到达你需要的任何成员来实现对标志的操作(检查 id,检查逻辑组成)。

使用几个 lambda 和宏,

validateFlags()
example)可以用不到 100 行代码非常可读地编写来处理无数难以理解的组合(4 个原子构成 96x95x94x93 ~ 8000 万种组合)。

您可以尝试使用您能想出的任何不太可能的组合在

validateFlags()
中通过
main()
!祝你好运
;-)

© www.soinside.com 2019 - 2024. All rights reserved.