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

Last change on this file since 168 was 150, checked in by sz, 10 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.