-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added a dictionary abstract data type. Currently it's implemented as
Estimated hours taken: 2 Added a dictionary abstract data type. Currently it's implemented as a dirt-simple ordered list, but it should later be reimplemented using a hash table. Note that C has only very poor support for ADTs and private data must be included in the header. We trust clients of the ADT not to use the private data. bytecode/dict.h: Interface of dictionary ADT. bytecode/dict.c: Implementation of dictionary ADT.
- Loading branch information
Bert Thompson
committed
May 28, 1997
1 parent
7f1d65c
commit 06454f7
Showing
2 changed files
with
244 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
|
||
/* | ||
** Copyright (C) 1997 University of Melbourne. | ||
** This file may only be copied under the terms of the GNU Library General | ||
** Public License - see the file COPYING.LIB in the Mercury distribution. | ||
** | ||
** $Id: dict.c,v 1.1 1997-05-28 05:58:55 aet Exp $ | ||
*/ | ||
|
||
/* Imports */ | ||
#include <stdlib.h> | ||
#include <unistd.h> | ||
#include <assert.h> | ||
|
||
#include "mem.h" | ||
#include "util.h" | ||
|
||
#include "dict.h" | ||
|
||
/* Exported definitions */ | ||
|
||
/* Local declarations */ | ||
|
||
static char | ||
rcs_id[] = "$Id: dict.c,v 1.1 1997-05-28 05:58:55 aet Exp $"; | ||
|
||
static p_Dict_Item * | ||
insert(KeyComparison cmp, void *key, void *val, p_Dict_Item *items); | ||
|
||
static MB_Bool | ||
lookup(KeyComparison cmp, void *key, p_Dict_Item *items, void **val_p); | ||
|
||
static p_Dict_Item * | ||
delete(KeyComparison cmp, void *key, p_Dict_Item *items); | ||
|
||
static p_Dict_Item * | ||
new_item_p(void *key, void *val, p_Dict_Item* next); | ||
|
||
/* Implementation */ | ||
|
||
/* | ||
** XXX: Yes, this implementation is hopelessly inefficient. | ||
** I'll replace it with a hash table when things are working. | ||
*/ | ||
|
||
Dict | ||
dict_new(KeyComparison key_cmp) | ||
{ | ||
Dict *new_dict_p; | ||
|
||
new_dict_p = (Dict*) MB_malloc(sizeof(Dict)); | ||
|
||
new_dict_p->p_key_cmp = key_cmp; | ||
new_dict_p->p_items = NULL; | ||
|
||
return *new_dict_p; | ||
} | ||
|
||
void | ||
dict_insert(void *key, void *val, Dict *dict_p) | ||
{ | ||
assert(dict_p != NULL); | ||
assert(dict_p->p_key_cmp != NULL); | ||
|
||
dict_p->p_items = insert(dict_p->p_key_cmp, key, val, dict_p->p_items); | ||
} | ||
|
||
/* | ||
** Insert items in ascending order sorted on keys. | ||
*/ | ||
static p_Dict_Item * | ||
insert(KeyComparison cmp, void *key, void *val, p_Dict_Item *items) | ||
{ | ||
if (items == NULL) { | ||
return new_item_p(key, val, NULL); | ||
} else if (cmp(key, items->p_key) < 0) { | ||
return new_item_p(key, val, items); | ||
} else if (cmp(key, items->p_key) > 0) { | ||
items->p_next = insert(cmp, key, val, items->p_next); | ||
return items; | ||
} else { /* keys are same */ | ||
items->p_val = val; | ||
return items; | ||
} | ||
} | ||
|
||
MB_Bool | ||
dict_lookup(void *key, Dict dict, void **val_p) | ||
{ | ||
assert (dict.p_key_cmp != NULL); | ||
return lookup(dict.p_key_cmp, key, dict.p_items, val_p); | ||
} | ||
|
||
static MB_Bool | ||
lookup(KeyComparison cmp, void *key, p_Dict_Item *items, void **val_p) | ||
{ | ||
p_Dict_Item *cur; | ||
|
||
cur = items; | ||
|
||
while (TRUE) { | ||
if (cur == NULL) { | ||
return FALSE; | ||
} else if (cmp(cur->p_key,key) == 0) { | ||
*val_p = cur->p_val; | ||
return TRUE; | ||
} else { | ||
cur = cur->p_next; | ||
} | ||
} | ||
} | ||
|
||
void | ||
dict_delete(void *key, Dict *dict_p) | ||
{ | ||
assert(dict_p != NULL); | ||
assert(dict_p->p_key_cmp != NULL); | ||
|
||
dict_p->p_items = delete(dict_p->p_key_cmp, key, dict_p->p_items); | ||
return; | ||
} | ||
|
||
static p_Dict_Item * | ||
delete(KeyComparison cmp, void *key, p_Dict_Item *items) | ||
{ | ||
if (items == NULL) { | ||
return NULL; | ||
} else if (cmp(key,items->p_key) == 0) { | ||
/* | ||
** XXX: Use Boehm GC to collect garbage node. | ||
*/ | ||
return items->p_next; | ||
} else { | ||
p_Dict_Item *new_items; | ||
|
||
items->p_next = delete(cmp, key, items->p_next); | ||
return items; | ||
} | ||
} | ||
|
||
|
||
KeyComparison | ||
dict_key_compare(Dict dict) | ||
{ | ||
return dict.p_key_cmp; | ||
} | ||
|
||
static p_Dict_Item * | ||
new_item_p(void *key, void *val, p_Dict_Item* next) | ||
{ | ||
p_Dict_Item *item_p; | ||
|
||
item_p = (p_Dict_Item*) MB_malloc(sizeof(p_Dict_Item)); | ||
|
||
item_p->p_key = key; | ||
item_p->p_val = val; | ||
item_p->p_next = next; | ||
|
||
assert(item_p != NULL); | ||
return item_p; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
** Copyright (C) 1997 University of Melbourne. | ||
** This file may only be copied under the terms of the GNU Library General | ||
** Public License - see the file COPYING.LIB in the Mercury distribution. | ||
** | ||
** $Id: dict.h,v 1.1 1997-05-28 05:58:59 aet Exp $ | ||
*/ | ||
|
||
|
||
#ifndef MB_DICT_H | ||
#define MB_DICT_H | ||
|
||
/* | ||
** A simple abstract data type for a key-value dictionary. | ||
** | ||
** Note that this type is ABSTRACT. Client code must not refer to | ||
** any types or fields prefixed with "p_" since they are private | ||
** (part of the implementation, not of the interface) and may be | ||
** changed or removed if the implementation changes. ADTs in C | ||
** are never pretty. | ||
** | ||
** Given how slow the current implementation is, you can be sure | ||
** it will change. | ||
** | ||
** Note: The "_p" -suffix- denotes a pointer, not a private type or data. | ||
*/ | ||
|
||
typedef int (*KeyComparison)(const void *, const void *); | ||
|
||
typedef struct p_Dict_Item { | ||
void *p_key; | ||
void *p_val; | ||
struct p_Dict_Item *p_next; | ||
} p_Dict_Item; | ||
|
||
|
||
typedef struct Dict { | ||
KeyComparison p_key_cmp; | ||
p_Dict_Item *p_items; | ||
} Dict; | ||
|
||
/* | ||
** Create a new dictionary that uses a given comparison function. | ||
** The comparsion function works like strcmp. Specifically, key_cmp(x1,x2) | ||
** returns negative if x1 < x2, zero if x1==x2, positive if x1>x2. | ||
** XXX: Should also pass in some sort of string to identify the dictionary? | ||
*/ | ||
Dict | ||
dict_new(KeyComparison key_cmp); | ||
|
||
/* | ||
** Insert key-value pair into dictionary. | ||
*/ | ||
void | ||
dict_insert(void *key, void *val, Dict *dict_p); | ||
|
||
/* | ||
** Lookup value corresponding to key. Returns TRUE if lookup succeeded, | ||
** FALSE if it failed. | ||
*/ | ||
MB_Bool | ||
dict_lookup(void *key, Dict dict, void **val_p); | ||
|
||
/* | ||
** Delete key-value pair corresponding to key. | ||
*/ | ||
void | ||
dict_delete(void *key, Dict *dict_p); | ||
|
||
/* | ||
** Return the key comparison function used by a dictionary. | ||
*/ | ||
KeyComparison | ||
dict_key_compare(Dict dict); | ||
|
||
/* | ||
** XXX: Need another function to allow us to iterate through the | ||
** contents of a dictionary. | ||
*/ | ||
|
||
#endif /* MB_DICT_H */ | ||
|
||
|