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

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

Strict parsing of genotype format prefix

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