CABMBitSet 和 CFlexBitSet - 紧凑存储, 易于使用





3.00/5 (2投票s)
创建用于存储 BOOL、枚举或其他有限值集合的紧凑型存储。
引言
在嵌入式和 GUI 世界中,我经常需要存储大量的 BOOL
标志或具有有限范围(例如 0 到 7)的 enum
s,但我不想为此占用一个 INT
来存储到磁盘。过去,我遵循了同事们的方法,创建整数和掩码来提取正确的位来存储或检索值。最近,一位同事提出了一个很好的想法,将此抽象化为数组。我决定从头开始尝试这个想法,并创建了 CABMBitSet
模板类。
想法是通过数组“[]
”运算符来访问位以设置和检索值,使其接受 BOOL
进行设置,并在检索时返回 BOOL
。然后我想更进一步。
为什么只限制接口为 BOOL
?我经常存储 enum
值,其中 enum
的范围相当小,肯定不是 32,000(左右)。所以我创建了 CFlexBitSet
模板类。这个类不仅允许您定义数组中有多少个元素,还允许您定义每个元素需要多少位,以及它应该如何(类类型(BOOL
、int
等))呈现给外部代码。
两者都允许您
- 使用“
[]
”运算符设置/获取值。 - 以字符串格式获取位值(主要用于调试)。
- 从您自己的
UINT32
值数组(将保存到磁盘)中获取/设置位数组。
背景
大多数人会觉得这段代码是过度设计……没关系。我写它是为了好玩,也是为了让我的生活更轻松。如果您觉得有用,那只是一个奖励。
另外,您会看到代码中使用了 CCDoc 风格的注释。如果您没有该工具(只是一个 EXE)并想重新生成文档,只需快速搜索 CCDoc 即可在 SF 上找到。如果您想查看 HTML 文档,演示项目下载中包含了文档……
使用代码
使用起来相当简单。下面我展示了一般的交互方式,并将保存到文件的部分留给用户。我注意到另一篇文章要求用户代码传入一个 (FILE*)
来保存/检索值。我没有这样做,因为在将数据发送到文件之前,用户可能有很多事情要做,而且用户代码可能不希望使用 (FILE*)
来持久化到磁盘。因此,这部分留给用户代码。
- 为您的需求 typedef 模板 - 对于此步骤,您需要知道您正在处理多少个元素。
typedef CFlexBitSet<10,1,BOOL> CFlexBitSet_10_BOOL; typedef CFlexBitSet<17,2,int> CFlexBitSet_17_int2; typedef CABMBitSet<17> CBitSetBOOL17;
- 声明变量实例以供使用.
CFlexBitSet_10_BOOL m_BitSet; CFlexBitSet_17_int2 m_BitSet2int; CBitSetBOOL17 m_BoolSet;
- 设置或获取变量的值.
m_BitSet2int[ m_iElement ] = m_iSetValue; m_BitSet[2] = TRUE; m_BoolSet[3] = TRUE; if ( m_BoolSet[2] ) { ... } if ( m_BitSet[2] ) { ... } If(m_BitSet2int[ m_iElement ] == iSomeTestValue){ ... }
- 从外部存储获取/设置整个数组值(用于在实例之间持久化数据).
UINT32* pTest = NULL; int SizeArray; BitSet.GetRawData(pTest, SizeArray); StoreUINT32ArrayToFile( pTest, SizeArray ); //some custom code you (user code) write < ... time passes and we need to get it from the file ... > GetFileStoredUINTArrayFromFile( pTest, SizeArray ); //some custom code you (user code) write BitSet.SetRawData(pTest, SizeArray); delete[] pTest;
关注点
- 问:嘿,你为什么把它做成模板类?如果将模板参数作为构造函数的一部分,可以以更灵活的方式完成。
答:嗯……你说的有道理。不过,我还是把它写成了模板。也许我应该改变它,但就目前而言,这似乎满足了我所有的需求。
- 问:CCDoc 注释是怎么回事?
答:自从我开始尝试 CCDoc 以来,我就爱上了它。我经常编写以后会用到的代码,但当我需要使用它时,我想要一份可以参考的文档,而无需去翻阅代码。CCDoc 提供了我发现有用的那种文档……只要我充分注释。
- 问:为什么要两个类?
CFlexBitSet
可以同时完成两者的任务。答:确实。但我编写
CABMBitSet
是为了立即满足我存储大量BOOL
标志的需求。但在写完那个之后,我想看看把它改造成处理可能需要 2、3 或更多位(最多 31 位)的元素需要多少工作。 - 问:在您的示例中,您使用了硬编码的索引号来访问某些元素。这样做明智吗?
答:当然不。在实际应用中,我会用“
#define
”的值或enum
来代替。但是,在示例中,我想保持简单。 - 问:为什么我要使用您的代码?
答:您不必……除非它满足您的需求,并且您不想重复编写所有内容。知道是一半的战斗,……善待他人……等等。
- 问:我喜欢您使用内部类来实现“
[]
”运算符的设置和获取功能。答:谢谢,但这主意的功劳我不能全收。这个想法是我从一位朋友 JAS 那里得到的,他也曾在网上某处发现了这个想法。我只是想确保这个想法被正式地公布出来……或者说,在这里。我能称这段代码为我的吗?不能。我也不声称完全拥有这个想法。但是,我不能阻止你,也不会尝试。呵呵,但是,你为什么要这样做呢?
- 问:嘿,想去喝杯啤酒吗?
答:好啊,我们走吧!
- 问:为什么对话框使用 Courier New 字体?
答:因为字符串表示
GetStrRepresentation(TRUE,FALSE);
使用两行,并且没有等宽字体,这看起来可能很奇怪。如果您想在测试中绕过这一点,那么将其发送到MessageBox( ... )
,然后当框出现时,按 <Ctrl>+C,打开记事本,然后粘贴在那里。我认为记事本默认使用等宽字体。
历史
(2005-03-27) 我的初始发布。