207 lines
6.4 KiB
Plaintext
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;
|
|
}
|