Implement a few "pair map" functions, mostly used for hash tables.

In order to efficiently check if nodes are contained within a
given set, without knowing exactly how many nodes there are and
allocating a ton of memory, it's probably best to use a hash table
(sparse sets would be more efficient but would require to allocate
all of their space at once). It's also pointless to reimplement most
of the hash table functionality from libds just to get it to work
with pairs (pattern id + node id), so pairmap.h provides a few
defaults that can be plugged into the default ht_s, as well as a
few macros to facilitate some hash table operations.
This commit is contained in:
Danila Fedorin 2017-01-27 22:16:31 -08:00
parent da48537f3c
commit 01d49eb397
3 changed files with 89 additions and 1 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.7)
project(liblex)
add_library(lex STATIC src/pattern.c)
add_library(lex STATIC src/pattern.c src/pairmap.c)
add_executable(liblex src/main.c)
add_subdirectory(external/libds)

59
include/pairmap.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef LIBLEX_PAIRMAP_H
#define LIBLEX_PAIRMAP_H
#define LIBLEX_PAIRMAP_SIZE 64
/**
* Since libds's hash table requires a pointer to a key object, it's necessary to modify a single
* key object (tmp) with the two values for the pair, and then pass it into the ht_xxx functions
* to be copied. This requires at least 3 things - set the x value, set the y value, call the
* hash table function the requires the key. These macros take care of these three things.
*/
#define PAIRMAP_PUT(map, tmp, newx, newy, data) do { (tmp)->x = newx; (tmp)->y = newy; ht_put(map, tmp, data); } while(0)
#define PAIRMAP_GET(map, tmp, newx, newy) ((tmp)->x = newx, (tmp)->y = newy, ht_get(map, tmp))
#include "ht.h"
/**
* A key object used for hash tables that take a pair of integers
* instead of a single pointer.
*/
struct pairmap_key_s {
int x;
int y;
};
typedef struct pairmap_key_s pairmap_key;
/**
* Hashes pairmap_key instead of the default string.
* This takes the lower 16 bits, and bit shifts them
* into a single integer.
*
* Why 16 bits? Well, the hash map implementation takes an unsigned long,
* which is only guaranteed to contain 32 bits. Therefore, assuming it
* has to be unique for any two equal-sized integers, it has to
* be twice the size. Hence, the largest the integers can be is 16.
* @param key the key for the hash table.
* @return the resulting hash.
*/
unsigned long pairmap_hash_func(void* key);
/**
* Compares two pairmap_key's.
* @param a the first pairmap_key
* @param b the second pairmap_key
* @return
*/
int pairmap_cmp_func(void* a, void* b);
/**
* Copies a pairmap_key.
* @param key the key to copy.
* @return the copy of the key.
*/
void* pairmap_copy_func(void* key);
/**
* Initializes a hash table with functions used for pair maps.
* @param ht the hash table to initialize.
*/
void pairmap_init_ht(ht* ht);
#endif

29
src/pairmap.c Normal file
View File

@ -0,0 +1,29 @@
#include "pairmap.h"
#include <stdlib.h>
unsigned long pairmap_hash_func(void* key){
pairmap_key* new_key = key;
unsigned int hash = 0;
hash |= ((new_key->x & 0xffff) << 8) + (new_key->y & 0xffff);
return hash;
}
int pairmap_cmp_func(void* a, void* b){
pairmap_key* new_key_a = a;
pairmap_key* new_key_b = b;
return (new_key_a->x == new_key_b->x) && (new_key_a->y == new_key_b->y);
}
void* pairmap_copy_func(void* key){
pairmap_key* copy_from = key;
pairmap_key* new_key = malloc(sizeof(*new_key));
if(new_key){
new_key->x = copy_from->x;
new_key->y = copy_from->y;
}
return new_key;
}
void pairmap_init_ht(ht* ht){
ht_init(ht);
ht->hash_func = pairmap_hash_func;
ht->cmp_func = pairmap_cmp_func;
ht->copy_func = pairmap_copy_func;
}