This article was reproduced from: http://segmentfault.com/blog/tree/1190000000718519
Hashtable is a very important data structure for PHP. Many of the internal implementations of PHP (variable scope, function table, class properties, methods, arrays) are implemented by Hashtable. Recently learned the implementation of PHP bottom Hashtable.
PHP bottom Hashtable implementation has two very important structures are: hashtable and buckets.
Let's talk about the hashtable structure:
The underlying implementation code for Hashtable is as follows:
typedef struct _hashtable{
UINT ntablesize; //hash bucket size, minimum of 8
UINT ntablemask; //ntablesize-1, optimization of index value
Total number of uint nnumofelements//buckets stored
ULONG nnextfreeelement //position of the next numeric index
Bucket *pinternalpointer //Current traversed pointer (the reason for the foreach to be faster)
Bucket *plisthead //head pointer for entire Hashtable
Bucket *plisttail //tail hands of the entire Hashtable
Bucket **argbuckets //buceket array, used to store data
doctor_func_t pdestructor //Delete element callback function for resource release
Zend_bool Persistent //bucket memory allocation method, true use the system's allocation function, false use PHP's memory allocation function
unsigned char napplycount //mark the number of times the current hash bucket is recursive
Zend_bool bapplyprotection
#If zend_debug
int Inconsistent
#EndIf
}hashtable
It is suggested that the students who do not understand the hash data structure should understand the hash structures briefly.
Simply say the initialization of Hashtable in PHP:
The code is as follows:
Zend_api int _zend_hash_init (HashTable *ht, uint nSize, hash_func_t phashfunction, dtor_func_t pdestructor, Zend_bool per Sistent zend_file_line_dc)
{
UINT i = 3;
//...
if (nSize >= 0x80000000) {
/ * Prevent overflow * /
Ht->ntablesize = 0x80000000;
} Else {
while ((1U << i) < nSize) {
i++;
}
Ht->ntablesize = 1 << i;
}
// ...
Ht->ntablemask = ht->ntablesize- 1;
/* Uses ecalloc () so, bucket* = = NULL */
if (persistent) {
TMP = (Bucket * *) calloc (ht->ntablesize, sizeof (bucket *));
if (!tmp) {
return FAILURE;
}
Ht->arbuckets = tmp;
} Else {
TMP = (Bucket * *) Ecalloc_rel (ht->ntablesize, sizeof (bucket *));
if (TMP) {
Ht->arbuckets = tmp;
}
}
return SUCCESS;
}
The first thing to judge is whether the hashtable size that needs to be initialized exceeds the maximum size that the system can use. Here is a handle to the size of the tablesize. Change the user-defined size to the size you want. For example, if the user-defined Hashtable size is 6, then the initialization will change 6 to 8, if the user-defined size is 11, then the initialized hashtable size is 16.
The following is a simple judgment to decide whether to allocate memory according to the memory function allocated by the C language itself, or to allocate memory based on the memory allocation function that PHP encapsulates.
Let's talk about the structure of the bucket.
typedef struct bucket{
ulong H; //After the key index value, the number key does not do Kash
UINT nkeylength; Length of//key
void *pdata;
void *pdataptr; //Pointer data, pointing to real data
struct bucket * plistnext; //The next element of the entire hash table
struct bucket *plistlast; //The last element of the entire hash table
struct bucket *pnext; //Inside the bucket, the next element
struct bucket *plast; //The previous element inside the bucket
Char arkey[1];
}bucket
Here is a very hot map on the network (the original address is not found, did not do source description):
The following is a reference to the insert instructions inside the tipi:
Reference address:tipi
The assumption in the lower-left corner assumes that the Bucket1,bucket2,bucket3 three elements are inserted sequentially:
1. When inserting Bucket1, the hash table is empty and the hash is positioned to the slot with index 1. At this point the 1 slots have only one element Bucket1. Where Bucket1 's pdata or pdataptr points to the data stored by BUCKET1. This is because there is no link relationship. Pnext, the Plast,plistnext,plistlast pointer is empty. The first element pointer of the entire hash table and the last element pointer are also preserved in the Hashtable structure, at which point the plisthead and plisttail pointers of the Hashtable are pointed to Bucket1.
2, insert Bucket2, because Bucket2 key and Bucket1 key conflict, this time will Bucket2 placed in front of the double-linked list. Since Bucket2 is inserted and placed at the front end of the list, Bucket2.pnext points to Bucket1, which is inserted after Bucket2. Bucket1.plistnext points to Bucket2, and Bucket2 is the last element of the hash table, which is hashtable.plisttail points to Bucket2. \3, insert Bucket3, the key is not hashed to slot 1, then bucket2.plistnext points to Bucket3, because Bucket3 is inserted after. At the same time Hashtable.plisttail to point to Bucket3.
Simply put, the bucket structure of the hash table maintains the order of the inserted elements in the Hashtable, and the Hashtable structure maintains the head and tail of the entire Hashtable. The relationship between budgets is always maintained during the operation of the hash table.
Implementation of PHP bottom Hashtable