use only generic structures
This commit is contained in:
parent
440e4499c7
commit
6503897ece
@ -1,17 +1,16 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL
|
LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL
|
||||||
CFLAGS = -g -Wall -Wextra -pedantic -fno-omit-frame-pointer
|
CFLAGS = -ggdb3 -Wall -Wextra -pedantic -fno-omit-frame-pointer
|
||||||
|
|
||||||
.PHONY: clean all
|
.PHONY: clean all
|
||||||
all: test
|
all: test
|
||||||
|
|
||||||
font.o: font.c font.h stb_truetype.h stb_image_write.h util.h \
|
font.o: font.c font.h stb_truetype.h stb_image_write.h util.h \
|
||||||
generic_cache.h hash.h
|
generic_cache.h generic_hash.h
|
||||||
hash.o: hash.c hash.h util.h
|
|
||||||
main.o: main.c ren.h util.h
|
main.o: main.c ren.h util.h
|
||||||
ren.o: ren.c util.h font.h ren.h generic_stack.h
|
ren.o: ren.c util.h font.h ren.h generic_stack.h
|
||||||
util.o: util.c util.h
|
util.o: util.c util.h
|
||||||
test: font.o hash.o main.o ren.o util.o
|
test: font.o main.o ren.o util.o
|
||||||
${CC} ${LDFLAGS} -o test font.o hash.o main.o ren.o util.o
|
${CC} ${LDFLAGS} -o test font.o main.o ren.o util.o
|
||||||
clean:
|
clean:
|
||||||
rm -f test font.o hash.o main.o ren.o util.o
|
rm -f test font.o main.o ren.o util.o
|
||||||
|
@ -12,8 +12,14 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
// generic cache type
|
// generic cache type
|
||||||
|
static unsigned int hash(unsigned int code)
|
||||||
|
{
|
||||||
|
// identity map the ascii range
|
||||||
|
if (code < 128) return code;
|
||||||
|
return (uint32_t)((uint64_t)(code*2654435761)>>32);
|
||||||
|
}
|
||||||
#include "generic_cache.h"
|
#include "generic_cache.h"
|
||||||
CACHE_DECL(cache, struct font_glyph)
|
CACHE_DECL(cache, struct font_glyph, hash, hash_cp_u32)
|
||||||
|
|
||||||
|
|
||||||
#define UTF8(c) (c&0x80)
|
#define UTF8(c) (c&0x80)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define CACHE_GENERIC_H
|
#define CACHE_GENERIC_H
|
||||||
|
|
||||||
|
|
||||||
#include "hash.h"
|
#include "generic_hash.h"
|
||||||
|
|
||||||
#define CACHE_SIZE 512
|
#define CACHE_SIZE 512
|
||||||
#define CACHE_NCYCLES (CACHE_SIZE/2)
|
#define CACHE_NCYCLES (CACHE_SIZE/2)
|
||||||
@ -11,6 +11,9 @@
|
|||||||
#define CACHE_BSET(b, x) b[(x)>>6] |= (uint64_t)1<<((x)%64)
|
#define CACHE_BSET(b, x) b[(x)>>6] |= (uint64_t)1<<((x)%64)
|
||||||
#define CACHE_BTEST(b, x) (b[(x)>>6]&((uint64_t)1<<((x)%64)))
|
#define CACHE_BTEST(b, x) (b[(x)>>6]&((uint64_t)1<<((x)%64)))
|
||||||
|
|
||||||
|
// FIXME: this cache implementation is not really generic since it expects an unsigned
|
||||||
|
// as the code and not a generic type
|
||||||
|
|
||||||
#define CACHE_SET(c, x) \
|
#define CACHE_SET(c, x) \
|
||||||
{ \
|
{ \
|
||||||
c->cycles = (c->cycles+1)%CACHE_NCYCLES; \
|
c->cycles = (c->cycles+1)%CACHE_NCYCLES; \
|
||||||
@ -19,9 +22,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define CACHE_DECL(cachename, type) \
|
#define CACHE_DECL(cachename, type, hashfn, comparefn) \
|
||||||
|
HASH_DECL(cachename##table, unsigned int, void *) \
|
||||||
struct cachename { \
|
struct cachename { \
|
||||||
struct hm_ref *table; \
|
struct cachename##table_ref *table; \
|
||||||
type *array; \
|
type *array; \
|
||||||
uint64_t *bitmap; \
|
uint64_t *bitmap; \
|
||||||
int cycles; \
|
int cycles; \
|
||||||
@ -30,7 +34,9 @@ struct cachename { \
|
|||||||
\
|
\
|
||||||
struct cachename cachename##_init(void) \
|
struct cachename cachename##_init(void) \
|
||||||
{ \
|
{ \
|
||||||
struct hm_ref *t = hm_create(CACHE_SIZE); \
|
struct cachename##table_ref *t = cachename##table_create( \
|
||||||
|
CACHE_SIZE, hashfn, comparefn \
|
||||||
|
); \
|
||||||
type *a = malloc(sizeof(type)*CACHE_SIZE); \
|
type *a = malloc(sizeof(type)*CACHE_SIZE); \
|
||||||
uint64_t *b = malloc(sizeof(uint64_t)*CACHE_BSIZE); \
|
uint64_t *b = malloc(sizeof(uint64_t)*CACHE_BSIZE); \
|
||||||
CACHE_BRESET(b); \
|
CACHE_BRESET(b); \
|
||||||
@ -41,7 +47,7 @@ struct cachename cachename##_init(void) \
|
|||||||
void cachename##_free(struct cachename *cache) \
|
void cachename##_free(struct cachename *cache) \
|
||||||
{ \
|
{ \
|
||||||
if (cache) { \
|
if (cache) { \
|
||||||
hm_destroy(cache->table); \
|
cachename##table_destroy(cache->table); \
|
||||||
free(cache->array); \
|
free(cache->array); \
|
||||||
free(cache->bitmap); \
|
free(cache->bitmap); \
|
||||||
} \
|
} \
|
||||||
@ -52,7 +58,8 @@ const type * cachename##_search(struct cachename *cache, unsigned int code) \
|
|||||||
{ \
|
{ \
|
||||||
if (!cache) \
|
if (!cache) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
struct hm_entry *r = hm_search(cache->table, code); \
|
struct cachename##table_entry *r; \
|
||||||
|
r = cachename##table_search(cache->table, code); \
|
||||||
/* MISS */ \
|
/* MISS */ \
|
||||||
if (!r) \
|
if (!r) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
@ -90,8 +97,8 @@ const type * cachename##_insert(struct cachename *cache, const type *g, unsigned
|
|||||||
CACHE_SET(cache, x) \
|
CACHE_SET(cache, x) \
|
||||||
spot = &(cache->array[x]); \
|
spot = &(cache->array[x]); \
|
||||||
*spot = *g; \
|
*spot = *g; \
|
||||||
struct hm_entry e = { .code = code, .data = spot}; \
|
struct cachename##table_entry e = { .code = code, .data = spot}; \
|
||||||
if (!hm_insert(cache->table, &e)) \
|
if (!cachename##table_insert(cache->table, &e)) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
return spot; \
|
return spot; \
|
||||||
} \
|
} \
|
||||||
|
@ -14,21 +14,21 @@
|
|||||||
|
|
||||||
|
|
||||||
/* Ready-made compares */
|
/* Ready-made compares */
|
||||||
int hash_compare_u32(unsigned int a, unsigned int b) { return a == b; }
|
static int hash_cp_u32(unsigned int a, unsigned int b) { return a == b; }
|
||||||
int hash_compare_u64(unsigned long long int a, unsigned long long int b) { return a == b; }
|
static int hash_cp_u64(unsigned long long int a, unsigned long long int b) { return a == b; }
|
||||||
int hash_compare_str(const char *a, const char *b) { return strcmp(a, b) == 0; }
|
static int hash_cp_str(const char *a, const char *b) { return strcmp(a, b) == 0; }
|
||||||
|
|
||||||
|
|
||||||
/* Ready-made hashes */
|
/* Ready-made hashes */
|
||||||
unsigned int hash_u64(unsigned long long int c)
|
static unsigned int hash_u64(unsigned long long int c)
|
||||||
{
|
{
|
||||||
return (unsigned long long int)((unsigned long long int)(c*HASH_RATIO64)>>32);
|
return (unsigned long long int)((unsigned long long int)(c*HASH_RATIO64)>>32);
|
||||||
}
|
}
|
||||||
unsigned int hash_u32(unsigned int c)
|
static unsigned int hash_u32(unsigned int c)
|
||||||
{
|
{
|
||||||
return (unsigned int)((unsigned long long int)(c*HASH_RATIO32)>>32);
|
return (unsigned int)((unsigned long long int)(c*HASH_RATIO32)>>32);
|
||||||
}
|
}
|
||||||
unsigned int hash_str(const char *s)
|
static unsigned int hash_str(const char *s)
|
||||||
{
|
{
|
||||||
unsigned int h = HASH_STRSALT;
|
unsigned int h = HASH_STRSALT;
|
||||||
const unsigned char *v = (const unsigned char *)(s);
|
const unsigned char *v = (const unsigned char *)(s);
|
||||||
@ -76,7 +76,7 @@ struct hashname##_ref * hashname##_create(unsigned int size, unsigned int (*hash
|
|||||||
h->size = size; \
|
h->size = size; \
|
||||||
h->hash = hash; \
|
h->hash = hash; \
|
||||||
h->compare = compare; \
|
h->compare = compare; \
|
||||||
memset(h->bucket, 0, sizeof(struct hashname##_ref)*size); \
|
memset(h->bucket, 0, sizeof(struct hashname##_entry)*size); \
|
||||||
} \
|
} \
|
||||||
return h; \
|
return h; \
|
||||||
} \
|
} \
|
||||||
|
@ -16,7 +16,7 @@ rm -f objlist
|
|||||||
cat > Makefile << EOF
|
cat > Makefile << EOF
|
||||||
CC = gcc
|
CC = gcc
|
||||||
LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL
|
LDFLAGS = -lm -lgrapheme -lSDL2 -lGLEW -lGL
|
||||||
CFLAGS = -g -Wall -Wextra -pedantic -fno-omit-frame-pointer
|
CFLAGS = -ggdb3 -Wall -Wextra -pedantic -fno-omit-frame-pointer
|
||||||
|
|
||||||
.PHONY: clean all
|
.PHONY: clean all
|
||||||
all: test
|
all: test
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
#define _POSIX_C_SOURCE 200809l
|
|
||||||
#define _DEFAULT_SOURCE
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "hash.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#define MAXSIZE 4096
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned int hash(unsigned int code)
|
|
||||||
{
|
|
||||||
// identity map the ascii range
|
|
||||||
if (code < 128) return code;
|
|
||||||
return (uint32_t)((uint64_t)(code*2654435761)>>32);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct hm_ref * hm_create(unsigned int size)
|
|
||||||
{
|
|
||||||
if (!size || size > MAXSIZE)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// round to the greater power of two
|
|
||||||
size = 1<<__builtin_clz(size);
|
|
||||||
|
|
||||||
// FIXME: check for intger overflow here
|
|
||||||
struct hm_ref *h = emalloc(sizeof(struct hm_ref)+sizeof(struct hm_entry)*size);
|
|
||||||
if (h) {
|
|
||||||
h->items = 0;
|
|
||||||
h->size = size;
|
|
||||||
memset(h->bucket, 0, sizeof(struct hm_ref)*size);
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void hm_destroy(struct hm_ref *hm)
|
|
||||||
{
|
|
||||||
efree(hm);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct hm_entry * lookup(struct hm_ref *hm, unsigned int code)
|
|
||||||
{
|
|
||||||
// fast modulo operation for power-of-2 size
|
|
||||||
unsigned int mask = hm->size - 1;
|
|
||||||
unsigned int i = hash(code);
|
|
||||||
for (unsigned int j = 1; ; i += j++) {
|
|
||||||
if (!hm->bucket[i&mask].code || hm->bucket[i].code == code)
|
|
||||||
return &(hm->bucket[i&mask]);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct hm_entry * hm_search(struct hm_ref *hm, unsigned int code)
|
|
||||||
{
|
|
||||||
struct hm_entry *r = lookup(hm, code);
|
|
||||||
if (r) {
|
|
||||||
if (r->code == code)
|
|
||||||
return r;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct hm_entry * hm_insert(struct hm_ref *hm, struct hm_entry *entry)
|
|
||||||
{
|
|
||||||
struct hm_entry *r = lookup(hm, entry->code);
|
|
||||||
if (r) *r = *entry;
|
|
||||||
return r;
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#ifndef _HASH_H
|
|
||||||
#define _HASH_H
|
|
||||||
|
|
||||||
struct hm_entry {
|
|
||||||
unsigned long code;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct hm_ref {
|
|
||||||
unsigned int items, size;
|
|
||||||
struct hm_entry bucket[];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct hm_ref * hm_create(unsigned int size);
|
|
||||||
void hm_destroy(struct hm_ref *hm);
|
|
||||||
struct hm_entry * hm_search(struct hm_ref *hm, unsigned int code);
|
|
||||||
struct hm_entry * hm_insert(struct hm_ref *hm, struct hm_entry *entry);
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user