nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

catalog.h (5857B)


      1 #ifndef CATALOG_H
      2 #define CATALOG_H
      3 
      4 #include <stdlib.h>
      5 #include "symbols.h"
      6 
      7 /* Helper to build more intuitive schema data with fully qualified names. */
      8 
      9 
     10 typedef struct entry entry_t;
     11 typedef entry_t object_entry_t;
     12 typedef entry_t enum_entry_t;
     13 typedef entry_t service_entry_t;
     14 typedef struct scope_entry scope_entry_t;
     15 
     16 struct entry {
     17     fb_compound_type_t *ct;
     18     char *name;
     19 };
     20 
     21 struct scope_entry {
     22     fb_scope_t *scope;
     23     char *name;
     24 };
     25 
     26 typedef struct catalog catalog_t;
     27 
     28 struct catalog {
     29     int qualify_names;
     30     int nobjects;
     31     int nenums;
     32     int nservices;
     33     size_t name_table_size;
     34     object_entry_t *objects;
     35     enum_entry_t *enums;
     36     service_entry_t *services;
     37     char *name_table;
     38     object_entry_t *next_object;
     39     enum_entry_t *next_enum;
     40     service_entry_t *next_service;
     41     char *next_name;
     42     fb_schema_t *schema;
     43 };
     44 
     45 #include <stdio.h>
     46 
     47 static void count_symbol(void *context, fb_symbol_t *sym)
     48 {
     49     catalog_t *catalog = context;
     50     fb_ref_t *scope_name;
     51     size_t n = 0;
     52     fb_compound_type_t *ct;
     53     
     54     if (!(ct = get_compound_if_visible(catalog->schema, sym))) {
     55         return;
     56     }
     57 
     58     /*
     59      * Find out how much space the name requires. We must store each
     60      * name in full for sorting because comparing a variable number of
     61      * parent scope names is otherwise tricky.
     62      */
     63     if (catalog->qualify_names) {
     64         scope_name = ct->scope->name;
     65         while (scope_name) {
     66             /* + 1 for '.'. */
     67             n += (size_t)scope_name->ident->len + 1;
     68             scope_name = scope_name->link;
     69         }
     70     }
     71     /* + 1 for '\0'. */
     72     n += (size_t)sym->ident->len + 1;
     73     catalog->name_table_size += n;
     74 
     75     switch (sym->kind) {
     76     case fb_is_struct:
     77     case fb_is_table:
     78         ++catalog->nobjects;
     79         break;
     80     case fb_is_union:
     81     case fb_is_enum:
     82         ++catalog->nenums;
     83         break;
     84     case fb_is_rpc_service:
     85         ++catalog->nservices;
     86         break;
     87     default: return;
     88     }
     89 }
     90 
     91 static void install_symbol(void *context, fb_symbol_t *sym)
     92 {
     93     catalog_t *catalog = context;
     94     fb_ref_t *scope_name;
     95     int n = 0;
     96     char *s, *name;
     97     fb_compound_type_t *ct;
     98     
     99     if (!(ct = get_compound_if_visible(catalog->schema, sym))) {
    100         return;
    101     }
    102 
    103     s = catalog->next_name;
    104     name = s;
    105     if (catalog->qualify_names) {
    106         scope_name = ct->scope->name;
    107         while (scope_name) {
    108             n = (int)scope_name->ident->len;
    109             memcpy(s, scope_name->ident->text, (size_t)n);
    110             s += n;
    111             *s++ = '.';
    112             scope_name = scope_name->link;
    113         }
    114     }
    115     n = (int)sym->ident->len;
    116     memcpy(s, sym->ident->text, (size_t)n);
    117     s += n;
    118     *s++ = '\0';
    119     catalog->next_name = s;
    120 
    121     switch (sym->kind) {
    122     case fb_is_struct:
    123     case fb_is_table:
    124         catalog->next_object->ct = (fb_compound_type_t *)sym;
    125         catalog->next_object->name = name;
    126         catalog->next_object++;
    127         break;
    128     case fb_is_union:
    129     case fb_is_enum:
    130         catalog->next_enum->ct = (fb_compound_type_t *)sym;
    131         catalog->next_enum->name = name;
    132         catalog->next_enum++;
    133         break;
    134     case fb_is_rpc_service:
    135         catalog->next_service->ct = (fb_compound_type_t *)sym;
    136         catalog->next_service->name = name;
    137         catalog->next_service++;
    138         break;
    139     default: break;
    140     }
    141 }
    142 
    143 static void count_symbols(void *context, fb_scope_t *scope)
    144 {
    145     fb_symbol_table_visit(&scope->symbol_index, count_symbol, context);
    146 }
    147 
    148 static void install_symbols(void *context, fb_scope_t *scope)
    149 {
    150     fb_symbol_table_visit(&scope->symbol_index, install_symbol, context);
    151 }
    152 
    153 static int compare_entries(const void *x, const void *y)
    154 {
    155     return strcmp(((const entry_t *)x)->name, ((const entry_t *)y)->name);
    156 }
    157 
    158 static void sort_entries(entry_t *entries, int count)
    159 {
    160     int i;
    161 
    162     qsort(entries, (size_t)count, sizeof(entries[0]), compare_entries);
    163 
    164     for (i = 0; i < count; ++i) {
    165         entries[i].ct->export_index = (size_t)i;
    166     }
    167 }
    168 
    169 static void clear_catalog(catalog_t *catalog)
    170 {
    171     if (catalog->objects) {
    172         free(catalog->objects);
    173     }
    174     if (catalog->enums) {
    175         free(catalog->enums);
    176     }
    177     if (catalog->services) {
    178         free(catalog->services);
    179     }
    180     if (catalog->name_table) {
    181         free(catalog->name_table);
    182     }
    183     memset(catalog, 0, sizeof(*catalog));
    184 }
    185 
    186 static int build_catalog(catalog_t *catalog, fb_schema_t *schema, int qualify_names, fb_scope_table_t *index)
    187 {
    188     memset(catalog, 0, sizeof(*catalog));
    189     catalog->qualify_names = qualify_names;
    190     catalog->schema = schema;
    191 
    192     /* Build support datastructures before export. */
    193     fb_scope_table_visit(index, count_symbols, catalog);
    194     catalog->objects = calloc((size_t)catalog->nobjects, sizeof(catalog->objects[0]));
    195     catalog->enums = calloc((size_t)catalog->nenums, sizeof(catalog->enums[0]));
    196     catalog->services = calloc((size_t)catalog->nservices, sizeof(catalog->services[0]));
    197     catalog->name_table = malloc(catalog->name_table_size);
    198     catalog->next_object = catalog->objects;
    199     catalog->next_enum = catalog->enums;
    200     catalog->next_service = catalog->services;
    201     catalog->next_name = catalog->name_table;
    202     if ((!catalog->objects && catalog->nobjects > 0) ||
    203         (!catalog->enums && catalog->nenums > 0) ||
    204         (!catalog->services && catalog->nservices > 0) ||
    205         (!catalog->name_table && catalog->name_table_size > 0)) {
    206         clear_catalog(catalog);
    207         return -1;
    208     }
    209     fb_scope_table_visit(index, install_symbols, catalog);
    210     /* Presort objects and enums because the sorted index is required in Type tables. */
    211     sort_entries(catalog->objects, catalog->nobjects);
    212     sort_entries(catalog->enums, catalog->nenums);
    213     sort_entries(catalog->services, catalog->nservices);
    214     return 0;
    215 }
    216 
    217 #endif /* CATALOG_H */