/* Pop a key from dict, NULL on not found. */ void * dict_ipop(struct dict *dict, char *key, size_t len) { assert(dict != NULL); size_t index = dict_table_idx(dict->idx, key, len); struct dict_node *node = (dict->table)[index]; struct dict_node *prev = NULL; while (node != NULL) { if (dict_key_equals(node->key, node->len, key, len)) { if (prev == NULL) { (dict->table)[index] = node->next; } else { prev->next = node->next; } void *val = node->val; dict_node_free(node); dict->len -= 1; return val; } prev = node; node = node->next; } return NULL; }
/* Resize and rehash dict. */ int dict_resize(struct dict *dict) { assert(dict != NULL && dict->idx <= dict_idx_max); size_t new_idx = dict->idx + 1; if (new_idx > dict_idx_max) return DICT_ENOMEM; size_t new_table_size = dict_table_sizes[new_idx]; struct dict_node **new_table = malloc( new_table_size * sizeof(struct dict_node *)); /* init table to all NULL */ size_t index; for (index = 0; index < new_table_size; index++) new_table[index] = NULL; size_t table_size = dict_table_sizes[dict->idx]; for (index = 0; index < table_size; index++) { struct dict_node *node = (dict->table)[index]; while (node != NULL) { struct dict_node *new_node = dict_node_new( node->key, node->len, node->val); if (new_node == NULL) return DICT_ENOMEM; size_t new_index = dict_table_idx( new_idx, new_node->key, new_node->len); struct dict_node *cursor = new_table[new_index]; if (cursor == NULL) { /* set as head node */ new_table[new_index] = new_node; } else { while (cursor->next != NULL) cursor = cursor->next; /* set as last node */ cursor->next = new_node; } /* shift next */ struct dict_node *next = node->next; dict_node_free(node); node = next; } } free(dict->table); dict->table = new_table; dict->idx = new_idx; return DICT_OK; }
/* Test if a key is in dict. */ int dict_ihas(struct dict *dict, char *key, size_t len) { assert(dict != NULL); size_t index = dict_table_idx(dict->idx, key, len); struct dict_node *node = (dict->table)[index]; while (node != NULL) { if (dict_key_equals(node->key, node->len, key, len)) return 1; node = node->next; } return 0; }
/* Set a key into dict. */ int dict_iset(struct dict *dict, char *key, size_t len, void *val) { assert(dict != NULL); if ((dict_table_sizes[dict->idx] * DICT_LOAD_LIMIT < dict->len + 1) && dict_resize(dict) != DICT_OK) return DICT_ENOMEM; size_t index = dict_table_idx(dict->idx, key, len); struct dict_node *node = (dict->table)[index]; /* try to find this key. */ while (node != NULL) { if (dict_key_equals(node->key, node->len, key, len)) { node->key = key; node->len = len; node->val = val; return DICT_OK; } node = node->next; } /* create node if not found */ struct dict_node *new_node = dict_node_new(key, len, val); if (new_node == NULL) return DICT_ENOMEM; /* rewind to list head */ node = (dict->table)[index]; if (node == NULL) { /* if list is empty, set as head node */ (dict->table)[index] = new_node; } else { /* else append as tail node */ while (node->next != NULL) node = node->next; node->next = new_node; } dict->len += 1; return DICT_OK; }