parent
41dd937d41
commit
3cacd9fa08
@ -0,0 +1,16 @@
|
||||
#include "test.h"
|
||||
|
||||
#include "trie.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
bool ffdb_test()
|
||||
{
|
||||
const char* d = "/tmp/ffdb-test";
|
||||
mkdir( d, 0755 );
|
||||
ffdb_trie_set( d, "https://example.com/actor", "T" );
|
||||
//ffdb_trie_set( d, "https://apogee.polaris-1.work/owner/actor", "T" );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -0,0 +1,207 @@
|
||||
#include "trie.h"
|
||||
|
||||
#include "json/json.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct edge {
|
||||
char* label;
|
||||
char* value;
|
||||
int count;
|
||||
};
|
||||
|
||||
/*
|
||||
{
|
||||
"k": "test",
|
||||
"t": 2,
|
||||
"z": 7
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
struct trie_entry
|
||||
{
|
||||
struct edge* edges;
|
||||
int count;
|
||||
};
|
||||
|
||||
static bool load_entry( FILE* f, struct trie_entry* e )
|
||||
{
|
||||
struct json_pull_parser jpp = {
|
||||
.f = f,
|
||||
.curr_state = jpp_initial_state,
|
||||
};
|
||||
if( !jpp.f ) { return false; }
|
||||
|
||||
int save;
|
||||
if( !json_pull_parser_begin_object(&jpp,&save) ) { goto failed; }
|
||||
|
||||
e->count = 0;
|
||||
|
||||
char* edge_label = NULL;
|
||||
while( edge_label = json_pull_parser_read_object_key(&jpp) ) {
|
||||
e->count += 1;
|
||||
e->edges = realloc( e->edges, sizeof(struct edge) * e->count );
|
||||
struct edge* ed = &e->edges[ e->count-1 ];
|
||||
memset(ed,0,sizeof(*ed));
|
||||
|
||||
ed->label = edge_label;
|
||||
ed->count = 1;
|
||||
if( !json_pull_parser_read_int( &jpp, &ed->count ) ) {
|
||||
char* value = json_pull_parser_read_string(&jpp);
|
||||
if( !value ) { goto failed; }
|
||||
|
||||
ed->value = value;
|
||||
}
|
||||
}
|
||||
|
||||
if( !json_pull_parser_end_object(&jpp,&save) ) { goto failed; }
|
||||
|
||||
return true;
|
||||
failed:
|
||||
fclose(jpp.f);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void save_entry( FILE* f, struct trie_entry* e )
|
||||
{
|
||||
fprintf( f, "{" );
|
||||
for( int i = 0; i < e->count; ++i ) {
|
||||
if( i != 0 ) {
|
||||
fprintf( f, ",\n\t" );
|
||||
} else {
|
||||
fprintf( f, "\n\t" );
|
||||
}
|
||||
|
||||
struct edge* ed = &e->edges[i];
|
||||
json_write_string( f, ed->label );
|
||||
fprintf( f, ": " );
|
||||
if( ed->count > 1 ) {
|
||||
fprintf( f, "%d", ed->count );
|
||||
} else {
|
||||
json_write_string( f, ed->value );
|
||||
}
|
||||
}
|
||||
fprintf( f, "\n}\n" );
|
||||
}
|
||||
|
||||
// Escape '/' as "%|" and '%' as "%%"
|
||||
static char* escape( const char* str )
|
||||
{
|
||||
int size = 0;
|
||||
for( const char* i = str; *i; ++i ) {
|
||||
switch( *i ) {
|
||||
case '/': size += 2; break;
|
||||
case '%': size += 2; break;
|
||||
default: size += 1; break;
|
||||
}
|
||||
}
|
||||
|
||||
char* result = malloc(size+1);
|
||||
char* o = result;
|
||||
for( const char* i = str; *i; ++i ) {
|
||||
switch( *i ) {
|
||||
case '/':
|
||||
o[0] = '%';
|
||||
o[1] = '|';
|
||||
o += 2;
|
||||
break;
|
||||
case '%':
|
||||
o[0] = '%';
|
||||
o[1] = '%';
|
||||
o += 2;
|
||||
break;
|
||||
default:
|
||||
*o = *i;
|
||||
++o;
|
||||
}
|
||||
}
|
||||
*o = '\0';
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
static int prefix_match( const char* a, const char* b )
|
||||
{
|
||||
int res = 0;
|
||||
while( *a && *b && *a == *b ) {
|
||||
a += 1;
|
||||
b += 1;
|
||||
res += 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool trie_set( struct trie_entry* e, const char* key, const char* value )
|
||||
{
|
||||
for( int i = 0; i < e->count; ++i ) {
|
||||
struct edge* ed = &e->edges[i];
|
||||
|
||||
int prefix_len = prefix_match( key, ed->label );
|
||||
if( prefix_len == strlen( ed->label ) ) {
|
||||
if( ed->count == 1 ) {
|
||||
free(ed->value);
|
||||
ed->value = strdup(value);
|
||||
return true;
|
||||
} else {
|
||||
printf( "TODO: exact match, go down this node\n" );
|
||||
}
|
||||
return false;
|
||||
} else if( prefix_len != 0 ) {
|
||||
printf( "TODO: create new node" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// No match in node, add
|
||||
printf( "Adding edge %s\n", key );
|
||||
e->count += 1;
|
||||
e->edges = realloc( e->edges, sizeof(struct edge) * e->count );
|
||||
struct edge* ed = &e->edges[e->count-1];
|
||||
ed->label = strdup(key);
|
||||
ed->value = strdup(value);
|
||||
ed->count = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffdb_trie_set( const char* filename, const char* key, const char* value )
|
||||
{
|
||||
char* key_escaped = escape(key);
|
||||
|
||||
struct trie_entry root;
|
||||
memset(&root,0,sizeof(root));
|
||||
|
||||
char buffer[512];
|
||||
snprintf( buffer, sizeof(buffer), "%s/%ROOT", filename );
|
||||
FILE* f = fopen( buffer, "r" );
|
||||
if( f ) {
|
||||
load_entry( f, &root );
|
||||
}
|
||||
|
||||
if( !trie_set( &root, key, value ) ) {
|
||||
printf( "Failed to set %s to %s\n", key, value );
|
||||
return false;
|
||||
}
|
||||
|
||||
f = fopen( buffer, "w" );
|
||||
save_entry( f, &root );
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
char* ffdb_trie_get( const char* filename, const char* key )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
bool ffdb_trie_remove( const char* filename, const char* key )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int ffdb_trie_count( const char* filename )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void ffdb_trie_clean( const char* filename )
|
||||
{
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool ffdb_trie_set( const char* filename, const char* key, const char* value );
|
||||
char* ffdb_trie_get( const char* filename, const char* key );
|
||||
bool ffdb_trie_remove( const char* filename, const char* key );
|
||||
int ffdb_trie_count( const char* filename );
|
||||
void ffdb_trie_clean( const char* filename );
|
||||
|
Loading…
Reference in new issue