// This file is a part of Framsticks SDK. http://www.framsticks.com/ // Copyright (C) 1999-2015 Maciej Komosinski and Szymon Ulatowski. // See LICENSE.txt for details. #include "geno.h" #include "genoconv.h" #include #include #include THREAD_LOCAL_DEF_PTR(Geno::Validators, geno_validators); THREAD_LOCAL_DEF_PTR(GenoConvManager, geno_converters); Geno::Validators* Geno::getValidators() {return tlsGetPtr(geno_validators);} GenoConvManager* Geno::getConverters() {return tlsGetPtr(geno_converters);} Geno::Validators* Geno::useValidators(Validators* val) {return tlsSetPtr(geno_validators,val);} GenoConvManager* Geno::useConverters(GenoConvManager* gcm) {return tlsSetPtr(geno_converters,gcm);} 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(gen.c_str(), '\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; } Validators* vals=getValidators(); if (vals!=NULL) { #ifdef WARN_VALIDATION_INCONSISTENCY vector results; int first_result=-1; FOREACH(GenoValidator*, v, (*vals)) { int r=v->testGenoValidity(*this); if (first_result<0) first_result=r; results.push_back(r); } int N=vals->size(); for(int i=1;i=0) return; #else FOREACH(GenoValidator*, v, (*vals)) if ((isvalid = v->testGenoValidity(*this)) >= 0) return; #endif } isvalid = 0; logPrintf("Geno", "validate", LOG_WARN, "Wrong configuration? No genotype validators defined for genetic format f%c.", format); } bool Geno::isValid(void) { if (isvalid<0) { LoggerToMemory err(LoggerBase::Enable | LoggerToMemory::StoreAllMessages,LOG_INFO); validate(); err.disable(); string msg=err.getCountSummary(); if (msg.size()>0) { msg+=ssprintf(" while checking validity of '%s'",getName().c_str()); msg+="\n"; msg+=err.getMessages(); logMessage("Geno","isValid",err.getErrorLevel(),msg.c_str()); } } 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 GenoConvManager *converters=getConverters(); if (converters) { if ((otherformat == '0') && (!m)) { if (!f0gen) f0gen = new Geno(converters->convert(*this, otherformat, NULL, converter_missing)); else { if (converter_missing) *converter_missing = false; } 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; }