- Timestamp:
- 01/14/18 11:25:02 (7 years ago)
- Location:
- cpp/frams
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
cpp/frams/neuro/neuroimpl.h
r646 r721 1 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-201 5Maciej Komosinski and Szymon Ulatowski.2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 3 // See LICENSE.txt for details. 4 4 … … 23 23 { 24 24 public: 25 NeuroNetConfig(NeuroFactory *fac);26 27 Param par;28 double randominit;29 double nnoise;30 double touchrange;31 32 NeuroFactory *factory;33 //static NeuroNetConfig& getGlobalConfig();25 NeuroNetConfig(NeuroFactory *fac); 26 27 Param par; 28 double randominit; 29 double nnoise; 30 double touchrange; 31 32 NeuroFactory *factory; 33 //static NeuroNetConfig& getGlobalConfig(); 34 34 }; 35 35 36 36 #ifdef NEURO_SIGNALS 37 class NeuroSignals : public SignalSet37 class NeuroSignals : public SignalSet 38 38 { 39 40 Creature *cr;41 NeuroImpl *owner;42 Creature *getCreature();43 44 45 NeuroSignals(NeuroImpl *n):cr(0),owner(n) {}39 protected: 40 Creature *cr; 41 NeuroImpl *owner; 42 Creature *getCreature(); 43 public: 44 45 NeuroSignals(NeuroImpl *n) :cr(0), owner(n) {} 46 46 47 47 #define STATRICKCLASS NeuroSignals 48 PARAMPROCDEF(p_add);49 PARAMPROCDEF(p_get);50 PARAMGETDEF(size);51 PARAMPROCDEF(p_receive);52 PARAMPROCDEF(p_receiveSet);53 PARAMPROCDEF(p_receiveFilter);54 PARAMPROCDEF(p_receiveSingle);48 PARAMPROCDEF(p_add); 49 PARAMPROCDEF(p_get); 50 PARAMGETDEF(size); 51 PARAMPROCDEF(p_receive); 52 PARAMPROCDEF(p_receiveSet); 53 PARAMPROCDEF(p_receiveFilter); 54 PARAMPROCDEF(p_receiveSingle); 55 55 #undef STATRICKCLASS 56 56 57 static Param& getStaticParam();57 static Param& getStaticParam(); 58 58 }; 59 59 #endif … … 62 62 class NeuroNetImpl 63 63 { 64 CallbackNode *cnode;65 Model &mod;66 SList neurons[4];67 NeuroNetConfig& config;68 int isbuilt,errorcount;69 STCALLBACKDEFC(NeuroNetImpl,destroyNN);70 int minorder,maxorder;71 72 73 #ifdef NEURO_SIGNALS 74 ChannelSpace *channels;75 #endif 76 static int mytags_id;77 static double getStateFromNeuro(Neuro *n);78 int getErrorCount() {return errorcount;}79 NeuroNetConfig &getConfig() {return config;}80 NeuroNetImpl(Model& model, NeuroNetConfig& conf81 #ifdef NEURO_SIGNALS 82 , ChannelSpace *ch=083 #endif 84 );85 ~NeuroNetImpl();86 void simulateNeuroNet();87 void simulateNeuroPhysics();88 89 static NeuroImpl *getImpl(Neuro* n) {return (NeuroImpl*)n->userdata[mytags_id];}64 CallbackNode *cnode; 65 Model &mod; 66 SList neurons[4]; 67 NeuroNetConfig& config; 68 int isbuilt, errorcount; 69 STCALLBACKDEFC(NeuroNetImpl, destroyNN); 70 int minorder, maxorder; 71 72 public: 73 #ifdef NEURO_SIGNALS 74 ChannelSpace *channels; 75 #endif 76 static int mytags_id; 77 static double getStateFromNeuro(Neuro *n); 78 int getErrorCount() { return errorcount; } 79 NeuroNetConfig &getConfig() { return config; } 80 NeuroNetImpl(Model& model, NeuroNetConfig& conf 81 #ifdef NEURO_SIGNALS 82 , ChannelSpace *ch = 0 83 #endif 84 ); 85 ~NeuroNetImpl(); 86 void simulateNeuroNet(); 87 void simulateNeuroPhysics(); 88 89 static NeuroImpl *getImpl(Neuro* n) { return (NeuroImpl*)n->userdata[mytags_id]; } 90 90 }; 91 91 … … 95 95 (Neuro::state) in each simulation step. 96 96 97 SUBCLASSING TUTORIAL98 ====================99 100 1.Derive your custom neuron from NeuroImpl class. The name must be prefixed with NI_101 102 class NI_MyNeuron: public NeuroImpl103 { ... };104 105 2.Public parameters106 Create any number of public fields, they will be adjustable from the genotype level.107 3 datatypes are supported: long, double and SString108 109 public:110 paInt intParameter;111 double fpParameter;112 SString txtParameter;113 114 115 3.Required method: "instantiator".116 It is always the same, just create a new instance of your neuron.117 public:118 NeuroImpl* makeNew() { return new NI_MyNeuron(); };119 120 121 4.Required method: default constructor122 Set the "paramentries" variable if you need public parameters in your neuron.123 NI_..._tab is created automatically and should be declared as: extern ParamEntry NI_..._tab[];124 At this stage the parameter values are not yet available.125 126 public:127 NI_MyNeuron() // no parameters!128 {129 paramentries=NI_MyNeuron_tab;130 // you add here: some general initialization131 }132 133 134 5.Optional method: initialization135 This method is called once before the neuron is actually used in the simulation.136 The parameter values are already initialized (according to the genotype) and the neuron is bound to the creature (i.e. this->neuro is valid).137 Return 0 if the neuron cannot be initialized.138 139 int lateinit()140 {141 // you add here: initialization using full neuron context142 // example: if (!neuro->joint) return 0; //this neuron must be attached to joint143 return 1;//OK144 }145 146 147 6.Required method: simulation step148 If it has output: calculate the next neuron state and call setState()149 If it is an effector: do anything else150 151 void go()152 {153 // you add here: things called every simulation step154 }155 156 Note: You can make your neuron fire before or after "regular" neurons by changing its "simorder" property (during initialization). The default value is 1, whereas receptors have simorder=0 and effectors have simorder=2.157 158 159 7.Neuron definition160 In order to incorporate the new neuron into Framsticks you need to provide some additional information (to be added to "f0.def" file).161 162 NEUROCLASS(MyNeuron,MN,This is the name,`Neuron description',-1,1,0)163 NEUROPROP(int,0,0,name of the int,d,,,,intParameter)164 NEUROPROP(fp,0,0,name of the floating point,f,,,,fpParameter)165 NEUROPROP(txt,0,0,name of the text,s,,,,txtParameter)166 ENDNEUROCLASS 167 168 NEUROCLASS:169 - MyNeuron: neuron class name (without the NI_ prefix)170 - MN: neuron symbol (used in genotypes)171 - full name and description172 - -1: preferred number of inputs (special case: -1=any)173 - 1: provides output: 1=yes/0=no174 - 0: preferred location: 0=none, 1=part, 2=joint175 176 NEUROPROP:177 - int/fp/txt: parameter names as visible in genotypes and scripting178 - "name of the ...": descriptive name179 - d/f/s: type (int/floating point/string)180 - intParameter/fpParameter/txtParameter: C++ field names181 182 183 */97 SUBCLASSING TUTORIAL 98 ==================== 99 100 1.Derive your custom neuron from NeuroImpl class. The name must be prefixed with NI_ 101 102 class NI_MyNeuron: public NeuroImpl 103 { ... }; 104 105 2.Public parameters 106 Create any number of public fields, they will be adjustable from the genotype level. 107 3 datatypes are supported: long, double and SString 108 109 public: 110 paInt intParameter; 111 double fpParameter; 112 SString txtParameter; 113 114 115 3.Required method: "instantiator". 116 It is always the same, just create a new instance of your neuron. 117 public: 118 NeuroImpl* makeNew() { return new NI_MyNeuron(); }; 119 120 121 4.Required method: default constructor 122 Set the "paramentries" variable if you need public parameters in your neuron. 123 NI_..._tab is created automatically and should be declared as: extern ParamEntry NI_..._tab[]; 124 At this stage the parameter values are not yet available. 125 126 public: 127 NI_MyNeuron() // no parameters! 128 { 129 paramentries=NI_MyNeuron_tab; 130 // you add here: some general initialization 131 } 132 133 134 5.Optional method: initialization 135 This method is called once before the neuron is actually used in the simulation. 136 The parameter values are already initialized (according to the genotype) and the neuron is bound to the creature (i.e. this->neuro is valid). 137 Return 0 if the neuron cannot be initialized. 138 139 int lateinit() 140 { 141 // you add here: initialization using full neuron context 142 // example: if (!neuro->joint) return 0; //this neuron must be attached to joint 143 return 1;//OK 144 } 145 146 147 6.Required method: simulation step 148 If it has output: calculate the next neuron state and call setState() 149 If it is an effector: do anything else 150 151 void go() 152 { 153 // you add here: things called every simulation step 154 } 155 156 Note: You can make your neuron fire before or after "regular" neurons by changing its "simorder" property (during initialization). The default value is 1, whereas receptors have simorder=0 and effectors have simorder=2. 157 158 159 7.Neuron definition 160 In order to incorporate the new neuron into Framsticks you need to provide some additional information (to be added to "f0.def" file). 161 162 NEUROCLASS(MyNeuron,MN,This is the name,`Neuron description',-1,1,0) 163 NEUROPROP(int,0,0,name of the int,d,,,,intParameter) 164 NEUROPROP(fp,0,0,name of the floating point,f,,,,fpParameter) 165 NEUROPROP(txt,0,0,name of the text,s,,,,txtParameter) 166 ENDNEUROCLASS 167 168 NEUROCLASS: 169 - MyNeuron: neuron class name (without the NI_ prefix) 170 - MN: neuron symbol (used in genotypes) 171 - full name and description 172 - -1: preferred number of inputs (special case: -1=any) 173 - 1: provides output: 1=yes/0=no 174 - 0: preferred location: 0=none, 1=part, 2=joint 175 176 NEUROPROP: 177 - int/fp/txt: parameter names as visible in genotypes and scripting 178 - "name of the ...": descriptive name 179 - d/f/s: type (int/floating point/string) 180 - intParameter/fpParameter/txtParameter: C++ field names 181 182 183 */ 184 184 class NeuroImpl 185 185 { 186 186 protected: 187 int simorder;188 int channels;189 SListTempl<double> chstate;190 SListTempl<double> chnewstate;191 Param *fields_param;192 ExtObject *fields_object;187 int simorder; 188 int channels; 189 SListTempl<double> chstate; 190 SListTempl<double> chnewstate; 191 Param *fields_param; 192 ExtObject *fields_object; 193 193 public: 194 static const int ENDDRAWING;195 static const int MAXDRAWINGXY;196 197 enum NeuroImplStats { BeforeInit=0, InitError=1, InitOk=2 };198 NeuroImplStats status;199 /** originating neuron object (from the model) */200 Neuro *neuro;201 NeuroClass *neuroclass;202 /** don't access directly */203 double newstate;204 NeuroNetImpl *owner;205 /** will be used by readParam() method, if not null */206 ParamEntry *paramentries; // no extra properties if ==0207 208 #ifdef NEURO_SIGNALS 209 NeuroSignals sigs;210 ExtObject sigs_obj;211 #endif 212 213 /** "virtual constructor" - NeuroFactory uses this method to create the proper implementation object.214 215 virtual NeuroImpl* makeNew() {return 0;} //216 /** read additional properties from "moredata" field of the originating Neuro */217 void readParam();218 /** called when all other neuro objects were already created and "moredata" transferred to219 220 221 222 */223 virtual int lateinit() {return 1;}224 /** calculate 'newstate - implementation dependent */225 virtual void go(){}226 /** for neurons doing some physical actions (called each simulation step when nnspeed!=1.0) */227 virtual void goPhysics(){}228 229 int getSimOrder() {return simorder;}230 virtual int getNeedPhysics() {return 0;}231 232 void setChannelCount(int c);233 int getChannelCount() {return channels;}234 235 int getInputCount() {return neuro->getInputCount();}236 int getInputChannelCount(int i);237 double getInputState(int i,int channel=0);238 double getWeightedInputState(int i,int channel=0);239 double getInputSum(int startwith=0);240 double getWeightedInputSum(int startwith=0);241 double getInputWeight(int i) {return neuro->getInputWeight(i);}242 void setState(double st,int channel);243 void setState(double st) {validateNeuroState(st); newstate=st;}244 double getState(int channel);245 double getState() {return neuro->state;}246 247 virtual int getDrawingCount() {return 0;}248 virtual int* getDrawing(int i) {return 0;}249 250 /** is this implementation current? script neurons retain their original implementation when reloading *.neuro */251 virtual bool isCurrent() {return true;}252 253 void commit();254 void validateNeuroState(double& st) {if (st<=-1e10) st=-1e10; else if (st>1e10) st=1e10;}255 256 NeuroImpl():simorder(1),channels(1),fields_param(0),fields_object(0),status(BeforeInit),neuro(0),newstate(0),owner(0),paramentries(0)257 #ifdef NEURO_SIGNALS 258 ,sigs(this),sigs_obj(&NeuroSignals::getStaticParam(),&sigs)259 #endif 260 261 virtual ~NeuroImpl();262 virtual void createFieldsObject();263 264 /** usually == "newstate" but will obey the "hold state" */265 double getNewState(int channel=0);266 267 /** don't use! */268 void setCurrentState(double st,int channel=0);269 270 bool getPosition(Pt3D &pos);271 Creature* getCreature();194 static const int ENDDRAWING; 195 static const int MAXDRAWINGXY; 196 197 enum NeuroImplStats { BeforeInit = 0, InitError = 1, InitOk = 2 }; 198 NeuroImplStats status; 199 /** originating neuron object (from the model) */ 200 Neuro *neuro; 201 NeuroClass *neuroclass; 202 /** don't access directly */ 203 double newstate; 204 NeuroNetImpl *owner; 205 /** will be used by readParam() method, if not null */ 206 ParamEntry *paramentries; // no extra properties if ==0 207 208 #ifdef NEURO_SIGNALS 209 NeuroSignals sigs; 210 ExtObject sigs_obj; 211 #endif 212 213 /** "virtual constructor" - NeuroFactory uses this method to create the proper implementation object. 214 subclasses must return new object here. */ 215 virtual NeuroImpl* makeNew() { return 0; } // 216 /** read additional properties from "moredata" field of the originating Neuro */ 217 void readParam(); 218 /** called when all other neuro objects were already created and "moredata" transferred to 219 object fields. 220 useful for initialization that cannot be performed in the constructor. 221 @return 1=ok 0=failure 222 */ 223 virtual int lateinit() { return 1; } 224 /** calculate 'newstate - implementation dependent */ 225 virtual void go(){} 226 /** for neurons doing some physical actions (called each simulation step when nnspeed!=1.0) */ 227 virtual void goPhysics(){} 228 229 int getSimOrder() { return simorder; } 230 virtual int getNeedPhysics() { return 0; } 231 232 void setChannelCount(int c); 233 int getChannelCount() { return channels; } 234 235 int getInputCount() { return neuro->getInputCount(); } 236 int getInputChannelCount(int i); 237 double getInputState(int i, int channel = 0); 238 double getWeightedInputState(int i, int channel = 0); 239 double getInputSum(int startwith = 0); 240 double getWeightedInputSum(int startwith = 0); 241 double getInputWeight(int i) { return neuro->getInputWeight(i); } 242 void setState(double st, int channel); 243 void setState(double st) { validateNeuroState(st); newstate = st; } 244 double getState(int channel); 245 double getState() { return neuro->state; } 246 247 virtual int getDrawingCount() { return 0; } 248 virtual int* getDrawing(int i) { return 0; } 249 250 /** is this implementation current? script neurons retain their original implementation when reloading *.neuro */ 251 virtual bool isCurrent() { return true; } 252 253 void commit(); 254 void validateNeuroState(double& st) { if (st <= -1e10) st = -1e10; else if (st > 1e10) st = 1e10; } 255 256 NeuroImpl() :simorder(1), channels(1), fields_param(0), fields_object(0), status(BeforeInit), neuro(0), newstate(0), owner(0), paramentries(0) 257 #ifdef NEURO_SIGNALS 258 , sigs(this), sigs_obj(&NeuroSignals::getStaticParam(), &sigs) 259 #endif 260 {} 261 virtual ~NeuroImpl(); 262 virtual void createFieldsObject(); 263 264 /** usually == "newstate" but will obey the "hold state" */ 265 double getNewState(int channel = 0); 266 267 /** don't use! */ 268 void setCurrentState(double st, int channel = 0); 269 270 bool getPosition(Pt3D &pos); 271 Creature* getCreature(); 272 272 273 273 #define STATRICKCLASS NeuroImpl 274 PARAMGETDEF(count) {arg1->setInt(getInputCount());}275 PARAMPROCDEF(p_get) {arg2->setDouble(getInputState(arg1->getInt()));}276 PARAMPROCDEF(p_getweight) {arg2->setDouble(getInputWeight(arg1->getInt()));}277 PARAMPROCDEF(p_getw) {arg2->setDouble(getWeightedInputState(arg1->getInt()));}278 PARAMPROCDEF(p_getsum) {arg2->setDouble(getInputSum(arg1->getInt()));}279 PARAMPROCDEF(p_getwsum) {arg2->setDouble(getWeightedInputSum(arg1->getInt()));}280 PARAMGETDEF(sum) {arg1->setDouble(getInputSum(0));}281 PARAMGETDEF(wsum) {arg1->setDouble(getWeightedInputSum(0));}282 PARAMPROCDEF(p_getchancount) {arg2->setInt(getInputChannelCount(arg1->getInt()));}283 PARAMPROCDEF(p_getchan) {arg2->setDouble(getInputState(arg1[1].getInt(),arg1[0].getInt()));}284 PARAMPROCDEF(p_getwchan) {arg2->setDouble(getWeightedInputState(arg1[1].getInt(),arg1[0].getInt()));}285 PARAMGETDEF(state) {arg1->setDouble(getState());}286 PARAMSETDEF(state) {setState(arg1->getDouble()); return 0;}287 PARAMGETDEF(cstate) {arg1->setDouble(neuro->state);}288 PARAMSETDEF(cstate) {setCurrentState(arg1->getDouble()); return 0;}289 PARAMGETDEF(hold) {arg1->setInt((neuro->flags&(Neuro::HoldState))?1:0);}290 PARAMSETDEF(hold) {neuro->flags=(neuro->flags&~Neuro::HoldState)|(arg1->getInt()?Neuro::HoldState:0); return 0;}291 PARAMGETDEF(channels) {arg1->setInt(getChannelCount());}292 PARAMSETDEF(channels) {setChannelCount(arg1->getInt()); return 0;}293 PARAMPROCDEF(p_getstate) {arg2->setDouble(getState(arg1->getInt()));}294 PARAMPROCDEF(p_setstate) {setState(arg1[0].getDouble(),arg1[1].getInt());}295 PARAMPROCDEF(p_setcstate) {setCurrentState(arg1[0].getDouble(),arg1[1].getInt());}296 PARAMGETDEF(creature);297 PARAMGETDEF(part);298 PARAMGETDEF(joint);299 PARAMGETDEF(position_x);300 PARAMGETDEF(position_y);301 PARAMGETDEF(position_z);302 PARAMGETDEF(fields);303 PARAMGETDEF(neurodef);304 PARAMGETDEF(classObject);274 PARAMGETDEF(count) { arg1->setInt(getInputCount()); } 275 PARAMPROCDEF(p_get) { arg2->setDouble(getInputState(arg1->getInt())); } 276 PARAMPROCDEF(p_getweight) { arg2->setDouble(getInputWeight(arg1->getInt())); } 277 PARAMPROCDEF(p_getw) { arg2->setDouble(getWeightedInputState(arg1->getInt())); } 278 PARAMPROCDEF(p_getsum) { arg2->setDouble(getInputSum(arg1->getInt())); } 279 PARAMPROCDEF(p_getwsum) { arg2->setDouble(getWeightedInputSum(arg1->getInt())); } 280 PARAMGETDEF(sum) { arg1->setDouble(getInputSum(0)); } 281 PARAMGETDEF(wsum) { arg1->setDouble(getWeightedInputSum(0)); } 282 PARAMPROCDEF(p_getchancount) { arg2->setInt(getInputChannelCount(arg1->getInt())); } 283 PARAMPROCDEF(p_getchan) { arg2->setDouble(getInputState(arg1[1].getInt(), arg1[0].getInt())); } 284 PARAMPROCDEF(p_getwchan) { arg2->setDouble(getWeightedInputState(arg1[1].getInt(), arg1[0].getInt())); } 285 PARAMGETDEF(state) { arg1->setDouble(getState()); } 286 PARAMSETDEF(state) { setState(arg1->getDouble()); return 0; } 287 PARAMGETDEF(cstate) { arg1->setDouble(neuro->state); } 288 PARAMSETDEF(cstate) { setCurrentState(arg1->getDouble()); return 0; } 289 PARAMGETDEF(hold) { arg1->setInt((neuro->flags&(Neuro::HoldState)) ? 1 : 0); } 290 PARAMSETDEF(hold) { neuro->flags = (neuro->flags&~Neuro::HoldState) | (arg1->getInt() ? Neuro::HoldState : 0); return 0; } 291 PARAMGETDEF(channels) { arg1->setInt(getChannelCount()); } 292 PARAMSETDEF(channels) { setChannelCount(arg1->getInt()); return 0; } 293 PARAMPROCDEF(p_getstate) { arg2->setDouble(getState(arg1->getInt())); } 294 PARAMPROCDEF(p_setstate) { setState(arg1[0].getDouble(), arg1[1].getInt()); } 295 PARAMPROCDEF(p_setcstate) { setCurrentState(arg1[0].getDouble(), arg1[1].getInt()); } 296 PARAMGETDEF(creature); 297 PARAMGETDEF(part); 298 PARAMGETDEF(joint); 299 PARAMGETDEF(position_x); 300 PARAMGETDEF(position_y); 301 PARAMGETDEF(position_z); 302 PARAMGETDEF(fields); 303 PARAMGETDEF(neurodef); 304 PARAMGETDEF(classObject); 305 305 #undef STATRICKCLASS 306 306 307 307 static Param& getStaticParam(); 308 308 }; 309 309 -
cpp/frams/param/multiparamload.h
r535 r721 1 1 // This file is a part of Framsticks SDK. http://www.framsticks.com/ 2 // Copyright (C) 1999-201 5Maciej Komosinski and Szymon Ulatowski.2 // Copyright (C) 1999-2018 Maciej Komosinski and Szymon Ulatowski. 3 3 // See LICENSE.txt for details. 4 4 … … 14 14 http://www.framsticks.com/common/formatspec.html 15 15 The loader can be configured to recognize multiple object types from object headers 16 and automatically call ParamInterface::load for the matching class. 17 18 Your code should repeatedly call MultiParamLoader::go() method and check the status after each call, until the end of file. 19 The loader pauses before and/or after each object giving you a chance to perform your application-specific actions (see MultiParamLoader::breakOn()). 20 If your application does not require any special actions, then the simple MultiParamLoader:run() can be used. 21 The word "record" (and "record type") used in this description refer to the textual form of a serialized object - this is to avoid confusion with 'live' objects passed to the loader methods. "Record type" can be the same as the class name, but it does not have to be the same. For example, the most common record type for storing the Genotype object is called "org" (think: organism) instead of "Genotype". 16 and automatically call ParamInterface::load for the matching class. 22 17 23 Typical usage scenarios: 24 1. Loading a file that contains at most one object of any given class: 25 - declare the object class(es) - MultiParamLoader::addClass() 26 - call MultiParamLoader::run() 27 - and that's all, the records from the file will be loaded into the corresponding objects 18 Your code should repeatedly call MultiParamLoader::go() method and check the status after each call, until the end of file. 19 The loader pauses before and/or after each object giving you a chance to perform your application-specific actions (see MultiParamLoader::breakOn()). 20 If your application does not require any special actions, then the simple MultiParamLoader:run() can be used. 21 The word "record" (and "record type") used in this description refer to the textual form of a serialized object - this is to avoid confusion with 'live' objects passed to the loader methods. "Record type" can be the same as the class name, but it does not have to be the same. For example, the most common record type for storing the Genotype object is called "org" (think: organism) instead of "Genotype". 28 22 29 2. Loading multiple objects and adding them to a list (see loadtest.cpp for a sample code that demonstrates this scenario) 30 - declare the object class giving the empty "template" object - MultiParamLoader::addClass() 31 - set breakOn(AfterObject) 32 - call MultiParamLoader::go() in a loop 33 - the returned status will be equal to AfterObject each time an object is loaded. One can detect this condition and create the real object from our template object 34 (alternatively, one could breakOn(BeforeObject) and use MultiParamLoader::loadObjectNow(ParamInterface*) to load the incoming object into a newly created object). 35 */ 23 Typical usage scenarios: 24 1. Loading a file that contains at most one object of any given class: 25 - declare the object class(es) - MultiParamLoader::addClass() 26 - call MultiParamLoader::run() 27 - and that's all, the records from the file will be loaded into the corresponding objects 28 29 2. Loading multiple objects and adding them to a list (see loadtest.cpp for a sample code that demonstrates this scenario) 30 - declare the object class giving the empty "template" object - MultiParamLoader::addClass() 31 - set breakOn(AfterObject) 32 - call MultiParamLoader::go() in a loop 33 - the returned status will be equal to AfterObject each time an object is loaded. One can detect this condition and create the real object from our template object 34 (alternatively, one could breakOn(BeforeObject) and use MultiParamLoader::loadObjectNow(ParamInterface*) to load the incoming object into a newly created object). 35 */ 36 36 class MultiParamLoader 37 37 { 38 VirtFILE *file;39 SListTempl<VirtFILE*> filestack;40 char ownfile;41 PtrListTempl<ExtObject*> objects;42 int status;43 SString lasterror, lastcomment, lastunknown;44 ExtObject lastobject;45 int breakcond;46 Param emptyparam;47 bool aborting;48 int linenum;38 VirtFILE *file; 39 SListTempl<VirtFILE*> filestack; 40 char ownfile; 41 PtrListTempl<ExtObject*> objects; 42 int status; 43 SString lasterror, lastcomment, lastunknown; 44 ExtObject lastobject; 45 int breakcond; 46 Param emptyparam; 47 bool aborting; 48 int linenum; 49 49 50 void init();50 void init(); 51 51 52 int maybeBreak(int cond) 53 { status=cond; return breakcond & cond; } 52 int maybeBreak(int cond) 53 { 54 status = cond; 55 return breakcond & cond; 56 } 54 57 55 VirtFILE* popstack();56 void clearstack();58 VirtFILE* popstack(); 59 void clearstack(); 57 60 58 59 MultiParamLoader() {init();}60 MultiParamLoader(VirtFILE *f) {init(); load(f);}61 MultiParamLoader(const char* filename) {init(); load(filename);}61 public: 62 MultiParamLoader() { init(); } 63 MultiParamLoader(VirtFILE *f) { init(); load(f); } 64 MultiParamLoader(const char* filename) { init(); load(filename); } 62 65 63 ~MultiParamLoader() {abort();clearObjects();}66 ~MultiParamLoader() { abort(); clearObjects(); } 64 67 65 void reset();68 void reset(); 66 69 67 void load(); //< use previously opened file68 void load(VirtFILE *f);69 void load(const char* filename);70 void load(); //< use previously opened file 71 void load(VirtFILE *f); 72 void load(const char* filename); 70 73 71 /** Register the object class. Class names will be matched with object headers ("xxx:" in the input file).72 73 74 75 void addObject(ParamInterface *pi) {objects+=new ExtObject(pi);}76 void removeObject(ParamInterface *pi) {removeObject(ExtObject(pi));}77 void addObject(const ExtObject &o) {objects+=new ExtObject(o);}78 void removeObject(const ExtObject &o);79 int findObject(const ExtObject &o);80 void clearObjects();74 /** Register the object class. Class names will be matched with object headers ("xxx:" in the input file). 75 Used with breakOn(BeforeObject) and/or breakOn(AfterObject). 76 Note that registered classes will only work when the record name matches the class name, otherwise breakOn(BeforeUnknown) must be used and then getClassName() to check for the expected record. 77 */ 78 void addObject(ParamInterface *pi) { objects += new ExtObject(pi); } 79 void removeObject(ParamInterface *pi) { removeObject(ExtObject(pi)); } 80 void addObject(const ExtObject &o) { objects += new ExtObject(o); } 81 void removeObject(const ExtObject &o); 82 int findObject(const ExtObject &o); 83 void clearObjects(); 81 84 82 /** To be used in the main loop: while(event=loader.go()) { ... }83 84 85 86 virtual int go();87 /** same value as 'go()' */88 int getStatus() {return status;}89 int finished() {return (status==Finished);}85 /** To be used in the main loop: while(event=loader.go()) { ... } 86 loader.go() will return on specified events (@see breakOn(), noBreakOn()), 87 then you can handle the event and resume loading. 88 */ 89 virtual int go(); 90 /** same value as 'go()' */ 91 int getStatus() { return status; } 92 int finished() { return (status == Finished); } 90 93 91 VirtFILE *getFile() {return file;}92 SString currentFilePathForErrorMessage();94 VirtFILE *getFile() { return file; } 95 SString currentFilePathForErrorMessage(); 93 96 94 /** Abort immediately and close the file if needed */ 95 void abort(); 96 /** @param conditions can be combined bitwise, eg. MultiParamLoader::BeforeObject | MultiParamLoader::OnComment 97 @see BreakConfitions 98 */ 99 void breakOn(int conditions) {breakcond|=conditions;} 100 void noBreakOn(int conditions) {breakcond&=~conditions;} 101 /** 102 These constants are used as arguments in breakOn(), and as status values from go() and getStatus(). 103 The user code can define some classes for automatic recognition (using addClass()); such records can be read without performing any additional actions. 104 105 - BeforeObject: found an object with recognized classname (addClass()). Application code can choose to skip the incoming record (skipObject()), redirect the incoming data into a different object (loadObjectNow(ParamInterface*)), or do nothing for default behavior (loading into previously registered object). 97 /** Abort immediately and close the file if needed */ 98 void abort(); 99 /** @param conditions can be combined bitwise, eg. MultiParamLoader::BeforeObject | MultiParamLoader::OnComment 100 @see BreakConfitions 101 */ 102 void breakOn(int conditions) { breakcond |= conditions; } 103 void noBreakOn(int conditions) { breakcond &= ~conditions; } 104 /** 105 These constants are used as arguments in breakOn(), and as status values from go() and getStatus(). 106 The user code can define some classes for automatic recognition (using addClass()); such records can be read without performing any additional actions. 106 107 107 - AfterObject: the object was loaded into the registered class interface (addClass()). This is to allow for additional actions after loading the object (e.g. data validation).108 - BeforeObject: found an object with recognized classname (addClass()). Application code can choose to skip the incoming record (skipObject()), redirect the incoming data into a different object (loadObjectNow(ParamInterface*)), or do nothing for default behavior (loading into previously registered object). 108 109 109 - BeforeUnknown: unknown (not registered) object header detected. Like in BeforeObject, the application can skipObject() or loadObjectNow().110 - AfterObject: the object was loaded into the registered class interface (addClass()). This is to allow for additional actions after loading the object (e.g. data validation). 110 111 111 @see getClass(), GetClassName() 112 */ 113 enum BreakConditions { Finished=0, BeforeObject=1, AfterObject=2, 114 BeforeUnknown=4, OnComment=8, OnError=16, Loading=32 }; 112 - BeforeUnknown: unknown (not registered) object header detected. Like in BeforeObject, the application can skipObject() or loadObjectNow(). 115 113 116 /** Can be used BeforeObject and AfterObject */ 117 ExtObject &getObject() {return lastobject;} 118 /** Can be used BeforeUnknown, BeforeObject, AfterObject */ 119 const SString& getObjectName() {return lastunknown;} 120 void setObjectName(SString n) {lastunknown=n;} 121 /** Unknown object will be loaded if you set its class BeforeUnknown */ 122 void setObject(ParamInterface *pi) {lastobject=ExtObject(pi);} 123 void setObject(const ExtObject& o) {lastobject=o;} 124 /** Can be used OnComment */ 125 const SString& getComment() {return lastcomment;} 126 /** Can be used OnError */ 127 const SString& getError() {return lasterror;} 128 /** Can be used BeforeObject and BeforeUnknown */ 129 int loadObjectNow(ParamInterface *pi,bool warn_unknown_fields=true) {return loadObjectNow(ExtObject(pi),warn_unknown_fields);} 130 int loadObjectNow(const ExtObject &o,bool warn_unknown_fields=true); 131 /** Can be used BeforeObject */ 132 int loadObjectNow() {return loadObjectNow(getObject());} 133 /** Can be used BeforeObject and BeforeUnknown. 134 Object data will not be loaded. */ 135 int skipObject() {return loadObjectNow(&emptyparam,false);} 136 /** @return 1 if no errors */ 137 int run(); 114 @see getClass(), GetClassName() 115 */ 116 enum BreakConditions { 117 Finished = 0, BeforeObject = 1, AfterObject = 2, 118 BeforeUnknown = 4, OnComment = 8, OnError = 16, Loading = 32 119 }; 138 120 139 void includeFile(SString& filename); 140 bool returnFromIncluded(); 141 bool alreadyIncluded(const char* filename); 121 /** Can be used BeforeObject and AfterObject */ 122 ExtObject &getObject() { return lastobject; } 123 /** Can be used BeforeUnknown, BeforeObject, AfterObject */ 124 const SString& getObjectName() { return lastunknown; } 125 void setObjectName(SString n) { lastunknown = n; } 126 /** Unknown object will be loaded if you set its class BeforeUnknown */ 127 void setObject(ParamInterface *pi) { lastobject = ExtObject(pi); } 128 void setObject(const ExtObject& o) { lastobject = o; } 129 /** Can be used OnComment */ 130 const SString& getComment() { return lastcomment; } 131 /** Can be used OnError */ 132 const SString& getError() { return lasterror; } 133 /** Can be used BeforeObject and BeforeUnknown */ 134 int loadObjectNow(ParamInterface *pi, bool warn_unknown_fields = true) { return loadObjectNow(ExtObject(pi), warn_unknown_fields); } 135 int loadObjectNow(const ExtObject &o, bool warn_unknown_fields = true); 136 /** Can be used BeforeObject */ 137 int loadObjectNow() { return loadObjectNow(getObject()); } 138 /** Can be used BeforeObject and BeforeUnknown. 139 Object data will not be loaded. */ 140 int skipObject() { return loadObjectNow(&emptyparam, false); } 141 /** @return 1 if no errors */ 142 int run(); 143 144 void includeFile(SString& filename); 145 bool returnFromIncluded(); 146 bool alreadyIncluded(const char* filename); 142 147 143 148 }; 144 149 145 150 #endif 146 -
cpp/frams/param/syntparam.h
r288 r721 9 9 10 10 /** Creates param + matching temporary object (ParamObject) 11 12 13 14 15 11 using the supplied ParamEntry'ies as a template. 12 This is mainly used for manipulating specialized neuron properties 13 (Neuro.d field) in absence of live neuron implementations 14 (these are only available in live creatures, but not when operating 15 on Models and Genotypes). 16 16 17 18 19 class SyntParam : public Param17 See also: genomanipulation.cpp 18 */ 19 class SyntParam : public Param 20 20 { 21 void* obj,*def_obj;22 ParamEntry *pe;23 SString* autostring;24 25 /** @param handle_defaults_when_saving creates a second object holding the default values so Param::save2 can use it for omitting defaults. can be disabled for compatiblity with previous behavior (defaults were ignored in SyntParam)26 */27 SyntParam(ParamEntry *pe,SString* autostring=0,bool handle_defaults_when_saving=true);28 SyntParam(const SyntParam& src);29 ~SyntParam();30 void setAutoUpdate(SString* autostr) {autostring=autostr;}31 void update(SString *s=0);32 void revert(SString *s=0);21 void* obj, *def_obj; 22 ParamEntry *pe; 23 SString* autostring; 24 public: 25 /** @param handle_defaults_when_saving creates a second object holding the default values so Param::save2 can use it for omitting defaults. can be disabled for compatiblity with previous behavior (defaults were ignored in SyntParam) 26 */ 27 SyntParam(ParamEntry *pe, SString* autostring = 0, bool handle_defaults_when_saving = true); 28 SyntParam(const SyntParam& src); 29 ~SyntParam(); 30 void setAutoUpdate(SString* autostr) { autostring = autostr; } 31 void update(SString *s = 0); 32 void revert(SString *s = 0); 33 33 }; 34 34
Note: See TracChangeset
for help on using the changeset viewer.