tagged release 0.7.1
[parrot.git] / src / dynpmc / gdbmhash.pmc
blob40a85f13d4f347f12b6791b2e393a007b3833397
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)
61         return VTABLE_get_string(interp, key);
63     Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_OUT_OF_BOUNDS,
64         "Hash: Cannot use NULL key");
69 pmclass GDBMHash provides hash dynpmc lib gdbm {
73 =item C<void class_init()>
75 Class initialization. GDBMHash is a dynamic PMC, meaning that a dynamically
76 loadable module is created. On Unix-like systems this is a shared library.
77 When it is available, the shared library has linked in the library 'gdbm'.
79 On WIN32 the relevant library seems to be called 'gdbm3'.
80 So we do a bit of cheating here, and load it during class initialization.
82 =cut
86     void class_init() {
87         if (pass) {
88 #ifdef WIN32
89             /* RT #46393: What if libgdbm.so cannot be loaded */
90             /* Parrot_load_lib(interp, slib, NULL); */
91             STRING *slib = CONST_STRING(interp, "gdbm3");
92 #endif
93         }
94     }
96     VTABLE void init() {
97         PMC_struct_val(SELF) = NULL;
98     }
100     void* get_pointer() {
101         return PMC_struct_val(SELF);
102     }
104     void set_pointer(void* p) {
105         PMC_struct_val(SELF) = p;
106     }
110 =item C<VOID set_string_native(STRING* value)>
112 Open a or create a new dbm file.
114 =cut
118     void set_string_native(STRING* value) {
119         char *c_db_name      = string_to_cstring(interp, value);
120         GDBM_FILE dbf        = gdbm_open(c_db_name, 0, GDBM_NEWDB, 0666, 0);
122         string_cstring_free(c_db_name);
124         PMC_struct_val(SELF) = dbf;
125     }
129 =item C<INTVAL get_integer()>
131 Returns the number of pairs in the hash.
132 A uninitialized GDBMHash returns 0.
134 =cut
136 RT#46395: This can be optimized by keeping track of number of elements
140     VTABLE INTVAL get_integer() {
141         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
142         if (! dbf) {
143             return 0;
144         }
145         else {
146             INTVAL cnt = 0;
147             datum key, nextkey;
148             for (key = gdbm_firstkey(dbf); key.dptr; key = nextkey) {
149                 cnt++;
150                 nextkey = gdbm_nextkey(dbf, key);
151                 free(key.dptr);
152             }
154             return cnt;
155         }
156     }
160 =item C<INTVAL get_bool()>
162 Returns true if the hash size is not zero.
164 =cut
168     VTABLE INTVAL get_bool() {
169         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
170         if (! dbf) {
171             return 0;
172         }
173         else {
174             datum key = gdbm_firstkey(dbf);
175             if (key.dptr) {
176                 return 1;
177             }
178             else {
179                 return 0;
180             }
181         }
182     }
186 =item C<void set_string_keyed(PMC *key, STRING *value)>
188 =cut
192     void set_string_keyed(PMC* key, STRING* value) {
193         STRING* keystr;
194         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
195         datum key_gdbm, val_gdbm;
197         if (!key) return;
198         if (!dbf) return;
199         keystr = make_hash_key(interp, key);
201         key_gdbm.dsize = keystr->strlen;
202         key_gdbm.dptr  = keystr->strstart;
203         val_gdbm.dsize = value->strlen;
204         val_gdbm.dptr  = value->strstart;
206         gdbm_store(dbf, key_gdbm, val_gdbm, GDBM_REPLACE);
208         return;
209     }
213 =item C<STRING *get_string_keyed(PMC *key)>
215 Returns the string value for the element at C<*key>.
217 =cut
221     STRING* get_string_keyed(PMC* key) {
222         STRING* keystr, *val;
223         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
224         datum key_gdbm, val_gdbm;
226         if (!key)
227             return CONST_STRING(INTERP, "");
228         if (!dbf)
229             return CONST_STRING(INTERP, "");
230         keystr = make_hash_key(interp, key);
232         key_gdbm.dsize = keystr->strlen;
233         key_gdbm.dptr  = keystr->strstart;
234         val_gdbm = gdbm_fetch(dbf, key_gdbm);
236         val = string_from_cstring(interp, val_gdbm.dptr, val_gdbm.dsize);
237         free(val_gdbm.dptr);
239         return val;
240     }
245 =item C<void set_pmc_keyed(PMC* key, PMC *value)>
247 Convert C<value> to a string and set the string for the C<key>.
249 =cut
253     void set_pmc_keyed(PMC* key, PMC* value) {
254         STRING *temp;
256         temp = VTABLE_get_string(interp, value);
257         SELF.set_string_keyed(key, temp);
258     }
262 =item C<PMC *get_pmc_keyed(PMC *key)>
264 Returns the PMC value for the element at C<*key>.
266 =cut
270     PMC* get_pmc_keyed(PMC* key) {
271         STRING * ret_string = SELF.get_string_keyed(key);
272         PMC *ret_pmc = pmc_new(interp, enum_class_String);
274         VTABLE_set_string_native(interp, ret_pmc, ret_string);
276         return ret_pmc;
277     }
281 =item C<void set_integer_keyed(PMC* key, INTVAL value)>
283 Convert C<value> to a string and set the string for the C<key>.
285 =cut
289     void set_integer_keyed(PMC* key, INTVAL value) {
290         PMC *temp;
292         temp = pmc_new(interp, enum_class_String);
293         VTABLE_set_integer_native(interp, temp, value);
294         SELF.set_pmc_keyed(key, temp);
295     }
300 =item C<void set_number_keyed(PMC* key, FLOATVAL value)>
302 Convert C<value> to a string and set the string for the C<key>.
304 =cut
308     void set_number_keyed(PMC* key, FLOATVAL value) {
309         PMC *temp;
311         temp = pmc_new(interp, enum_class_String);
312         VTABLE_set_number_native(interp, temp, value);
313         SELF.set_pmc_keyed(key, temp);
314     }
318 =item C<INTVAL exists_keyed(PMC *key)>
320 Returns whether a key C<*key> exists in the hash.
322 =cut
326     INTVAL exists_keyed(PMC* key) {
327         STRING* keystr;
328         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
329         datum key_gdbm;
331         if (!key) return 0;
332         if (!dbf) return 0;
333         keystr = make_hash_key(interp, key);
335         key_gdbm.dsize = keystr->strlen;
336         key_gdbm.dptr  = keystr->strstart;
338         return gdbm_exists(dbf, key_gdbm);
339     }
343 =item C<void delete_keyed(PMC *key)>
345 Deletes the element associated with C<*key>.
347 =cut
351     void delete_keyed(PMC* key) {
352         STRING* keystr;
353         GDBM_FILE dbf = (GDBM_FILE)PMC_struct_val(SELF);
354         datum key_gdbm;
356         if (!key) return;
357         if (!dbf) return;
358         keystr = make_hash_key(interp, key);
360         key_gdbm.dsize = keystr->strlen;
361         key_gdbm.dptr  = keystr->strstart;
363         if (gdbm_exists(dbf, key_gdbm)) {
364            gdbm_delete(dbf, key_gdbm);
365         }
367         return;
368     }
373 =back
375 =head1 SEE ALSO
377 F<docs/pdds/pdd08_keys.pod>, L<http://gdbm.gnu.org>
379 =cut
384  * Local variables:
385  *   c-file-style: "parrot"
386  * End:
387  * vim: expandtab shiftwidth=4:
388  */