Browse Source

Add hash_table_remove(); pass callback func in constructor.

master
Ben Kurtovic 9 years ago
parent
commit
2b5b7d8b23
3 changed files with 79 additions and 35 deletions
  1. +47
    -8
      src/assembler/hash_table.c
  2. +10
    -6
      src/assembler/hash_table.h
  3. +22
    -21
      src/assembler/state.c

+ 47
- 8
src/assembler/hash_table.c View File

@@ -36,8 +36,21 @@ static inline size_t hash_key(const HashTable *table, const char *key)

/*
Create and return a new HashTable.

These HashTables are designed to be generic, a sort of poor-man's C++
template. They can store any kind of node data as long as they are structs
with a char* field (for the node key), and a pointer to its own type (to
implement separate chaining).

key_offset is the (byte) offset of the key field, and next_offset is the
offset of the self-pointer. The callback function is called on a node when
it is removed from the table. Typically, it should free() the node's
members and then free() the node itself.

The hash_table_NEW macro can be used to call this function more easily.
*/
HashTable* hash_table_new(size_t key_offset, size_t next_offset)
HashTable* hash_table_new(
size_t key_offset, size_t next_offset, HashFreeCallback callback)
{
HashTable *table;
if (!(table = malloc(sizeof(HashTable))))
@@ -49,17 +62,14 @@ HashTable* hash_table_new(size_t key_offset, size_t next_offset)
table->buckets = INITIAL_BUCKETS;
table->key_offset = key_offset;
table->next_offset = next_offset;
table->free = callback;
return table;
}

/*
Deallocate a HashTable. This function does nothing if the table is NULL.

The given callback function is called on each node as it is removed from
the table. Typically, it will free() the node's members and then free()
the node itself.
*/
void hash_table_free(HashTable *table, HashFreeCallback callback)
void hash_table_free(HashTable *table)
{
if (!table)
return;
@@ -68,7 +78,7 @@ void hash_table_free(HashTable *table, HashFreeCallback callback)
HashNode *node = table->nodes[bucket];
while (node) {
HashNode *temp = NEXT_NODE(table, node);
callback(node);
table->free(node);
node = temp;
}
}
@@ -94,7 +104,10 @@ const HashNode* hash_table_find(const HashTable *table, const char *key)
/*
Insert a node into the table.

This doesn't check for duplicate keys, so you must do that beforehand.
This doesn't prevent inserting duplicate keys. If a duplicate key is
inserted, the table acts like a stack; the new one will shadow the old one,
and hash_table_remove() will remove the most-recently inserted key to
reveal the second-most recent.
*/
void hash_table_insert(HashTable *table, HashNode *node)
{
@@ -102,3 +115,29 @@ void hash_table_insert(HashTable *table, HashNode *node)
NEXT_NODE(table, node) = table->nodes[index];
table->nodes[index] = node;
}

/*
(Try to) remove a node with the given key from the table.

Return true if the node was removed, or false if it was not found.
*/
bool hash_table_remove(HashTable *table, const char *key)
{
size_t index = hash_key(table, key);
HashNode *node = table->nodes[index], *prev = NULL, *next;

while (node) {
next = NEXT_NODE(table, node);
if (!strcmp(key, NODE_KEY(table, node))) {
if (prev)
NEXT_NODE(table, prev) = next;
else
table->nodes[index] = next;
table->free(node);
return true;
}
prev = node;
node = next;
}
return false;
}

+ 10
- 6
src/assembler/hash_table.h View File

@@ -3,27 +3,31 @@

#pragma once

#include <stdbool.h>
#include <stddef.h>

#define hash_table_NEW(node, key, next) \
hash_table_new(offsetof(node, key), offsetof(node, next))
#define hash_table_NEW(node, key, next, callback) \
hash_table_new(offsetof(node, key), offsetof(node, next), \
(HashFreeCallback) callback)

/* Structs */

typedef struct HashNode HashNode;

typedef void (*HashFreeCallback)(HashNode*);

typedef struct {
HashNode **nodes;
size_t buckets;
size_t key_offset;
size_t next_offset;
HashFreeCallback free;
} HashTable;

typedef void (*HashFreeCallback)(HashNode*);

/* Functions */

HashTable* hash_table_new(size_t, size_t);
void hash_table_free(HashTable*, HashFreeCallback);
HashTable* hash_table_new(size_t, size_t, HashFreeCallback);
void hash_table_free(HashTable*);
const HashNode* hash_table_find(const HashTable*, const char*);
void hash_table_insert(HashTable*, HashNode*);
bool hash_table_remove(HashTable*, const char*);

+ 22
- 21
src/assembler/state.c View File

@@ -41,11 +41,29 @@ void state_free(AssemblerState *state)
}

/*
Callback function for freeing an ASMSymbol.
*/
static void free_asm_symbol(ASMSymbol *node)
{
free(node->symbol);
free(node);
}

/*
Initialize an ASMSymbolTable and place it in *symtable_ptr.
*/
void asm_symtable_init(ASMSymbolTable **symtable_ptr)
{
*symtable_ptr = hash_table_NEW(ASMSymbol, symbol, next);
*symtable_ptr = hash_table_NEW(ASMSymbol, symbol, next, free_asm_symbol);
}

/*
Callback function for freeing an ASMDefine.
*/
static void free_asm_define(ASMDefine *node)
{
free(node->name);
free(node);
}

/*
@@ -53,7 +71,7 @@ void asm_symtable_init(ASMSymbolTable **symtable_ptr)
*/
ASMDefineTable* asm_deftable_new()
{
return hash_table_NEW(ASMDefine, name, next);
return hash_table_NEW(ASMDefine, name, next, free_asm_define);
}

/*
@@ -110,37 +128,20 @@ void asm_data_free(ASMData *data)
}

/*
Callback function for freeing an ASMSymbol.
*/
static void free_asm_symbol(HashNode *node)
{
free(((ASMSymbol*) node)->symbol);
free(node);
}

/*
Deallocate an ASMSymbolTable.
*/
void asm_symtable_free(ASMSymbolTable *symtable)
{
hash_table_free(symtable, free_asm_symbol);
hash_table_free(symtable);
}

/*
Callback function for freeing an ASMDefine.
*/
static void free_asm_define(HashNode *node)
{
free(((ASMDefine*) node)->name);
free(node);
}

/*
Deallocate an ASMDefineTable.
*/
void asm_deftable_free(ASMDefineTable *deftable)
{
hash_table_free(deftable, free_asm_define);
hash_table_free(deftable);
}

/*


Loading…
Cancel
Save