source: cpp/frams/genetics/genoconv.cpp @ 150

Last change on this file since 150 was 150, checked in by sz, 9 years ago

Warn against missing converter, convert() caller can differentiate between conversion failure and missing converter.

  • Property svn:eol-style set to native
File size: 5.0 KB
Line 
1// This file is a part of the Framsticks GDK.
2// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
3// Refer to http://www.framsticks.com/ for further information.
4
5#include <common/nonstd.h>
6
7#include <stdlib.h>
8#include <math.h>
9#include <stdio.h>
10#include <string.h>
11#include <ctype.h>
12#include <time.h>
13#include <errno.h>
14
15#include "genoconv.h"
16#include <frams/util/multimap.h>
17
18///////////////////////////////////////////////////////////////////////////
19
20GenoConvParam::GenoConvParam(GenoConvManager *g) :Param(0), gcm(g)
21{
22        updatetab();
23}
24
25void GenoConvParam::freetab()
26{
27        if (tab) free(tab);
28        tab = 0;
29}
30
31const char *GenoConvParam::id(int i)
32{
33        if (i >= gcm->converters.size()) return 0;
34        sprintf(tmp_id, "genkonw%d", i);
35        return tmp_id;
36}
37
38void GenoConvParam::updatetab()
39{
40        int i;
41        GenoConverter *gk;
42        ParamEntry *pe;
43        int ile = gcm->converters.size();
44        freetab();
45        tab = (ParamEntry*)calloc(2 + ile, sizeof(ParamEntry));
46        tab[0].id = "Genetics: Conversions";
47        tab[0].group = 1;
48        tab[0].flags = (short)ile;
49        tab[0].name = "gkparam:";
50        gcnames.clear();
51        for (i = 0, pe = tab + 1; gk = (GenoConverter *)gcm->converters(i); pe++, i++)
52        {
53                pe->id = "?";
54                pe->group = 0;
55                pe->flags = 0;
56                std::string descr = "f";
57                descr += gk->in_format;
58                descr += " -> f";
59                descr += gk->out_format;
60                descr += " : ";
61                descr += gk->name;
62                gcnames.push_back(descr);
63                pe->name = descr.c_str();
64                pe->type = "d 0 1";
65                pe->help = gk->info;
66        }
67        pe->id = 0;
68}
69
70GenoConvParam::~GenoConvParam()
71{
72        freetab();
73}
74
75void *GenoConvParam::getTarget(int i)
76{
77        GenoConverter *gk = (GenoConverter *)gcm->converters(i);
78        return &gk->enabled;
79}
80
81GenoConvManager::GenoConvManager()
82:param(this)
83{
84}
85
86GenoConvManager::~GenoConvManager()
87{
88        FOREACH(GenoConverter*, gc, converters) delete gc;
89}
90
91void GenoConvManager::addConverter(GenoConverter *gc)
92{
93        converters += gc;
94        param.updatetab();
95}
96void GenoConvManager::removeConverter(GenoConverter *gc)
97{
98        converters -= gc;
99        param.updatetab();
100}
101
102GenoConverter *GenoConvManager::findConverters(SListTempl<GenoConverter*>* result, char in, char out, int enabled, char* name)
103{
104        GenoConverter *gk, *retval = 0;
105        int i = 0;
106        for (; gk = (GenoConverter*)converters(i); i++)
107        {
108                if ((in != -1) && (in != gk->in_format)) continue;
109                if ((out != -1) && (out != gk->out_format)) continue;
110                if ((enabled != -1) && (enabled != gk->enabled)) continue;
111                if ((name) && (strcmp(name, gk->name))) continue;
112                if (!retval) { retval = gk; if (!result) break; }
113                if (result) result->append(gk);
114        }
115        return retval;
116}
117
118/// Writes path into 'path'.
119/// return the last path element (return >= path)
120/// null -> path not found
121/// @param mapavailable will receive 1 if conversion map is supported by all converters in path
122/// (can be NULL if you don't need this information)
123
124char *GenoConvManager::getPath(char in, char out, char *path, int maxlen, int *mapavailable)
125{
126        if (!maxlen) return 0;
127        GenoConverter *gk;
128        int i = 0;
129        for (; gk = (GenoConverter*)converters(i); i++)
130        {
131                if ((gk->enabled) && (gk->in_format == in))
132                {
133                        *path = (char)i;
134                        if (gk->out_format == out)
135                        {
136                                if (mapavailable)
137                                        *mapavailable = gk->mapsupport;
138                                return path;
139                        }
140                        else
141                        {
142                                int mapavail;
143                                char *ret = getPath(gk->out_format, out, path + 1, maxlen - 1, &mapavail);
144                                if (ret)
145                                {
146                                        if (mapavailable)
147                                                *mapavailable = gk->mapsupport && mapavail;
148                                        return ret;
149                                }
150                        }
151                }
152        }
153        return 0;
154}
155
156char *GenoConvManager::getFormatPath(char in, char out, char *path, int maxlen, int *mapavailable)
157{
158        char *ret = getPath(in, out, path, maxlen, mapavailable);
159        if (ret)
160        {
161                for (char*t = path; t <= ret; t++)
162                        *t = ((GenoConverter*)converters(*t))->out_format;
163        }
164        return ret;
165}
166
167Geno GenoConvManager::convert(Geno &in, char format, MultiMap *map, bool *converter_missing)
168{
169        if (in.getFormat() == format) { if (converter_missing) *converter_missing = false; return in; }
170        char path[10];
171        int dep;
172        char *ret;
173        if (in.isInvalid()) { if (converter_missing) *converter_missing = false; return Geno("", 0, "", "invalid genotype cannot be converted"); }
174        int mapavail;
175        for (dep = 1; dep < (int)sizeof(path); dep++) //iterative deepening
176                if (ret = getPath(in.getFormat(), format, path, dep, &mapavail)) break;
177        if (!ret) { if (converter_missing) *converter_missing = true; return Geno("", 0, "", "converter not found"); }
178        if (converter_missing) *converter_missing = false;
179        if (!map) mapavail = 0;
180        char *t = path;
181        SString tmp;
182        tmp = in.getGene();
183        MultiMap lastmap, tmpmap;
184        int firstmap = 1;
185        for (; t <= ret; t++)
186        {
187                GenoConverter *gk = (GenoConverter*)converters(*t);
188                tmp = gk->convert(tmp, mapavail ? &tmpmap : 0);
189                if (!tmp.len())
190                {
191                        char t[100];
192                        sprintf(t, "f%c->f%c conversion failed (%s)", gk->in_format, gk->out_format, gk->name);
193                        return Geno(0, 0, 0, t);
194                }
195                if (mapavail)
196                {
197                        if (firstmap)
198                        {
199                                lastmap = tmpmap;
200                                firstmap = 0;
201                        }
202                        else
203                        {
204                                MultiMap m;
205                                m.addCombined(lastmap, tmpmap);
206                                lastmap = m;
207                        }
208                        tmpmap.clear();
209                }
210        }
211        if (map)
212                *map = lastmap;
213        return Geno(tmp, format, in.getName(), in.getComment());
214}
Note: See TracBrowser for help on using the repository browser.