dump1090-fa/starch/templates/dispatcher.c.template

207 lines
6.4 KiB
Plaintext

### Copyright (c) 2020, FlightAware LLC.
### All rights reserved.
### See the LICENSE file for licensing terms.
/* starch generated code. Do not edit. */
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "${os.path.relpath(gen.generated_include_path, current_dir)}"
/* helper for re-sorting registries */
struct starch_regentry_prefix {
int rank;
};
static int starch_regentry_rank_compare (const void *l, const void *r)
{
const struct starch_regentry_prefix *left = l, *right = r;
return left->rank - right->rank;
}
% for function in gen.functions.values():
/* dispatcher / registry for ${function.name} */
${function.regentry_type} * ${function.select_symbol}() {
for (${function.regentry_type} *entry = ${function.registry_symbol};
entry->name;
++entry)
{
if (entry->flavor_supported && !(entry->flavor_supported()))
continue;
return entry;
}
return NULL;
}
static ${function.returntype} ${function.dispatcher_symbol} ( ${function.declaration_arglist} ) {
${function.regentry_type} *entry = ${function.select_symbol}();
if (!entry)
abort();
${function.callable_symbol} = entry->callable;
% if function.returntype == 'void':
${function.callable_symbol} ( ${function.named_arglist} );
% else:
return ${function.callable_symbol} ( ${function.named_arglist} );
% endif
}
${function.pointer_type} ${function.callable_symbol} = ${function.dispatcher_symbol};
void ${function.set_wisdom_symbol} (const char * const * received_wisdom)
{
/* re-rank the registry based on received wisdom */
${function.regentry_type} *entry;
for (entry = ${function.registry_symbol}; entry->name; ++entry) {
const char * const *search;
for (search = received_wisdom; *search; ++search) {
if (!strcmp(*search, entry->name)) {
break;
}
}
if (*search) {
/* matches an entry in the wisdom list, order by position in the list */
entry->rank = search - received_wisdom;
} else {
/* no match, rank after all possible matches, retaining existing order */
entry->rank = (search - received_wisdom) + (entry - ${function.registry_symbol});
}
}
/* re-sort based on the new ranking */
qsort(${function.registry_symbol}, entry - ${function.registry_symbol}, sizeof(${function.regentry_type}), starch_regentry_rank_compare);
/* reset the implementation pointer so the next call will re-select */
${function.callable_symbol} = ${function.dispatcher_symbol};
}
${function.regentry_type} ${function.registry_symbol}[] = {
% for mix in gen.mixes.values():
<%
# gather all implementations for this mix, sort by wisdom
def rank_key(value, wisdom=mix.function_wisdom(function)):
impl, flavor = value
try:
return wisdom.index(impl.wisdom_name(flavor))
except ValueError:
return len(wisdom)
mix_impls = []
for flavor in mix.flavors:
if function.aligned and function.aligned_pair:
if flavor.alignment > 1:
# add aligned impls
for impl in function.impls:
if impl.feature is None or impl.feature in flavor.features:
mix_impls.append( (impl, flavor) )
# add unaligned impls
for impl in function.aligned_pair.impls:
if impl.feature is None or impl.feature in flavor.features:
mix_impls.append( (impl, flavor) )
else:
# no alignment specialization
for impl in function.impls:
if impl.feature is None or impl.feature in flavor.features:
mix_impls.append( (impl, flavor) )
mix_impls.sort(key=rank_key)
%>
#ifdef ${mix.macro}
% for rank, (impl, flavor) in enumerate(mix_impls):
{ ${rank}, "${impl.wisdom_name(flavor)}", "${flavor.name}", ${impl.impl_symbol(flavor)}, ${flavor.test_function_expr} },
% endfor
#endif /* ${mix.macro} */
% endfor
{ 0, NULL, NULL, NULL, NULL }
};
% endfor
int ${gen.sym("read_wisdom")} (const char * path)
{
FILE *fp = fopen(path, "r");
if (!fp)
return -1;
/* reset all ranks to identify entries not listed in the wisdom file; we'll assign ranks at the end to produce a stable sort */
% for function in gen.functions.values():
int rank_${function.name} = 0;
for (${function.regentry_type} *entry = ${function.registry_symbol}; entry->name; ++entry) {
entry->rank = 0;
}
% endfor
char linebuf[512];
while (fgets(linebuf, sizeof(linebuf), fp)) {
/* split name and impl on whitespace, handle comments etc */
char *name = linebuf;
while (*name && isspace(*name))
++name;
if (!*name || *name == '#')
continue;
char *end = name;
while (*end && !isspace(*end))
++end;
if (!*end)
continue;
*end = 0;
char *impl = end + 1;
while (*impl && isspace(*impl))
++impl;
if (!*impl)
continue;
end = impl;
while (*end && !isspace(*end))
++end;
*end = 0;
/* try to find a matching registry entry */
% for function in gen.functions.values():
if (!strcmp(name, "${function.name}")) {
for (${function.regentry_type} *entry = ${function.registry_symbol}; entry->name; ++entry) {
if (!strcmp(impl, entry->name)) {
entry->rank = ++rank_${function.name};
break;
}
}
continue;
}
% endfor
}
if (ferror(fp)) {
fclose(fp);
return -1;
}
fclose(fp);
/* assign ranks to unmatched items to (stable) sort them last; re-sort everything */
% for function in gen.functions.values():
{
${function.regentry_type} *entry;
for (entry = ${function.registry_symbol}; entry->name; ++entry) {
if (!entry->rank)
entry->rank = ++rank_${function.name};
}
qsort(${function.registry_symbol}, entry - ${function.registry_symbol}, sizeof(${function.regentry_type}), starch_regentry_rank_compare);
/* reset the implementation pointer so the next call will re-select */
${function.callable_symbol} = ${function.dispatcher_symbol};
}
% endfor
return 0;
}