The Dictionary Interface
The dictionary interface inherits from
IBase just as the vector does, and is very similar (see
Listing 1).
Those who read Part 1 will recognize the function names, although the signatures have changed to better meet the needs of a dictionary as opposed to a hash. While the vector and dictionary components were never meant to be caste-compatible, they need to be as similar as possible. This similarity ensures that developers using one kind of collection can easily transfer their knowledge to the other.
Under the hood, the dictionary structure is simple:
typedef struct CDictionary
{
struct IDictionaryVtbl *pvt;
uint32 nRefs;
uint32 maskElements;
uint32 consumed;
Node *pElements;
PFNFREE pfnDeallocator;
uint32 cursor;
// The virtual table
IDictionaryVtbl vt;
} CDictionary;
Of course, the
CDictionary structure underlying the data must be cast-compatible with the
IDictionary interface; this is the purpose of the first element. The second field is the reference count used when you implement the reference counting required by
IBase. The remainder of the fields constitute the data fields for the dictionary itself:
- maskElements: This field is a bit mask indicating the number of nodes in the collection for the dictionary.
- consumed: This field indicates the number of nodes currently in use in the collection for the dictionary.
- pElements: This field is a pointer to the collection of nodes containing the dictionary's data.
- pfnDeallocator: This field is a pointer to the destructor used by the dictionary to release a node's value when it is deleted or replaced.
- cursor: This field is used by the enumeration interface while an enumeration is in process to store the state of the enumeration.
Setting up a dictionary is not unlike setting up any other component: allocate memory for the object, initialize its fields, initialize the virtual table, and then link the pointer to the virtual table to the table itself (see
Listing 2).
The only thing worth noting here is that the dictionary provides a default destructor, DefaultFree, which simply calls Brew's FREE function. If the dictionary was to store something elsevectors, sayI'd pass in a different destructor (such as IVECTOR_Release()).