source: cpp/frams/param/param.h @ 786

Last change on this file since 786 was 786, checked in by Maciej Komosinski, 6 years ago

Improved shortening of long stringified values in error messages

  • Property svn:eol-style set to native
File size: 15.1 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[650]2// Copyright (C) 1999-2017  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[109]4
5#ifndef _PARAM_H_
6#define _PARAM_H_
7
8#include <stdio.h>
[247]9#include <stdint.h>
[109]10#include <frams/util/sstring.h>
[784]11#include <frams/util/sstringutils.h>
[109]12#include <frams/util/list.h>
13#include <frams/util/statrick.h>
[382]14#include <common/virtfile/virtfile.h>
[375]15#include <common/log.h>
[109]16
17class ExtValue;
18class ExtObject;
19
20// ParamInterface flags:
[316]21#define PARAM_READONLY       1  //< Param is not able to change this member
22#define PARAM_DONTSAVE       2  //< Param will not save this member
23#define PARAM_SETLEVEL(x) (((x)&3)<<2)  //< internal use
24#define PARAM_LEVEL(x)    (((x)>>2)&3)  //< internal use
25#define PARAM_USERREADONLY  16  //< GUI should not change this member (even if Param can)
26#define PARAM_USERHIDDEN    32  //< GUI should not display this member
27#define MUTPARAM_ALLOCENTRY 64  //< for mutableparam (private!)
28#define MUTPARAM_ALLOCDATA 128  //< for mutableparam (private!)
29#define PARAM_NOSTATIC  256     //< (FramScript) don't access this member in a static object (ClassName.field)
30#define PARAM_CONST     512     //< (FramScript) constant value
[720]31#define PARAM_CANOMITNAME 1024  //< affects Param::saveSingleLine()/loadSingleLine() - for example one-liners in f0 genetic encoding
[316]32#define PARAM_DONTLOAD    2048  //< Param::load() skips this field
33#define PARAM_NOISOLATION 4096  //< don't use proxy object in master/slave interactions
34#define PARAM_DEPRECATED  8192  //< this member is deprecated
[333]35#define PARAM_LINECOMMENT 16384 //< Param::load() adds "@line ..." comment when loading multiline (internal use)
[478]36#define PARAM_OBJECTSET 32768   //< setting this field is handled by the object's assign(...) function and cannot change the object reference
[109]37
[247]38typedef int32_t paInt;
39#define PA_INT_SCANF "%d"
[284]40#define PA_INT_SCANF_X "%x"
[247]41
[154]42// the result of param::set() is a combination of bits:
[109]43
[154]44// read-only: cannot modify
[109]45#define PSET_RONLY      1
46
[154]47// value has been modified
[109]48#define PSET_CHANGED    2
49
[154]50//value has been adjusted because it tried to exceed min or max
[109]51#define PSET_HITMIN     4
52#define PSET_HITMAX     8
53
[393]54#define PSET_NOPROPERTY 16
55
56#define PSET_PARSEFAILED        32
57
[154]58// useful combination: need to get and display the value so that a user knows that the value they tried to set has been rejected or changed
[393]59#define PSET_WARN (PSET_RONLY | PSET_HITMIN | PSET_HITMAX | PSET_PARSEFAILED)
[109]60
61
62struct ParamEntry;
63
64/** Property get/set interface - runtime access to named properties */
65class ParamInterface
66{
67public:
[319]68        virtual ~ParamInterface() {}
69
[154]70        virtual int getGroupCount() = 0; ///< @return the number of property groups
71        virtual int getPropCount() = 0; ///< @return the number of properties
[109]72
[154]73        virtual const char* getName() = 0;
74        virtual const char* getDescription() { return 0; }
75        virtual ParamEntry *getParamTab() const { return NULL; }
[109]76
[154]77        int findId(const char *n);      ///< find id number for internal name
78        int findIdn(const char *naz, int n);
[109]79
[154]80        virtual const char *id(int i) = 0;      ///< get internal name
81        virtual const char *name(int i) = 0;    ///< get the human-readable name
[109]82
[154]83        /** get type description.
84                first character defines basic datatype:
85                - d = integer
86                - f = floating point
87                - s = string
88                - o = ExtObject
89                - x = ExtValue (universal datatype)
90                */
91        virtual const char *type(int i) = 0;
[109]92
[154]93        virtual const char *help(int i) = 0;    ///< get long description (tooltip)
[109]94
[154]95        virtual int flags(int i) = 0;           ///< get flags
[109]96
[154]97        virtual int group(int i) = 0;           ///< get group id for a property
98        virtual const char *grname(int gi) = 0; ///< get group name
99        virtual int grmember(int gi, int n) = 0;        ///< get property id for n'th member of group "gi"
[109]100
[154]101        virtual void call(int i, ExtValue* args, ExtValue *ret) = 0;
[109]102
[154]103        void get(int, ExtValue &retval);        ///< most universal get, can be used for every datatype
[109]104
[154]105        virtual SString getString(int) = 0;     ///< get string value, you can only use this for "s" type property
[247]106        virtual paInt getInt(int) = 0;  ///< get long value, you can only use this for "d" type property
[154]107        virtual double getDouble(int) = 0;      ///< get double value, you can only use this for "f" type property
108        virtual ExtObject getObject(int) = 0;   ///< get object reference, you can only use this for "o" type property
109        virtual ExtValue getExtValue(int) = 0;  ///< get extvalue object, you can only use this for "x" type property
[109]110
[154]111        SString get(int);               ///< old style get, can convert long or double to string
112        SString getText(int);           ///< like getString, returns enumeration label for subtype "d 0 n ~enum1~enum2...
[109]113
[154]114        SString getStringById(const char*prop);  ///< get string value, you can only use this for "s" type property
[247]115        paInt getIntById(const char* prop);    ///< get long value, you can only use this for "d" type property
[154]116        double getDoubleById(const char* prop);///< get double value, you can only use this for "f" type property
117        ExtObject getObjectById(const char* prop);///< get object reference, you can only use this for "o" type property
118        ExtValue getExtValueById(const char* prop);///< get extvalue object, you can only use this for "x" type property
119        ExtValue getById(const char* prop);
[109]120
[743]121        int setIntFromString(int i, const char* str, bool strict = false);
122        int setDoubleFromString(int i, const char* str);
[247]123        virtual int setInt(int, paInt) = 0;             ///< set long value, you can only use this for "d" type prop
[154]124        virtual int setDouble(int, double) = 0; ///< set double value, you can only use this for "f" type prop
125        virtual int setString(int, const SString &) = 0;        ///< set string value, you can only use this for "s" type prop
126        virtual int setObject(int, const ExtObject &) = 0;      ///< set object reference, you can only use this for "o" type prop
127        virtual int setExtValue(int, const ExtValue &) = 0;     ///< 4 in 1
[109]128
[154]129        int set(int, const ExtValue &);///< most universal set, can be used for every datatype
[109]130
[743]131        int setFromString(int, const char*, bool strict = false);               ///< oldstyle set, can convert string to long or double
[109]132
[247]133        int setIntById(const char* prop, paInt);///< set long value, you can only use this for "d" type prop
[154]134        int setDoubleById(const char* prop, double);///< set double value, you can only use this for "f" type prop
135        int setStringById(const char* prop, const SString &);///< set string value, you can only use this for "s" type prop
136        int setObjectById(const char* prop, const ExtObject &);///< set object reference, you can only use this for "o" type prop
137        int setExtValueById(const char* prop, const ExtValue &); ///< for ExtValue types only
138        int setById(const char* prop, const ExtValue &);///< can be used for all property types
[109]139
[154]140        /** get valid minimum, maximum and default value for property 'prop'
141                @return 0 if min/max/def information is not available */
[743]142        int getMinMaxInt(int prop, paInt& minumum, paInt& maximum, paInt& def);
[154]143        /** get valid minimum, maximum and default value for property 'prop'
144                @return 0 if min/max/def information is not available */
[743]145        int getMinMaxDouble(int prop, double& minumum, double& maximum, double& def);
146        int getMinMaxString(int prop, int& minumum, int& maximum, SString& def);
147        static int getMinMaxIntFromTypeDef(const char* type, paInt& minumum, paInt& maximum, paInt& def);
148        static int getMinMaxDoubleFromTypeDef(const char* type, double& minumum, double& maximum, double& def);
149        static int getMinMaxStringFromTypeDef(const char* type, int& minumum, int& maximum, SString& def);
[109]150
[278]151        virtual void setDefault();
152        virtual void setDefault(int i);
[154]153        void setMin();
154        void setMax();
155        void setMin(int i);
156        void setMax(int i);
[109]157
[640]158        /** return the human readable description of the given type */
[743]159        static SString friendlyTypeDescrFromTypeDef(const char* type);
160        SString friendlyTypeDescr(int i) { return friendlyTypeDescrFromTypeDef(type(i)); }
[650]161
[154]162        /** copy all property values from other ParamInterface object */
163        void copyFrom(ParamInterface *src);
[109]164
[154]165        /** Copy all property values from compatible ParamInterface object.
166                This method is more efficient than copyFrom,
167                but can be used only if the other object has the same properties sequence, e.g.:
168                - any two Param objects having common paramtab
169                - any ParamInterface object and the Param with paramtab constructed by ParamObject::makeParamTab
170                */
171        void quickCopyFrom(ParamInterface *src);
[109]172
[720]173        enum FileFormat { FormatMultiLine, FormatSingleLine }; // FormatJSON in the future?
174        struct LoadOptions {
175                bool warn_unknown_fields; bool *abortable; int *linenum; int offset; bool parse_failed;
176                LoadOptions() : warn_unknown_fields(false), abortable(NULL), linenum(NULL), offset(0), parse_failed(false) {}
177        };
178
[745]179        int saveMultiLine(VirtFILE*, const char* altname = NULL, bool force = 0);
[154]180        int saveprop(VirtFILE*, int i, const char* p, bool force = 0);
[109]181
[720]182        int load(FileFormat format, VirtFILE*, LoadOptions *load_options = NULL);///< @return the number of fields loaded
183        int load(FileFormat format, const SString &, LoadOptions *load_options = NULL);///< @return the number of fields loaded
184protected:
185        int loadMultiLine(VirtFILE*, LoadOptions &options);///< @return the number of fields loaded
186        int loadSingleLine(const SString &, LoadOptions &options);///< @return the number of fields loaded
187public:
188
[154]189        static const char* SERIALIZATION_PREFIX;
[230]190
[535]191        static bool isValidTypeDescription(const char* t);
[483]192#ifdef _DEBUG
[230]193        virtual void sanityCheck(int i) {}
194#endif
[109]195};
196
197// implementations:
198
199extern char MakeCodeGuardHappy;
200
201#define PROCOFFSET(_proc_) ( (void (*)(void*,ExtValue*,ExtValue*)) &(FIELDSTRUCT :: _proc_ ## _statrick))
202#define STATICPROCOFFSET(_proc_) ( (void (*)(void*,ExtValue*,ExtValue*)) &(FIELDSTRUCT :: _proc_))
203#define GETOFFSET(_proc_) ( (void (*)(void*,ExtValue*)) &(FIELDSTRUCT :: _proc_ ## _statrick))
204#define SETOFFSET(_proc_) ( (int (*)(void*,const ExtValue*)) &(FIELDSTRUCT :: _proc_ ## _statrick))
205
[247]206#define FIELDOFFSET(_fld_) ((intptr_t)((char*)(&((FIELDSTRUCT*)&MakeCodeGuardHappy)->_fld_)-((char*)((FIELDSTRUCT*)&MakeCodeGuardHappy))))
[109]207
[483]208#ifdef _DEBUG
[247]209#define PARAM_ILLEGAL_OFFSET ((intptr_t)0xdeadbeef)
[230]210#else
211#define PARAM_ILLEGAL_OFFSET 0
212#endif
213
[109]214#define FIELD(_fld_) FIELDOFFSET(_fld_),0,0
215#define LONGOFFSET(_o_) (_o_),0,0
[230]216#define PROCEDURE(_proc_) PARAM_ILLEGAL_OFFSET,(void*)PROCOFFSET(_proc_),0
217#define STATICPROCEDURE(_proc_) PARAM_ILLEGAL_OFFSET,(void*)STATICPROCOFFSET(_proc_),0
218#define GETSET(_proc_) PARAM_ILLEGAL_OFFSET,(void*)GETOFFSET(get_ ## _proc_),(void*)SETOFFSET(set_ ## _proc_)
[109]219#define GETFIELD(_proc_) FIELDOFFSET(_proc_),(void*)GETOFFSET(get_ ## _proc_),0
220#define SETFIELD(_proc_) FIELDOFFSET(_proc_),0,(void*)SETOFFSET(set_ ## _proc_)
[230]221#define GETONLY(_proc_) PARAM_ILLEGAL_OFFSET,(void*)GETOFFSET(get_ ## _proc_),0
222#define SETONLY(_proc_) PARAM_ILLEGAL_OFFSET,0,(void*)SETOFFSET(set_ ## _proc_)
[109]223
224#define PARAMPROCARGS ExtValue* args,ExtValue* ret
225#define PARAMSETARGS const ExtValue* arg
226#define PARAMGETARGS ExtValue* ret
227
228#define PARAMPROCDEF(name) STATRICKDEF2(name,ExtValue*,ExtValue*)
229#define PARAMGETDEF(name) STATRICKDEF1(get_ ## name,ExtValue*)
230#define PARAMSETDEF(name) STATRICKRDEF1(int,set_ ## name,const ExtValue*)
231
232///////////////////////////////
233
234struct ParamEntry
235{
[154]236        const char *id;
[478]237        paInt group, flags;
[154]238        const char *name, *type;
[247]239        intptr_t offset;
[154]240        void *fun1; ///< procedure or get
241        void *fun2; ///< set
242        const char *help;
[109]243};
244
[154]245struct ParamEntryConstructor : public ParamEntry
[109]246{
247public:
[478]248        ParamEntryConstructor(const char *_id, paInt _group = 0, paInt _flags = 0, const char *_name = 0, const char *_type = 0, intptr_t _offset = 0, void *_fun1 = 0, void *_fun2 = 0, const char *_help = 0)
[154]249        {
250                id = _id; group = _group; flags = _flags; name = _name; type = _type; offset = _offset; fun1 = _fun1; fun2 = _fun2; help = _help;
251        }
[109]252};
253
[786]254template<typename T> struct quote_in_messages { constexpr static const char* value = "'"; };
255template<> struct quote_in_messages < SString > { constexpr static const char* value = "\""; };
256template<typename T> struct length_in_messages { static const bool value = false; };
257template<> struct length_in_messages < SString > { static const bool value = true; };
258
[154]259class SimpleAbstractParam : public virtual ParamInterface
[109]260{
261protected:
[154]262        virtual void *getTarget(int i);
263        const char* myname;
264        bool dontcheckchanges;
[109]265
266public:
[154]267        void *object;
[109]268
[154]269        const char* getName() { return myname; }
270        void setName(const char* n) { myname = n; }
[109]271
[154]272        /**
273                @param t ParamEntry table
274                @param o controlled object
275                @param n Param's name
276                */
277        SimpleAbstractParam(void* o = 0, const char*n = 0) :myname(n), dontcheckchanges(0), object(o) {}
278        void setDontCheckChanges(bool x) { dontcheckchanges = x; }
[109]279
[154]280        void select(void *o) { object = o; }
281        void* getSelected() { return object; }
[109]282
[253]283        virtual ParamEntry *entry(int i) = 0;
[154]284        const char *id(int i) { return (i >= getPropCount()) ? 0 : entry(i)->id; }
285        const char *name(int i) { return entry(i)->name; }
286        const char *type(int i) { return entry(i)->type; }
287        const char *help(int i) { return entry(i)->help; }
288        int flags(int i) { return entry(i)->flags; }
289        int group(int i) { return entry(i)->group; }
290        void call(int i, ExtValue* args, ExtValue *ret);
[109]291
[154]292        SString getString(int);
[247]293        paInt getInt(int);
[154]294        double getDouble(int);
295        ExtObject getObject(int);
296        ExtValue getExtValue(int);
[109]297
[154]298        template<typename T> void messageOnExceedRange(int i, int setflags, T valuetoset) ///< prints a warning when setflags indicates that allowed param range has been exceeded during set
299        {
300                if (setflags & (PSET_HITMIN | PSET_HITMAX))
301                {
302                        SString svaluetoset = SString::valueOf(valuetoset); //converts any type to SString
303                        SString actual = get(i);
[784]304                        bool s_type = type(i)[0] == 's';
[786]305                        logPrintf("Param", "set", LOG_WARN, "Setting %s.%s = %s exceeded allowed range (too %s). %s to %s.",
306                                getName(), id(i),
307                                ::sstringDelimitAndShorten(svaluetoset, 30, length_in_messages<T>::value, quote_in_messages<T>::value, quote_in_messages<T>::value).c_str(),
308                                (setflags&PSET_HITMAX) ? (s_type ? "long" : "big") : "small", s_type ? "Truncated" : "Adjusted",
309                                ::sstringDelimitAndShorten(actual, 30, length_in_messages<T>::value, quote_in_messages<T>::value, quote_in_messages<T>::value).c_str()
310                                );
[154]311                }
312        }
[109]313
[247]314        int setInt(int, paInt);
[154]315        int setDouble(int, double);
316        int setString(int, const SString &);
317        int setObject(int, const ExtObject &);
318        int setExtValue(int, const ExtValue &);
[109]319
[154]320        int isequal(int i, void* defdata);
[720]321        void saveSingleLine(SString&, void *defdata, bool addcr = true, bool all_names = true);
[109]322
[278]323        virtual void setDefault();
324        virtual void setDefault(int i);
[230]325
[483]326#ifdef _DEBUG
[230]327        void sanityCheck(int i);
328#endif
[109]329};
330
[154]331class Param : public SimpleAbstractParam
[109]332{
333protected:
[154]334        ParamEntry *entry(int i) { return tab + tab[0].group + i; }
[109]335public:
[154]336        ParamEntry *tab;
337        /**
338                @param t ParamEntry table
339                @param o controlled object
340                @param n Param's name
341                */
[109]342
[154]343        Param(ParamEntry *t = 0, void* o = 0, const char*n = 0) :SimpleAbstractParam(o, n), tab(t)
344        {
345                if (!n&&tab) myname = tab[0].name;
346        }
[109]347
[154]348        Param(const Param& p) :SimpleAbstractParam(p.object, p.myname), tab(p.tab) {}
349        void operator=(const Param&p) { object = p.object; myname = p.myname; tab = p.tab; }
[109]350
[154]351        const char* getDescription() { return tab[0].type; }
[109]352
[154]353        int getGroupCount() { return tab[0].group; }
354        int getPropCount() { return tab[0].flags; }
355        const char *grname(int i) { return (i < getGroupCount()) ? tab[i].id : 0; }
356        int grmember(int, int);
357        void setParamTab(ParamEntry *t, int dontupdatename = 0) { tab = t; if ((!dontupdatename) && tab) myname = tab[0].name; }
358        ParamEntry *getParamTab() const { return tab; }
[109]359};
360
361extern ParamEntry empty_paramtab[];
362
363#endif
Note: See TracBrowser for help on using the repository browser.