169 lines
4.1 KiB
C
169 lines
4.1 KiB
C
#ifndef BLOCKS_H
|
|
#define BLOCKS_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include "ValueList.h"
|
|
|
|
struct BlockLevel {
|
|
long* data;
|
|
size_t size;
|
|
size_t capacity;
|
|
struct ValueList* list;
|
|
};
|
|
|
|
struct Blocks {
|
|
struct BlockLevel* levels;
|
|
size_t depth;
|
|
};
|
|
|
|
static int ilog2(unsigned long value) {
|
|
int result = -1;
|
|
while (value) value >>= 1, result++;
|
|
return result;
|
|
}
|
|
|
|
static long blockInsert(struct Blocks* blocks, long value, size_t depth) {
|
|
struct BlockLevel* level = blocks->levels + depth;
|
|
|
|
if (blocks->depth - 1 != depth) {
|
|
if ((value = blockInsert(blocks, value, depth + 1)) == -1)
|
|
return -1;
|
|
}
|
|
|
|
level->data[level->size++] = value;
|
|
if (level->size >= level->capacity) {
|
|
level->size = 0;
|
|
|
|
if (depth == 0 || (value = valueListFind(level->list, level->data, level->capacity)) == -1) {
|
|
value = valueListIntern(&level->list, level->data, level->capacity);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static long blockFindR(struct Blocks* blocks, long value, long offset, size_t depth) {
|
|
struct BlockLevel* level = &blocks->levels[depth];
|
|
struct ValueList* current;
|
|
size_t i, bits = 0;
|
|
|
|
for (i = depth + 1; i < blocks->depth; i++) {
|
|
bits += ilog2(blocks->levels[i].capacity);
|
|
}
|
|
|
|
current = level->list;
|
|
while (offset--) current = current->next;
|
|
|
|
offset = (value >> bits) & ((unsigned long)level->capacity - 1);
|
|
offset = current->data[offset];
|
|
|
|
if (depth != blocks->depth - 1)
|
|
return blockFindR(blocks, value, offset, depth + 1);
|
|
|
|
return offset;
|
|
}
|
|
|
|
static long blockFind(struct Blocks* blocks, long value) {
|
|
size_t i, bits = 0;
|
|
long offset;
|
|
|
|
for (i = 0; i < blocks->depth; i++) {
|
|
bits += ilog2(blocks->levels[i].capacity);
|
|
}
|
|
|
|
offset = value >> bits;
|
|
return blockFindR(blocks, value, offset, 0);
|
|
}
|
|
|
|
static void blockInit(struct Blocks* blocks, size_t depth, ...) {
|
|
va_list args;
|
|
|
|
blocks->depth = 0;
|
|
if (!(blocks->levels = malloc(sizeof(struct BlockLevel) * depth)))
|
|
abort();
|
|
|
|
va_start(args, depth);
|
|
|
|
while (blocks->depth < depth) {
|
|
struct BlockLevel* level = &blocks->levels[blocks->depth];
|
|
|
|
level->list = NULL;
|
|
level->size = 0;
|
|
level->capacity = va_arg(args, int);
|
|
if (!(level->data = malloc(level->capacity * sizeof(long))))
|
|
abort();
|
|
blocks->depth++;
|
|
}
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
static void blockDump(struct Blocks* blocks, size_t depth, FILE* out,
|
|
const char* name, const char* type) {
|
|
struct BlockLevel* level = &blocks->levels[depth];
|
|
struct ValueList* current;
|
|
size_t i, j, printed = 0;
|
|
|
|
fprintf(out, "static const %s %s[] = {\n ", type, name);
|
|
current = level->list;
|
|
for (current = level->list; current; current = current->next) {
|
|
for (i = 0; i < level->capacity; i++) {
|
|
if (printed++ >= 15) {
|
|
fprintf(out, "\n ");
|
|
printed = 1;
|
|
}
|
|
fprintf(out, "%ld, ", current->data[i]);
|
|
}
|
|
}
|
|
fprintf(out, "\n};\n\n");
|
|
}
|
|
|
|
static void blockAccess(struct Blocks* blocks, size_t depth, FILE* out,
|
|
const char* var, const char* arg, const char* name) {
|
|
struct BlockLevel* level = &blocks->levels[depth];
|
|
long i, bits = 0, offset, mask;
|
|
|
|
for (i = depth + 1; i < blocks->depth; i++) {
|
|
bits += ilog2(blocks->levels[i].capacity);
|
|
}
|
|
|
|
offset = ilog2(blocks->levels[depth].capacity);
|
|
mask = level->capacity - 1;
|
|
|
|
fprintf(out, " %s = (long)%s", var, name);
|
|
if (depth) {
|
|
if (offset) {
|
|
fprintf(out, "[(%s<<%ld)", var, offset);
|
|
} else {
|
|
fprintf(out, "[%s", var);
|
|
}
|
|
}
|
|
else
|
|
fprintf(out, "[");
|
|
|
|
if (mask || !depth) {
|
|
if (depth)
|
|
fprintf(out, "+");
|
|
|
|
if (mask)
|
|
fprintf(out, "(");
|
|
|
|
if (bits)
|
|
fprintf(out, "(%s>>%ld)", arg, (long)bits);
|
|
else
|
|
fprintf(out, "%s", arg);
|
|
|
|
if (depth)
|
|
fprintf(out, "&%ld", mask);
|
|
|
|
if (mask)
|
|
fprintf(out, ")");
|
|
}
|
|
|
|
fprintf(out, "];\n");
|
|
}
|
|
|
|
#endif /* BLOCKS_H */
|