// This file is a part of Framsticks SDK. http://www.framsticks.com/ // Copyright (C) 1999-2020 Maciej Komosinski and Szymon Ulatowski. // See LICENSE.txt for details. #include #include #include #include #include #include #include #include #include "genoconv.h" #include #include /////////////////////////////////////////////////////////////////////////// GenoConvParam::GenoConvParam(GenoConvManager *g) :Param(0), gcm(g) { updatetab(); } void GenoConvParam::freetab() { if (tab) free(tab); tab = 0; } const char *GenoConvParam::id(int i) { if (i >= gcm->converters.size()) return 0; sprintf(tmp_id, "genkonw%d", i); return tmp_id; } void GenoConvParam::updatetab() { int i; GenoConverter *gk; ParamEntry *pe; int ile = gcm->converters.size(); freetab(); tab = (ParamEntry*)calloc(2 + ile, sizeof(ParamEntry)); tab[0].id = "Genetics: Conversions"; tab[0].group = 1; tab[0].flags = (paInt)ile; tab[0].name = "gkparam:"; gcnames.clear(); gcnames.reserve(gcm->converters.size()); //avoid reallocations in the loop below, since we externally store pointers to objects saved in this vector for (i = 0, pe = tab + 1; gk = (GenoConverter *)gcm->converters(i); pe++, i++) { pe->id = "?"; pe->group = 0; pe->flags = 0; std::string descr = "f"; descr += gk->in_format.c_str(); descr += " --> f"; descr += gk->out_format.c_str(); descr += " : "; descr += gk->name; gcnames.push_back(descr); pe->name = gcnames.back().c_str(); //externally store a pointer to the object just saved in the vector pe->type = "d 0 1"; } pe->id = 0; } GenoConvParam::~GenoConvParam() { freetab(); } void *GenoConvParam::getTarget(int i) { GenoConverter *gk = (GenoConverter *)gcm->converters(i); return &gk->enabled; } GenoConvManager::GenoConvManager() :param(this) { } GenoConvManager::~GenoConvManager() { FOREACH(GenoConverter*, gc, converters) delete gc; } void GenoConvManager::addConverter(GenoConverter *gc) { converters += gc; param.updatetab(); } void GenoConvManager::removeConverter(GenoConverter *gc) { converters -= gc; param.updatetab(); } GenoConverter *GenoConvManager::findConverters(SListTempl* result, const SString& in, const SString& out, int enabled, char* name) { GenoConverter *gk, *retval = 0; int i = 0; for (; gk = (GenoConverter*)converters(i); i++) { if ((in != Geno::UNKNOWN_FORMAT) && (in != gk->in_format)) continue; if ((out != Geno::UNKNOWN_FORMAT) && (out != gk->out_format)) continue; if ((enabled != -1) && (enabled != gk->enabled)) continue; if ((name) && (strcmp(name, gk->name))) continue; if (!retval) { retval = gk; if (!result) break; } if (result) result->append(gk); } return retval; } /// Writes path into 'path'. /// return the last path element (return >= path) /// null -> path not found /// @param mapavailable will receive 1 if conversion map is supported by all converters in path /// (can be NULL if you don't need this information) GenoConverter **GenoConvManager::getPath(const SString& in_format, const SString& out_format_list, GenoConverter **path, int maxlen, int *mapavailable) { if (!maxlen) return 0; GenoConverter *gk; int i = 0; for (; gk = (GenoConverter*)converters(i); i++) { if ((gk->enabled) && (gk->in_format == in_format)) { *path = gk; if (Geno::formatIsOneOf(gk->out_format, out_format_list)) { if (mapavailable) *mapavailable = gk->mapsupport; return path; } else { int mapavail; GenoConverter **ret = getPath(gk->out_format, out_format_list, path + 1, maxlen - 1, &mapavail); if (ret) { if (mapavailable) *mapavailable = gk->mapsupport && mapavail; return ret; } } } } return 0; } Geno GenoConvManager::convert(Geno &in, SString format_list, MultiMap *map, bool using_checkpoints, bool *converter_missing) { if (Geno::formatIsOneOf(in.getFormat(), format_list)) { if (converter_missing) *converter_missing = false; return in; } GenoConverter *path[10]; int dep; GenoConverter **ret; if (in.isInvalid()) { if (converter_missing) *converter_missing = false; return Geno("", Geno::INVALID_FORMAT, "", "invalid genotype cannot be converted"); } int mapavail; for (dep = 1; dep < (int)sizeof(path); dep++) //iterative deepening if (ret = getPath(in.getFormat(), format_list, path, dep, &mapavail)) break; if (!ret) { if (converter_missing) *converter_missing = true; return Geno("", Geno::INVALID_FORMAT, "", "converter not found"); } if (converter_missing) *converter_missing = false; if (!map) mapavail = 0; GenoConverter **t = path; SString tmp, out_format; tmp = in.getGenes(); MultiMap lastmap, tmpmap; int firstmap = 1; for (; t <= ret; t++) { GenoConverter *gk = *t; tmp = gk->convert(tmp, mapavail ? &tmpmap : 0, using_checkpoints); out_format = gk->out_format; if (!tmp.length()) { string t = ssprintf("f%s->f%s conversion failed (%s)", gk->in_format.c_str(), gk->out_format.c_str(), gk->name); return Geno("", Geno::INVALID_FORMAT, "", t.c_str()); } if (mapavail) { if (firstmap) { lastmap = tmpmap; firstmap = 0; } else { MultiMap m; m.addCombined(lastmap, tmpmap); lastmap = m; } tmpmap.clear(); } } if (map) *map = lastmap; return Geno(tmp, out_format, in.getName(), in.getComment()); }