Statistics
| Branch: | Tag: | Revision:

root / xseg / xtypes / xhash.c @ 5be18103

History | View | Annotate | Download (23.6 kB)

1
/*
2
 * Copyright 2012 GRNET S.A. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or
5
 * without modification, are permitted provided that the following
6
 * conditions are met:
7
 *
8
 *   1. Redistributions of source code must retain the above
9
 *      copyright notice, this list of conditions and the following
10
 *      disclaimer.
11
 *   2. Redistributions in binary form must reproduce the above
12
 *      copyright notice, this list of conditions and the following
13
 *      disclaimer in the documentation and/or other materials
14
 *      provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
 * POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * The views and conclusions contained in the software and
30
 * documentation are those of the authors and should not be
31
 * interpreted as representing official policies, either expressed
32
 * or implied, of GRNET S.A.
33
 */
34

    
35
/* python hash for C
36
 *  originally by gtsouk@cslab.ece.ntua.gr
37
 *  -- kkourt@cslab.ece.ntua.gr
38
 */
39

    
40
#include <xtypes/xhash.h>
41

    
42
#define UNUSED (~(xhashidx)0)      /* this entry was never used */
43
#define DUMMY  ((~(xhashidx)0)-1)  /* this entry was used, but now its empty */
44

    
45
//#define VAL_OVERLOAD
46
//#define KEY_OVERLOAD
47
//#define NO_OVERLOAD /* use separate bitarray -- not implemented */
48

    
49
#define PERTURB_SHIFT 5
50

    
51
static inline xhashidx hash_int(xhashidx key)
52
{
53
        return key;
54
}
55

    
56
static inline int cmp_int(xhashidx key1, xhashidx key2)
57
{
58
        return (key1 == key2);
59
}
60

    
61
static inline xhashidx hash_string(xhashidx key) 
62
{
63
        //assume a valid NULL terminated string
64
        
65
        //function to access key if in container
66
        char *string = (char *) key;
67
        unsigned int i, len = strlen(string);
68
        xhashidx hv = string[0] << 7;
69
        for (i = 1; i <= len; i++) {
70
                hv = (hv * 1000003) ^ string[i];
71
        }
72
        if (hv == Noxhashidx)
73
                hv = Noxhashidx -1;
74

    
75
//        XSEGLOG("String %s (%lx). Hash value: %llu",
76
//                        string, string, hv);
77
        return hv; 
78
}
79

    
80
static inline int cmp_string(xhashidx key1, xhashidx key2)
81
{
82
        char *string1 = (char *) key1;
83
        char *string2 = (char *) key2;
84
        int value = !strcmp(string1, string2);
85
//        XSEGLOG("String1 %s (%lx), string2: %s(%lx), r: %d",
86
//                        string1, (unsigned long) string1,
87
//                        string2, (unsigned long) string2,
88
//                        value);
89

    
90
        return (value);
91
}
92

    
93
typedef int (*xhash_cmp_fun_t)(xhashidx key1, xhashidx key2);
94
typedef xhashidx (*xhash_hash_fun_t)(xhashidx key);
95

    
96
struct types_functions {
97
//        int (*cmp_fun)(xhashidx key1, xhashidx key2);
98
//        xhashidx (*hash_fun)(xhashidx key);
99
        xhash_cmp_fun_t cmp_fun;
100
        xhash_hash_fun_t hash_fun;
101
};
102

    
103
static struct types_functions types_fun[] = {
104
        { .cmp_fun = cmp_int, .hash_fun = hash_int },
105
        { .cmp_fun = cmp_string, .hash_fun = hash_string }
106
};
107

    
108

    
109
static inline void
110
set_dummy_key(xhash_t *xhash, xhashidx idx)
111
{
112
    xhashidx *kvs = xhash_kvs(xhash);
113
    kvs[idx] = DUMMY;
114
}
115

    
116
static inline void
117
set_dummy_val(xhash_t *xhash, xhashidx idx)
118
{
119
    xhashidx *vals = xhash_vals(xhash);
120
    vals[idx] = DUMMY;
121
}
122

    
123
static bool
124
item_dummy(xhash_t *xhash, xhashidx idx, bool vals)
125
{
126
    bool ret;
127
    xhashidx *pvals;
128
    xhashidx *kvs = xhash_kvs(xhash);
129

    
130
    if (!vals) {
131
        ret = (kvs[idx] == DUMMY);
132
    } else {
133
        #if defined(VAL_OVERLOAD)
134
        pvals = xhash_vals(xhash);
135
        ret = (pvals[idx] == DUMMY);
136
        #elif defined(KEY_OVERLOAD)
137
        ret = (kvs[idx] == DUMMY);
138
        #endif
139
    }
140
    return ret;
141

    
142
}
143

    
144
static void set_dummy_item(xhash_t *xhash, xhashidx idx, bool vals)
145
{
146
    if (!vals) {
147
        set_dummy_key(xhash, idx);
148
        return;
149
    }
150

    
151
    #ifdef VAL_OVERLOAD
152
    set_dummy_val(xhash, idx);
153
    return;
154
    #elif defined(KEY_OVERLOAD)
155
    set_dummy_key(xhash, idx);
156
    return;
157
    #endif
158
}
159
static inline void
160
set_unused_key(xhash_t *xhash, xhashidx idx)
161
{
162
    xhashidx *kvs = xhash_kvs(xhash);
163
    kvs[idx] = UNUSED;
164
}
165

    
166
static inline void
167
set_unused_val(xhash_t *xhash, xhashidx idx)
168
{
169
    xhashidx *vals = xhash_vals(xhash);
170
    vals[idx] = UNUSED;
171
}
172

    
173
static inline bool
174
val_unused(xhash_t *xhash, xhashidx idx)
175
{
176
    xhashidx *vals = xhash_vals(xhash);
177
    return vals[idx] == UNUSED;
178
}
179

    
180
static bool
181
item_unused(xhash_t *xhash, xhashidx idx, bool vals)
182
{
183
    xhashidx *kvs = xhash_kvs(xhash);
184
    if (!vals) {
185
        return kvs[idx] == UNUSED;
186
    }
187

    
188
    #if defined(VAL_OVERLOAD)
189
    return val_unused(xhash, idx);
190
    #elif defined(KEY_OVERLOAD)
191
    return kvs[idx] == UNUSED;
192
    #endif
193

    
194
}
195

    
196
static inline unsigned item_valid(xhash_t *xhash, xhashidx idx, bool vals)
197
{
198
    return !(item_dummy(xhash, idx, vals) || item_unused(xhash, idx, vals));
199
}
200
/*
201
static void __attribute__((unused))
202
assert_key(xhashidx key)
203
{
204
    assert((key != UNUSED) && (key != DUMMY));
205
}
206

207
static void
208
assert_val(xhashidx val)
209
{
210
    assert((val != UNUSED) && (val != DUMMY));
211
}
212

213
static inline void
214
assert_kv(xhashidx k, xhashidx v)
215
{
216
    #if defined(KEY_OVERLOAD)
217
    assert_key(k);
218
    #elif defined(VAL_OVERLOAD)
219
    assert_val(v);
220
    #endif
221
}
222
*/
223

    
224
void
225
xhash_init__(xhash_t *xhash, xhashidx size_shift, xhashidx minsize_shift,
226
                xhashidx limit, enum xhash_type type, bool vals)
227
{
228
    xhashidx nr_items = 1UL << size_shift;
229
    xhashidx *kvs = (xhashidx *) ((char *) xhash + sizeof(struct xhash));
230
    xhashidx i;
231

    
232
    XPTRSET(&xhash->kvs, kvs);
233

    
234

    
235
    if (!vals) {
236
        for (i=0; i < nr_items; i++)
237
            kvs[i] = UNUSED;
238
        goto out;
239
    }
240

    
241
    for (i=0; i < nr_items; i++){
242
        #if defined(VAL_OVERLOAD)
243
        kvs[nr_items + i] = UNUSED;
244
        #elif  defined(KEY_OVERLOAD)
245
        kvs[i] = UNUSED;
246
        #endif
247
    }
248

    
249
out:
250
    xhash->dummies = xhash->used = 0;
251
    xhash->size_shift = size_shift;
252
    xhash->minsize_shift = minsize_shift;
253
    xhash->limit = limit;
254
    xhash->type = type;
255

    
256
    ZEROSTAT(xhash->inserts);
257
    ZEROSTAT(xhash->deletes);
258
    ZEROSTAT(xhash->lookups);
259
    ZEROSTAT(xhash->bounces);
260
}
261

    
262
static ssize_t
263
get_alloc_size(xhashidx size_shift, bool vals)
264
{
265
    xhashidx nr_items = 1UL << size_shift;
266
    size_t keys_size = nr_items*sizeof(xhashidx);
267
    size_t alloc_size = vals ? keys_size<<1 : keys_size;
268
    return sizeof(struct xhash) + alloc_size;
269
}
270

    
271

    
272
xhash_t *
273
xhash_new__(xhashidx size_shift, xhashidx minsize_shift, xhashidx limit, 
274
                enum xhash_type type, bool vals) 
275
{
276
    struct xhash *xhash;
277
    xhash = xtypes_malloc(get_alloc_size(size_shift, vals));
278
    if (!xhash) {
279
        XSEGLOG("couldn't malloc\n");
280
        return NULL;
281
    }
282

    
283
    xhash_init__(xhash, size_shift, minsize_shift, limit, type, vals);
284
    
285
    return xhash;
286
}
287

    
288

    
289
xhash_t *
290
xhash_resize__(struct xhash *xhash, xhashidx new_size_shift, xhashidx new_limit,
291
                bool vals)
292
{
293
    return xhash_new__(new_size_shift, xhash->minsize_shift, new_limit, 
294
                            xhash->type, vals);
295
}
296

    
297
int
298
xhash_delete__(xhash_t *xhash, xhashidx key, bool vals)
299
{
300
//    XSEGLOG("Deleting %lx", key);
301
    xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
302
    xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun; 
303
    xhashidx perturb = hash_fun(key);
304
    xhashidx mask = xhash_size(xhash)-1;
305
    xhashidx idx = hash_fun(key) & mask;
306
    xhashidx *kvs = xhash_kvs(xhash);
307

    
308
    for (;;) {
309
        if ( item_unused(xhash, idx, vals) ){
310
            return -2;
311
        }
312

    
313
        if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
314
            INCSTAT(xhash->deletes);
315
            set_dummy_item(xhash, idx, vals);
316
            xhash->dummies++;
317
            //fprintf(stderr, "rm: used: %lu\n", xhash->used);
318
            xhash->used--;
319
            return 0;
320
        }
321

    
322
        INCSTAT(xhash->bounces);
323
        idx = ((idx<<2) + idx + 1 + perturb) & mask;
324
        perturb >>= PERTURB_SHIFT;
325
    }
326
}
327

    
328
xhashidx
329
xhash_grow_size_shift(xhash_t *xhash)
330
{
331
    xhashidx old_size_shift = xhash->size_shift;
332
    xhashidx new_size_shift;
333
    xhashidx u;
334

    
335
    u = xhash->used;
336
    //printf("used: %lu\n", u);
337
    if (u/2 + u >= ((xhashidx)1 << old_size_shift)) {
338
        new_size_shift = old_size_shift + 1;
339
    } else {
340
        new_size_shift = old_size_shift;
341
    }
342

    
343
    return new_size_shift;
344
}
345

    
346
xhashidx
347
xhash_shrink_size_shift(xhash_t *xhash)
348
{
349
    xhashidx old_size_shift = xhash->size_shift;
350
    xhashidx new_size_shift;
351
    new_size_shift = old_size_shift - 1;
352
    if (new_size_shift < xhash->minsize_shift) {
353
        new_size_shift = xhash->minsize_shift;
354
    }
355
    return new_size_shift;
356
}
357

    
358
static bool
359
grow_check(xhash_t *xhash)
360
{
361
    xhashidx size_shift = xhash->size_shift;
362
    xhashidx u = xhash->used + xhash->dummies;
363
    xhashidx size = (xhashidx)1UL<<size_shift;
364
    return ((u/2 + u) >= size) ? true : false;
365
}
366

    
367
static bool
368
shrink_check(xhash_t *xhash)
369
{
370
    xhashidx size_shift = xhash->size_shift;
371
    xhashidx size = (xhashidx)1<<size_shift;
372
    xhashidx u = xhash->used;
373
    return (4*u < size && size_shift > xhash->minsize_shift) ? true : false;
374
}
375

    
376

    
377
/**
378
 * Phash functions
379
 */
380

    
381
ssize_t 
382
xhash_get_alloc_size(xhashidx size_shift)
383
{
384
        return get_alloc_size(size_shift, true);
385
}
386

    
387
xhash_t *
388
xhash_new(xhashidx minsize_shift, xhashidx limit, enum xhash_type type)
389
{
390
    return xhash_new__(minsize_shift, minsize_shift, limit,  type, true);
391
}
392

    
393
void xhash_free(struct xhash *xhash)
394
{
395
    xtypes_free(xhash);
396
}
397

    
398
void xhash_init(struct xhash *xhash, xhashidx minsize_shift, xhashidx limit,
399
                enum xhash_type type)
400
{
401
        xhash_init__(xhash, minsize_shift, minsize_shift, limit, type, true);
402
}
403

    
404
/*
405
xhash_t *
406
xhash_grow(struct xhash *xhash)
407
{
408
    xhashidx new_size_shift = xhash_grow_size_shift(xhash);
409
    return xhash_resize(xhash, new_size_shift);
410
}
411

412
xhash_t *
413
xhash_shrink(struct xhash *xhash)
414
{
415
    xhashidx new_size_shift = xhash_shrink_size_shift(xhash);
416
    return xhash_resize(xhash, new_size_shift);
417
}
418

419
static inline xhash_t*
420
xhash_grow_check(xhash_t *xhash)
421
{
422
    if (grow_check(xhash))
423
        return xhash_grow(xhash);
424
    else 
425
        return NULL;
426
}
427
*/
428

    
429
#define PHASH_UPDATE(xhash, key, val, vals_flag)      \
430
{                                                     \
431
    xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;         \
432
    xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun;       \
433
    xhashidx size = 1UL<<(xhash->size_shift);         \
434
    xhashidx perturb = hash_fun(key);                           \
435
    xhashidx mask = size-1;                           \
436
    xhashidx idx = hash_fun(key) & mask;              \
437
    xhashidx *kvs = xhash_kvs(xhash);                 \
438
                                                      \
439
    INCSTAT(xhash->inserts);                          \
440
    for (;;) {                                        \
441
        if ( !item_valid(xhash, idx, vals_flag) ){    \
442
             PHUPD_SET__(xhash, idx, key, val);       \
443
             break;                                   \
444
        }                                             \
445
        if (cmp_fun(kvs[idx], key)){                  \
446
            PHUPD_UPDATE__(xhash, idx, key, val);     \
447
            break;                                    \
448
        }                                             \
449
                                                      \
450
        again: __attribute__((unused))                \
451
        INCSTAT(xhash->bounces);                      \
452
        idx = ((idx<<2) + idx + 1 + perturb) & mask;  \
453
        perturb >>= PERTURB_SHIFT;                    \
454
    }                                                 \
455
}
456

    
457
static inline void
458
set_val(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
459
{
460
    xhashidx *kvs = xhash_kvs(p);
461
    xhashidx *vals = xhash_vals(p);
462
    kvs[idx] = key;
463
    vals[idx] = val;
464
    //XSEGLOG("Seting idx %llu to key: %lx, val: %lx", idx, key, val);
465
}
466

    
467
void static inline xhash_upd_set(xhash_t *p, xhashidx idx, xhashidx key, xhashidx val)
468
{
469
    xhashidx *kvs = xhash_kvs(p);
470
    xhashidx *vals = xhash_vals(p);
471
    if (item_dummy(p, idx, true))
472
        p->dummies--;
473
    p->used++;
474
    kvs[idx] = key;
475
    vals[idx] = val;
476
    //XSEGLOG("Seting idx %llu to key: %lx, val: %lx", idx, key, val);
477
}
478

    
479
static inline void
480
inc_val(xhash_t *p, xhashidx idx, xhashidx val)
481
{
482
    xhashidx *vals = xhash_vals(p);
483
    vals[idx] += val;
484
}
485

    
486
void xhash_insert__(struct xhash *xhash, xhashidx key, xhashidx val)
487
{
488
    //XSEGLOG("inserting %lx", key);
489
    //fprintf(stderr, "insert: (%lu,%lu)\n", key, val);
490
    #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
491
    #define PHUPD_SET__(_p, _i, _k, _v)    xhash_upd_set(_p, _i, _k, _v)
492
    PHASH_UPDATE(xhash, key, val, true)
493
    #undef PHUPD_UPDATE__
494
    #undef PHUPD_SET__
495
}
496

    
497
int xhash_insert(struct xhash *xhash, xhashidx key, xhashidx val)
498
{
499
    if (xhash->limit && xhash->used >= xhash->limit)
500
        return -XHASH_ENOSPC;
501
    if (grow_check(xhash))
502
        return -XHASH_ERESIZE;
503
    xhash_insert__(xhash, key, val);
504
    return 0;
505
}
506

    
507

    
508
void xhash_freql_update__(struct xhash *xhash, xhashidx key, xhashidx val)
509
{
510
    #define PHUPD_UPDATE__(_p, _i, _k, _v) inc_val(_p, _i, _v)
511
    #define PHUPD_SET__(_p, _i, _k, _v)    xhash_upd_set(_p, _i, _k, _v)
512
    PHASH_UPDATE(xhash, key, val, true)
513
    #undef PHUPD_UPDATE__
514
    #undef PHUPD_SET__
515
}
516

    
517
int xhash_freql_update(struct xhash *xhash, xhashidx key, xhashidx val)
518
{
519
    if (grow_check(xhash))
520
        return -XHASH_ERESIZE;
521
    xhash_freql_update__(xhash, key, val);
522
    return 0;
523
}
524

    
525
xhash_t *
526
xhash_resize(xhash_t *xhash, xhashidx new_size_shift, xhashidx new_limit,
527
                xhash_t *new)
528
{
529
    //XSEGLOG("Resizing xhash from %llu to %llu", xhash->size_shift, new_size_shift);
530
    xhashidx i;
531
    int f = !!new;
532
    if (!f)
533
        new = xhash_new__(new_size_shift, xhash->minsize_shift, new_limit,
534
                                xhash->type, true);
535
    else
536
        xhash_init__(new, new_size_shift, xhash->minsize_shift, new_limit,
537
                                xhash->type, true);
538

    
539
    if (!new)
540
            return NULL;
541
        
542
    //fprintf(stderr, "resizing: (%lu,%lu,%lu)\n", xhash->size_shift, xhash->used, xhash->dummies);
543
    for (i = 0; i < xhash_size(xhash); i++) {
544
        if (item_valid(xhash, i, true)){
545
            //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
546
            xhash_insert__(new, *(xhash_kvs(xhash) + i), *(xhash_vals(xhash) + i));
547
        }
548
    }
549

    
550
    if (!f)
551
        xtypes_free(xhash);
552
    return new;
553
}
554

    
555
/*
556
 * note that his function does not modify the internal structure of the hash
557
 * and thus its safe to use it for updating values during a xhash_iterate()
558
 */
559
int xhash_update(struct xhash *xhash, xhashidx key, xhashidx val) {
560

    
561
    //fprintf(stderr, "update: (%lu,%lu)\n", key, val);
562
    #define PHUPD_UPDATE__(_p, _i, _k, _v) set_val(_p, _i, _k, _v)
563
    #define PHUPD_SET__(_p, _i, _k, _v)    goto again
564
    PHASH_UPDATE(xhash, key, val, true)
565
    #undef PHUPD_UPDATE__
566
    #undef PHUPD_SET__
567

    
568
    return 1;
569
}
570

    
571

    
572
int xhash_delete(struct xhash *xhash, xhashidx key)
573
{
574
    if (shrink_check(xhash))
575
            return -XHASH_ERESIZE;
576
    return xhash_delete__(xhash, key, true);
577
}
578

    
579
int xhash_lookup__(xhash_t *xhash, xhashidx key, xhashidx *idx_ret, bool vals)
580
{
581
    //XSEGLOG("looking up %lx", key);
582
    xhash_cmp_fun_t cmp_fun = types_fun[xhash->type].cmp_fun;
583
    xhash_hash_fun_t hash_fun = types_fun[xhash->type].hash_fun; 
584
    xhashidx size_shift = xhash->size_shift;
585
    xhashidx size = (1UL)<<size_shift;
586
    xhashidx perturb = hash_fun(key);
587
    xhashidx mask = size-1;
588
    xhashidx idx = hash_fun(key) & mask;
589
    xhashidx *kvs = xhash_kvs(xhash);
590

    
591
    INCSTAT(xhash->lookups);
592
    for (;;) {
593
        //XSEGLOG("size %llu, perturb %llu idx %llu mask %llu",
594
        //            size, perturb, idx, mask);                
595
        if ( item_unused(xhash, idx, vals) )
596
            return -XHASH_EEXIST;
597

    
598
        if ( !item_dummy(xhash, idx, vals) && cmp_fun(kvs[idx],key)){
599
            *idx_ret = idx;
600
            return 0;
601
        }
602

    
603
        INCSTAT(xhash->bounces);
604
        idx = ((idx<<2) + idx + 1 + perturb) & mask;
605
        perturb >>= PERTURB_SHIFT;
606
    }
607
}
608

    
609
int xhash_lookup(struct xhash *xhash, xhashidx key, xhashidx *val)
610
{
611
    xhashidx idx;
612
    int ret = xhash_lookup__(xhash, key, &idx, true);
613
    if (ret == 0) {
614
        xhashidx *values = xhash_vals(xhash);
615
        *val = values[idx];
616
    }
617
    return ret;
618
}
619

    
620
//FIXME iteration broken
621
void
622
xhash_iter_init(xhash_t *xhash, xhash_iter_t *pi)
623
{
624
    pi->cnt = pi->loc = 0;
625
}
626

    
627
int
628
xhash_iterate__(xhash_t *xhash, bool vals,
629
                xhash_iter_t *pi, xhashidx *key_ret,  xhashidx *idx_ret)
630
{
631
    xhashidx idx = pi->loc;
632
    xhashidx size = (xhashidx)1<<xhash->size_shift;
633
    xhashidx *kvs = xhash_kvs(xhash);
634
    INCSTAT(xhash->lookups);
635
    for (;;){
636
        if (xhash->used == pi->cnt || idx >= size)
637
            return 0;
638

    
639
        if (item_valid(xhash, idx, vals)){
640
            *key_ret = kvs[idx];
641
            *idx_ret = idx++;
642
            pi->loc = idx;
643
            pi->cnt++;
644
            return 1;
645
        }
646

    
647
        idx++;
648
    }
649
}
650

    
651
int xhash_iterate(xhash_t *xhash, xhash_iter_t *pi, xhashidx *key, xhashidx *val)
652
{
653
    xhashidx idx;
654
    int ret = xhash_iterate__(xhash, true, pi, key, &idx);
655
    if (ret) {
656
        xhashidx *vals = xhash_vals(xhash);
657
        *val = vals[idx];
658
    }
659
    return ret;
660
}
661

    
662
void xhash_print(xhash_t *xhash)
663
{
664
    xhashidx key, val;
665
    xhash_iter_t pi;
666
    int ret;
667

    
668
    xhash_iter_init(xhash, &pi);
669
    XSEGLOG("PHASH(%p):\n", xhash);
670
    for (;;){
671
        ret = xhash_iterate(xhash, &pi, &key, &val);
672
        if (!ret){
673
            break;
674
        }
675
        XSEGLOG(" 0x%017lx : 0x%017lx\n", key, val);
676
    }
677
    XSEGLOG("\n");
678
}
679

    
680
#ifdef PHASH_MAIN
681
#define BUFLEN 1024
682
void help()
683
{
684
    printf("Help:\n"
685
           "  insert : I <key> <val> \n"
686
           "  update : U <key> <val> (->v += val if exists) \n"
687
           "  get    : G <key>       \n"
688
           "  delete : D <key>       \n"
689
           "  size   : S             \n"
690
           "  print  : P             \n");
691
}
692

    
693
int main(int argc, char **argv)
694
{
695
    struct xhash *ph;
696
    char *s, buf[BUFLEN];
697
    xhashidx key, val;
698
    int ret;
699

    
700
    ph = xhash_new(2, INTEGER);
701

    
702
    for (;;){
703
        s = fgets(buf, BUFLEN-1, stdin);
704
        if (s == NULL){
705
            break;
706
        }
707

    
708
        switch (*s) {
709
            case 'I':
710
            ret = sscanf(s+1, "%lu %lu", &key, &val);
711
            if (ret == 2){
712
                xhash_insert(ph, key, val);
713
            }
714
            break;
715

    
716
            case 'U':
717
            ret = sscanf(s+1, "%lu %lu", &key, &val);
718
            if (ret == 2){
719
                xhash_freql_update(ph, key, val);
720
            }
721
            break;
722

    
723
            case 'G':
724
            ret = sscanf(s+1, "%lu", &key);
725
            if (ret == 1){
726
                ret = xhash_lookup(ph, key, &val);
727
                if (ret){
728
                    printf("%lu\n", val);
729
                } else {
730
                    printf("<None>\n");
731
                }
732
            }
733
            break;
734

    
735
            case 'D':
736
            ret = sscanf(s+1, "%lu", &key);
737
            if (ret == 1){
738
                xhash_delete(ph, key);
739
            }
740
            break;
741

    
742
            case 'S':
743
            printf("%lu\n", xhash_elements(ph));
744
            break;
745

    
746
            case 'P':
747
            xhash_print(ph);
748
            break;
749

    
750
            case '#':
751
            break;
752

    
753
            default:
754
            help();
755
            break;
756

    
757
        }
758
        fflush(stdout);
759
    }
760

    
761
    xhash_free(ph);
762
    return 0;
763
}
764
#endif
765

    
766
#if 0
767
/**
768
 * Pset functions
769
 */
770
pset_t *
771
pset_new(xhashidx minsize_shift)
772
{
773
    pset_t *pset;
774
    pset = malloc(sizeof(pset_t));
775
    if (!pset) {
776
        perror("malloc");
777
        exit(1);
778
    }
779
    xhash_init__(&pset->ph_, minsize_shift, false);
780
    return pset;
781
}
782

783
void
784
pset_init(pset_t *pset, xhashidx minsize_shift)
785
{
786
    xhash_init__(&pset->ph_, minsize_shift, false);
787
}
788

789
void
790
pset_free(pset_t *pset)
791
{
792
    xhash_tfree(&pset->ph_);
793
    free(pset);
794
}
795

796
void
797
pset_tfree(pset_t *pset)
798
{
799
    xhash_tfree(&pset->ph_);
800
}
801

802
void
803
pset_resize(pset_t *pset, xhashidx new_size_shift)
804
{
805
    pset_t  old;
806
    xhash_cp(&(old.ph_), &pset->ph_);
807

808
    xhash_resize__(&pset->ph_, new_size_shift, false);
809
    for (xhashidx i = 0; i < pset_size(&old); i++) {
810
        if (item_valid(&(old.ph_), i, false)){
811
            //fprintf(stderr, "rs: inserting (%lu,%lu)\n", item->k, item->v);
812
            pset_insert(pset, old.ph_.kvs[i]);
813
        }
814
    }
815
    free(old.ph_.kvs);
816
}
817

818
void
819
pset_grow(pset_t *pset)
820
{
821
    xhashidx new_size_shift = grow_size_shift(&pset->ph_);
822
    pset_resize(pset, new_size_shift);
823
}
824

825
static inline void
826
pset_grow_check(pset_t *pset)
827
{
828
    if (grow_check(&pset->ph_))
829
        pset_grow(pset);
830
}
831

832
void static inline pset_upd_set(xhash_t *p, xhashidx idx, xhashidx key)
833
{
834
    if (item_dummy(p, idx, false))
835
        p->dummies--;
836
    p->used++;
837
    p->kvs[idx] = key;
838
}
839

840
void pset_insert(pset_t *pset, xhashidx key)
841
{
842
    xhash_t *ph = &pset->ph_;
843
    assert_key(key);
844
    pset_grow_check(pset);
845
    #define PHUPD_UPDATE__(_p, _i, _k, _v) do { } while (0)
846
    #define PHUPD_SET__(_p, _i, _k, _v) pset_upd_set(_p, _i, _k)
847
    PHASH_UPDATE(ph, key, 0xdeadbabe, false)
848
    #undef PHUPD_UPDATE__
849
    #undef PHUPD_SET__
850
}
851

852
void
853
pset_shrink(pset_t *pset)
854
{
855
    xhashidx new_size_shift = shrink_size_shift(&pset->ph_);
856
    pset_resize(pset, new_size_shift);
857
}
858

859
int pset_delete(pset_t *pset, xhashidx key)
860
{
861
    if (pset->ph_.used == 0)
862
        return false;
863

864
    assert_key(key);
865
    xhashidx size_shift = pset->ph_.size_shift;
866
    xhashidx size = (xhashidx)1<<size_shift;
867
    xhashidx u = pset->ph_.used;
868
    if (4*u < size)
869
        pset_shrink(pset);
870
    return xhash_delete__(&pset->ph_, key, false);
871
}
872

873
bool pset_lookup(pset_t *pset, xhashidx key)
874
{
875
    xhashidx idx;
876
    return !!xhash_lookup__(&pset->ph_, key, &idx, false);
877
}
878

879
int pset_iterate(pset_t *pset, xhash_iter_t *pi, xhashidx *key)
880
{
881
    xhashidx idx;
882
    int ret = xhash_iterate__(&pset->ph_, false, pi, key, &idx);
883
    return ret;
884
}
885

886
void pset_print(pset_t *pset)
887
{
888
    xhashidx key;
889
    int ret;
890
    pset_iter_t pi;
891

892
    pset_iter_init(pset, &pi);
893
    printf("PSET(%p):\n", pset);
894
    for (;;){
895
        ret = pset_iterate(pset, &pi, &key);
896
        if (!ret){
897
            break;
898
        }
899
        printf(" 0x%017lx\n", key);
900
    }
901
    printf("\n");
902
}
903

904
#if defined(PSET_MAIN)
905
#define BUFLEN 1024
906
void help()
907
{
908
    printf("Help:\n"
909
           "  insert : I <key> <val> \n"
910
           "  get    : G <key>       \n"
911
           "  delete : D <key>       \n"
912
           "  size   : S             \n"
913
           "  print  : P             \n");
914
}
915

916
int main(int argc, char **argv)
917
{
918
    pset_t *ps;
919
    char *s, buf[BUFLEN];
920
    xhashidx key;
921
    int ret;
922

923
    ps = pset_new(2);
924

925
    for (;;){
926
        s = fgets(buf, BUFLEN-1, stdin);
927
        if (s == NULL){
928
            break;
929
        }
930

931
        switch (*s) {
932
            case 'I':
933
            ret = sscanf(s+1, "%lu", &key);
934
            if (ret == 1){
935
                pset_insert(ps, key);
936
            }
937
            break;
938

939
            case 'G':
940
            ret = sscanf(s+1, "%lu", &key);
941
            if (ret == 1){
942
                ret = pset_lookup(ps, key);
943
                printf("%lu -> %s\n", key, ret ? "true" : "false");
944
            }
945
            break;
946

947
            case 'D':
948
            ret = sscanf(s+1, "%lu", &key);
949
            if (ret == 1){
950
                pset_delete(ps, key);
951
            }
952
            break;
953

954
            case 'S':
955
            printf("%lu\n", pset_elements(ps));
956
            break;
957

958
            case 'P':
959
            pset_print(ps);
960
            break;
961

962
            case '#':
963
            break;
964

965
            default:
966
            help();
967
            break;
968

969
        }
970
        fflush(stdout);
971
    }
972

973
    pset_free(ps);
974
    return 0;
975
}
976
#endif
977

    
978
#endif //if 0
979

    
980
#ifdef __KERNEL__
981
#include <linux/module.h>
982
#include <xtypes/xhash_exports.h>
983
#endif
984

    
985
// vim:expandtab:tabstop=8:shiftwidth=4:softtabstop=4