3 MPDM - Minimum Profit Data Manager
4 Copyright (C) 2003/2007 Angel Ortega <angel@triptico.com>
6 mpdm_h.c - Hash management
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
39 /* prototype for the one-time wrapper hash function */
40 static int switch_hash_func(const wchar_t *, int);
42 /* pointer to the hashing function */
43 static int (*mpdm_hash_func
) (const wchar_t *, int) = switch_hash_func
;
45 static int standard_hash_func(const wchar_t * string
, int mod
)
46 /* computes a hashing function on string */
50 for (c
= 0; *string
!= L
'\0'; string
++)
57 static int null_hash_func(const wchar_t * string
, int mod
)
62 static int switch_hash_func(const wchar_t * string
, int mod
)
63 /* one-time wrapper for hash method autodetection */
65 /* commute the real hashing function on
66 having the MPDM_NULL_HASH environment variable set */
67 if (getenv("MPDM_NULL_HASH") != NULL
)
68 mpdm_hash_func
= null_hash_func
;
70 mpdm_hash_func
= standard_hash_func
;
72 /* and fall back to it */
73 return mpdm_hash_func(string
, mod
);
76 #define HASH_BUCKET(h, k) (mpdm_hash_func(mpdm_string(k), mpdm_size(h)))
81 * mpdm_hsize - Returns the number of pairs of a hash.
84 * Returns the number of key-value pairs of a hash.
87 int mpdm_hsize(const mpdm_t h
)
92 for (n
= 0; n
< mpdm_size(h
); n
++) {
93 mpdm_t b
= mpdm_aget(h
, n
);
102 * mpdm_hget - Gets a value from a hash.
106 * Gets the value from the hash @h having @k as key, or
107 * NULL if the key does not exist.
110 mpdm_t
mpdm_hget(const mpdm_t h
, const mpdm_t k
)
117 /* if hash is not empty... */
118 if ((b
= mpdm_aget(h
, HASH_BUCKET(h
, k
))) != NULL
) {
119 /* if bucket exists, binary-seek it */
120 if ((n
= mpdm_bseek(b
, k
, 2, NULL
)) >= 0)
121 v
= mpdm_aget(b
, n
+ 1);
130 * mpdm_hget_s - Gets the value from a hash (string version).
134 * Gets the value from the hash @h having @k as key, or
135 * NULL if the key does not exist.
138 mpdm_t
mpdm_hget_s(const mpdm_t h
, const wchar_t * k
)
140 return mpdm_hget(h
, MPDM_LS(k
));
145 * mpdm_exists - Tests if a key exists.
149 * Returns 1 if @k is defined in @h, or 0 othersize.
152 int mpdm_exists(const mpdm_t h
, const mpdm_t k
)
159 /* if hash is not empty... */
160 if ((b
= mpdm_aget(h
, HASH_BUCKET(h
, k
))) != NULL
) {
161 /* if bucket exists, binary-seek it */
162 if ((n
= mpdm_bseek(b
, k
, 2, NULL
)) >= 0)
172 * mpdm_hset - Sets a value in a hash.
177 * Sets the value @v to the key @k in the hash @h. Returns
178 * the previous value of the key, or NULL if the key was
179 * previously undefined.
182 mpdm_t
mpdm_hset(mpdm_t h
, mpdm_t k
, mpdm_t v
)
187 /* if hash is empty, create an optimal number of buckets */
188 if (mpdm_size(h
) == 0)
189 mpdm_expand(h
, 0, mpdm
->hash_buckets
);
191 n
= HASH_BUCKET(h
, k
);
193 if ((b
= mpdm_aget(h
, n
)) != NULL
) {
196 /* bucket exists; try to find the key there */
197 if ((n
= mpdm_bseek(b
, k
, 2, &pos
)) < 0) {
198 /* the pair does not exist: create it */
200 mpdm_expand(b
, n
, 2);
205 /* the bucket does not exist; create it */
208 /* put the bucket into the hash */
218 return mpdm_aset(b
, v
, n
+ 1);
223 * mpdm_hset_s - Sets a value in a hash (string version).
228 * Sets the value @v to the key @k in the hash @h. Returns
229 * the previous value of the key, or NULL if the key was
230 * previously undefined.
233 mpdm_t
mpdm_hset_s(mpdm_t h
, const wchar_t * k
, mpdm_t v
)
235 return mpdm_hset(h
, MPDM_LS(k
), v
);
240 * mpdm_hdel - Deletes a key from a hash.
244 * Deletes the key @k from the hash @h. Returns the previous
245 * value, or NULL if the key was not defined.
248 mpdm_t
mpdm_hdel(mpdm_t h
, const mpdm_t k
)
254 if ((b
= mpdm_aget(h
, HASH_BUCKET(h
, k
))) != NULL
) {
256 if ((n
= mpdm_bseek(b
, k
, 2, NULL
)) >= 0) {
257 /* the pair exists: set key and value to NULL */
258 mpdm_aset(b
, NULL
, n
);
259 v
= mpdm_aset(b
, NULL
, n
+ 1);
261 /* collapse the bucket */
262 mpdm_collapse(b
, n
, 2);
271 * mpdm_keys - Returns the keys of a hash.
274 * Returns an array containing all the keys of the @h hash.
278 mpdm_t
mpdm_keys(const mpdm_t h
)
284 /* create an array with the same number of elements */
285 a
= MPDM_A(mpdm_hsize(h
));
287 /* sequentially fill with keys */
288 for (n
= i
= 0; n
< mpdm_size(h
); n
++) {
289 if ((b
= mpdm_aget(h
, n
)) != NULL
) {
290 for (m
= 0; m
< mpdm_size(b
); m
+= 2)
291 mpdm_aset(a
, mpdm_aget(b
, m
), i
++);
299 static mpdm_t
mpdm_sym(mpdm_t r
, mpdm_t k
, mpdm_t v
, int s
)
307 /* splits the path, if needed */
308 if (k
->flags
& MPDM_MULTIPLE
)
311 p
= mpdm_split(MPDM_LS(L
"."), k
);
313 for (n
= 0; n
< mpdm_size(p
) - s
; n
++) {
315 /* is executable? run it and take its output */
316 while (MPDM_IS_EXEC(r
))
317 r
= mpdm_exec(r
, NULL
);
320 r
= mpdm_hget(r
, mpdm_aget(p
, n
));
322 if (MPDM_IS_ARRAY(r
)) {
323 int i
= mpdm_ival(mpdm_aget(p
, n
));
333 /* if want to set, do it */
334 if (s
&& r
!= NULL
) {
335 if (r
->flags
& MPDM_HASH
)
336 r
= mpdm_hset(r
, mpdm_aget(p
, n
), v
);
338 int i
= mpdm_ival(mpdm_aget(p
, n
));
339 r
= mpdm_aset(r
, v
, i
);
347 mpdm_t
mpdm_sget(mpdm_t r
, mpdm_t k
)
349 return mpdm_sym(r
, k
, NULL
, 0);
353 mpdm_t
mpdm_sset(mpdm_t r
, mpdm_t k
, mpdm_t v
)
355 return mpdm_sym(r
, k
, v
, 1);