// This file is a part of the Framsticks GDK. // Copyright (C) 2002-2014 Maciej Komosinski and Szymon Ulatowski. See LICENSE.txt for details. // Refer to http://www.framsticks.com/ for further information. #include "geno.h" #include "genoconv.h" #include SListTempl Geno::validators; GenoConvManager *Geno::converters = NULL; void Geno::init(const SString& genstring, char genformat, const SString& genname, const SString& comment) { refcount = 1; owner = 0; f0gen = 0; mapinshift = 0; mapoutshift = 0; isvalid = -1; SString gencopy(genstring); if (genformat == -1) { // unknown format genformat = '1'; if (genstring.charAt(0) == '/') { int end; SString newcomment; switch (genstring.charAt(1)) { case '/': genformat = genstring.charAt(2); if ((end = genstring.indexOf('\n')) >= 0) { newcomment = genstring.substr(2, end - 2); gencopy = genstring.substr(end + 1); mapinshift = end + 1; } else { gencopy = 0; mapinshift = genstring.len(); } break; case '*': genformat = genstring.charAt(2); if ((end = genstring.indexOf("*/")) >= 0) { newcomment = genstring.substr(2, end - 2); gencopy = genstring.substr(end + 2); mapinshift = end + 2; } else { gencopy = 0; mapinshift = genstring.len(); } break; } if (newcomment.len() > 0) { SString token; int pos = 0; if (newcomment.getNextToken(pos, token, ';')) if (newcomment.getNextToken(pos, token, ';')) { if (token.len()) txt = token; if (newcomment.getNextToken(pos, token, ';')) if (token.len()) name = token; } } } } gen = gencopy; format = genformat; if (!name.len()) name = genname; if (!txt.len()) txt = comment; multiline = (strchr((const char*)gen, '\n') != 0); // mapoutshift...? } void Geno::freeF0() { if (f0gen) { delete f0gen; f0gen = 0; } } Geno::Geno(const char *genstring, char genformat, const char *genname, const char *comment) { init(SString(genstring), genformat, SString(genname), SString(comment)); } Geno::Geno(const SString& genstring, char genformat, const SString& genname, const SString& comment) { init(genstring, genformat, genname, comment); } Geno::Geno(const Geno& src) :gen(src.gen), name(src.name), format(src.format), txt(src.txt), isvalid(src.isvalid), f0gen(0), mapinshift(src.mapinshift), mapoutshift(src.mapinshift), multiline(src.multiline), owner(0) { f0gen = src.f0gen ? new Geno(*src.f0gen) : 0; refcount = 1; } void Geno::operator=(const Geno& src) { freeF0(); gen = src.gen; name = src.name; format = src.format; txt = src.txt; isvalid = src.isvalid; mapinshift = src.mapinshift; mapoutshift = src.mapinshift; multiline = src.multiline; f0gen = src.f0gen ? new Geno(*src.f0gen) : 0; owner = 0; } Geno::Geno(const SString& src) { init(src, -1, SString::empty(), SString::empty()); } void Geno::setGene(const SString& g, char newformat) { gen = g; isvalid = -1; freeF0(); if (newformat >= 0) format = newformat; } void Geno::setString(const SString& g) { freeF0(); init(g, -1, SString::empty(), SString::empty()); } void Geno::setName(const SString& n) { name = n; } void Geno::setComment(const SString& c) { txt = c; } SString Geno::toString(void) const { SString out; int comment = 0; if ((format != '1') || (comment = (txt.len() || name.len()))) { if (multiline) out += "//"; else out += "/*"; out += format; if (comment) { if (txt.len()) { out += ";"; out += txt; } if (name.len()){ out += ";"; out += name; } } if (multiline) out += "\n"; else out += "*/"; } out += gen; return out; } SString Geno::shortString(void) const { SString out; if (format != '1') { if (multiline) out += "//"; else out += "/*"; if (format == 0) out += "invalid"; else out += format; if (multiline) out += "\n"; else out += "*/"; } out += gen; return out; } int Geno::mapGenToString(int genpos) const { if (genpos > gen.len()) return -2; if (genpos<0) return -1; return mapinshift + genpos; } int Geno::mapStringToGen(int stringpos) const { stringpos -= mapinshift; if (stringpos>gen.len()) return -2; if (stringpos < 0) return -1; return stringpos; } SString Geno::getGene(void) const { return gen; } SString Geno::getName(void) const { return name; } char Geno::getFormat(void) const { return format; } SString Geno::getComment(void) const { return txt; } int ModelGenoValidator::testGenoValidity(Geno& g) { if (g.getFormat() == '0') { Model mod(g); return mod.isValid(); } else { bool converter_missing; Geno f0geno = g.getConverted('0', NULL, &converter_missing); if (converter_missing) return -1;//no result return f0geno.isValid(); } } void Geno::validate() { if (isvalid >= 0) return; if (gen.len() == 0) { isvalid = 0; return; } FOREACH(GenoValidator*, v, validators) if ((isvalid = v->testGenoValidity(*this)) >= 0) return; isvalid = 0; FMprintf("Geno", "validate", FMLV_WARN, "Wrong configuration? No genotype validators defined for genetic format f%c.", format); } bool Geno::isValid(void) { if (isvalid<0) validate(); return isvalid>0; } Geno Geno::getConverted(char otherformat, MultiMap *m, bool *converter_missing) { if (otherformat == getFormat()) { if (converter_missing) *converter_missing = false; return *this; } #ifndef NO_GENOCONVMANAGER if (converters) { if ((otherformat == '0') && (!m)) { if (!f0gen) f0gen = new Geno(converters->convert(*this, otherformat, NULL, converter_missing)); return *f0gen; } else return converters->convert(*this, otherformat, m, converter_missing); } #endif if (converter_missing) *converter_missing = true; return (otherformat == getFormat()) ? *this : Geno(0, 0, 0, "GenConvManager not available"); } Geno::~Geno() { if (f0gen) delete f0gen; }