### Copyright (c) 2020, FlightAware LLC. ### All rights reserved. ### See the LICENSE file for licensing terms. /* starch generated code. Do not edit. */ #include #include #include #include #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 sorted(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 sorted(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 sorted(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 sorted(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 sorted(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; }