source: cpp/frams/genetics/geno.cpp @ 518

Last change on this file since 518 was 518, checked in by Maciej Komosinski, 8 years ago

More strict parsing of genotype format prefix

  • Property svn:eol-style set to native
File size: 7.2 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "geno.h"
6#include "genoconv.h"
7#include <common/loggers/loggers.h>
8#include <common/stl-util.h>
9#include <frams/model/model.h>
10
11THREAD_LOCAL_DEF_PTR(Geno::Validators, geno_validators);
12THREAD_LOCAL_DEF_PTR(GenoConvManager, geno_converters);
13
14Geno::Validators* Geno::getValidators() {return tlsGetPtr(geno_validators);}
15GenoConvManager* Geno::getConverters() {return tlsGetPtr(geno_converters);}
16
17Geno::Validators* Geno::useValidators(Validators* val)
18{return tlsSetPtr(geno_validators,val);}
19GenoConvManager* Geno::useConverters(GenoConvManager* gcm)
20{return tlsSetPtr(geno_converters,gcm);}
21
22void Geno::init(const SString& genstring, char genformat, const SString& genname, const SString& comment)
23{
24        refcount = 1;
25        owner = 0;
26        f0gen = 0;
27        mapinshift = 0;
28        mapoutshift = 0;
29        isvalid = -1;
30        SString gencopy(genstring);
31        if (genformat == -1)
32        { // unknown format
33                genformat = '1';
34                if (genstring.charAt(0) == '/')
35                {
36                        int end;
37                        switch (genstring.charAt(1))
38                        {
39                        case '/':
40                                genformat = genstring.charAt(2);
41                                if ((genformat=='\0')||(genformat=='\n'))
42                                        genformat=INVALID_FORMAT;
43                                if ((end = genstring.indexOf('\n')) >= 0)
44                                {
45                                        if (end!=3) genformat=INVALID_FORMAT;
46                                        gencopy = genstring.substr(end + 1);
47                                        mapinshift = end + 1;
48                                }
49                                else
50                                {
51                                        if (genstring.len()!=3) genformat=INVALID_FORMAT;
52                                        gencopy = 0;
53                                        mapinshift = genstring.len();
54                                }
55                                break;
56                        case '*':
57                                genformat = genstring.charAt(2);
58                                if ((genformat=='\0')||(genformat=='\n'))
59                                        genformat=INVALID_FORMAT;
60                                if ((end = genstring.indexOf("*/")) >= 0)
61                                {
62                                        if (end!=3) genformat=INVALID_FORMAT;
63                                        gencopy = genstring.substr(end + 2);
64                                        mapinshift = end + 2;
65                                }
66                                else
67                                {
68                                        if (genstring.len()!=5) genformat=INVALID_FORMAT;
69                                        gencopy = 0;
70                                        mapinshift = genstring.len();
71                                }
72                                break;
73                        }
74                }
75        }
76
77        gen = gencopy;
78        format = genformat;
79        name = genname;
80        txt = comment;
81        multiline = (strchr(gen.c_str(), '\n') != 0);
82        // mapoutshift...?
83}
84
85void Geno::freeF0()
86{
87        if (f0gen) { delete f0gen; f0gen = 0; }
88}
89
90Geno::Geno(const char *genstring, char genformat, const char *genname, const char *comment)
91{
92        init(SString(genstring), genformat, SString(genname), SString(comment));
93}
94
95Geno::Geno(const SString& genstring, char genformat, const SString& genname, const SString& comment)
96{
97        init(genstring, genformat, genname, comment);
98}
99
100Geno::Geno(const Geno& src)
101:gen(src.gen), name(src.name), format(src.format), txt(src.txt), isvalid(src.isvalid),
102f0gen(0), mapinshift(src.mapinshift), mapoutshift(src.mapinshift),
103multiline(src.multiline), owner(0)
104{
105        f0gen = src.f0gen ? new Geno(*src.f0gen) : 0; refcount = 1;
106}
107
108void Geno::operator=(const Geno& src)
109{
110        freeF0();
111        gen = src.gen;
112        name = src.name;
113        format = src.format;
114        txt = src.txt;
115        isvalid = src.isvalid;
116        mapinshift = src.mapinshift;
117        mapoutshift = src.mapinshift;
118        multiline = src.multiline;
119        f0gen = src.f0gen ? new Geno(*src.f0gen) : 0;
120        owner = 0;
121}
122
123Geno::Geno(const SString& src)
124{
125        init(src, -1, SString::empty(), SString::empty());
126}
127
128void Geno::setGene(const SString& g, char newformat)
129{
130        gen = g;
131        isvalid = -1;
132        freeF0();
133        if (newformat >= 0) format = newformat;
134}
135
136void Geno::setString(const SString& g)
137{
138        freeF0();
139        init(g, -1, SString::empty(), SString::empty());
140}
141
142void Geno::setName(const SString& n)
143{
144        name = n;
145}
146
147void Geno::setComment(const SString& c)
148{
149        txt = c;
150}
151
152SString Geno::toString(void) const
153{
154        SString out;
155        int comment = 0;
156        if ((format != '1') || (comment = (txt.len() || name.len())))
157        {
158                if (multiline)
159                        out += "//";
160                else
161                        out += "/*";
162                out += format;
163                if (comment)
164                {
165                        if (txt.len()) { out += ";"; out += txt; }
166                        if (name.len()){ out += ";"; out += name; }
167                }
168                if (multiline)
169                        out += "\n";
170                else
171                        out += "*/";
172        }
173        out += gen;
174        return out;
175}
176
177SString Geno::shortString(void) const
178{
179        SString out;
180        if (format != '1')
181        {
182                if (multiline)
183                        out += "//";
184                else
185                        out += "/*";
186                if (format == 0)
187                        out += "invalid";
188                else
189                        out += format;
190                if (multiline)
191                        out += "\n";
192                else
193                        out += "*/";
194        }
195        out += gen;
196        return out;
197}
198
199int Geno::mapGenToString(int genpos) const
200{
201        if (genpos > gen.len()) return -2;
202        if (genpos<0) return -1;
203        return mapinshift + genpos;
204}
205
206int Geno::mapStringToGen(int stringpos) const
207{
208        stringpos -= mapinshift;
209        if (stringpos>gen.len()) return -2;
210        if (stringpos < 0) return -1;
211        return stringpos;
212}
213
214SString Geno::getGene(void) const { return gen; }
215SString Geno::getName(void) const { return name; }
216char Geno::getFormat(void) const { return format; }
217SString Geno::getComment(void) const { return txt; }
218
219int ModelGenoValidator::testGenoValidity(Geno& g)
220{
221        if (g.getFormat() == '0')
222        {
223                Model mod(g);
224                return mod.isValid();
225        }
226        else
227        {
228                bool converter_missing;
229                Geno f0geno = g.getConverted('0', NULL, &converter_missing);
230                if (converter_missing)
231                        return -1;//no result
232                return f0geno.isValid();
233        }
234}
235
236void Geno::validate()
237{
238        if (isvalid >= 0) return;
239        if (gen.len() == 0) { isvalid = 0; return; }
240        if (format == INVALID_FORMAT) { isvalid = 0; return; }
241        Validators* vals=getValidators();
242        if (vals!=NULL)
243                {
244#ifdef WARN_VALIDATION_INCONSISTENCY
245                vector<int> results;
246                int first_result=-1;
247                FOREACH(GenoValidator*, v, (*vals))
248                        {
249                        int r=v->testGenoValidity(*this);
250                        if (first_result<0) first_result=r;
251                        results.push_back(r);
252                        }
253                int N=vals->size();
254                for(int i=1;i<N;i++)
255                        if (results[i]!=results[0])
256                                {
257                                SString txt="Inconsistent validation results";
258                                for(int i=0;i<N;i++)
259                                        txt+=SString::sprintf(" %d",results[i]);
260                                txt+=" for genotype '";
261                                txt+=getGene();
262                                txt+="'";
263                                logPrintf("Geno","validate",LOG_WARN,txt.c_str());
264                                break;
265                                }
266                isvalid=first_result;
267                if (isvalid>=0)
268                        return;
269#else
270        FOREACH(GenoValidator*, v, (*vals))
271                if ((isvalid = v->testGenoValidity(*this)) >= 0)
272                        return;
273#endif
274                }
275        isvalid = 0;
276        logPrintf("Geno", "validate", LOG_WARN, "Wrong configuration? No genotype validators defined for genetic format f%c.", format);
277}
278
279bool Geno::isValid(void)
280{
281        if (isvalid<0)
282                {
283                LoggerToMemory err(LoggerBase::Enable | LoggerToMemory::StoreAllMessages,LOG_INFO);
284                validate();
285                err.disable();
286                string msg=err.getCountSummary();
287                if (msg.size()>0)
288                        {
289                        msg+=ssprintf(" while checking validity of '%s'",getName().c_str());
290                        msg+="\n";
291                        msg+=err.getMessages();
292                        logMessage("Geno","isValid",err.getErrorLevel(),msg.c_str());
293                        }
294                }
295        return isvalid>0;
296}
297
298Geno Geno::getConverted(char otherformat, MultiMap *m, bool *converter_missing)
299{
300        if (otherformat == getFormat()) { if (converter_missing) *converter_missing = false; return *this; }
301#ifndef NO_GENOCONVMANAGER
302        GenoConvManager *converters=getConverters();
303        if (converters)
304        {
305                if ((otherformat == '0') && (!m))
306                {
307                        if (!f0gen)
308                                f0gen = new Geno(converters->convert(*this, otherformat, NULL, converter_missing));
309                        else
310                                { if (converter_missing) *converter_missing = false; }
311                        return *f0gen;
312                }
313                else
314                        return converters->convert(*this, otherformat, m, converter_missing);
315        }
316#endif
317        if (converter_missing) *converter_missing = true;
318        return (otherformat == getFormat()) ? *this : Geno(0, 0, 0, "GenConvManager not available");
319}
320
321Geno::~Geno()
322{
323        if (f0gen) delete f0gen;
324}
Note: See TracBrowser for help on using the repository browser.