just use a single 16bit index

This commit is contained in:
Alain Zscheile 2023-01-01 01:26:17 +01:00
parent bf9048443b
commit 4e5fd39cc9
4 changed files with 152 additions and 56 deletions

View file

@ -1,6 +1,6 @@
project('y16t 16-field quad tree library', 'c',
default_options : ['c_std=c17'],
version : '0.0.0'
version : '0.0.0',
license : 'Apache-2.0',
meson_version : '>=0.50')
@ -10,9 +10,17 @@ liby16t = shared_library('y16t',
files('y16t.c'),
version : '0.0.0',
c_args : ['-fno-plt', '-fno-unwind-tables', '-fno-exceptions', '-Werror=return-type'],
include_directories : include_directories('.')
include_directories : include_directories('.'),
install : true)
executable('y16t-printall',
files('y16t_printall.c'),
link_with : [liby16t],
c_args : ['-fno-plt', '-fno-unwind-tables', '-fno-exceptions', '-Werror=return-type'],
include_directories : include_directories('.'),
install : true
)
pkg_mod = import('pkgconfig')
pkg_mod.generate(
libraries : [liby16t],

101
y16t.c
View file

@ -1,37 +1,86 @@
// SPDX-License-Identifier: ISC
#include "y16t.h"
#include <arpa/inet.h>
#include <errno.h>
// conversion to ις-points interleaved coordinates
static __attribute__((pure))
uint8_t y16t_loc2blk_coords(
const y16t_location_t loc, const uint32_t offset
) {
const uint32_t byteoffset = offset >> 1;
const uint8_t shiftval = 4 * (1 - offset & 1);
const uint8_t xres = (loc.x[byteoffset] >> shiftval) & 15;
const uint8_t yres = (loc.y[byteoffset] >> shiftval) & 15;
return (xres << 4) | yres;
uint16_t y16t_interleave2(const uint8_t x, const uint8_t y)
{
return
((uint16_t)((x & 0x55) | (y & 0xaa)) << 8)
|
(uint16_t)((x & 0xaa) | (y & 0x55))
;
}
void y16t_lookup(
y16t_lookup_t * ret,
const uint32_t * data,
const size_t datalen,
const y16t_location_t * loc
) {
const size_t datalen_blks = datalen >> 8;
const y16t_location_t loc_ = *loc;
size_t datoffset = ret->datoffset;
static __attribute__((pure))
uint32_t y16t_table_at(const uint8_t x, const uint8_t y)
{
return ((uint32_t)y16t_interleave2(x, y)) << 2;
}
for ( ; /* bounds checks */ ret->inpoffset < loc_.xylen && datoffset < datalen_blks; ) {
datoffset = ntohl(data[(datoffset << 8) | y16t_loc2blk_coords(loc_, ret->inpoffset)]);
ret->inpoffset += 1;
if(0 == datoffset) {
// NULL pointer
break;
}
int y16t_idx_lookup(
FILE *fh,
uint8_t x,
uint8_t y,
uint32_t *result
) {
const uint32_t key = y16t_table_at(x, y);
if(fseek(fh, (long)key, SEEK_SET) == -1)
return -EIO;
if(fread(result, 4, 1, fh) != 1)
return -EIO;
return 0;
}
int y16t_idx_update(
FILE *fh,
const uint8_t x,
const uint8_t y,
const uint32_t newval
) {
const uint32_t key = y16t_table_at(x, y);
if(fseek(fh, (long)key, SEEK_SET) == -1)
return -EIO;
if(fwrite(&newval, 4, 1, fh) != 1)
return -EIO;
return 0;
}
int y16t_idx_foreach_x(
FILE *fh,
uint8_t y,
int (*callback)(uint32_t, void*),
void *context
) {
for (uint16_t x = 0; x < 0xff; ++x) {
uint32_t value = 0;
int tmp = y16t_idx_lookup(fh, x, y, &value);
if(tmp != 0) return tmp;
tmp = callback(value, context);
if(tmp != 0) return tmp;
}
ret->datoffset = datoffset;
return 0;
}
int y16t_idx_foreach_y(
FILE *fh,
uint8_t x,
int (*callback)(uint32_t, void*),
void *context
) {
for (uint16_t y = 0; y < 0xff; ++y) {
uint32_t value = 0;
int tmp = y16t_idx_lookup(fh, x, y, &value);
if(tmp != 0) return tmp;
tmp = callback(value, context);
if(tmp != 0) return tmp;
}
return 0;
}

63
y16t.h
View file

@ -2,33 +2,40 @@
#pragma once
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
typedef struct {
uint8_t *x;
uint8_t *y;
// x and y should have the same length, and xylen = bytescount * 2
uint32_t xylen;
} y16t_location_t;
typedef struct {
// the offset indicates how far the lookup could traverse the tree
uint32_t inpoffset;
// the final data pointer, it doesn't have to be aligned to block boundaries
// if it ends up at the starting point, but the offset isn't 0,
// then a NULL pointer was hit
size_t datoffset;
} y16t_lookup_t;
// @param ret ... the starting point; gets updated to the latest via the given path
// reachable point
// @param data ... a pointer to a mmap-ed file. we convert pointers inside of the file
// from network byte order to host byte order before following them.
// @param datalen ... the length of the block that data points to, in 4 byte units (= file size in bytes / 4)
__attribute__((pure, nonnull))
void y16t_lookup(
y16t_lookup_t * ret,
const uint32_t * data,
const size_t datalen,
const y16t_location_t * loc
// try to lookup the given coordinates, and return the corresponding location
// via `result`.
// the file given as `fh` is expected to be at least 256KiB large
// returns a negative errno number in case of failure
__attribute__((nonnull))
int y16t_idx_lookup(
FILE *fh,
uint8_t x,
uint8_t y,
uint32_t *result
);
// update a table entry.
__attribute__((nonnull))
int y16t_idx_update(
FILE *fh,
uint8_t x,
uint8_t y,
uint32_t newval
);
// iterate over columns or rows
int y16t_idx_foreach_x(
FILE *fh,
uint8_t y,
int (*callback)(uint32_t, void*),
void *context
);
int y16t_idx_foreach_y(
FILE *fh,
uint8_t χ,
int (*callback)(uint32_t, void*),
void *context
);

32
y16t_printall.c Normal file
View file

@ -0,0 +1,32 @@
#include "y16t.h"
#include <stdlib.h>
#include <stdio.h>
int printall_fecb(uint32_t x, void*)
{
printf("%08x\n", x);
return 0;
}
int main(int argc, char *argv[])
{
if(argc < 4) {
fprintf(stderr, "USAGE: y16t-print FILE x|y VALUE\n");
return -1;
}
FILE *fh = fopen(argv[1], "r");
if(!fh) {
fprintf(stderr, "ERROR: unable to open file\n");
return -1;
}
uint8_t value = atoi(argv[3]);
switch(argv[2][0]) {
case 'x': return y16t_idx_foreach_x(fh, value, printall_fecb, 0);
case 'y': return y16t_idx_foreach_y(fh, value, printall_fecb, 0);
default: return -1;
}
}