File: hash.c

package info (click to toggle)
libr3 1.3.4-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster, stretch
  • size: 1,084 kB
  • ctags: 1,086
  • sloc: ansic: 13,117; cpp: 175; makefile: 112; sh: 64; ruby: 52
file content (110 lines) | stat: -rw-r--r-- 3,318 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

#include "hash.h"

HashTable * zend_hash_clone_persistent(HashTable* src TSRMLS_DC)
{
    zval **tmp;
    return my_copy_hashtable(NULL, src, (ht_copy_fun_t) my_copy_zval_ptr, (void*) &tmp, sizeof(zval *), 1 TSRMLS_CC);
}

HashTable * zend_hash_clone(HashTable* src TSRMLS_DC)
{
    zval **tmp;
    return my_copy_hashtable(NULL, src, (ht_copy_fun_t) my_copy_zval_ptr, (void*) &tmp, sizeof(zval *), 0 TSRMLS_CC);
}


/**
 * Recursively copy hash and all its value.
 *
 * This replaces zend_hash_copy
 */
HashTable * my_copy_hashtable(HashTable *target, HashTable *source, ht_copy_fun_t copy_fn, void *tmp, uint size, int persistent TSRMLS_DC)
{
    Bucket *curr = NULL, *prev = NULL , *newp = NULL;
    void *new_entry;
    int first = 1;

    assert(source != NULL);

    // allocate persistent memory for target and initialize it.
    if (!target) {
        target = pemalloc(sizeof(source[0]), persistent);
    }
    memcpy(target, source, sizeof(source[0]));
    target->arBuckets = pemalloc(target->nTableSize * sizeof(Bucket*), persistent);

    memset(target->arBuckets, 0, target->nTableSize * sizeof(Bucket*));
    target->pInternalPointer = NULL;
    target->pListHead = NULL;

    // since it's persistent, destructor should be NULL
    target->persistent = persistent;

    if (! target->persistent) {
        target->pDestructor = ZVAL_PTR_DTOR;
    }

    curr = source->pListHead;
    while (curr) {
        // hash index
        int n = curr->h % target->nTableSize;

        // allocate new bucket
// from apc
#ifdef ZEND_ENGINE_2_4
        if (!curr->nKeyLength) {
            newp = (Bucket*) pemalloc(sizeof(Bucket), persistent);
            memcpy(newp, curr, sizeof(Bucket));
        } else if (IS_INTERNED(curr->arKey)) {
            newp = (Bucket*) pemalloc(sizeof(Bucket), persistent);
            memcpy(newp, curr, sizeof(Bucket));
        } else {
            // ugly but we need to copy
            newp = (Bucket*) pemalloc(sizeof(Bucket) + curr->nKeyLength, persistent);
            memcpy(newp, curr, sizeof(Bucket) + curr->nKeyLength );
            newp->arKey = (const char*)(newp+1);
        }
#else
        newp = (Bucket*) pecalloc(1, (sizeof(Bucket) + curr->nKeyLength - 1), persistent);
        memcpy(newp, curr, sizeof(Bucket) + curr->nKeyLength - 1);
#endif


        /* insert 'newp' into the linked list at its hashed index */
        if (target->arBuckets[n]) {
            newp->pNext = target->arBuckets[n];
            newp->pLast = NULL;
            newp->pNext->pLast = newp;
        } else {
            newp->pNext = newp->pLast = NULL;
        }
        target->arBuckets[n] = newp;

        // now we copy the bucket data using our 'copy_fn'
        newp->pData = copy_fn(NULL, curr->pData, persistent TSRMLS_CC);
        memcpy(&newp->pDataPtr, newp->pData, sizeof(void*));

        /* insert 'newp' into the table-thread linked list */
        newp->pListLast = prev;
        newp->pListNext = NULL;

        if (prev) {
            prev->pListNext = newp;
        }
        if (first) {
            target->pListHead = newp;
            first = 0;
        }
        prev = newp;

        curr = curr->pListNext;
    }

    target->pListTail = newp;
    zend_hash_internal_pointer_reset(target);

    // return the newly allocated memory
    return target;
}