tagged release 0.6.4
[parrot.git] / src / dynpmc / gdbmhash.pmc
blob271b34821674bfb3bcc6463065505aaa9bc92873
1 /* gdbmhash.pmc
2  *  Copyright (C) 2005-2008, The Perl Foundation.
3  *  SVN Info
4  *     $Id$
5  *  Overview:
6  *     These are the vtable functions for the GDBMHash PMC
7  *  Data Structure and Algorithms:
8  *  History:
9  *  Notes:
10  *     Please remove unneeded entries.
11  *  References:
13 =head1 NAME
15 src/dynpmc/gdbmhash.pmc - GDBM PMC
17 =head1 DESCRIPTION
19 This is an interface to the GNU dbm library.
21 =head1 keys
23 On inserted and fetch, keys are converted to STRINGs.
25 =head2 store
27 PMC insert values are converted to STRINGs.
29 =head2 fetch
31 get_integer_keyed() and get_number_keyed() probably don't make any sense,
32 as integers usually can't be converted.
34 When a PMC is requested, a String PMC is returned.
37 =head2 Functions
39 =over 4
41 =cut
43  */
45 #include <gdbm.h>
46 #include "parrot/extend.h"
50 =item C<static STRING* make_hash_key(PARROT_INTERP, PMC *key)>
52 Returns a Parrot string for C<*key>.
54 =cut
58 static STRING* make_hash_key(PARROT_INTERP, NOTNULL(PMC * key))
60     if (key == NULL) {
61         real_exception(interp, NULL, OUT_OF_BOUNDS, "Hash: Cannot use NULL key");
62     }
63     return key_string(interp, key);
67 pmclass GDBMHash provides hash dynpmc lib gdbm {
71 =item C<void class_init()>
73 Class initialization. GDBMHash is a dynamic PMC, meaning that a dynamically
74 loadable module is created. On Unix-like systems this is a shared library.
75 When it is available, the shared library has linked in the library 'gdbm'.
77 On WIN32 the relevant library seems to be called 'gdbm3'.
78 So we do a bit of cheating here, and load it during class initialization.
80 =cut
84     void class_init() {
85         if (pass) {
86 #ifdef WIN32
87             /* RT#46393: What if libgdbm.so cannot be loaded */
88             /* Parrot_load_lib(interp, slib, NULL); */
89             STRING *slib = string_from_literal(interp, "gdbm3");
90 #endif
91         }
92     }
94     VTABLE void init() {
95         PMC_struct_val(SELF) = NULL;
96     }
98     void* get_pointer() {
99         return PMC_struct_val(SELF);
100     }
102     void set_pointer(void* p) {
103         PMC_struct_val(SELF) = p;
104     }
108 =item C<VOID set_string_native(STRING* value)>
110 Open a or create a new dbm file.
112 =cut
116     void set_string_native(STRING* value) {
117         char *c_db_name      = string_to_cstring(interp, value);
118         GDBM_FILE dbf        = gdbm_open(c_db_name, 0, GDBM_NEWDB, 0666, 0);
120         string_cstring_free(c_db_name);
122         PMC_struct_val(SELF) = dbf;
123     }
127 =item C<INTVAL get_integer()>
129 Returns the number of pairs in the hash.
130 A uninitialized GDBMHash returns 0.
132 =cut
134 RT#46395: This can be optimized by keeping track of number of elements
138     VTABLE INTVAL get_integer() {
139         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
140         if (! dbf) {
141             return 0;
142         }
143         else {
144             INTVAL cnt = 0;
145             datum key, nextkey;
146             for (key = gdbm_firstkey(dbf); key.dptr; key = nextkey) {
147                 cnt++;
148                 nextkey = gdbm_nextkey(dbf, key);
149                 free(key.dptr);
150             }
152             return cnt;
153         }
154     }
158 =item C<INTVAL get_bool()>
160 Returns true if the hash size is not zero.
162 =cut
166     VTABLE INTVAL get_bool() {
167         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
168         if (! dbf) {
169             return 0;
170         }
171         else {
172             datum key = gdbm_firstkey(dbf);
173             if (key.dptr) {
174                 return 1;
175             }
176             else {
177                 return 0;
178             }
179         }
180     }
184 =item C<void set_string_keyed(PMC *key, STRING *value)>
186 =cut
190     void set_string_keyed(PMC* key, STRING* value) {
191         STRING* keystr;
192         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
193         datum key_gdbm, val_gdbm;
195         if (!key) return;
196         if (!dbf) return;
197         keystr = make_hash_key(interp, key);
199         key_gdbm.dsize = keystr->strlen;
200         key_gdbm.dptr  = keystr->strstart;
201         val_gdbm.dsize = value->strlen;
202         val_gdbm.dptr  = value->strstart;
204         gdbm_store(dbf, key_gdbm, val_gdbm, GDBM_REPLACE);
206         return;
207     }
211 =item C<STRING *get_string_keyed(PMC *key)>
213 Returns the string value for the element at C<*key>.
215 =cut
219     STRING* get_string_keyed(PMC* key) {
220         STRING* keystr, *val;
221         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
222         datum key_gdbm, val_gdbm;
224         if (!key)
225             return CONST_STRING(INTERP, "");
226         if (!dbf)
227             return CONST_STRING(INTERP, "");
228         keystr = make_hash_key(interp, key);
230         key_gdbm.dsize = keystr->strlen;
231         key_gdbm.dptr  = keystr->strstart;
232         val_gdbm = gdbm_fetch(dbf, key_gdbm);
234         val = string_from_cstring(interp, val_gdbm.dptr, val_gdbm.dsize);
235         free(val_gdbm.dptr);
237         return val;
238     }
243 =item C<void set_pmc_keyed(PMC* key, PMC *value)>
245 Convert C<value> to a string and set the string for the C<key>.
247 =cut
251     void set_pmc_keyed(PMC* key, PMC* value) {
252         STRING *temp;
254         temp = VTABLE_get_string(interp, value);
255         SELF.set_string_keyed(key, temp);
256     }
260 =item C<PMC *get_pmc_keyed(PMC *key)>
262 Returns the PMC value for the element at C<*key>.
264 =cut
268     PMC* get_pmc_keyed(PMC* key) {
269         STRING * ret_string = SELF.get_string_keyed(key);
270         PMC *ret_pmc = pmc_new(interp, enum_class_String);
272         VTABLE_set_string_native(interp, ret_pmc, ret_string);
274         return ret_pmc;
275     }
279 =item C<void set_integer_keyed(PMC* key, INTVAL value)>
281 Convert C<value> to a string and set the string for the C<key>.
283 =cut
287     void set_integer_keyed(PMC* key, INTVAL value) {
288         PMC *temp;
290         temp = pmc_new(interp, enum_class_String);
291         VTABLE_set_integer_native(interp, temp, value);
292         SELF.set_pmc_keyed(key, temp);
293     }
298 =item C<void set_number_keyed(PMC* key, FLOATVAL value)>
300 Convert C<value> to a string and set the string for the C<key>.
302 =cut
306     void set_number_keyed(PMC* key, FLOATVAL value) {
307         PMC *temp;
309         temp = pmc_new(interp, enum_class_String);
310         VTABLE_set_number_native(interp, temp, value);
311         SELF.set_pmc_keyed(key, temp);
312     }
316 =item C<INTVAL exists_keyed(PMC *key)>
318 Returns whether a key C<*key> exists in the hash.
320 =cut
324     INTVAL exists_keyed(PMC* key) {
325         STRING* keystr;
326         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
327         datum key_gdbm;
329         if (!key) return 0;
330         if (!dbf) return 0;
331         keystr = make_hash_key(interp, key);
333         key_gdbm.dsize = keystr->strlen;
334         key_gdbm.dptr  = keystr->strstart;
336         return gdbm_exists(dbf, key_gdbm);
337     }
341 =item C<void delete_keyed(PMC *key)>
343 Deletes the element associated with C<*key>.
345 =cut
349     void delete_keyed(PMC* key) {
350         STRING* keystr;
351         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
352         datum key_gdbm;
354         if (!key) return;
355         if (!dbf) return;
356         keystr = make_hash_key(interp, key);
358         key_gdbm.dsize = keystr->strlen;
359         key_gdbm.dptr  = keystr->strstart;
361         if (gdbm_exists(dbf, key_gdbm)) {
362            gdbm_delete(dbf, key_gdbm);
363         }
365         return;
366     }
371 =back
373 =head1 SEE ALSO
375 F<docs/pdds/pdd08_keys.pod>, L<http://gdbm.gnu.org>
377 =cut
382  * Local variables:
383  *   c-file-style: "parrot"
384  * End:
385  * vim: expandtab shiftwidth=4:
386  */