OpenCASCADE内用到了很多由诸如NCollection_Map, NCollection_DataMap, NCollection_DoubleMap, NCollection_IndexedMap, NCollection_IndexedDataMap之类模板衍生出来的类,比如TopTools_IndexedMapOfShape,BOPCol_MapOfShape等等,不多举例了。
另外在源码里经常typedef重定义出一个数据类型,想想也是醉了,可能以前旧版里的数据类型太多了,现在虽然采用模板了,但还是typedef重定义出原来的那些类型。
NCollection_Map, NCollection_DataMap, NCollection_DoubleMap, NCollection_IndexedMap, NCollection_IndexedDataMap它们都派生自NCollection_BaseMap,哈希形式的数据结构。继承派生图表如下:
NCollection_*Map的哈希结构
NCollection_BaseMap
根类,使用NCollection_ListNode为节点基类,后续派生类的节点也继承自NCollection_ListNode。
- Standard_Integer myNbBuckets; 桶的数量 总是取下一个质数为桶数量(在TCollection.cxx内的Primes数组存有)
- Standard_Integer mySize; 加入的成员数量
- BeginResize() 申请节点内存空间(NCollection_ListNode*地址指针类型,不会限制派生类的节点空间需求),EndResize() 将申请的指针赋给myData1, myData2;
NCollection_Map
模板参数仅接受一个 TheKeyType (不理会那个Hasher),节点为 NCollection_Map::MapNode 继承自NCollection_TListNode
理解:类似std::unorder_set,存储数据无次序比较,不像基于红黑树的std::set,数据会呈有序排布
应用举例:比如 BRepMesh_IncrementalMesh::collectFaces()里用的 TColStd_MapOfTransient aTFaceMap(1, anAlloc); !aTFaceMap.Add(aTFace) 收集TopoDS_TShape,阻止第二次的加入
NCollection_DataMap
模板参数接受二个,TheKeyType, TheItemType,节点为 NCollection_DataMap::DataMapNode
理解:可以理解为std::unorder_map,从key快速找到对应的value
典型应用,比如在 Standard_Type.cxx 内的typedef NCollection_DataMap<Standard_CString, Standard_Type*, CStringHasher> registry_type; 可以从名字搜索到类型
NCollection_DoubleMap
模板参数接受二个,TheKey1Type, TheKey2Type,节点为 NCollection_DoubleMap::DoubleMapNode,可以理解为一个双向的哈希数据结构
NCollection_IndexedMap
模板参数为一个,TheKeyType,节点参数为 NCollection_IndexedMap::IndexedMapNode
理解:可以理解为固定theKey2Type为Standard_Integer的NCollection_DoubleMap
典型应用,比如在 TopTools_ShapeSet::Add(const TopoDS_Shape& S) 内,myShapes.FindIndex(S2) 返回index,若index==0才添加myShapes.Add(S2),返回index,之后就可以依据index查找到TopoDS_Shape,这样就可以用这个index对应TopoDS_Shape,OCC源码内很多地方这么用。
NCollection_IndexedDataMap
模板参数接受二个 TheKeyType, TheItemType,节点参数为 NCollection_IndexedDataMap::IndexedDataMapNode,与NCollection_DataMap类似,但附加了Indexed功能,也可以通过index索引
典型应用: 比如TopExp::MapShapesAndAncestors(Shape, TopAbs_Edge, TopAbs_Face, Map)函数中Map对应的数据类型是 TopTools_IndexedDataMapOfShapeListOfShape,该函数是生成边-面的映射,可以从Map中便捷地找到拥有该边的面。
在Visual Studio中的调试可视化
VS2012版之后,支持natvis格式的文件定义类型在调试时的可视化。VS2010版的则是在AutoExp.dat文件中添加,都在这一个文件里,多少不便捷。而VS2012之后的可以多个文件,存放在Documents目录下的Visual Studio 2012/2015下边的Visualizers文件夹里边也可以(这样就不用到Visual Studio程序目录里边做什么了)。
OpenCASCADE在源码doxdev_guidesdebug下边有文件occt.natvis,但是里边很多数据类型的定义还是旧版的多,比如NCollection_Array1模板衍生的类TColStd_Array1OfInteger。
对此我基于自己的经验改写了一个版本,并在github上建了一个仓库OcctDebugNatvis,下载项目中的occt.natvis文件即可,以后视情况更新。
需要说明的是
- NCollection_Array2是二维的数组,由于
维数描述也需要数组,但NCollection_Array2维数尺寸并非数组,所以该文件里边的NCollection_Array2仅在行与列相等时才会显示完整的数据成员。 - NCollection_BaseMap派生的哈希结构,可视化描述需要CustomListItems,但是VS2012并不支持这个,VS2013尚未可知,VS2015在调试可视化方面可能改进很多。我是在官方VS2015的文档中才发现提供有此成员来支持哈希的数据结构调试可视化,在VS2012中CustomListItems会导致该数据结构描述失效。
- 此外NCollection_BaseMap在哈希碰撞时会在同一位置取Next吧,而我的occt.natvis仅写了一层,理论上来说仅在深度为1时适用,不过这种情况相对少见吧,估计这样子也够用了吧。
此文件缺陷肯定是有的,覆盖性也不足,不过代表了我这一段时间来对OCC内的数据结构的认识。