RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Back to Basics: Manage Collections with a Custom Dictionary : Page 2

Dictionaries are an essential data structure in many of today's programming environments. Use this one in your next Brew application.

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 else—vectors, say—I'd pass in a different destructor (such as IVECTOR_Release()).

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date