27 > If you want to lazy-initialize maps, you can use the global `cxEmptyMap` symbol as a placeholder instead of using a `NULL`-pointer. |
27 > If you want to lazy-initialize maps, you can use the global `cxEmptyMap` symbol as a placeholder instead of using a `NULL`-pointer. |
28 > While you *must not* insert elements into that map, you can safely access this map or create iterators. |
28 > While you *must not* insert elements into that map, you can safely access this map or create iterators. |
29 > This allows you to write clean code without checking for `NULL`-pointer everywhere. |
29 > This allows you to write clean code without checking for `NULL`-pointer everywhere. |
30 > You still need to make sure that the placeholder is replaced with an actual map before inserting elements. |
30 > You still need to make sure that the placeholder is replaced with an actual map before inserting elements. |
31 |
31 |
32 ## Overview |
32 ## Examples |
33 |
33 |
34 <warning> |
34 ```C |
35 TODO: example |
35 #include <stdio.h> |
36 </warning> |
36 #include <cx/hash_map.h> |
|
37 |
|
38 int main() { |
|
39 CxMap *contacts = cxHashMapCreateSimple(CX_STORE_POINTERS); |
|
40 |
|
41 // Build a small phone book |
|
42 cxMapPut(contacts, "John", "123-0815"); |
|
43 cxMapPut(contacts, "Jane", "987-4711"); |
|
44 cxMapPut(contacts, "Michelle", "555-3141"); |
|
45 cxMapPut(contacts, "Oliver", "000-9999"); |
|
46 |
|
47 // Retrieve a phone number |
|
48 const char *janes_phone = cxMapGet(contacts, "Jane"); |
|
49 printf("The number of Jane is: %s\n", janes_phone); |
|
50 |
|
51 // Update number |
|
52 cxMapPut(contacts, "Jane", "987-1337"); |
|
53 |
|
54 // Remove and retrieve number |
|
55 cxMapRemoveAndGet(contacts, "Jane", &janes_phone); |
|
56 printf("The number of Jane was: %s\n", janes_phone); |
|
57 janes_phone = cxMapGet(contacts, "Jane"); |
|
58 if (janes_phone == NULL) printf("Jane's number was deleted.\n"); |
|
59 |
|
60 // Iterate through the contact list |
|
61 CxMapIterator iter = cxMapIterator(contacts); |
|
62 cx_foreach(CxMapEntry *, entry, iter) { |
|
63 cxstring name = cx_strn(entry->key->data, entry->key->len); |
|
64 const char *phone = entry->value; |
|
65 printf("%.*s: %s\n", (int) name.length, name.ptr, phone); |
|
66 } |
|
67 |
|
68 cxMapFree(contacts); |
|
69 |
|
70 return 0; |
|
71 } |
|
72 ``` |
|
73 |
|
74 The above example illustrates basic operations with a map. |
|
75 |
|
76 In the first part we add several entries to the map. |
|
77 Then the example shows retrieval, updating, and removal of information. |
|
78 The last part shows how to iterate over the pairs of the map and how to recover the string from the key. |
|
79 |
|
80 In real world situations, however, it is quite unlikely that you will use a map to store string literals. |
|
81 The next example shows a more realistic program, where it is necessary to store strings based on user input. |
|
82 |
|
83 ```C |
|
84 #include <stdio.h> |
|
85 #include <string.h> |
|
86 #include <cx/hash_map.h> |
|
87 |
|
88 int main() { |
|
89 // store strings in the map... |
|
90 CxMap *contacts = cxHashMapCreateSimple(sizeof(cxmutstr)); |
|
91 // ...which are automatically freed when removed |
|
92 cxDefineDestructor(contacts, cx_strfree); |
|
93 |
|
94 // build a small interactive program |
|
95 const unsigned buffer_size = 256; |
|
96 char input[buffer_size]; |
|
97 bool running = true; |
|
98 |
|
99 while (running) { |
|
100 puts("\n*** Contacts - Menu ***"); |
|
101 puts("1) Add entry"); |
|
102 puts("2) Look up entry"); |
|
103 puts("3) Remove entry"); |
|
104 puts("4) Show all entries"); |
|
105 puts("0) Exit"); |
|
106 fputs("> ", stdout); |
|
107 |
|
108 if (fgets(input, buffer_size, stdin)) { |
|
109 if (input[1] != '\n') { |
|
110 puts("Please select a menu item.\n"); |
|
111 } else if (input[0] == '1') { |
|
112 fputs("Name > ", stdout); |
|
113 if (fgets(input, buffer_size, stdin)) { |
|
114 // Copy the name (alternative: use 2nd input buf) |
|
115 cxmutstr name = cx_strdup( |
|
116 cx_strn(input, strcspn(input, "\n"))); |
|
117 fputs("Phone > ", stdout); |
|
118 if (fgets(input, buffer_size, stdin)) { |
|
119 // add the entry, note that only the contents |
|
120 // of the cxmutstr are copied, not the string |
|
121 // data - therefore we have to call cx_strdup |
|
122 cxmutstr phone = cx_strdup( |
|
123 cx_strn(input, strcspn(input, "\n"))); |
|
124 // note, that we can simply use the cxmutstr |
|
125 // for the name as key, because cxMapPut uses |
|
126 // generic selection |
|
127 cxMapPut(contacts, name, &phone); |
|
128 } |
|
129 cx_strfree(&name); |
|
130 } |
|
131 } else if (input[0] == '2') { |
|
132 fputs("Name > ", stdout); |
|
133 if (fgets(input, buffer_size, stdin)) { |
|
134 // Look up the name |
|
135 input[strcspn(input, "\n")] = '\0'; |
|
136 cxmutstr *phone = cxMapGet(contacts, input); |
|
137 if (phone == NULL) { |
|
138 puts("No record."); |
|
139 } else { |
|
140 printf("Result: %.*s\n", |
|
141 (int) phone->length, phone->ptr); |
|
142 } |
|
143 } |
|
144 } else if (input[0] == '3') { |
|
145 fputs("Name > ", stdout); |
|
146 if (fgets(input, buffer_size, stdin)) { |
|
147 // Remove the entry |
|
148 // Since we registered cx_strfree as destructor, |
|
149 // the memory is automatically freed |
|
150 input[strcspn(input, "\n")] = '\0'; |
|
151 if (cxMapRemove(contacts, input)) { |
|
152 puts("No such record."); |
|
153 } else { |
|
154 puts("Removed."); |
|
155 } |
|
156 } |
|
157 } else if (input[0] == '4') { |
|
158 // Almost the same iteration loop as above ... |
|
159 CxMapIterator iter = cxMapIterator(contacts); |
|
160 cx_foreach(CxMapEntry *, entry, iter) { |
|
161 cxstring name = cx_strn(entry->key->data, |
|
162 entry->key->len); |
|
163 // ... except that here we get cxmutstr* |
|
164 cxmutstr *phone = entry->value; |
|
165 printf("%.*s: %.*s\n", |
|
166 (int) name.length, name.ptr, |
|
167 (int) phone->length, phone->ptr); |
|
168 } |
|
169 } else if (input[0] == '0') { |
|
170 running = false; |
|
171 } else { |
|
172 puts("Please select a menu item.\n"); |
|
173 } |
|
174 } else { |
|
175 running = false; |
|
176 } |
|
177 } |
|
178 |
|
179 // this will free all remaining strings that are in the map |
|
180 cxMapFree(contacts); |
|
181 |
|
182 return 0; |
|
183 } |
|
184 ``` |
37 |
185 |
38 > In the following Sections, the type for the key is denoted `KeyType`. |
186 > In the following Sections, the type for the key is denoted `KeyType`. |
39 > All functions are implemented as generics, so that the following types are supported: |
187 > All functions are implemented as generics, so that the following types are supported: |
40 > `CxHashKey`, `cxstring`, `cxmutstr`, `const char*`, and `char*`. |
188 > `CxHashKey`, `cxstring`, `cxmutstr`, `const char*`, and `char*`. |
41 > {style="note"} |
189 > {style="note"} |